Chromium Code Reviews| 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 } // namespace | |
| 42 | |
| 21 namespace skia { | 43 namespace skia { |
| 22 | 44 |
| 23 AnalysisDevice::AnalysisDevice(const SkBitmap& bm) | 45 AnalysisDevice::AnalysisDevice(const SkBitmap& bm) |
| 24 : INHERITED(bm) | 46 : INHERITED(bm) |
| 25 , estimatedCost_(0) { | 47 , estimatedCost_(0) |
| 48 , isForcedNotSolid_(false) | |
| 49 , isForcedNotTransparent_(false) | |
| 50 , isSolidColor_(false) | |
| 51 , isTransparent_(false) { | |
| 26 | 52 |
| 27 } | 53 } |
| 28 | 54 |
| 29 AnalysisDevice::~AnalysisDevice() { | 55 AnalysisDevice::~AnalysisDevice() { |
| 30 | |
|
Tom Hudson
2013/02/27 14:49:36
Nit: Is this whitespace change dictated by the Chr
| |
| 31 } | 56 } |
| 32 | 57 |
| 33 int AnalysisDevice::getEstimatedCost() const { | 58 int AnalysisDevice::getEstimatedCost() const { |
| 34 return estimatedCost_; | 59 return estimatedCost_; |
| 35 } | 60 } |
| 36 | 61 |
| 62 bool AnalysisDevice::getColorIfSolid(SkColor* color) const { | |
| 63 if (isSolidColor_) | |
| 64 *color = color_; | |
| 65 return isSolidColor_; | |
| 66 } | |
| 67 | |
| 68 bool AnalysisDevice::isTransparent() const { | |
| 69 return isTransparent_; | |
| 70 } | |
| 71 | |
| 72 void AnalysisDevice::setForceNotSolid(bool flag) { | |
| 73 isForcedNotSolid_ = flag; | |
| 74 if (isForcedNotSolid_) | |
| 75 isSolidColor_ = false; | |
| 76 } | |
| 77 | |
| 78 void AnalysisDevice::setForceNotTransparent(bool flag) { | |
| 79 isForcedNotTransparent_ = flag; | |
| 80 if (isForcedNotTransparent_) | |
| 81 isTransparent_ = false; | |
| 82 } | |
| 83 | |
| 37 void AnalysisDevice::clear(SkColor color) { | 84 void AnalysisDevice::clear(SkColor color) { |
| 38 ++estimatedCost_; | 85 ++estimatedCost_; |
| 86 | |
| 87 isTransparent_ = (!isForcedNotTransparent_ && SkColorGetA(color) == 0); | |
| 88 | |
| 89 if (!isForcedNotSolid_ && SkColorGetA(color) == 255) { | |
| 90 isSolidColor_ = true; | |
| 91 color_ = color; | |
| 92 } | |
| 93 else { | |
| 94 isSolidColor_ = false; | |
| 95 } | |
| 39 } | 96 } |
| 40 | 97 |
| 41 void AnalysisDevice::drawPaint(const SkDraw&, const SkPaint& paint) { | 98 void AnalysisDevice::drawPaint(const SkDraw&, const SkPaint& paint) { |
| 42 ++estimatedCost_; | 99 ++estimatedCost_; |
| 100 isSolidColor_ = false; | |
| 101 isTransparent_ = false; | |
| 43 } | 102 } |
| 44 | 103 |
| 45 void AnalysisDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode, | 104 void AnalysisDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode, |
| 46 size_t count, const SkPoint[], | 105 size_t count, const SkPoint[], |
| 47 const SkPaint& paint) { | 106 const SkPaint& paint) { |
| 48 ++estimatedCost_; | 107 ++estimatedCost_; |
| 108 isSolidColor_ = false; | |
| 109 isTransparent_ = false; | |
| 49 } | 110 } |
| 50 | 111 |
| 51 void AnalysisDevice::drawRect(const SkDraw&, const SkRect& r, | 112 void AnalysisDevice::drawRect(const SkDraw& draw, const SkRect& rect, |
| 52 const SkPaint& paint) { | 113 const SkPaint& paint) { |
| 114 | |
| 53 // FIXME: if there's a pending image decode & resize, more expensive | 115 // FIXME: if there's a pending image decode & resize, more expensive |
| 54 if (paint.getMaskFilter()) { | 116 if (paint.getMaskFilter()) { |
| 55 estimatedCost_ += 300; | 117 estimatedCost_ += 300; |
| 56 } | 118 } |
| 57 ++estimatedCost_; | 119 ++estimatedCost_; |
| 120 | |
| 121 SkRect drawBitmapRect; | |
| 122 draw.fBitmap->getBounds(&drawBitmapRect); | |
| 123 SkRect clipRect = SkRect::Make(draw.fRC->getBounds()); | |
| 124 SkRect canvasRect = SkRect::MakeWH(width(), height()); | |
| 125 SkRect deviceRect; | |
| 126 draw.fMatrix->mapRect(&deviceRect, rect); | |
| 127 | |
| 128 | |
| 129 // This draw is equivalent to clear(), if the following conditions hold: | |
| 130 // - Clip rect is an actual rectangle. | |
| 131 // - The rect we're drawing (post-transform) contains the clip rect. | |
| 132 // That is, all of clip rect will be colored by the rect. | |
| 133 // - Clip rect contains the canvas rect. | |
| 134 // That is, we're not clipping to a portion of this canvas. | |
| 135 bool isFullQuad = (draw.fRC->isRect() && | |
| 136 deviceRect.contains(clipRect) && | |
| 137 clipRect.contains(canvasRect) && | |
| 138 drawBitmapRect.contains(canvasRect)); | |
| 139 | |
| 140 SkXfermode::Mode xferMode; | |
| 141 SkXfermode::AsMode(paint.getXfermode(), &xferMode); | |
| 142 | |
| 143 // This canvas will become transparent if the following holds: | |
| 144 // - The quad is a full tile quad | |
| 145 // - We're not in "forced not transparent" mode | |
| 146 // - Transfer mode is clear (0 color, 0 alpha) | |
| 147 // | |
| 148 // If the paint alpha is not 0, or if the transfrer mode is | |
| 149 // not src, then this canvas will not be transparent. | |
| 150 // | |
| 151 // In all other cases, we keep the current transparent value | |
| 152 if (isFullQuad && | |
| 153 !isForcedNotTransparent_ && | |
| 154 xferMode == SkXfermode::kClear_Mode) { | |
| 155 isTransparent_ = true; | |
| 156 } | |
| 157 else if (paint.getAlpha() != 0 || | |
| 158 xferMode != SkXfermode::kSrc_Mode) { | |
| 159 isTransparent_ = false; | |
| 160 } | |
| 161 | |
| 162 // This bitmap is solid if and only if the following holds. | |
| 163 // Note that this might be overly conservative: | |
| 164 // - We're not in "forced not solid" mode | |
| 165 // - Paint is solid color | |
| 166 // - The quad is a full tile quad | |
| 167 if (!isForcedNotSolid_ && | |
| 168 isSolidColorPaint(paint) && | |
| 169 isFullQuad) { | |
| 170 isSolidColor_ = true; | |
| 171 color_ = paint.getColor(); | |
| 172 } | |
| 173 else { | |
| 174 isSolidColor_ = false; | |
| 175 } | |
| 58 } | 176 } |
| 59 | 177 |
| 60 void AnalysisDevice::drawOval(const SkDraw&, const SkRect& oval, | 178 void AnalysisDevice::drawOval(const SkDraw&, const SkRect& oval, |
| 61 const SkPaint& paint) { | 179 const SkPaint& paint) { |
| 62 ++estimatedCost_; | 180 ++estimatedCost_; |
| 181 isSolidColor_ = false; | |
| 182 isTransparent_ = false; | |
| 63 } | 183 } |
| 64 | 184 |
| 65 void AnalysisDevice::drawPath(const SkDraw&, const SkPath& path, | 185 void AnalysisDevice::drawPath(const SkDraw&, const SkPath& path, |
| 66 const SkPaint& paint, | 186 const SkPaint& paint, |
| 67 const SkMatrix* prePathMatrix , | 187 const SkMatrix* prePathMatrix , |
| 68 bool pathIsMutable ) { | 188 bool pathIsMutable ) { |
| 69 // On Z620, every antialiased path costs us about 300us. | 189 // On Z620, every antialiased path costs us about 300us. |
| 70 // We've only seen this in practice on filled paths, but | 190 // We've only seen this in practice on filled paths, but |
| 71 // we expect it to apply to all path stroking modes. | 191 // we expect it to apply to all path stroking modes. |
| 72 if (paint.getMaskFilter()) { | 192 if (paint.getMaskFilter()) { |
| 73 estimatedCost_ += 300; | 193 estimatedCost_ += 300; |
| 74 } | 194 } |
| 75 ++estimatedCost_; | 195 ++estimatedCost_; |
| 196 isSolidColor_ = false; | |
| 197 isTransparent_ = false; | |
| 76 } | 198 } |
| 77 | 199 |
| 78 void AnalysisDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, | 200 void AnalysisDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, |
| 79 const SkIRect* srcRectOrNull, | 201 const SkIRect* srcRectOrNull, |
| 80 const SkMatrix& matrix, const SkPaint& paint) | 202 const SkMatrix& matrix, const SkPaint& paint) { |
| 81 { | |
| 82 ++estimatedCost_; | 203 ++estimatedCost_; |
| 204 isSolidColor_ = false; | |
| 205 isTransparent_ = false; | |
| 83 } | 206 } |
| 84 | 207 |
| 85 void AnalysisDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, | 208 void AnalysisDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, |
| 86 int x, int y, const SkPaint& paint) { | 209 int x, int y, const SkPaint& paint) { |
| 87 ++estimatedCost_; | 210 ++estimatedCost_; |
| 211 isSolidColor_ = false; | |
| 212 isTransparent_ = false; | |
| 88 } | 213 } |
| 89 | 214 |
| 90 void AnalysisDevice::drawBitmapRect(const SkDraw&, const SkBitmap&, | 215 void AnalysisDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap&, |
| 91 const SkRect* srcOrNull, const SkRect& dst, | 216 const SkRect* srcOrNull, const SkRect& rect, |
|
Tom Hudson
2013/02/27 14:49:36
Nit: I think you've changed this parameter name fr
| |
| 92 const SkPaint& paint) { | 217 const SkPaint& paint) { |
| 93 ++estimatedCost_; | 218 ++estimatedCost_; |
| 219 isSolidColor_ = false; | |
| 220 | |
| 221 SkRect drawBitmapRect; | |
| 222 draw.fBitmap->getBounds(&drawBitmapRect); | |
| 223 SkRect clipRect = SkRect::Make(draw.fRC->getBounds()); | |
| 224 SkRect bitmapRect = SkRect::MakeWH(width(), height()); | |
| 225 SkRect deviceRect; | |
| 226 draw.fMatrix->mapRect(&deviceRect, rect); | |
| 227 | |
| 228 // This draw is equivalent to clear(), if the following conditions hold: | |
|
Tom Hudson
2013/02/27 14:49:36
Both of these clauses are duplicated from drawRect
| |
| 229 // - Clip rect is an actual rectangle. | |
| 230 // - The rect we're drawing (post-transform) contains the clip rect. | |
| 231 // That is, all of clip rect will be colored by the rect. | |
| 232 // - Clip rect contains the canvas rect. | |
| 233 // That is, we're not clipping to a portion of this canvas. | |
| 234 bool isFullQuad = (draw.fRC->isRect() && | |
| 235 deviceRect.contains(clipRect) && | |
| 236 clipRect.contains(bitmapRect) && | |
| 237 drawBitmapRect.contains(bitmapRect)); | |
| 238 | |
| 239 SkXfermode::Mode xferMode; | |
| 240 SkXfermode::AsMode(paint.getXfermode(), &xferMode); | |
| 241 | |
| 242 // This canvas will become transparent if the following holds: | |
| 243 // - The quad is a full tile quad | |
| 244 // - We're not in "forced not transparent" mode | |
| 245 // - Transfer mode is clear (0 color, 0 alpha) | |
| 246 // | |
| 247 // If the paint alpha is not 0, or if the transfrer mode is | |
| 248 // not src, then this canvas will not be transparent. | |
| 249 // | |
| 250 // In all other cases, we keep the current transparent value | |
| 251 if (isFullQuad && | |
| 252 !isForcedNotTransparent_ && | |
| 253 xferMode == SkXfermode::kClear_Mode) { | |
| 254 isTransparent_ = true; | |
| 255 } | |
| 256 else if (paint.getAlpha() != 0 || | |
| 257 xferMode != SkXfermode::kSrc_Mode) { | |
| 258 isTransparent_ = false; | |
| 259 } | |
| 94 } | 260 } |
| 95 | 261 |
| 96 | 262 |
| 97 void AnalysisDevice::drawText(const SkDraw&, const void* text, size_t len, | 263 void AnalysisDevice::drawText(const SkDraw&, const void* text, size_t len, |
| 98 SkScalar x, SkScalar y, const SkPaint& paint) | 264 SkScalar x, SkScalar y, const SkPaint& paint) { |
| 99 { | |
| 100 ++estimatedCost_; | 265 ++estimatedCost_; |
| 266 isSolidColor_ = false; | |
| 267 isTransparent_ = false; | |
| 101 } | 268 } |
| 102 | 269 |
| 103 void AnalysisDevice::drawPosText(const SkDraw& draw, const void* text, size_t le n, | 270 void AnalysisDevice::drawPosText(const SkDraw& draw, const void* text, size_t le n, |
| 104 const SkScalar pos[], SkScalar constY, | 271 const SkScalar pos[], SkScalar constY, |
| 105 int scalarsPerPos, const SkPaint& paint) { | 272 int scalarsPerPos, const SkPaint& paint) { |
| 106 // FIXME: On Z620, every glyph cache miss costs us about 10us. | 273 // FIXME: On Z620, every glyph cache miss costs us about 10us. |
| 107 // We don't have a good mechanism for predicting glyph cache misses. | 274 // We don't have a good mechanism for predicting glyph cache misses. |
| 108 ++estimatedCost_; | 275 ++estimatedCost_; |
| 276 isSolidColor_ = false; | |
| 277 isTransparent_ = false; | |
| 109 } | 278 } |
| 110 | 279 |
| 111 void AnalysisDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, | 280 void AnalysisDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, |
| 112 const SkPath& path, const SkMatrix* matrix, | 281 const SkPath& path, const SkMatrix* matrix, |
| 113 const SkPaint& paint) { | 282 const SkPaint& paint) { |
| 114 ++estimatedCost_; | 283 ++estimatedCost_; |
| 284 isSolidColor_ = false; | |
| 285 isTransparent_ = false; | |
| 115 } | 286 } |
| 116 | 287 |
| 117 #ifdef SK_BUILD_FOR_ANDROID | 288 #ifdef SK_BUILD_FOR_ANDROID |
| 118 void AnalysisDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, | 289 void AnalysisDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, |
| 119 size_t len, | 290 size_t len, |
| 120 const SkPoint pos[], const SkPaint& paint, | 291 const SkPoint pos[], const SkPaint& paint, |
| 121 const SkPath& path, const SkMatrix* matrix) | 292 const SkPath& path, const SkMatrix* matrix) { |
| 122 { | |
| 123 ++estimatedCost_; | 293 ++estimatedCost_; |
| 294 isSolidColor_ = false; | |
| 295 isTransparent_ = false; | |
| 124 } | 296 } |
| 125 #endif | 297 #endif |
| 126 | 298 |
| 127 void AnalysisDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, | 299 void AnalysisDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, |
| 128 int vertexCount, | 300 int vertexCount, |
| 129 const SkPoint verts[], const SkPoint texs[], | 301 const SkPoint verts[], const SkPoint texs[], |
| 130 const SkColor colors[], SkXfermode* xmode, | 302 const SkColor colors[], SkXfermode* xmode, |
| 131 const uint16_t indices[], int indexCount, | 303 const uint16_t indices[], int indexCount, |
| 132 const SkPaint& paint) { | 304 const SkPaint& paint) { |
| 133 ++estimatedCost_; | 305 ++estimatedCost_; |
| 306 isSolidColor_ = false; | |
| 307 isTransparent_ = false; | |
| 134 } | 308 } |
| 135 | 309 |
| 136 void AnalysisDevice::drawDevice(const SkDraw&, SkDevice*, int x, int y, | 310 void AnalysisDevice::drawDevice(const SkDraw&, SkDevice*, int x, int y, |
| 137 const SkPaint&) { | 311 const SkPaint&) { |
| 138 ++estimatedCost_; | 312 ++estimatedCost_; |
| 313 isSolidColor_ = false; | |
| 314 isTransparent_ = false; | |
| 139 } | 315 } |
| 140 | 316 |
| 141 | 317 |
| 142 | 318 |
| 143 | |
| 144 AnalysisCanvas::AnalysisCanvas(AnalysisDevice* device) | 319 AnalysisCanvas::AnalysisCanvas(AnalysisDevice* device) |
| 145 : INHERITED(device) { | 320 : INHERITED(device) |
| 146 | 321 , savedLayerStackSize_(0) { |
| 147 } | 322 } |
| 148 | 323 |
| 149 AnalysisCanvas::~AnalysisCanvas() { | 324 AnalysisCanvas::~AnalysisCanvas() { |
| 150 } | 325 } |
| 151 | 326 |
| 152 | 327 |
| 153 bool AnalysisCanvas::isCheap() const { | 328 bool AnalysisCanvas::isCheap() const { |
| 154 return getEstimatedCost() < gPictureCostThreshold; | 329 return getEstimatedCost() < gPictureCostThreshold; |
| 155 } | 330 } |
| 156 | 331 |
| 332 bool AnalysisCanvas::getColorIfSolid(SkColor* color) const { | |
| 333 return (static_cast<AnalysisDevice*>(getDevice()))->getColorIfSolid(color); | |
| 334 } | |
| 335 | |
| 336 bool AnalysisCanvas::isTransparent() const { | |
| 337 return (static_cast<AnalysisDevice*>(getDevice()))->isTransparent(); | |
| 338 } | |
| 339 | |
| 157 int AnalysisCanvas::getEstimatedCost() const { | 340 int AnalysisCanvas::getEstimatedCost() const { |
| 158 return (static_cast<AnalysisDevice*>(getDevice()))->getEstimatedCost(); | 341 return (static_cast<AnalysisDevice*>(getDevice()))->getEstimatedCost(); |
| 159 } | 342 } |
| 160 | 343 |
| 161 | |
| 162 bool AnalysisCanvas::clipRect(const SkRect& rect, SkRegion::Op op, | 344 bool AnalysisCanvas::clipRect(const SkRect& rect, SkRegion::Op op, |
| 163 bool doAA) { | 345 bool doAA) { |
| 164 return INHERITED::clipRect(rect, op, doAA); | 346 return INHERITED::clipRect(rect, op, doAA); |
| 165 } | 347 } |
| 166 | 348 |
| 167 bool AnalysisCanvas::clipPath(const SkPath& path, SkRegion::Op op, | 349 bool AnalysisCanvas::clipPath(const SkPath& path, SkRegion::Op op, |
| 168 bool doAA) { | 350 bool doAA) { |
| 169 return INHERITED::clipRect(path.getBounds(), op, doAA); | 351 return INHERITED::clipRect(path.getBounds(), op, doAA); |
| 170 } | 352 } |
| 171 | 353 |
| 172 bool AnalysisCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, | 354 bool AnalysisCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, |
| 173 bool doAA) { | 355 bool doAA) { |
| 174 return INHERITED::clipRect(rrect.getBounds(), op, doAA); | 356 return INHERITED::clipRect(rrect.getBounds(), op, doAA); |
| 175 } | 357 } |
| 176 | 358 |
| 177 int AnalysisCanvas::saveLayer(const SkRect* bounds, const SkPaint*, | 359 int AnalysisCanvas::save(SkCanvas::SaveFlags flags) { |
| 360 INHERITED::save(flags); | |
| 361 } | |
| 362 | |
| 363 int AnalysisCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, | |
| 178 SkCanvas::SaveFlags flags) { | 364 SkCanvas::SaveFlags flags) { |
| 365 // If after we draw to the saved layer, we have to blend with the current | |
| 366 // layer, then we can conservatively say that the canvas will not be of | |
| 367 // solid color. | |
|
Tom Hudson
2013/02/27 14:49:36
Thanks for adding these explanations.
| |
| 368 if ((paint && !isSolidColorPaint(*paint)) || | |
| 369 (bounds && !bounds->contains( | |
| 370 SkRect::MakeWH(getDevice()->width(), getDevice()->height())))) | |
| 371 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(true); | |
| 372 | |
| 373 // If after we draw to the save layer, we have to blend with the current | |
| 374 // layer using any part of the current layer's alpha, then we can | |
| 375 // conservatively say that the canvas will not be transparent. | |
| 376 SkXfermode::Mode xferMode = SkXfermode::kSrc_Mode; | |
| 377 if (paint) | |
| 378 SkXfermode::AsMode(paint->getXfermode(), &xferMode); | |
| 379 if (xferMode != SkXfermode::kSrc_Mode) | |
| 380 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(true); | |
| 381 | |
| 382 ++savedLayerStackSize_; | |
| 383 | |
| 179 // Actually saving a layer here could cause a new bitmap to be created | 384 // Actually saving a layer here could cause a new bitmap to be created |
| 180 // and real rendering to occur. | 385 // and real rendering to occur. |
| 181 int count = SkCanvas::save(flags); | 386 int count = INHERITED::save(flags); |
| 182 if (bounds) { | 387 if (bounds) { |
| 183 INHERITED::clipRectBounds(bounds, flags, NULL); | 388 INHERITED::clipRectBounds(bounds, flags, NULL); |
| 184 } | 389 } |
| 185 return count; | 390 return count; |
| 186 } | 391 } |
| 187 | 392 |
| 393 void AnalysisCanvas::restore() { | |
| 394 INHERITED::restore(); | |
| 395 | |
| 396 if (--savedLayerStackSize_ == 0) { | |
| 397 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(false); | |
| 398 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(false); | |
| 399 } | |
| 400 } | |
| 401 | |
| 188 } // namespace skia | 402 } // namespace skia |
| 189 | 403 |
| 190 | 404 |
| OLD | NEW |