15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (c) 2012, Google Inc. All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions are
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * met:
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Redistributions of source code must retain the above copyright
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer.
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Redistributions in binary form must reproduce the above
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * in the documentation and/or other materials provided with the
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * distribution.
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Neither the name of Google Inc. nor the names of its
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * contributors may be used to endorse or promote products derived from
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * this software without specific prior written permission.
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
33c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)#include "platform/graphics/RegionTracker.h"
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
35a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/graphics/GraphicsContext.h"
36c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)#include "third_party/skia/include/core/SkColorFilter.h"
37c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)#include "third_party/skia/include/core/SkShader.h"
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
39c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink {
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
41c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)RegionTracker::RegionTracker()
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    : m_opaqueRect(SkRect::MakeEmpty())
43c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    , m_trackedRegionType(Opaque)
44c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles){
45c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)}
46c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)
47c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)void RegionTracker::reset()
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
49c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    ASSERT(m_canvasLayerStack.isEmpty());
50c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    m_opaqueRect = SkRect::MakeEmpty();
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
53c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)IntRect RegionTracker::asRect() const
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Returns the largest enclosed rect.
5609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    // TODO: actually, this logic looks like its returning the smallest.
5709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    //       to return largest, shouldn't we take floor of left/top
5809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    //       and the ceil of right/bottom?
5909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    int left = SkScalarCeilToInt(m_opaqueRect.fLeft);
6009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    int top = SkScalarCeilToInt(m_opaqueRect.fTop);
6109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    int right = SkScalarFloorToInt(m_opaqueRect.fRight);
6209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    int bottom = SkScalarFloorToInt(m_opaqueRect.fBottom);
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return IntRect(left, top, right-left, bottom-top);
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Returns true if the xfermode will force the dst to be opaque, regardless of the current dst.
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static inline bool xfermodeIsOpaque(const SkPaint& paint, bool srcIsOpaque)
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!srcIsOpaque)
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkXfermode* xfermode = paint.getXfermode();
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!xfermode)
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true; // default to kSrcOver_Mode
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkXfermode::Mode mode;
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!xfermode->asMode(&mode))
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    switch (mode) {
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kSrc_Mode: // source
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kSrcOver_Mode: // source + dest - source*dest
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kDstOver_Mode: // source + dest - source*dest
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kDstATop_Mode: // source
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kPlus_Mode: // source+dest
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    default: // the rest are all source + dest - source*dest
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kClear_Mode: // 0
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kDst_Mode: // dest
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kSrcIn_Mode: // source * dest
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kDstIn_Mode: // dest * source
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kSrcOut_Mode: // source * (1-dest)
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kDstOut_Mode: // dest * (1-source)
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kSrcATop_Mode: // dest
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kXor_Mode: // source + dest - 2*(source*dest)
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
99c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)static inline bool xfermodeIsOverwrite(const SkPaint& paint)
100c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles){
101c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    SkXfermode* xfermode = paint.getXfermode();
102c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (!xfermode)
103c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        return false; // default to kSrcOver_Mode
104c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    SkXfermode::Mode mode;
105c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (!xfermode->asMode(&mode))
106c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        return false;
107c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    switch (mode) {
108c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    case SkXfermode::kSrc_Mode:
109c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    case SkXfermode::kClear_Mode:
110c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        return true;
111c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    default:
112c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        return false;
113c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    }
114c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)}
115c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Returns true if the xfermode will keep the dst opaque, assuming the dst is already opaque.
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static inline bool xfermodePreservesOpaque(const SkPaint& paint, bool srcIsOpaque)
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkXfermode* xfermode = paint.getXfermode();
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!xfermode)
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true; // default to kSrcOver_Mode
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkXfermode::Mode mode;
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!xfermode->asMode(&mode))
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    switch (mode) {
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kDst_Mode: // dest
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kSrcOver_Mode: // source + dest - source*dest
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kDstOver_Mode: // source + dest - source*dest
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kSrcATop_Mode: // dest
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kPlus_Mode: // source+dest
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    default: // the rest are all source + dest - source*dest
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kClear_Mode: // 0
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kSrcOut_Mode: // source * (1-dest)
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kDstOut_Mode: // dest * (1-source)
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kXor_Mode: // source + dest - 2*(source*dest)
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kSrc_Mode: // source
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kSrcIn_Mode: // source * dest
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kDstIn_Mode: // dest * source
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case SkXfermode::kDstATop_Mode: // source
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return srcIsOpaque;
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Returns true if all pixels painted will be opaque.
148c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)static inline bool paintIsOpaque(const SkPaint& paint, RegionTracker::DrawType drawType, const SkBitmap* bitmap)
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (paint.getAlpha() < 0xFF)
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
152c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    bool checkFillOnly = drawType != RegionTracker::FillOrStroke;
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!checkFillOnly && paint.getStyle() != SkPaint::kFill_Style && paint.isAntiAlias())
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkShader* shader = paint.getShader();
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (shader && !shader->isOpaque())
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (bitmap && !bitmap->isOpaque())
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (paint.getLooper())
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (paint.getImageFilter())
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (paint.getMaskFilter())
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkColorFilter* colorFilter = paint.getColorFilter();
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (colorFilter && !(colorFilter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag))
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Returns true if there is a rectangular clip, with the result in |deviceClipRect|.
17353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)static inline bool getDeviceClipAsRect(const GraphicsContext* context, SkRect& deviceClipRect)
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Get the current clip in device coordinate space.
176e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)    if (!context->canvas()->isClipRect()) {
177e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)        deviceClipRect.setEmpty();
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
179e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)    }
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkIRect deviceClipIRect;
18281a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)    if (context->canvas()->getClipDeviceBounds(&deviceClipIRect))
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        deviceClipRect.set(deviceClipIRect);
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        deviceClipRect.setEmpty();
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
190c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)void RegionTracker::pushCanvasLayer(const SkPaint* paint)
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    CanvasLayerState state;
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (paint)
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        state.paint = *paint;
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_canvasLayerStack.append(state);
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
198c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)void RegionTracker::popCanvasLayer(const GraphicsContext* context)
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(!m_canvasLayerStack.isEmpty());
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_canvasLayerStack.isEmpty())
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const CanvasLayerState& canvasLayer = m_canvasLayerStack.last();
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkRect layerOpaqueRect = canvasLayer.opaqueRect;
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkPaint layerPaint = canvasLayer.paint;
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Apply the image mask.
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (canvasLayer.hasImageMask && !layerOpaqueRect.intersect(canvasLayer.imageOpaqueRect))
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        layerOpaqueRect.setEmpty();
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_canvasLayerStack.removeLast();
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    applyOpaqueRegionFromLayer(context, layerOpaqueRect, layerPaint);
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
217c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)void RegionTracker::setImageMask(const SkRect& imageOpaqueRect)
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(!m_canvasLayerStack.isEmpty());
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_canvasLayerStack.last().hasImageMask = true;
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_canvasLayerStack.last().imageOpaqueRect = imageOpaqueRect;
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
224c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)void RegionTracker::didDrawRect(const GraphicsContext* context, const SkRect& fillRect, const SkPaint& paint, const SkBitmap* sourceBitmap)
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Any stroking may put alpha in pixels even if the filling part does not.
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (paint.getStyle() != SkPaint::kFill_Style) {
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        bool fillsBounds = false;
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
230c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        if (!paint.canComputeFastBounds()) {
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            didDrawUnbounded(context, paint, FillOrStroke);
232c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        } else {
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            SkRect strokeRect;
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            strokeRect = paint.computeFastBounds(fillRect, &strokeRect);
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            didDraw(context, strokeRect, paint, sourceBitmap, fillsBounds, FillOrStroke);
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool fillsBounds = paint.getStyle() != SkPaint::kStroke_Style;
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    didDraw(context, fillRect, paint, sourceBitmap, fillsBounds, FillOnly);
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
243c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)void RegionTracker::didDrawPath(const GraphicsContext* context, const SkPath& path, const SkPaint& paint)
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkRect rect;
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (path.isRect(&rect)) {
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        didDrawRect(context, rect, paint, 0);
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool fillsBounds = false;
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
253c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (!paint.canComputeFastBounds()) {
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        didDrawUnbounded(context, paint, FillOrStroke);
255c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    } else {
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        rect = paint.computeFastBounds(path.getBounds(), &rect);
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        didDraw(context, rect, paint, 0, fillsBounds, FillOrStroke);
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
261c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)void RegionTracker::didDrawPoints(const GraphicsContext* context, SkCanvas::PointMode mode, int numPoints, const SkPoint points[], const SkPaint& paint)
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!numPoints)
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkRect rect;
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    rect.fLeft = points[0].fX;
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    rect.fRight = points[0].fX + 1;
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    rect.fTop = points[0].fY;
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    rect.fBottom = points[0].fY + 1;
2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (int i = 1; i < numPoints; ++i) {
2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        rect.fLeft = std::min(rect.fLeft, points[i].fX);
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        rect.fRight = std::max(rect.fRight, points[i].fX + 1);
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        rect.fTop = std::min(rect.fTop, points[i].fY);
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        rect.fBottom = std::max(rect.fBottom, points[i].fY + 1);
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool fillsBounds = false;
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
281c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (!paint.canComputeFastBounds()) {
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        didDrawUnbounded(context, paint, FillOrStroke);
283c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    } else {
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        rect = paint.computeFastBounds(rect, &rect);
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        didDraw(context, rect, paint, 0, fillsBounds, FillOrStroke);
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
289c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)void RegionTracker::didDrawBounded(const GraphicsContext* context, const SkRect& bounds, const SkPaint& paint)
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool fillsBounds = false;
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
293c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (!paint.canComputeFastBounds()) {
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        didDrawUnbounded(context, paint, FillOrStroke);
295c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    } else {
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        SkRect rect;
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        rect = paint.computeFastBounds(bounds, &rect);
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        didDraw(context, rect, paint, 0, fillsBounds, FillOrStroke);
2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
302c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)void RegionTracker::didDraw(const GraphicsContext* context, const SkRect& rect, const SkPaint& paint, const SkBitmap* sourceBitmap, bool fillsBounds, DrawType drawType)
3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkRect targetRect = rect;
3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Apply the transform to device coordinate space.
30781a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)    SkMatrix canvasTransform = context->canvas()->getTotalMatrix();
3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!canvasTransform.mapRect(&targetRect))
3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        fillsBounds = false;
3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Apply the current clip.
3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkRect deviceClipRect;
3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!getDeviceClipAsRect(context, deviceClipRect))
3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        fillsBounds = false;
3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else if (!targetRect.intersect(deviceClipRect))
3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
318c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (m_trackedRegionType == Overwrite && fillsBounds && xfermodeIsOverwrite(paint)) {
319c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        markRectAsOpaque(targetRect);
320c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        return;
321c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    }
322c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool drawsOpaque = paintIsOpaque(paint, drawType, sourceBitmap);
3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool xfersOpaque = xfermodeIsOpaque(paint, drawsOpaque);
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
326c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (fillsBounds && xfersOpaque) {
3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        markRectAsOpaque(targetRect);
328c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    } else if (m_trackedRegionType == Opaque && !xfermodePreservesOpaque(paint, drawsOpaque)) {
3295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        markRectAsNonOpaque(targetRect);
330c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    }
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
333c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)void RegionTracker::didDrawUnbounded(const GraphicsContext* context, const SkPaint& paint, DrawType drawType)
3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool drawsOpaque = paintIsOpaque(paint, drawType, 0);
3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool preservesOpaque = xfermodePreservesOpaque(paint, drawsOpaque);
3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (preservesOpaque)
3395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkRect deviceClipRect;
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    getDeviceClipAsRect(context, deviceClipRect);
3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    markRectAsNonOpaque(deviceClipRect);
3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
346c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)void RegionTracker::applyOpaqueRegionFromLayer(const GraphicsContext* context, const SkRect& layerOpaqueRect, const SkPaint& paint)
3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkRect deviceClipRect;
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool deviceClipIsARect = getDeviceClipAsRect(context, deviceClipRect);
3505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
351e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)    if (deviceClipIsARect && deviceClipRect.isEmpty())
3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkRect sourceOpaqueRect = layerOpaqueRect;
3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Save the opaque area in the destination, so we can preserve the parts of it under the source opaque area if possible.
356926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    SkRect destinationOpaqueRect = currentTrackingOpaqueRect();
3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool outsideSourceOpaqueRectPreservesOpaque = xfermodePreservesOpaque(paint, false);
359e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)    if (!outsideSourceOpaqueRectPreservesOpaque) {
360e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)        if (!deviceClipIsARect) {
361e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)            markAllAsNonOpaque();
362e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)            return;
363e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)        }
3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        markRectAsNonOpaque(deviceClipRect);
365e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)    }
3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!deviceClipIsARect)
3685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!sourceOpaqueRect.intersect(deviceClipRect))
3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool sourceOpaqueRectDrawsOpaque = paintIsOpaque(paint, FillOnly, 0);
3735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool sourceOpaqueRectXfersOpaque = xfermodeIsOpaque(paint, sourceOpaqueRectDrawsOpaque);
3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool sourceOpaqueRectPreservesOpaque = xfermodePreservesOpaque(paint, sourceOpaqueRectDrawsOpaque);
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // If the layer's opaque area is being drawn opaque in the layer below, then mark it opaque. Otherwise,
3775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // if it preserves opaque then keep the intersection of the two.
3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (sourceOpaqueRectXfersOpaque)
3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        markRectAsOpaque(sourceOpaqueRect);
3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else if (sourceOpaqueRectPreservesOpaque && sourceOpaqueRect.intersect(destinationOpaqueRect))
3815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        markRectAsOpaque(sourceOpaqueRect);
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
384c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)void RegionTracker::markRectAsOpaque(const SkRect& rect)
3855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // We want to keep track of an opaque region but bound its complexity at a constant size.
3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // We keep track of the largest rectangle seen by area. If we can add the new rect to this
3885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // rectangle then we do that, as that is the cheapest way to increase the area returned
3895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // without increasing the complexity.
3905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
391926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    SkRect& opaqueRect = currentTrackingOpaqueRect();
3925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (rect.isEmpty())
3945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
3955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (opaqueRect.contains(rect))
3965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
3975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (rect.contains(opaqueRect)) {
3985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        opaqueRect = rect;
3995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
4005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (rect.fTop <= opaqueRect.fTop && rect.fBottom >= opaqueRect.fBottom) {
4035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (rect.fLeft < opaqueRect.fLeft && rect.fRight >= opaqueRect.fLeft)
4045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            opaqueRect.fLeft = rect.fLeft;
4055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (rect.fRight > opaqueRect.fRight && rect.fLeft <= opaqueRect.fRight)
4065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            opaqueRect.fRight = rect.fRight;
4075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } else if (rect.fLeft <= opaqueRect.fLeft && rect.fRight >= opaqueRect.fRight) {
4085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (rect.fTop < opaqueRect.fTop && rect.fBottom >= opaqueRect.fTop)
4095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            opaqueRect.fTop = rect.fTop;
4105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (rect.fBottom > opaqueRect.fBottom && rect.fTop <= opaqueRect.fBottom)
4115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            opaqueRect.fBottom = rect.fBottom;
4125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    long opaqueArea = (long)opaqueRect.width() * (long)opaqueRect.height();
4155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    long area = (long)rect.width() * (long)rect.height();
4165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (area > opaqueArea)
4175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        opaqueRect = rect;
4185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
420c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)void RegionTracker::markRectAsNonOpaque(const SkRect& rect)
4215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // We want to keep as much of the current opaque rectangle as we can, so find the one largest
4235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // rectangle inside m_opaqueRect that does not intersect with |rect|.
4245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
425926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    SkRect& opaqueRect = currentTrackingOpaqueRect();
4265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!SkRect::Intersects(rect, opaqueRect))
4285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
4295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (rect.contains(opaqueRect)) {
4305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        markAllAsNonOpaque();
4315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
4325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int deltaLeft = rect.fLeft - opaqueRect.fLeft;
4355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int deltaRight = opaqueRect.fRight - rect.fRight;
4365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int deltaTop = rect.fTop - opaqueRect.fTop;
4375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int deltaBottom = opaqueRect.fBottom - rect.fBottom;
4385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // horizontal is the larger of the two rectangles to the left or to the right of |rect| and inside opaqueRect.
4405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // vertical is the larger of the two rectangles above or below |rect| and inside opaqueRect.
4415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkRect horizontal = opaqueRect;
4425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (deltaTop > deltaBottom)
4435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        horizontal.fBottom = rect.fTop;
4445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else
4455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        horizontal.fTop = rect.fBottom;
4465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SkRect vertical = opaqueRect;
4475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (deltaLeft > deltaRight)
4485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        vertical.fRight = rect.fLeft;
4495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else
4505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        vertical.fLeft = rect.fRight;
4515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if ((long)horizontal.width() * (long)horizontal.height() > (long)vertical.width() * (long)vertical.height())
4535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        opaqueRect = horizontal;
4545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else
4555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        opaqueRect = vertical;
4565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
458c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)void RegionTracker::markAllAsNonOpaque()
4595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
460926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    SkRect& opaqueRect = currentTrackingOpaqueRect();
4615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    opaqueRect.setEmpty();
4625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
464c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)SkRect& RegionTracker::currentTrackingOpaqueRect()
465926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
466926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // If we are drawing into a canvas layer, then track the opaque rect in that layer.
467926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    return m_canvasLayerStack.isEmpty() ? m_opaqueRect : m_canvasLayerStack.last().opaqueRect;
468926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
469926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
470c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)} // namespace blink
471