Roll leveldb from r73 to r75.
[chromium-blink-merge.git] / skia / ext / analysis_canvas.cc
blob6c3f5ca7d37c6bd6d7b5e4e24d203186a216eded
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
3 // found in the LICENSE file.
5 #include "base/debug/trace_event.h"
6 #include "skia/ext/analysis_canvas.h"
7 #include "third_party/skia/include/core/SkDevice.h"
8 #include "third_party/skia/include/core/SkDraw.h"
9 #include "third_party/skia/include/core/SkRRect.h"
10 #include "third_party/skia/include/core/SkShader.h"
11 #include "third_party/skia/src/core/SkRasterClip.h"
12 #include "ui/gfx/rect_conversions.h"
14 namespace {
16 const int kNoLayer = -1;
18 bool IsSolidColorPaint(const SkPaint& paint) {
19 SkXfermode::Mode xfermode;
21 // getXfermode can return a NULL, but that is handled
22 // gracefully by AsMode (NULL turns into kSrcOver mode).
23 SkXfermode::AsMode(paint.getXfermode(), &xfermode);
25 // Paint is solid color if the following holds:
26 // - Alpha is 1.0, style is fill, and there are no special effects
27 // - Xfer mode is either kSrc or kSrcOver (kSrcOver is equivalent
28 // to kSrc if source alpha is 1.0, which is already checked).
29 return (paint.getAlpha() == 255 &&
30 !paint.getShader() &&
31 !paint.getLooper() &&
32 !paint.getMaskFilter() &&
33 !paint.getColorFilter() &&
34 paint.getStyle() == SkPaint::kFill_Style &&
35 (xfermode == SkXfermode::kSrc_Mode ||
36 xfermode == SkXfermode::kSrcOver_Mode));
39 bool IsFullQuad(const SkDraw& draw,
40 const SkRect& canvas_rect,
41 const SkRect& drawn_rect) {
43 // If the transform results in a non-axis aligned
44 // rect, then be conservative and return false.
45 if (!draw.fMatrix->rectStaysRect())
46 return false;
48 SkRect draw_bitmap_rect;
49 draw.fBitmap->getBounds(&draw_bitmap_rect);
50 SkRect clip_rect = SkRect::Make(draw.fRC->getBounds());
51 SkRect device_rect;
52 draw.fMatrix->mapRect(&device_rect, drawn_rect);
54 // The drawn rect covers the full canvas, if the following conditions hold:
55 // - Clip rect is an actual rectangle.
56 // - The rect we're drawing (post-transform) contains the clip rect.
57 // That is, all of clip rect will be colored by the rect.
58 // - Clip rect contains the canvas rect.
59 // That is, we're not clipping to a portion of this canvas.
60 // - The bitmap into which the draw call happens is at least as
61 // big as the canvas rect
62 return draw.fRC->isRect() &&
63 device_rect.contains(clip_rect) &&
64 clip_rect.contains(canvas_rect) &&
65 draw_bitmap_rect.contains(canvas_rect);
68 } // namespace
70 namespace skia {
72 AnalysisDevice::AnalysisDevice(const SkBitmap& bitmap)
73 : INHERITED(bitmap),
74 is_forced_not_solid_(false),
75 is_forced_not_transparent_(false),
76 is_solid_color_(true),
77 is_transparent_(true),
78 has_text_(false) {}
80 AnalysisDevice::~AnalysisDevice() {}
82 bool AnalysisDevice::GetColorIfSolid(SkColor* color) const {
83 if (is_transparent_) {
84 *color = SK_ColorTRANSPARENT;
85 return true;
87 if (is_solid_color_) {
88 *color = color_;
89 return true;
91 return false;
94 bool AnalysisDevice::HasText() const {
95 return has_text_;
98 void AnalysisDevice::SetForceNotSolid(bool flag) {
99 is_forced_not_solid_ = flag;
100 if (is_forced_not_solid_)
101 is_solid_color_ = false;
104 void AnalysisDevice::SetForceNotTransparent(bool flag) {
105 is_forced_not_transparent_ = flag;
106 if (is_forced_not_transparent_)
107 is_transparent_ = false;
110 void AnalysisDevice::clear(SkColor color) {
111 is_transparent_ = (!is_forced_not_transparent_ && SkColorGetA(color) == 0);
112 has_text_ = false;
114 if (!is_forced_not_solid_ && SkColorGetA(color) == 255) {
115 is_solid_color_ = true;
116 color_ = color;
117 } else {
118 is_solid_color_ = false;
122 void AnalysisDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
123 is_solid_color_ = false;
124 is_transparent_ = false;
127 void AnalysisDevice::drawPoints(const SkDraw& draw,
128 SkCanvas::PointMode mode,
129 size_t count,
130 const SkPoint points[],
131 const SkPaint& paint) {
132 is_solid_color_ = false;
133 is_transparent_ = false;
136 void AnalysisDevice::drawRect(const SkDraw& draw,
137 const SkRect& rect,
138 const SkPaint& paint) {
139 bool does_cover_canvas =
140 IsFullQuad(draw, SkRect::MakeWH(width(), height()), rect);
142 SkXfermode::Mode xfermode;
143 SkXfermode::AsMode(paint.getXfermode(), &xfermode);
145 // This canvas will become transparent if the following holds:
146 // - The quad is a full tile quad
147 // - We're not in "forced not transparent" mode
148 // - Transfer mode is clear (0 color, 0 alpha)
150 // If the paint alpha is not 0, or if the transfrer mode is
151 // not src, then this canvas will not be transparent.
153 // In all other cases, we keep the current transparent value
154 if (does_cover_canvas &&
155 !is_forced_not_transparent_ &&
156 xfermode == SkXfermode::kClear_Mode) {
157 is_transparent_ = true;
158 has_text_ = false;
159 } else if (paint.getAlpha() != 0 || xfermode != SkXfermode::kSrc_Mode) {
160 is_transparent_ = false;
163 // This bitmap is solid if and only if the following holds.
164 // Note that this might be overly conservative:
165 // - We're not in "forced not solid" mode
166 // - Paint is solid color
167 // - The quad is a full tile quad
168 if (!is_forced_not_solid_ && IsSolidColorPaint(paint) && does_cover_canvas) {
169 is_solid_color_ = true;
170 color_ = paint.getColor();
171 has_text_ = false;
172 } else {
173 is_solid_color_ = false;
177 void AnalysisDevice::drawOval(const SkDraw& draw,
178 const SkRect& oval,
179 const SkPaint& paint) {
180 is_solid_color_ = false;
181 is_transparent_ = false;
184 void AnalysisDevice::drawPath(const SkDraw& draw,
185 const SkPath& path,
186 const SkPaint& paint,
187 const SkMatrix* pre_path_matrix,
188 bool path_is_mutable) {
189 is_solid_color_ = false;
190 is_transparent_ = false;
193 void AnalysisDevice::drawBitmap(const SkDraw& draw,
194 const SkBitmap& bitmap,
195 const SkIRect* src_rect_or_null,
196 const SkMatrix& matrix,
197 const SkPaint& paint) {
198 is_solid_color_ = false;
199 is_transparent_ = false;
202 void AnalysisDevice::drawSprite(const SkDraw& draw,
203 const SkBitmap& bitmap,
204 int x,
205 int y,
206 const SkPaint& paint) {
207 is_solid_color_ = false;
208 is_transparent_ = false;
211 void AnalysisDevice::drawBitmapRect(const SkDraw& draw,
212 const SkBitmap& bitmap,
213 const SkRect* src_or_null,
214 const SkRect& dst,
215 const SkPaint& paint) {
216 // Call drawRect to determine transparency,
217 // but reset solid color to false.
218 drawRect(draw, dst, paint);
219 is_solid_color_ = false;
222 void AnalysisDevice::drawText(const SkDraw& draw,
223 const void* text,
224 size_t len,
225 SkScalar x,
226 SkScalar y,
227 const SkPaint& paint) {
228 is_solid_color_ = false;
229 is_transparent_ = false;
230 has_text_ = true;
233 void AnalysisDevice::drawPosText(const SkDraw& draw,
234 const void* text,
235 size_t len,
236 const SkScalar pos[],
237 SkScalar const_y,
238 int scalars_per_pos,
239 const SkPaint& paint) {
240 is_solid_color_ = false;
241 is_transparent_ = false;
242 has_text_ = true;
245 void AnalysisDevice::drawTextOnPath(const SkDraw& draw,
246 const void* text,
247 size_t len,
248 const SkPath& path,
249 const SkMatrix* matrix,
250 const SkPaint& paint) {
251 is_solid_color_ = false;
252 is_transparent_ = false;
253 has_text_ = true;
256 #ifdef SK_BUILD_FOR_ANDROID
257 void AnalysisDevice::drawPosTextOnPath(const SkDraw& draw,
258 const void* text,
259 size_t len,
260 const SkPoint pos[],
261 const SkPaint& paint,
262 const SkPath& path,
263 const SkMatrix* matrix) {
264 is_solid_color_ = false;
265 is_transparent_ = false;
266 has_text_ = true;
268 #endif
270 void AnalysisDevice::drawVertices(const SkDraw& draw,
271 SkCanvas::VertexMode,
272 int vertex_count,
273 const SkPoint verts[],
274 const SkPoint texs[],
275 const SkColor colors[],
276 SkXfermode* xmode,
277 const uint16_t indices[],
278 int index_count,
279 const SkPaint& paint) {
280 is_solid_color_ = false;
281 is_transparent_ = false;
284 void AnalysisDevice::drawDevice(const SkDraw& draw,
285 SkDevice* device,
286 int x,
287 int y,
288 const SkPaint& paint) {
289 is_solid_color_ = false;
290 is_transparent_ = false;
293 AnalysisCanvas::AnalysisCanvas(AnalysisDevice* device)
294 : INHERITED(device),
295 saved_stack_size_(0),
296 force_not_solid_stack_level_(kNoLayer),
297 force_not_transparent_stack_level_(kNoLayer) {}
299 AnalysisCanvas::~AnalysisCanvas() {}
301 bool AnalysisCanvas::GetColorIfSolid(SkColor* color) const {
302 return (static_cast<AnalysisDevice*>(getDevice()))->GetColorIfSolid(color);
305 bool AnalysisCanvas::HasText() const {
306 return (static_cast<AnalysisDevice*>(getDevice()))->HasText();
309 bool AnalysisCanvas::abortDrawing() {
310 // Early out as soon as we have detected that the tile has text.
311 return HasText();
314 bool AnalysisCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool do_aa) {
315 return INHERITED::clipRect(rect, op, do_aa);
318 bool AnalysisCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool do_aa) {
319 // clipPaths can make our calls to IsFullQuad invalid (ie have false
320 // positives). As a precaution, force the setting to be non-solid
321 // and non-transparent until we pop this
322 if (force_not_solid_stack_level_ == kNoLayer) {
323 force_not_solid_stack_level_ = saved_stack_size_;
324 (static_cast<AnalysisDevice*>(getDevice()))->SetForceNotSolid(true);
326 if (force_not_transparent_stack_level_ == kNoLayer) {
327 force_not_transparent_stack_level_ = saved_stack_size_;
328 (static_cast<AnalysisDevice*>(getDevice()))->SetForceNotTransparent(true);
331 return INHERITED::clipRect(path.getBounds(), op, do_aa);
334 bool AnalysisCanvas::clipRRect(const SkRRect& rrect,
335 SkRegion::Op op,
336 bool do_aa) {
337 // clipRRect can make our calls to IsFullQuad invalid (ie have false
338 // positives). As a precaution, force the setting to be non-solid
339 // and non-transparent until we pop this
340 if (force_not_solid_stack_level_ == kNoLayer) {
341 force_not_solid_stack_level_ = saved_stack_size_;
342 (static_cast<AnalysisDevice*>(getDevice()))->SetForceNotSolid(true);
344 if (force_not_transparent_stack_level_ == kNoLayer) {
345 force_not_transparent_stack_level_ = saved_stack_size_;
346 (static_cast<AnalysisDevice*>(getDevice()))->SetForceNotTransparent(true);
349 return INHERITED::clipRect(rrect.getBounds(), op, do_aa);
352 int AnalysisCanvas::save(SkCanvas::SaveFlags flags) {
353 ++saved_stack_size_;
354 return INHERITED::save(flags);
357 int AnalysisCanvas::saveLayer(const SkRect* bounds,
358 const SkPaint* paint,
359 SkCanvas::SaveFlags flags) {
360 ++saved_stack_size_;
362 // If after we draw to the saved layer, we have to blend with the current
363 // layer, then we can conservatively say that the canvas will not be of
364 // solid color.
365 if ((paint && !IsSolidColorPaint(*paint)) ||
366 (bounds && !bounds->contains(SkRect::MakeWH(getDevice()->width(),
367 getDevice()->height())))) {
368 if (force_not_solid_stack_level_ == kNoLayer) {
369 force_not_solid_stack_level_ = saved_stack_size_;
370 (static_cast<AnalysisDevice*>(getDevice()))->SetForceNotSolid(true);
374 // If after we draw to the save layer, we have to blend with the current
375 // layer using any part of the current layer's alpha, then we can
376 // conservatively say that the canvas will not be transparent.
377 SkXfermode::Mode xfermode = SkXfermode::kSrc_Mode;
378 if (paint)
379 SkXfermode::AsMode(paint->getXfermode(), &xfermode);
380 if (xfermode != SkXfermode::kSrc_Mode) {
381 if (force_not_transparent_stack_level_ == kNoLayer) {
382 force_not_transparent_stack_level_ = saved_stack_size_;
383 (static_cast<AnalysisDevice*>(getDevice()))->SetForceNotTransparent(true);
387 // Actually saving a layer here could cause a new bitmap to be created
388 // and real rendering to occur.
389 int count = INHERITED::save(flags);
390 if (bounds) {
391 INHERITED::clipRectBounds(bounds, flags, NULL);
393 return count;
396 void AnalysisCanvas::restore() {
397 INHERITED::restore();
399 DCHECK(saved_stack_size_);
400 if (saved_stack_size_) {
401 --saved_stack_size_;
402 if (saved_stack_size_ < force_not_solid_stack_level_) {
403 (static_cast<AnalysisDevice*>(getDevice()))->SetForceNotSolid(false);
404 force_not_solid_stack_level_ = kNoLayer;
406 if (saved_stack_size_ < force_not_transparent_stack_level_) {
407 (static_cast<AnalysisDevice*>(getDevice()))->SetForceNotTransparent(
408 false);
409 force_not_transparent_stack_level_ = kNoLayer;
414 } // namespace skia