OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/debug/trace_event.h" | 5 #include "base/debug/trace_event.h" |
6 #include "skia/ext/analysis_canvas.h" | 6 #include "skia/ext/analysis_canvas.h" |
7 #include "third_party/skia/include/core/SkDevice.h" | 7 #include "third_party/skia/include/core/SkDevice.h" |
8 #include "third_party/skia/include/core/SkDraw.h" | 8 #include "third_party/skia/include/core/SkDraw.h" |
9 #include "third_party/skia/include/core/SkRRect.h" | 9 #include "third_party/skia/include/core/SkRRect.h" |
| 10 #include "third_party/skia/src/core/SkRasterClip.h" |
10 #include "ui/gfx/rect_conversions.h" | 11 #include "ui/gfx/rect_conversions.h" |
11 | 12 |
12 namespace { | 13 namespace { |
13 | 14 |
14 // FIXME: Arbitrary number. Requires tuning & experimentation. | 15 // FIXME: Arbitrary number. Requires tuning & experimentation. |
15 // Probably requires per-platform tuning; N10 average draw call takes | 16 // Probably requires per-platform tuning; N10 average draw call takes |
16 // 25x as long as Z620. | 17 // 25x as long as Z620. |
17 const int gPictureCostThreshold = 1000; | 18 const int gPictureCostThreshold = 1000; |
18 | 19 |
| 20 static bool isSolidColorPaint(const SkPaint& paint) { |
| 21 SkXfermode::Mode xferMode; |
| 22 |
| 23 // getXfermode can return a NULL, but that is handled |
| 24 // gracefully by AsMode (NULL turns into kSrcOver mode). |
| 25 SkXfermode::AsMode(paint.getXfermode(), &xferMode); |
| 26 |
| 27 // Paint is solid color if the following holds: |
| 28 // - Alpha is 1.0, style is fill, and there are no special effects |
| 29 // - Xfer mode is either kSrc or kSrcOver (kSrcOver is equivalent |
| 30 // to kSrc if source alpha is 1.0, which is already checked). |
| 31 return (paint.getAlpha() == 255 && |
| 32 !paint.getShader() && |
| 33 !paint.getLooper() && |
| 34 !paint.getMaskFilter() && |
| 35 !paint.getColorFilter() && |
| 36 paint.getStyle() == SkPaint::kFill_Style && |
| 37 (xferMode == SkXfermode::kSrc_Mode || |
| 38 xferMode == SkXfermode::kSrcOver_Mode)); |
19 } | 39 } |
20 | 40 |
| 41 static bool isFullQuad(const SkDraw& draw, |
| 42 const SkRect& canvasRect, |
| 43 const SkRect& drawnRect) { |
| 44 |
| 45 // If the transform results in a non-axis aligned |
| 46 // rect, then be conservative and return false. |
| 47 if (!draw.fMatrix->rectStaysRect()) |
| 48 return false; |
| 49 |
| 50 SkRect drawBitmapRect; |
| 51 draw.fBitmap->getBounds(&drawBitmapRect); |
| 52 SkRect clipRect = SkRect::Make(draw.fRC->getBounds()); |
| 53 SkRect deviceRect; |
| 54 draw.fMatrix->mapRect(&deviceRect, drawnRect); |
| 55 |
| 56 // The drawn rect covers the full canvas, if the following conditions hold: |
| 57 // - Clip rect is an actual rectangle. |
| 58 // - The rect we're drawing (post-transform) contains the clip rect. |
| 59 // That is, all of clip rect will be colored by the rect. |
| 60 // - Clip rect contains the canvas rect. |
| 61 // That is, we're not clipping to a portion of this canvas. |
| 62 // - The bitmap into which the draw call happens is at least as |
| 63 // big as the canvas rect |
| 64 return draw.fRC->isRect() && |
| 65 deviceRect.contains(clipRect) && |
| 66 clipRect.contains(canvasRect) && |
| 67 drawBitmapRect.contains(canvasRect); |
| 68 } |
| 69 |
| 70 } // namespace |
| 71 |
21 namespace skia { | 72 namespace skia { |
22 | 73 |
23 AnalysisDevice::AnalysisDevice(const SkBitmap& bm) | 74 AnalysisDevice::AnalysisDevice(const SkBitmap& bm) |
24 : INHERITED(bm) | 75 : INHERITED(bm) |
25 , estimatedCost_(0) { | 76 , estimatedCost_(0) |
| 77 , isForcedNotSolid_(false) |
| 78 , isForcedNotTransparent_(false) |
| 79 , isSolidColor_(false) |
| 80 , isTransparent_(false) { |
26 | 81 |
27 } | 82 } |
28 | 83 |
29 AnalysisDevice::~AnalysisDevice() { | 84 AnalysisDevice::~AnalysisDevice() { |
30 | 85 |
31 } | 86 } |
32 | 87 |
33 int AnalysisDevice::getEstimatedCost() const { | 88 int AnalysisDevice::getEstimatedCost() const { |
34 return estimatedCost_; | 89 return estimatedCost_; |
35 } | 90 } |
36 | 91 |
| 92 bool AnalysisDevice::getColorIfSolid(SkColor* color) const { |
| 93 if (isSolidColor_) |
| 94 *color = color_; |
| 95 return isSolidColor_; |
| 96 } |
| 97 |
| 98 bool AnalysisDevice::isTransparent() const { |
| 99 return isTransparent_; |
| 100 } |
| 101 |
| 102 void AnalysisDevice::setForceNotSolid(bool flag) { |
| 103 isForcedNotSolid_ = flag; |
| 104 if (isForcedNotSolid_) |
| 105 isSolidColor_ = false; |
| 106 } |
| 107 |
| 108 void AnalysisDevice::setForceNotTransparent(bool flag) { |
| 109 isForcedNotTransparent_ = flag; |
| 110 if (isForcedNotTransparent_) |
| 111 isTransparent_ = false; |
| 112 } |
| 113 |
37 void AnalysisDevice::clear(SkColor color) { | 114 void AnalysisDevice::clear(SkColor color) { |
38 ++estimatedCost_; | 115 ++estimatedCost_; |
| 116 |
| 117 isTransparent_ = (!isForcedNotTransparent_ && SkColorGetA(color) == 0); |
| 118 |
| 119 if (!isForcedNotSolid_ && SkColorGetA(color) == 255) { |
| 120 isSolidColor_ = true; |
| 121 color_ = color; |
| 122 } |
| 123 else { |
| 124 isSolidColor_ = false; |
| 125 } |
39 } | 126 } |
40 | 127 |
41 void AnalysisDevice::drawPaint(const SkDraw&, const SkPaint& paint) { | 128 void AnalysisDevice::drawPaint(const SkDraw&, const SkPaint& paint) { |
42 ++estimatedCost_; | 129 ++estimatedCost_; |
| 130 isSolidColor_ = false; |
| 131 isTransparent_ = false; |
43 } | 132 } |
44 | 133 |
45 void AnalysisDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode, | 134 void AnalysisDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode, |
46 size_t count, const SkPoint[], | 135 size_t count, const SkPoint[], |
47 const SkPaint& paint) { | 136 const SkPaint& paint) { |
48 ++estimatedCost_; | 137 ++estimatedCost_; |
| 138 isSolidColor_ = false; |
| 139 isTransparent_ = false; |
49 } | 140 } |
50 | 141 |
51 void AnalysisDevice::drawRect(const SkDraw&, const SkRect& r, | 142 void AnalysisDevice::drawRect(const SkDraw& draw, const SkRect& rect, |
52 const SkPaint& paint) { | 143 const SkPaint& paint) { |
| 144 |
53 // FIXME: if there's a pending image decode & resize, more expensive | 145 // FIXME: if there's a pending image decode & resize, more expensive |
54 if (paint.getMaskFilter()) { | 146 if (paint.getMaskFilter()) { |
55 estimatedCost_ += 300; | 147 estimatedCost_ += 300; |
56 } | 148 } |
57 ++estimatedCost_; | 149 ++estimatedCost_; |
| 150 |
| 151 bool doesCoverCanvas = isFullQuad(draw, |
| 152 SkRect::MakeWH(width(), height()), |
| 153 rect); |
| 154 |
| 155 SkXfermode::Mode xferMode; |
| 156 SkXfermode::AsMode(paint.getXfermode(), &xferMode); |
| 157 |
| 158 // This canvas will become transparent if the following holds: |
| 159 // - The quad is a full tile quad |
| 160 // - We're not in "forced not transparent" mode |
| 161 // - Transfer mode is clear (0 color, 0 alpha) |
| 162 // |
| 163 // If the paint alpha is not 0, or if the transfrer mode is |
| 164 // not src, then this canvas will not be transparent. |
| 165 // |
| 166 // In all other cases, we keep the current transparent value |
| 167 if (doesCoverCanvas && |
| 168 !isForcedNotTransparent_ && |
| 169 xferMode == SkXfermode::kClear_Mode) { |
| 170 isTransparent_ = true; |
| 171 } |
| 172 else if (paint.getAlpha() != 0 || |
| 173 xferMode != SkXfermode::kSrc_Mode) { |
| 174 isTransparent_ = false; |
| 175 } |
| 176 |
| 177 // This bitmap is solid if and only if the following holds. |
| 178 // Note that this might be overly conservative: |
| 179 // - We're not in "forced not solid" mode |
| 180 // - Paint is solid color |
| 181 // - The quad is a full tile quad |
| 182 if (!isForcedNotSolid_ && |
| 183 isSolidColorPaint(paint) && |
| 184 doesCoverCanvas) { |
| 185 isSolidColor_ = true; |
| 186 color_ = paint.getColor(); |
| 187 } |
| 188 else { |
| 189 isSolidColor_ = false; |
| 190 } |
58 } | 191 } |
59 | 192 |
60 void AnalysisDevice::drawOval(const SkDraw&, const SkRect& oval, | 193 void AnalysisDevice::drawOval(const SkDraw&, const SkRect& oval, |
61 const SkPaint& paint) { | 194 const SkPaint& paint) { |
62 ++estimatedCost_; | 195 ++estimatedCost_; |
| 196 isSolidColor_ = false; |
| 197 isTransparent_ = false; |
63 } | 198 } |
64 | 199 |
65 void AnalysisDevice::drawPath(const SkDraw&, const SkPath& path, | 200 void AnalysisDevice::drawPath(const SkDraw&, const SkPath& path, |
66 const SkPaint& paint, | 201 const SkPaint& paint, |
67 const SkMatrix* prePathMatrix , | 202 const SkMatrix* prePathMatrix , |
68 bool pathIsMutable ) { | 203 bool pathIsMutable ) { |
69 // On Z620, every antialiased path costs us about 300us. | 204 // On Z620, every antialiased path costs us about 300us. |
70 // We've only seen this in practice on filled paths, but | 205 // We've only seen this in practice on filled paths, but |
71 // we expect it to apply to all path stroking modes. | 206 // we expect it to apply to all path stroking modes. |
72 if (paint.getMaskFilter()) { | 207 if (paint.getMaskFilter()) { |
73 estimatedCost_ += 300; | 208 estimatedCost_ += 300; |
74 } | 209 } |
75 ++estimatedCost_; | 210 ++estimatedCost_; |
| 211 isSolidColor_ = false; |
| 212 isTransparent_ = false; |
76 } | 213 } |
77 | 214 |
78 void AnalysisDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, | 215 void AnalysisDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, |
79 const SkIRect* srcRectOrNull, | 216 const SkIRect* srcRectOrNull, |
80 const SkMatrix& matrix, const SkPaint& paint) | 217 const SkMatrix& matrix, const SkPaint& paint) { |
81 { | |
82 ++estimatedCost_; | 218 ++estimatedCost_; |
| 219 isSolidColor_ = false; |
| 220 isTransparent_ = false; |
83 } | 221 } |
84 | 222 |
85 void AnalysisDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, | 223 void AnalysisDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, |
86 int x, int y, const SkPaint& paint) { | 224 int x, int y, const SkPaint& paint) { |
87 ++estimatedCost_; | 225 ++estimatedCost_; |
| 226 isSolidColor_ = false; |
| 227 isTransparent_ = false; |
88 } | 228 } |
89 | 229 |
90 void AnalysisDevice::drawBitmapRect(const SkDraw&, const SkBitmap&, | 230 void AnalysisDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap&, |
91 const SkRect* srcOrNull, const SkRect& dst, | 231 const SkRect* srcOrNull, const SkRect& dst, |
92 const SkPaint& paint) { | 232 const SkPaint& paint) { |
93 ++estimatedCost_; | 233 ++estimatedCost_; |
| 234 |
| 235 // Call drawRect to determine transparency, |
| 236 // but reset solid color to false. |
| 237 drawRect(draw, dst, paint); |
| 238 isSolidColor_ = false; |
94 } | 239 } |
95 | 240 |
96 | 241 |
97 void AnalysisDevice::drawText(const SkDraw&, const void* text, size_t len, | 242 void AnalysisDevice::drawText(const SkDraw&, const void* text, size_t len, |
98 SkScalar x, SkScalar y, const SkPaint& paint) | 243 SkScalar x, SkScalar y, const SkPaint& paint) { |
99 { | |
100 ++estimatedCost_; | 244 ++estimatedCost_; |
| 245 isSolidColor_ = false; |
| 246 isTransparent_ = false; |
101 } | 247 } |
102 | 248 |
103 void AnalysisDevice::drawPosText(const SkDraw& draw, const void* text, size_t le
n, | 249 void AnalysisDevice::drawPosText(const SkDraw& draw, const void* text, size_t le
n, |
104 const SkScalar pos[], SkScalar constY, | 250 const SkScalar pos[], SkScalar constY, |
105 int scalarsPerPos, const SkPaint& paint) { | 251 int scalarsPerPos, const SkPaint& paint) { |
106 // FIXME: On Z620, every glyph cache miss costs us about 10us. | 252 // FIXME: On Z620, every glyph cache miss costs us about 10us. |
107 // We don't have a good mechanism for predicting glyph cache misses. | 253 // We don't have a good mechanism for predicting glyph cache misses. |
108 ++estimatedCost_; | 254 ++estimatedCost_; |
| 255 isSolidColor_ = false; |
| 256 isTransparent_ = false; |
109 } | 257 } |
110 | 258 |
111 void AnalysisDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, | 259 void AnalysisDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, |
112 const SkPath& path, const SkMatrix* matrix, | 260 const SkPath& path, const SkMatrix* matrix, |
113 const SkPaint& paint) { | 261 const SkPaint& paint) { |
114 ++estimatedCost_; | 262 ++estimatedCost_; |
| 263 isSolidColor_ = false; |
| 264 isTransparent_ = false; |
115 } | 265 } |
116 | 266 |
117 #ifdef SK_BUILD_FOR_ANDROID | 267 #ifdef SK_BUILD_FOR_ANDROID |
118 void AnalysisDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, | 268 void AnalysisDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, |
119 size_t len, | 269 size_t len, |
120 const SkPoint pos[], const SkPaint& paint, | 270 const SkPoint pos[], const SkPaint& paint, |
121 const SkPath& path, const SkMatrix* matrix) | 271 const SkPath& path, const SkMatrix* matrix) { |
122 { | |
123 ++estimatedCost_; | 272 ++estimatedCost_; |
| 273 isSolidColor_ = false; |
| 274 isTransparent_ = false; |
124 } | 275 } |
125 #endif | 276 #endif |
126 | 277 |
127 void AnalysisDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, | 278 void AnalysisDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, |
128 int vertexCount, | 279 int vertexCount, |
129 const SkPoint verts[], const SkPoint texs[], | 280 const SkPoint verts[], const SkPoint texs[], |
130 const SkColor colors[], SkXfermode* xmode, | 281 const SkColor colors[], SkXfermode* xmode, |
131 const uint16_t indices[], int indexCount, | 282 const uint16_t indices[], int indexCount, |
132 const SkPaint& paint) { | 283 const SkPaint& paint) { |
133 ++estimatedCost_; | 284 ++estimatedCost_; |
| 285 isSolidColor_ = false; |
| 286 isTransparent_ = false; |
134 } | 287 } |
135 | 288 |
136 void AnalysisDevice::drawDevice(const SkDraw&, SkDevice*, int x, int y, | 289 void AnalysisDevice::drawDevice(const SkDraw&, SkDevice*, int x, int y, |
137 const SkPaint&) { | 290 const SkPaint&) { |
138 ++estimatedCost_; | 291 ++estimatedCost_; |
| 292 isSolidColor_ = false; |
| 293 isTransparent_ = false; |
139 } | 294 } |
140 | 295 |
141 | 296 |
142 | 297 const int AnalysisCanvas::kNoLayer = -1; |
143 | 298 |
144 AnalysisCanvas::AnalysisCanvas(AnalysisDevice* device) | 299 AnalysisCanvas::AnalysisCanvas(AnalysisDevice* device) |
145 : INHERITED(device) { | 300 : INHERITED(device) |
146 | 301 , savedStackSize_(0) |
| 302 , forceNotSolidStackLevel_(kNoLayer) |
| 303 , forceNotTransparentStackLevel_(kNoLayer) { |
147 } | 304 } |
148 | 305 |
149 AnalysisCanvas::~AnalysisCanvas() { | 306 AnalysisCanvas::~AnalysisCanvas() { |
150 } | 307 } |
151 | 308 |
152 | 309 |
153 bool AnalysisCanvas::isCheap() const { | 310 bool AnalysisCanvas::isCheap() const { |
154 return getEstimatedCost() < gPictureCostThreshold; | 311 return getEstimatedCost() < gPictureCostThreshold; |
155 } | 312 } |
156 | 313 |
| 314 bool AnalysisCanvas::getColorIfSolid(SkColor* color) const { |
| 315 return (static_cast<AnalysisDevice*>(getDevice()))->getColorIfSolid(color); |
| 316 } |
| 317 |
| 318 bool AnalysisCanvas::isTransparent() const { |
| 319 return (static_cast<AnalysisDevice*>(getDevice()))->isTransparent(); |
| 320 } |
| 321 |
157 int AnalysisCanvas::getEstimatedCost() const { | 322 int AnalysisCanvas::getEstimatedCost() const { |
158 return (static_cast<AnalysisDevice*>(getDevice()))->getEstimatedCost(); | 323 return (static_cast<AnalysisDevice*>(getDevice()))->getEstimatedCost(); |
159 } | 324 } |
160 | 325 |
161 | |
162 bool AnalysisCanvas::clipRect(const SkRect& rect, SkRegion::Op op, | 326 bool AnalysisCanvas::clipRect(const SkRect& rect, SkRegion::Op op, |
163 bool doAA) { | 327 bool doAA) { |
164 return INHERITED::clipRect(rect, op, doAA); | 328 return INHERITED::clipRect(rect, op, doAA); |
165 } | 329 } |
166 | 330 |
167 bool AnalysisCanvas::clipPath(const SkPath& path, SkRegion::Op op, | 331 bool AnalysisCanvas::clipPath(const SkPath& path, SkRegion::Op op, |
168 bool doAA) { | 332 bool doAA) { |
| 333 // clipPaths can make our calls to isFullQuad invalid (ie have false |
| 334 // positives). As a precaution, force the setting to be non-solid |
| 335 // and non-transparent until we pop this |
| 336 if (forceNotSolidStackLevel_ == kNoLayer) { |
| 337 forceNotSolidStackLevel_ = savedStackSize_; |
| 338 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(true); |
| 339 } |
| 340 if (forceNotTransparentStackLevel_ == kNoLayer) { |
| 341 forceNotTransparentStackLevel_ = savedStackSize_; |
| 342 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(true); |
| 343 } |
| 344 |
169 return INHERITED::clipRect(path.getBounds(), op, doAA); | 345 return INHERITED::clipRect(path.getBounds(), op, doAA); |
170 } | 346 } |
171 | 347 |
172 bool AnalysisCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, | 348 bool AnalysisCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, |
173 bool doAA) { | 349 bool doAA) { |
| 350 // clipRRect can make our calls to isFullQuad invalid (ie have false |
| 351 // positives). As a precaution, force the setting to be non-solid |
| 352 // and non-transparent until we pop this |
| 353 if (forceNotSolidStackLevel_ == kNoLayer) { |
| 354 forceNotSolidStackLevel_ = savedStackSize_; |
| 355 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(true); |
| 356 } |
| 357 if (forceNotTransparentStackLevel_ == kNoLayer) { |
| 358 forceNotTransparentStackLevel_ = savedStackSize_; |
| 359 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(true); |
| 360 } |
| 361 |
174 return INHERITED::clipRect(rrect.getBounds(), op, doAA); | 362 return INHERITED::clipRect(rrect.getBounds(), op, doAA); |
175 } | 363 } |
176 | 364 |
177 int AnalysisCanvas::saveLayer(const SkRect* bounds, const SkPaint*, | 365 int AnalysisCanvas::save(SkCanvas::SaveFlags flags) { |
| 366 ++savedStackSize_; |
| 367 return INHERITED::save(flags); |
| 368 } |
| 369 |
| 370 int AnalysisCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, |
178 SkCanvas::SaveFlags flags) { | 371 SkCanvas::SaveFlags flags) { |
| 372 ++savedStackSize_; |
| 373 |
| 374 // If after we draw to the saved layer, we have to blend with the current |
| 375 // layer, then we can conservatively say that the canvas will not be of |
| 376 // solid color. |
| 377 if ((paint && !isSolidColorPaint(*paint)) || |
| 378 (bounds && !bounds->contains( |
| 379 SkRect::MakeWH(getDevice()->width(), getDevice()->height())))) { |
| 380 if (forceNotSolidStackLevel_ == kNoLayer) { |
| 381 forceNotSolidStackLevel_ = savedStackSize_; |
| 382 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(true); |
| 383 } |
| 384 } |
| 385 |
| 386 // If after we draw to the save layer, we have to blend with the current |
| 387 // layer using any part of the current layer's alpha, then we can |
| 388 // conservatively say that the canvas will not be transparent. |
| 389 SkXfermode::Mode xferMode = SkXfermode::kSrc_Mode; |
| 390 if (paint) |
| 391 SkXfermode::AsMode(paint->getXfermode(), &xferMode); |
| 392 if (xferMode != SkXfermode::kSrc_Mode) { |
| 393 if (forceNotTransparentStackLevel_ == kNoLayer) { |
| 394 forceNotTransparentStackLevel_ = savedStackSize_; |
| 395 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(true); |
| 396 } |
| 397 } |
| 398 |
179 // Actually saving a layer here could cause a new bitmap to be created | 399 // Actually saving a layer here could cause a new bitmap to be created |
180 // and real rendering to occur. | 400 // and real rendering to occur. |
181 int count = SkCanvas::save(flags); | 401 int count = INHERITED::save(flags); |
182 if (bounds) { | 402 if (bounds) { |
183 INHERITED::clipRectBounds(bounds, flags, NULL); | 403 INHERITED::clipRectBounds(bounds, flags, NULL); |
184 } | 404 } |
185 return count; | 405 return count; |
186 } | 406 } |
187 | 407 |
| 408 void AnalysisCanvas::restore() { |
| 409 INHERITED::restore(); |
| 410 |
| 411 DCHECK(savedStackSize_); |
| 412 if (savedStackSize_) { |
| 413 --savedStackSize_; |
| 414 if (savedStackSize_ < forceNotSolidStackLevel_) { |
| 415 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(false); |
| 416 forceNotSolidStackLevel_ = kNoLayer; |
| 417 } |
| 418 if (savedStackSize_ < forceNotTransparentStackLevel_) { |
| 419 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(false)
; |
| 420 forceNotTransparentStackLevel_ = kNoLayer; |
| 421 } |
| 422 } |
| 423 } |
| 424 |
188 } // namespace skia | 425 } // namespace skia |
189 | 426 |
190 | 427 |
OLD | NEW |