OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012, Google Inc. All rights reserved. | 2 * Copyright (c) 2012, Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 12 matching lines...) Expand all Loading... |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 */ | 29 */ |
30 | 30 |
31 #include "config.h" | 31 #include "config.h" |
32 | 32 |
33 #include "platform/graphics/skia/OpaqueRegionSkia.h" | 33 #include "platform/graphics/RegionTracker.h" |
34 | 34 |
35 #include "platform/graphics/GraphicsContext.h" | 35 #include "platform/graphics/GraphicsContext.h" |
36 | 36 #include "third_party/skia/include/core/SkColorFilter.h" |
37 #include "SkColorFilter.h" | 37 #include "third_party/skia/include/core/SkShader.h" |
38 #include "SkShader.h" | |
39 | 38 |
40 namespace blink { | 39 namespace blink { |
41 | 40 |
42 OpaqueRegionSkia::OpaqueRegionSkia() | 41 RegionTracker::RegionTracker() |
43 : m_opaqueRect(SkRect::MakeEmpty()) | 42 : m_opaqueRect(SkRect::MakeEmpty()) |
| 43 , m_trackedRegionType(Opaque) |
44 { | 44 { |
45 } | 45 } |
46 | 46 |
47 void OpaqueRegionSkia::reset() | 47 void RegionTracker::reset() |
48 { | 48 { |
49 ASSERT(m_canvasLayerStack.isEmpty()); | 49 ASSERT(m_canvasLayerStack.isEmpty()); |
50 m_opaqueRect = SkRect::MakeEmpty(); | 50 m_opaqueRect = SkRect::MakeEmpty(); |
51 } | 51 } |
52 | 52 |
53 IntRect OpaqueRegionSkia::asRect() const | 53 IntRect RegionTracker::asRect() const |
54 { | 54 { |
55 // Returns the largest enclosed rect. | 55 // Returns the largest enclosed rect. |
56 // TODO: actually, this logic looks like its returning the smallest. | 56 // TODO: actually, this logic looks like its returning the smallest. |
57 // to return largest, shouldn't we take floor of left/top | 57 // to return largest, shouldn't we take floor of left/top |
58 // and the ceil of right/bottom? | 58 // and the ceil of right/bottom? |
59 int left = SkScalarCeilToInt(m_opaqueRect.fLeft); | 59 int left = SkScalarCeilToInt(m_opaqueRect.fLeft); |
60 int top = SkScalarCeilToInt(m_opaqueRect.fTop); | 60 int top = SkScalarCeilToInt(m_opaqueRect.fTop); |
61 int right = SkScalarFloorToInt(m_opaqueRect.fRight); | 61 int right = SkScalarFloorToInt(m_opaqueRect.fRight); |
62 int bottom = SkScalarFloorToInt(m_opaqueRect.fBottom); | 62 int bottom = SkScalarFloorToInt(m_opaqueRect.fBottom); |
63 return IntRect(left, top, right-left, bottom-top); | 63 return IntRect(left, top, right-left, bottom-top); |
(...skipping 25 matching lines...) Expand all Loading... |
89 case SkXfermode::kSrcIn_Mode: // source * dest | 89 case SkXfermode::kSrcIn_Mode: // source * dest |
90 case SkXfermode::kDstIn_Mode: // dest * source | 90 case SkXfermode::kDstIn_Mode: // dest * source |
91 case SkXfermode::kSrcOut_Mode: // source * (1-dest) | 91 case SkXfermode::kSrcOut_Mode: // source * (1-dest) |
92 case SkXfermode::kDstOut_Mode: // dest * (1-source) | 92 case SkXfermode::kDstOut_Mode: // dest * (1-source) |
93 case SkXfermode::kSrcATop_Mode: // dest | 93 case SkXfermode::kSrcATop_Mode: // dest |
94 case SkXfermode::kXor_Mode: // source + dest - 2*(source*dest) | 94 case SkXfermode::kXor_Mode: // source + dest - 2*(source*dest) |
95 return false; | 95 return false; |
96 } | 96 } |
97 } | 97 } |
98 | 98 |
| 99 static inline bool xfermodeIsOverwrite(const SkPaint& paint) |
| 100 { |
| 101 SkXfermode* xfermode = paint.getXfermode(); |
| 102 if (!xfermode) |
| 103 return false; // default to kSrcOver_Mode |
| 104 SkXfermode::Mode mode; |
| 105 if (!xfermode->asMode(&mode)) |
| 106 return false; |
| 107 switch (mode) { |
| 108 case SkXfermode::kSrc_Mode: |
| 109 case SkXfermode::kClear_Mode: |
| 110 return true; |
| 111 default: |
| 112 return false; |
| 113 } |
| 114 } |
| 115 |
99 // Returns true if the xfermode will keep the dst opaque, assuming the dst is al
ready opaque. | 116 // Returns true if the xfermode will keep the dst opaque, assuming the dst is al
ready opaque. |
100 static inline bool xfermodePreservesOpaque(const SkPaint& paint, bool srcIsOpaqu
e) | 117 static inline bool xfermodePreservesOpaque(const SkPaint& paint, bool srcIsOpaqu
e) |
101 { | 118 { |
102 SkXfermode* xfermode = paint.getXfermode(); | 119 SkXfermode* xfermode = paint.getXfermode(); |
103 if (!xfermode) | 120 if (!xfermode) |
104 return true; // default to kSrcOver_Mode | 121 return true; // default to kSrcOver_Mode |
105 SkXfermode::Mode mode; | 122 SkXfermode::Mode mode; |
106 if (!xfermode->asMode(&mode)) | 123 if (!xfermode->asMode(&mode)) |
107 return false; | 124 return false; |
108 | 125 |
(...skipping 12 matching lines...) Expand all Loading... |
121 return false; | 138 return false; |
122 case SkXfermode::kSrc_Mode: // source | 139 case SkXfermode::kSrc_Mode: // source |
123 case SkXfermode::kSrcIn_Mode: // source * dest | 140 case SkXfermode::kSrcIn_Mode: // source * dest |
124 case SkXfermode::kDstIn_Mode: // dest * source | 141 case SkXfermode::kDstIn_Mode: // dest * source |
125 case SkXfermode::kDstATop_Mode: // source | 142 case SkXfermode::kDstATop_Mode: // source |
126 return srcIsOpaque; | 143 return srcIsOpaque; |
127 } | 144 } |
128 } | 145 } |
129 | 146 |
130 // Returns true if all pixels painted will be opaque. | 147 // Returns true if all pixels painted will be opaque. |
131 static inline bool paintIsOpaque(const SkPaint& paint, OpaqueRegionSkia::DrawTyp
e drawType, const SkBitmap* bitmap) | 148 static inline bool paintIsOpaque(const SkPaint& paint, RegionTracker::DrawType d
rawType, const SkBitmap* bitmap) |
132 { | 149 { |
133 if (paint.getAlpha() < 0xFF) | 150 if (paint.getAlpha() < 0xFF) |
134 return false; | 151 return false; |
135 bool checkFillOnly = drawType != OpaqueRegionSkia::FillOrStroke; | 152 bool checkFillOnly = drawType != RegionTracker::FillOrStroke; |
136 if (!checkFillOnly && paint.getStyle() != SkPaint::kFill_Style && paint.isAn
tiAlias()) | 153 if (!checkFillOnly && paint.getStyle() != SkPaint::kFill_Style && paint.isAn
tiAlias()) |
137 return false; | 154 return false; |
138 SkShader* shader = paint.getShader(); | 155 SkShader* shader = paint.getShader(); |
139 if (shader && !shader->isOpaque()) | 156 if (shader && !shader->isOpaque()) |
140 return false; | 157 return false; |
141 if (bitmap && !bitmap->isOpaque()) | 158 if (bitmap && !bitmap->isOpaque()) |
142 return false; | 159 return false; |
143 if (paint.getLooper()) | 160 if (paint.getLooper()) |
144 return false; | 161 return false; |
145 if (paint.getImageFilter()) | 162 if (paint.getImageFilter()) |
(...skipping 15 matching lines...) Expand all Loading... |
161 | 178 |
162 SkIRect deviceClipIRect; | 179 SkIRect deviceClipIRect; |
163 if (context->canvas()->getClipDeviceBounds(&deviceClipIRect)) | 180 if (context->canvas()->getClipDeviceBounds(&deviceClipIRect)) |
164 deviceClipRect.set(deviceClipIRect); | 181 deviceClipRect.set(deviceClipIRect); |
165 else | 182 else |
166 deviceClipRect.setEmpty(); | 183 deviceClipRect.setEmpty(); |
167 | 184 |
168 return true; | 185 return true; |
169 } | 186 } |
170 | 187 |
171 void OpaqueRegionSkia::pushCanvasLayer(const SkPaint* paint) | 188 void RegionTracker::pushCanvasLayer(const SkPaint* paint) |
172 { | 189 { |
173 CanvasLayerState state; | 190 CanvasLayerState state; |
174 if (paint) | 191 if (paint) |
175 state.paint = *paint; | 192 state.paint = *paint; |
176 m_canvasLayerStack.append(state); | 193 m_canvasLayerStack.append(state); |
177 } | 194 } |
178 | 195 |
179 void OpaqueRegionSkia::popCanvasLayer(const GraphicsContext* context) | 196 void RegionTracker::popCanvasLayer(const GraphicsContext* context) |
180 { | 197 { |
181 ASSERT(!context->paintingDisabled()); | 198 ASSERT(!context->paintingDisabled()); |
182 ASSERT(!m_canvasLayerStack.isEmpty()); | 199 ASSERT(!m_canvasLayerStack.isEmpty()); |
183 if (m_canvasLayerStack.isEmpty()) | 200 if (m_canvasLayerStack.isEmpty()) |
184 return; | 201 return; |
185 | 202 |
186 const CanvasLayerState& canvasLayer = m_canvasLayerStack.last(); | 203 const CanvasLayerState& canvasLayer = m_canvasLayerStack.last(); |
187 SkRect layerOpaqueRect = canvasLayer.opaqueRect; | 204 SkRect layerOpaqueRect = canvasLayer.opaqueRect; |
188 SkPaint layerPaint = canvasLayer.paint; | 205 SkPaint layerPaint = canvasLayer.paint; |
189 | 206 |
190 // Apply the image mask. | 207 // Apply the image mask. |
191 if (canvasLayer.hasImageMask && !layerOpaqueRect.intersect(canvasLayer.image
OpaqueRect)) | 208 if (canvasLayer.hasImageMask && !layerOpaqueRect.intersect(canvasLayer.image
OpaqueRect)) |
192 layerOpaqueRect.setEmpty(); | 209 layerOpaqueRect.setEmpty(); |
193 | 210 |
194 m_canvasLayerStack.removeLast(); | 211 m_canvasLayerStack.removeLast(); |
195 | 212 |
196 applyOpaqueRegionFromLayer(context, layerOpaqueRect, layerPaint); | 213 applyOpaqueRegionFromLayer(context, layerOpaqueRect, layerPaint); |
197 } | 214 } |
198 | 215 |
199 void OpaqueRegionSkia::setImageMask(const SkRect& imageOpaqueRect) | 216 void RegionTracker::setImageMask(const SkRect& imageOpaqueRect) |
200 { | 217 { |
201 ASSERT(!m_canvasLayerStack.isEmpty()); | 218 ASSERT(!m_canvasLayerStack.isEmpty()); |
202 m_canvasLayerStack.last().hasImageMask = true; | 219 m_canvasLayerStack.last().hasImageMask = true; |
203 m_canvasLayerStack.last().imageOpaqueRect = imageOpaqueRect; | 220 m_canvasLayerStack.last().imageOpaqueRect = imageOpaqueRect; |
204 } | 221 } |
205 | 222 |
206 void OpaqueRegionSkia::didDrawRect(const GraphicsContext* context, const SkRect&
fillRect, const SkPaint& paint, const SkBitmap* sourceBitmap) | 223 void RegionTracker::didDrawRect(const GraphicsContext* context, const SkRect& fi
llRect, const SkPaint& paint, const SkBitmap* sourceBitmap) |
207 { | 224 { |
208 ASSERT(!context->paintingDisabled()); | 225 ASSERT(!context->paintingDisabled()); |
209 // Any stroking may put alpha in pixels even if the filling part does not. | 226 // Any stroking may put alpha in pixels even if the filling part does not. |
210 if (paint.getStyle() != SkPaint::kFill_Style) { | 227 if (paint.getStyle() != SkPaint::kFill_Style) { |
211 bool fillsBounds = false; | 228 bool fillsBounds = false; |
212 | 229 |
213 if (!paint.canComputeFastBounds()) | 230 if (!paint.canComputeFastBounds()) { |
214 didDrawUnbounded(context, paint, FillOrStroke); | 231 didDrawUnbounded(context, paint, FillOrStroke); |
215 else { | 232 } else { |
216 SkRect strokeRect; | 233 SkRect strokeRect; |
217 strokeRect = paint.computeFastBounds(fillRect, &strokeRect); | 234 strokeRect = paint.computeFastBounds(fillRect, &strokeRect); |
218 didDraw(context, strokeRect, paint, sourceBitmap, fillsBounds, FillO
rStroke); | 235 didDraw(context, strokeRect, paint, sourceBitmap, fillsBounds, FillO
rStroke); |
219 } | 236 } |
220 } | 237 } |
221 | 238 |
222 bool fillsBounds = paint.getStyle() != SkPaint::kStroke_Style; | 239 bool fillsBounds = paint.getStyle() != SkPaint::kStroke_Style; |
223 didDraw(context, fillRect, paint, sourceBitmap, fillsBounds, FillOnly); | 240 didDraw(context, fillRect, paint, sourceBitmap, fillsBounds, FillOnly); |
224 } | 241 } |
225 | 242 |
226 void OpaqueRegionSkia::didDrawPath(const GraphicsContext* context, const SkPath&
path, const SkPaint& paint) | 243 void RegionTracker::didDrawPath(const GraphicsContext* context, const SkPath& pa
th, const SkPaint& paint) |
227 { | 244 { |
228 ASSERT(!context->paintingDisabled()); | 245 ASSERT(!context->paintingDisabled()); |
229 SkRect rect; | 246 SkRect rect; |
230 if (path.isRect(&rect)) { | 247 if (path.isRect(&rect)) { |
231 didDrawRect(context, rect, paint, 0); | 248 didDrawRect(context, rect, paint, 0); |
232 return; | 249 return; |
233 } | 250 } |
234 | 251 |
235 bool fillsBounds = false; | 252 bool fillsBounds = false; |
236 | 253 |
237 if (!paint.canComputeFastBounds()) | 254 if (!paint.canComputeFastBounds()) { |
238 didDrawUnbounded(context, paint, FillOrStroke); | 255 didDrawUnbounded(context, paint, FillOrStroke); |
239 else { | 256 } else { |
240 rect = paint.computeFastBounds(path.getBounds(), &rect); | 257 rect = paint.computeFastBounds(path.getBounds(), &rect); |
241 didDraw(context, rect, paint, 0, fillsBounds, FillOrStroke); | 258 didDraw(context, rect, paint, 0, fillsBounds, FillOrStroke); |
242 } | 259 } |
243 } | 260 } |
244 | 261 |
245 void OpaqueRegionSkia::didDrawPoints(const GraphicsContext* context, SkCanvas::P
ointMode mode, int numPoints, const SkPoint points[], const SkPaint& paint) | 262 void RegionTracker::didDrawPoints(const GraphicsContext* context, SkCanvas::Poin
tMode mode, int numPoints, const SkPoint points[], const SkPaint& paint) |
246 { | 263 { |
247 ASSERT(!context->paintingDisabled()); | 264 ASSERT(!context->paintingDisabled()); |
248 if (!numPoints) | 265 if (!numPoints) |
249 return; | 266 return; |
250 | 267 |
251 SkRect rect; | 268 SkRect rect; |
252 rect.fLeft = points[0].fX; | 269 rect.fLeft = points[0].fX; |
253 rect.fRight = points[0].fX + 1; | 270 rect.fRight = points[0].fX + 1; |
254 rect.fTop = points[0].fY; | 271 rect.fTop = points[0].fY; |
255 rect.fBottom = points[0].fY + 1; | 272 rect.fBottom = points[0].fY + 1; |
256 | 273 |
257 for (int i = 1; i < numPoints; ++i) { | 274 for (int i = 1; i < numPoints; ++i) { |
258 rect.fLeft = std::min(rect.fLeft, points[i].fX); | 275 rect.fLeft = std::min(rect.fLeft, points[i].fX); |
259 rect.fRight = std::max(rect.fRight, points[i].fX + 1); | 276 rect.fRight = std::max(rect.fRight, points[i].fX + 1); |
260 rect.fTop = std::min(rect.fTop, points[i].fY); | 277 rect.fTop = std::min(rect.fTop, points[i].fY); |
261 rect.fBottom = std::max(rect.fBottom, points[i].fY + 1); | 278 rect.fBottom = std::max(rect.fBottom, points[i].fY + 1); |
262 } | 279 } |
263 | 280 |
264 bool fillsBounds = false; | 281 bool fillsBounds = false; |
265 | 282 |
266 if (!paint.canComputeFastBounds()) | 283 if (!paint.canComputeFastBounds()) { |
267 didDrawUnbounded(context, paint, FillOrStroke); | 284 didDrawUnbounded(context, paint, FillOrStroke); |
268 else { | 285 } else { |
269 rect = paint.computeFastBounds(rect, &rect); | 286 rect = paint.computeFastBounds(rect, &rect); |
270 didDraw(context, rect, paint, 0, fillsBounds, FillOrStroke); | 287 didDraw(context, rect, paint, 0, fillsBounds, FillOrStroke); |
271 } | 288 } |
272 } | 289 } |
273 | 290 |
274 void OpaqueRegionSkia::didDrawBounded(const GraphicsContext* context, const SkRe
ct& bounds, const SkPaint& paint) | 291 void RegionTracker::didDrawBounded(const GraphicsContext* context, const SkRect&
bounds, const SkPaint& paint) |
275 { | 292 { |
276 ASSERT(!context->paintingDisabled()); | 293 ASSERT(!context->paintingDisabled()); |
277 bool fillsBounds = false; | 294 bool fillsBounds = false; |
278 | 295 |
279 if (!paint.canComputeFastBounds()) | 296 if (!paint.canComputeFastBounds()) { |
280 didDrawUnbounded(context, paint, FillOrStroke); | 297 didDrawUnbounded(context, paint, FillOrStroke); |
281 else { | 298 } else { |
282 SkRect rect; | 299 SkRect rect; |
283 rect = paint.computeFastBounds(bounds, &rect); | 300 rect = paint.computeFastBounds(bounds, &rect); |
284 didDraw(context, rect, paint, 0, fillsBounds, FillOrStroke); | 301 didDraw(context, rect, paint, 0, fillsBounds, FillOrStroke); |
285 } | 302 } |
286 } | 303 } |
287 | 304 |
288 void OpaqueRegionSkia::didDraw(const GraphicsContext* context, const SkRect& rec
t, const SkPaint& paint, const SkBitmap* sourceBitmap, bool fillsBounds, DrawTyp
e drawType) | 305 void RegionTracker::didDraw(const GraphicsContext* context, const SkRect& rect,
const SkPaint& paint, const SkBitmap* sourceBitmap, bool fillsBounds, DrawType d
rawType) |
289 { | 306 { |
290 ASSERT(!context->paintingDisabled()); | 307 ASSERT(!context->paintingDisabled()); |
291 SkRect targetRect = rect; | 308 SkRect targetRect = rect; |
292 | 309 |
293 // Apply the transform to device coordinate space. | 310 // Apply the transform to device coordinate space. |
294 SkMatrix canvasTransform = context->canvas()->getTotalMatrix(); | 311 SkMatrix canvasTransform = context->canvas()->getTotalMatrix(); |
295 if (!canvasTransform.mapRect(&targetRect)) | 312 if (!canvasTransform.mapRect(&targetRect)) |
296 fillsBounds = false; | 313 fillsBounds = false; |
297 | 314 |
298 // Apply the current clip. | 315 // Apply the current clip. |
299 SkRect deviceClipRect; | 316 SkRect deviceClipRect; |
300 if (!getDeviceClipAsRect(context, deviceClipRect)) | 317 if (!getDeviceClipAsRect(context, deviceClipRect)) |
301 fillsBounds = false; | 318 fillsBounds = false; |
302 else if (!targetRect.intersect(deviceClipRect)) | 319 else if (!targetRect.intersect(deviceClipRect)) |
303 return; | 320 return; |
304 | 321 |
| 322 if (m_trackedRegionType == Overwrite && fillsBounds && xfermodeIsOverwrite(p
aint)) { |
| 323 markRectAsOpaque(targetRect); |
| 324 return; |
| 325 } |
| 326 |
305 bool drawsOpaque = paintIsOpaque(paint, drawType, sourceBitmap); | 327 bool drawsOpaque = paintIsOpaque(paint, drawType, sourceBitmap); |
306 bool xfersOpaque = xfermodeIsOpaque(paint, drawsOpaque); | 328 bool xfersOpaque = xfermodeIsOpaque(paint, drawsOpaque); |
307 bool preservesOpaque = xfermodePreservesOpaque(paint, drawsOpaque); | |
308 | 329 |
309 if (fillsBounds && xfersOpaque) | 330 if (fillsBounds && xfersOpaque) { |
310 markRectAsOpaque(targetRect); | 331 markRectAsOpaque(targetRect); |
311 else if (!preservesOpaque) | 332 } else if (m_trackedRegionType == Opaque && !xfermodePreservesOpaque(paint,
drawsOpaque)) { |
312 markRectAsNonOpaque(targetRect); | 333 markRectAsNonOpaque(targetRect); |
| 334 } |
313 } | 335 } |
314 | 336 |
315 void OpaqueRegionSkia::didDrawUnbounded(const GraphicsContext* context, const Sk
Paint& paint, DrawType drawType) | 337 void RegionTracker::didDrawUnbounded(const GraphicsContext* context, const SkPai
nt& paint, DrawType drawType) |
316 { | 338 { |
317 ASSERT(!context->paintingDisabled()); | 339 ASSERT(!context->paintingDisabled()); |
318 bool drawsOpaque = paintIsOpaque(paint, drawType, 0); | 340 bool drawsOpaque = paintIsOpaque(paint, drawType, 0); |
319 bool preservesOpaque = xfermodePreservesOpaque(paint, drawsOpaque); | 341 bool preservesOpaque = xfermodePreservesOpaque(paint, drawsOpaque); |
320 | 342 |
321 if (preservesOpaque) | 343 if (preservesOpaque) |
322 return; | 344 return; |
323 | 345 |
324 SkRect deviceClipRect; | 346 SkRect deviceClipRect; |
325 getDeviceClipAsRect(context, deviceClipRect); | 347 getDeviceClipAsRect(context, deviceClipRect); |
326 markRectAsNonOpaque(deviceClipRect); | 348 markRectAsNonOpaque(deviceClipRect); |
327 } | 349 } |
328 | 350 |
329 void OpaqueRegionSkia::applyOpaqueRegionFromLayer(const GraphicsContext* context
, const SkRect& layerOpaqueRect, const SkPaint& paint) | 351 void RegionTracker::applyOpaqueRegionFromLayer(const GraphicsContext* context, c
onst SkRect& layerOpaqueRect, const SkPaint& paint) |
330 { | 352 { |
331 SkRect deviceClipRect; | 353 SkRect deviceClipRect; |
332 bool deviceClipIsARect = getDeviceClipAsRect(context, deviceClipRect); | 354 bool deviceClipIsARect = getDeviceClipAsRect(context, deviceClipRect); |
333 | 355 |
334 if (deviceClipRect.isEmpty()) | 356 if (deviceClipRect.isEmpty()) |
335 return; | 357 return; |
336 | 358 |
337 SkRect sourceOpaqueRect = layerOpaqueRect; | 359 SkRect sourceOpaqueRect = layerOpaqueRect; |
338 // Save the opaque area in the destination, so we can preserve the parts of
it under the source opaque area if possible. | 360 // Save the opaque area in the destination, so we can preserve the parts of
it under the source opaque area if possible. |
339 SkRect destinationOpaqueRect = currentTrackingOpaqueRect(); | 361 SkRect destinationOpaqueRect = currentTrackingOpaqueRect(); |
(...skipping 12 matching lines...) Expand all Loading... |
352 bool sourceOpaqueRectPreservesOpaque = xfermodePreservesOpaque(paint, source
OpaqueRectDrawsOpaque); | 374 bool sourceOpaqueRectPreservesOpaque = xfermodePreservesOpaque(paint, source
OpaqueRectDrawsOpaque); |
353 | 375 |
354 // If the layer's opaque area is being drawn opaque in the layer below, then
mark it opaque. Otherwise, | 376 // If the layer's opaque area is being drawn opaque in the layer below, then
mark it opaque. Otherwise, |
355 // if it preserves opaque then keep the intersection of the two. | 377 // if it preserves opaque then keep the intersection of the two. |
356 if (sourceOpaqueRectXfersOpaque) | 378 if (sourceOpaqueRectXfersOpaque) |
357 markRectAsOpaque(sourceOpaqueRect); | 379 markRectAsOpaque(sourceOpaqueRect); |
358 else if (sourceOpaqueRectPreservesOpaque && sourceOpaqueRect.intersect(desti
nationOpaqueRect)) | 380 else if (sourceOpaqueRectPreservesOpaque && sourceOpaqueRect.intersect(desti
nationOpaqueRect)) |
359 markRectAsOpaque(sourceOpaqueRect); | 381 markRectAsOpaque(sourceOpaqueRect); |
360 } | 382 } |
361 | 383 |
362 void OpaqueRegionSkia::markRectAsOpaque(const SkRect& rect) | 384 void RegionTracker::markRectAsOpaque(const SkRect& rect) |
363 { | 385 { |
364 // We want to keep track of an opaque region but bound its complexity at a c
onstant size. | 386 // We want to keep track of an opaque region but bound its complexity at a c
onstant size. |
365 // We keep track of the largest rectangle seen by area. If we can add the ne
w rect to this | 387 // We keep track of the largest rectangle seen by area. If we can add the ne
w rect to this |
366 // rectangle then we do that, as that is the cheapest way to increase the ar
ea returned | 388 // rectangle then we do that, as that is the cheapest way to increase the ar
ea returned |
367 // without increasing the complexity. | 389 // without increasing the complexity. |
368 | 390 |
369 SkRect& opaqueRect = currentTrackingOpaqueRect(); | 391 SkRect& opaqueRect = currentTrackingOpaqueRect(); |
370 | 392 |
371 if (rect.isEmpty()) | 393 if (rect.isEmpty()) |
372 return; | 394 return; |
(...skipping 15 matching lines...) Expand all Loading... |
388 if (rect.fBottom > opaqueRect.fBottom && rect.fTop <= opaqueRect.fBottom
) | 410 if (rect.fBottom > opaqueRect.fBottom && rect.fTop <= opaqueRect.fBottom
) |
389 opaqueRect.fBottom = rect.fBottom; | 411 opaqueRect.fBottom = rect.fBottom; |
390 } | 412 } |
391 | 413 |
392 long opaqueArea = (long)opaqueRect.width() * (long)opaqueRect.height(); | 414 long opaqueArea = (long)opaqueRect.width() * (long)opaqueRect.height(); |
393 long area = (long)rect.width() * (long)rect.height(); | 415 long area = (long)rect.width() * (long)rect.height(); |
394 if (area > opaqueArea) | 416 if (area > opaqueArea) |
395 opaqueRect = rect; | 417 opaqueRect = rect; |
396 } | 418 } |
397 | 419 |
398 void OpaqueRegionSkia::markRectAsNonOpaque(const SkRect& rect) | 420 void RegionTracker::markRectAsNonOpaque(const SkRect& rect) |
399 { | 421 { |
400 // We want to keep as much of the current opaque rectangle as we can, so fin
d the one largest | 422 // We want to keep as much of the current opaque rectangle as we can, so fin
d the one largest |
401 // rectangle inside m_opaqueRect that does not intersect with |rect|. | 423 // rectangle inside m_opaqueRect that does not intersect with |rect|. |
402 | 424 |
403 SkRect& opaqueRect = currentTrackingOpaqueRect(); | 425 SkRect& opaqueRect = currentTrackingOpaqueRect(); |
404 | 426 |
405 if (!SkRect::Intersects(rect, opaqueRect)) | 427 if (!SkRect::Intersects(rect, opaqueRect)) |
406 return; | 428 return; |
407 if (rect.contains(opaqueRect)) { | 429 if (rect.contains(opaqueRect)) { |
408 markAllAsNonOpaque(); | 430 markAllAsNonOpaque(); |
(...skipping 17 matching lines...) Expand all Loading... |
426 vertical.fRight = rect.fLeft; | 448 vertical.fRight = rect.fLeft; |
427 else | 449 else |
428 vertical.fLeft = rect.fRight; | 450 vertical.fLeft = rect.fRight; |
429 | 451 |
430 if ((long)horizontal.width() * (long)horizontal.height() > (long)vertical.wi
dth() * (long)vertical.height()) | 452 if ((long)horizontal.width() * (long)horizontal.height() > (long)vertical.wi
dth() * (long)vertical.height()) |
431 opaqueRect = horizontal; | 453 opaqueRect = horizontal; |
432 else | 454 else |
433 opaqueRect = vertical; | 455 opaqueRect = vertical; |
434 } | 456 } |
435 | 457 |
436 void OpaqueRegionSkia::markAllAsNonOpaque() | 458 void RegionTracker::markAllAsNonOpaque() |
437 { | 459 { |
438 SkRect& opaqueRect = currentTrackingOpaqueRect(); | 460 SkRect& opaqueRect = currentTrackingOpaqueRect(); |
439 opaqueRect.setEmpty(); | 461 opaqueRect.setEmpty(); |
440 } | 462 } |
441 | 463 |
442 SkRect& OpaqueRegionSkia::currentTrackingOpaqueRect() | 464 SkRect& RegionTracker::currentTrackingOpaqueRect() |
443 { | 465 { |
444 // If we are drawing into a canvas layer, then track the opaque rect in that
layer. | 466 // If we are drawing into a canvas layer, then track the opaque rect in that
layer. |
445 return m_canvasLayerStack.isEmpty() ? m_opaqueRect : m_canvasLayerStack.last
().opaqueRect; | 467 return m_canvasLayerStack.isEmpty() ? m_opaqueRect : m_canvasLayerStack.last
().opaqueRect; |
446 } | 468 } |
447 | 469 |
448 } // namespace blink | 470 } // namespace blink |
OLD | NEW |