Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkBBoxHierarchyRecord.cpp
1
2 /*
3  * Copyright 2012 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8
9 #include "SkBBoxHierarchyRecord.h"
10 #include "SkPictureStateTree.h"
11
12 SkBBoxHierarchyRecord::SkBBoxHierarchyRecord(const SkISize& size,
13                                              uint32_t recordFlags,
14                                              SkBBoxHierarchy* h)
15     : INHERITED(size, recordFlags) {
16     fStateTree = SkNEW(SkPictureStateTree);
17     fBoundingHierarchy = h;
18     fBoundingHierarchy->ref();
19     fBoundingHierarchy->setClient(this);
20 }
21
22 void SkBBoxHierarchyRecord::handleBBox(const SkRect& bounds) {
23     SkPictureStateTree::Draw* draw = fStateTree->appendDraw(this->writeStream().bytesWritten());
24     fBoundingHierarchy->insert(draw, bounds, true);
25 }
26
27 void SkBBoxHierarchyRecord::willSave() {
28     fStateTree->appendSave();
29     this->INHERITED::willSave();
30 }
31
32 SkCanvas::SaveLayerStrategy SkBBoxHierarchyRecord::willSaveLayer(const SkRect* bounds,
33                                                                  const SkPaint* paint,
34                                                                  SaveFlags flags) {
35     // For now, assume all filters affect transparent black.
36     // FIXME: This could be made less conservative as an optimization.
37     bool paintAffectsTransparentBlack = paint &&
38         ((paint->getImageFilter()) ||
39          (paint->getColorFilter()));
40     bool needToHandleBBox = paintAffectsTransparentBlack;
41     if (!needToHandleBBox && paint) {
42       // Unusual Xfermodes require us to process a saved layer
43       // even with operations outisde the clip.
44       // For example, DstIn is used by masking layers.
45       // https://code.google.com/p/skia/issues/detail?id=1291
46       SkXfermode* xfermode = paint->getXfermode();
47       SkXfermode::Mode mode;
48       // SrcOver is the common case with a NULL xfermode, so we should
49       // make that the fast path and bypass the mode extraction and test.
50       if (xfermode && xfermode->asMode(&mode)) {
51         switch (mode) {
52           case SkXfermode::kClear_Mode:
53           case SkXfermode::kSrc_Mode:
54           case SkXfermode::kSrcIn_Mode:
55           case SkXfermode::kDstIn_Mode:
56           case SkXfermode::kSrcOut_Mode:
57           case SkXfermode::kDstATop_Mode:
58           case SkXfermode::kModulate_Mode:
59             needToHandleBBox = true;
60             break;
61           default:
62             break;
63         }
64       }
65     }
66
67     SkRect drawBounds;
68     if (needToHandleBBox) {
69         SkIRect deviceBounds;
70         this->getClipDeviceBounds(&deviceBounds);
71         drawBounds.set(deviceBounds);
72     }
73     fStateTree->appendSaveLayer(this->writeStream().bytesWritten());
74     SkCanvas::SaveLayerStrategy strategy = this->INHERITED::willSaveLayer(bounds, paint, flags);
75     if (needToHandleBBox) {
76         this->handleBBox(drawBounds);
77         this->addNoOp();
78     }
79     return strategy;
80 }
81
82 void SkBBoxHierarchyRecord::willRestore() {
83     fStateTree->appendRestore();
84     this->INHERITED::willRestore();
85 }
86
87 void SkBBoxHierarchyRecord::didConcat(const SkMatrix& matrix) {
88     fStateTree->appendTransform(getTotalMatrix());
89     INHERITED::didConcat(matrix);
90 }
91
92 void SkBBoxHierarchyRecord::didSetMatrix(const SkMatrix& matrix) {
93     fStateTree->appendTransform(getTotalMatrix());
94     INHERITED::didSetMatrix(matrix);
95 }
96
97 void SkBBoxHierarchyRecord::onClipRect(const SkRect& rect,
98                                        SkRegion::Op op,
99                                        ClipEdgeStyle edgeStyle) {
100     fStateTree->appendClip(this->writeStream().bytesWritten());
101     this->INHERITED::onClipRect(rect, op, edgeStyle);
102 }
103
104 void SkBBoxHierarchyRecord::onClipRegion(const SkRegion& region,
105                                          SkRegion::Op op) {
106     fStateTree->appendClip(this->writeStream().bytesWritten());
107     this->INHERITED::onClipRegion(region, op);
108 }
109
110 void SkBBoxHierarchyRecord::onClipPath(const SkPath& path,
111                                        SkRegion::Op op,
112                                        ClipEdgeStyle edgeStyle) {
113     fStateTree->appendClip(this->writeStream().bytesWritten());
114     this->INHERITED::onClipPath(path, op, edgeStyle);
115 }
116
117 void SkBBoxHierarchyRecord::onClipRRect(const SkRRect& rrect,
118                                         SkRegion::Op op,
119                                         ClipEdgeStyle edgeStyle) {
120     fStateTree->appendClip(this->writeStream().bytesWritten());
121     this->INHERITED::onClipRRect(rrect, op, edgeStyle);
122 }
123
124 bool SkBBoxHierarchyRecord::shouldRewind(void* data) {
125     // SkBBoxHierarchy::rewindInserts is called by SkPicture after the
126     // SkPicture has rewound its command stream.  To match that rewind in the
127     // BBH, we rewind all draws that reference commands that were recorded
128     // past the point to which the SkPicture has rewound, which is given by
129     // writeStream().bytesWritten().
130     SkPictureStateTree::Draw* draw = static_cast<SkPictureStateTree::Draw*>(data);
131     return draw->fOffset >= writeStream().bytesWritten();
132 }