Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkPictureStateTree.cpp
index 9f2db25..d2f0e6e 100644 (file)
@@ -9,33 +9,28 @@
 #include "SkPictureStateTree.h"
 #include "SkCanvas.h"
 
-SK_DEFINE_INST_COUNT(SkPictureStateTree)
-
 SkPictureStateTree::SkPictureStateTree()
     : fAlloc(2048)
-    , fRoot(NULL)
     , fLastRestoredNode(NULL)
     , fStateStack(sizeof(Draw), 16) {
-    SkMatrix* identity = static_cast<SkMatrix*>(fAlloc.allocThrow(sizeof(SkMatrix)));
-    identity->reset();
-    fRoot = static_cast<Node*>(fAlloc.allocThrow(sizeof(Node)));
-    fRoot->fParent = NULL;
-    fRoot->fMatrix = identity;
-    fRoot->fFlags = Node::kSave_Flag;
-    fRoot->fOffset = 0;
-    fRoot->fLevel = 0;
-    fCurrentState.fNode = fRoot;
-    fCurrentState.fMatrix = identity;
+    fRootMatrix.reset();
+    fRoot.fParent = NULL;
+    fRoot.fMatrix = &fRootMatrix;
+    fRoot.fFlags = Node::kSave_Flag;
+    fRoot.fOffset = 0;
+    fRoot.fLevel = 0;
+    fCurrentState.fNode = &fRoot;
+    fCurrentState.fMatrix = &fRootMatrix;
     *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState;
 }
 
 SkPictureStateTree::~SkPictureStateTree() {
 }
 
-SkPictureStateTree::Draw* SkPictureStateTree::appendDraw(uint32_t offset) {
+SkPictureStateTree::Draw* SkPictureStateTree::appendDraw(size_t offset) {
     Draw* draw = static_cast<Draw*>(fAlloc.allocThrow(sizeof(Draw)));
     *draw = fCurrentState;
-    draw->fOffset = offset;
+    draw->fOffset = SkToU32(offset);
     return draw;
 }
 
@@ -44,7 +39,7 @@ void SkPictureStateTree::appendSave() {
     fCurrentState.fNode->fFlags |= Node::kSave_Flag;
 }
 
-void SkPictureStateTree::appendSaveLayer(uint32_t offset) {
+void SkPictureStateTree::appendSaveLayer(size_t offset) {
     *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState;
     this->appendNode(offset);
     fCurrentState.fNode->fFlags |= Node::kSaveLayer_Flag;
@@ -74,18 +69,19 @@ void SkPictureStateTree::appendTransform(const SkMatrix& trans) {
     fCurrentState.fMatrix = m;
 }
 
-void SkPictureStateTree::appendClip(uint32_t offset) {
+void SkPictureStateTree::appendClip(size_t offset) {
     this->appendNode(offset);
 }
 
-SkPictureStateTree::Iterator SkPictureStateTree::getIterator(const SkTDArray<void*>& draws,
-                                                             SkCanvas* canvas) {
-    return Iterator(draws, canvas, fRoot);
+void SkPictureStateTree::initIterator(SkPictureStateTree::Iterator* iter,
+                                      const SkTDArray<void*>& draws,
+                                      SkCanvas* canvas) {
+    iter->init(draws, canvas, &fRoot);
 }
 
-void SkPictureStateTree::appendNode(uint32_t offset) {
+void SkPictureStateTree::appendNode(size_t offset) {
     Node* n = static_cast<Node*>(fAlloc.allocThrow(sizeof(Node)));
-    n->fOffset = offset;
+    n->fOffset = SkToU32(offset);
     n->fFlags = 0;
     n->fParent = fCurrentState.fNode;
     n->fLevel = fCurrentState.fNode->fLevel + 1;
@@ -93,37 +89,65 @@ void SkPictureStateTree::appendNode(uint32_t offset) {
     fCurrentState.fNode = n;
 }
 
-SkPictureStateTree::Iterator::Iterator(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root)
-    : fDraws(&draws)
-    , fCanvas(canvas)
-    , fCurrentNode(root)
-    , fPlaybackMatrix(canvas->getTotalMatrix())
-    , fCurrentMatrix(NULL)
-    , fPlaybackIndex(0)
-    , fSave(false)
-    , fValid(true) {
+void SkPictureStateTree::Iterator::init(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root) {
+    SkASSERT(!fValid);
+    fDraws = &draws;
+    fCanvas = canvas;
+    fCurrentNode = root;
+    fPlaybackMatrix = canvas->getTotalMatrix();
+    fCurrentMatrix = NULL;
+    fPlaybackIndex = 0;
+    fSave = false;
+    fValid = true;
+}
+
+void SkPictureStateTree::Iterator::setCurrentMatrix(const SkMatrix* matrix) {
+    SkASSERT(NULL != matrix);
+
+    if (matrix == fCurrentMatrix) {
+        return;
+    }
+
+    // The matrix is in recording space, but we also inherit
+    // a playback matrix from out target canvas.
+    SkMatrix m = *matrix;
+    m.postConcat(fPlaybackMatrix);
+    fCanvas->setMatrix(m);
+    fCurrentMatrix = matrix;
+}
+
+uint32_t SkPictureStateTree::Iterator::finish() {
+    if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) {
+        fCanvas->restore();
+    }
+
+    for (fCurrentNode = fCurrentNode->fParent; fCurrentNode;
+            fCurrentNode = fCurrentNode->fParent) {
+        // Note: we call restore() twice when both flags are set.
+        if (fCurrentNode->fFlags & Node::kSave_Flag) {
+            fCanvas->restore();
+        }
+        if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) {
+            fCanvas->restore();
+        }
+    }
+
+    fCanvas->setMatrix(fPlaybackMatrix);
+    fCurrentMatrix = NULL;
+    return kDrawComplete;
 }
 
-uint32_t SkPictureStateTree::Iterator::draw() {
+uint32_t SkPictureStateTree::Iterator::nextDraw() {
     SkASSERT(this->isValid());
     if (fPlaybackIndex >= fDraws->count()) {
-        // restore back to where we started
-        if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
-        fCurrentNode = fCurrentNode->fParent;
-        while (NULL != fCurrentNode) {
-            if (fCurrentNode->fFlags & Node::kSave_Flag) { fCanvas->restore(); }
-            if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
-            fCurrentNode = fCurrentNode->fParent;
-        }
-        fCanvas->setMatrix(fPlaybackMatrix);
-        return kDrawComplete;
+        return this->finish();
     }
 
     Draw* draw = static_cast<Draw*>((*fDraws)[fPlaybackIndex]);
     Node* targetNode = draw->fNode;
 
     if (fSave) {
-        fCanvas->save(SkCanvas::kClip_SaveFlag);
+        fCanvas->save();
         fSave = false;
     }
 
@@ -142,8 +166,16 @@ uint32_t SkPictureStateTree::Iterator::draw() {
                 uint16_t currentLevel = tmp->fLevel;
                 uint16_t targetLevel = ancestor->fLevel;
                 if (currentLevel >= targetLevel) {
-                    if (tmp != fCurrentNode && tmp->fFlags & Node::kSave_Flag) { fCanvas->restore(); }
-                    if (tmp->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
+                    if (tmp != fCurrentNode && tmp->fFlags & Node::kSave_Flag) {
+                        fCanvas->restore();
+                        // restore() may change the matrix, so we need to reapply.
+                        fCurrentMatrix = NULL;
+                    }
+                    if (tmp->fFlags & Node::kSaveLayer_Flag) {
+                        fCanvas->restore();
+                        // restore() may change the matrix, so we need to reapply.
+                        fCurrentMatrix = NULL;
+                    }
                     tmp = tmp->fParent;
                 }
                 if (currentLevel <= targetLevel) {
@@ -153,8 +185,14 @@ uint32_t SkPictureStateTree::Iterator::draw() {
             }
 
             if (ancestor->fFlags & Node::kSave_Flag) {
-                if (fCurrentNode != ancestor) { fCanvas->restore(); }
-                if (targetNode != ancestor) { fCanvas->save(SkCanvas::kClip_SaveFlag); }
+                if (fCurrentNode != ancestor) {
+                    fCanvas->restore();
+                    // restore() may change the matrix, so we need to reapply.
+                    fCurrentMatrix = NULL;
+                }
+                if (targetNode != ancestor) {
+                    fCanvas->save();
+                }
             }
             fCurrentNode = ancestor;
         }
@@ -162,29 +200,18 @@ uint32_t SkPictureStateTree::Iterator::draw() {
         // If we're not at the target node yet, we'll need to return an offset to make the caller
         // apply the next clip or saveLayer.
         if (fCurrentNode != targetNode) {
-            if (fCurrentMatrix != fNodes.top()->fMatrix) {
-                fCurrentMatrix = fNodes.top()->fMatrix;
-                SkMatrix tmp = *fNodes.top()->fMatrix;
-                tmp.postConcat(fPlaybackMatrix);
-                fCanvas->setMatrix(tmp);
-            }
             uint32_t offset = fNodes.top()->fOffset;
             fCurrentNode = fNodes.top();
             fSave = fCurrentNode != targetNode && fCurrentNode->fFlags & Node::kSave_Flag;
             fNodes.pop();
+            this->setCurrentMatrix(fCurrentNode->fMatrix);
             return offset;
         }
     }
 
     // If we got this far, the clip/saveLayer state is all set, so we can proceed to set the matrix
     // for the draw, and return its offset.
-
-    if (fCurrentMatrix != draw->fMatrix) {
-        SkMatrix tmp = *draw->fMatrix;
-        tmp.postConcat(fPlaybackMatrix);
-        fCanvas->setMatrix(tmp);
-        fCurrentMatrix = draw->fMatrix;
-    }
+    this->setCurrentMatrix(draw->fMatrix);
 
     ++fPlaybackIndex;
     return draw->fOffset;