OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkLayerInfo.h" | 8 #include "SkLayerInfo.h" |
9 #include "SkRecordDraw.h" | 9 #include "SkRecordDraw.h" |
10 #include "SkPatchUtils.h" | 10 #include "SkPatchUtils.h" |
11 | 11 |
12 void SkRecordDraw(const SkRecord& record, | 12 void SkRecordDraw(const SkRecord& record, |
13 SkCanvas* canvas, | 13 SkCanvas* canvas, |
14 SkPicture const* const drawablePicts[], int drawableCount, | 14 SkPicture const* const drawablePicts[], |
| 15 SkCanvasDrawable* const drawables[], |
| 16 int drawableCount, |
15 const SkBBoxHierarchy* bbh, | 17 const SkBBoxHierarchy* bbh, |
16 SkDrawPictureCallback* callback) { | 18 SkDrawPictureCallback* callback) { |
17 SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/); | 19 SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/); |
18 | 20 |
19 if (bbh) { | 21 if (bbh) { |
20 // Draw only ops that affect pixels in the canvas's current clip. | 22 // Draw only ops that affect pixels in the canvas's current clip. |
21 // The SkRecord and BBH were recorded in identity space. This canvas | 23 // The SkRecord and BBH were recorded in identity space. This canvas |
22 // is not necessarily in that same space. getClipBounds() returns us | 24 // is not necessarily in that same space. getClipBounds() returns us |
23 // this canvas' clip bounds transformed back into identity space, which | 25 // this canvas' clip bounds transformed back into identity space, which |
24 // lets us query the BBH. | 26 // lets us query the BBH. |
25 SkRect query; | 27 SkRect query; |
26 if (!canvas->getClipBounds(&query)) { | 28 if (!canvas->getClipBounds(&query)) { |
27 // We want to make sure our query rectangle is never totally empty. | 29 // We want to make sure our query rectangle is never totally empty. |
28 // Clear ignores the clip, so it must draw even if the clip is logic
ally empty. | 30 // Clear ignores the clip, so it must draw even if the clip is logic
ally empty. |
29 query = SkRect::MakeWH(SK_ScalarNearlyZero, SK_ScalarNearlyZero); | 31 query = SkRect::MakeWH(SK_ScalarNearlyZero, SK_ScalarNearlyZero); |
30 } | 32 } |
31 | 33 |
32 SkTDArray<unsigned> ops; | 34 SkTDArray<unsigned> ops; |
33 bbh->search(query, &ops); | 35 bbh->search(query, &ops); |
34 | 36 |
35 SkRecords::Draw draw(canvas, drawablePicts, drawableCount); | 37 SkRecords::Draw draw(canvas, drawablePicts, drawables, drawableCount); |
36 for (int i = 0; i < ops.count(); i++) { | 38 for (int i = 0; i < ops.count(); i++) { |
37 if (callback && callback->abortDrawing()) { | 39 if (callback && callback->abortDrawing()) { |
38 return; | 40 return; |
39 } | 41 } |
40 // This visit call uses the SkRecords::Draw::operator() to call | 42 // This visit call uses the SkRecords::Draw::operator() to call |
41 // methods on the |canvas|, wrapped by methods defined with the | 43 // methods on the |canvas|, wrapped by methods defined with the |
42 // DRAW() macro. | 44 // DRAW() macro. |
43 record.visit<void>(ops[i], draw); | 45 record.visit<void>(ops[i], draw); |
44 } | 46 } |
45 } else { | 47 } else { |
46 // Draw all ops. | 48 // Draw all ops. |
47 SkRecords::Draw draw(canvas, drawablePicts, drawableCount); | 49 SkRecords::Draw draw(canvas, drawablePicts, drawables, drawableCount); |
48 for (unsigned i = 0; i < record.count(); i++) { | 50 for (unsigned i = 0; i < record.count(); i++) { |
49 if (callback && callback->abortDrawing()) { | 51 if (callback && callback->abortDrawing()) { |
50 return; | 52 return; |
51 } | 53 } |
52 // This visit call uses the SkRecords::Draw::operator() to call | 54 // This visit call uses the SkRecords::Draw::operator() to call |
53 // methods on the |canvas|, wrapped by methods defined with the | 55 // methods on the |canvas|, wrapped by methods defined with the |
54 // DRAW() macro. | 56 // DRAW() macro. |
55 record.visit<void>(i, draw); | 57 record.visit<void>(i, draw); |
56 } | 58 } |
57 } | 59 } |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 DRAW(DrawTextBlob, drawTextBlob(r.blob, r.x, r.y, r.paint)); | 128 DRAW(DrawTextBlob, drawTextBlob(r.blob, r.x, r.y, r.paint)); |
127 DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, r.matrix, r.pa
int)); | 129 DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, r.matrix, r.pa
int)); |
128 DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.co
lors, | 130 DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.co
lors, |
129 r.xmode.get(), r.indices, r.indexCount, r.paint)
); | 131 r.xmode.get(), r.indices, r.indexCount, r.paint)
); |
130 DRAW(DrawData, drawData(r.data, r.length)); | 132 DRAW(DrawData, drawData(r.data, r.length)); |
131 #undef DRAW | 133 #undef DRAW |
132 | 134 |
133 template <> void Draw::draw(const DrawDrawable& r) { | 135 template <> void Draw::draw(const DrawDrawable& r) { |
134 SkASSERT(r.index >= 0); | 136 SkASSERT(r.index >= 0); |
135 SkASSERT(r.index < fDrawableCount); | 137 SkASSERT(r.index < fDrawableCount); |
136 fCanvas->drawPicture(fDrawablePicts[r.index]); | 138 if (fDrawables) { |
| 139 SkASSERT(NULL == fDrawablePicts); |
| 140 fCanvas->EXPERIMENTAL_drawDrawable(fDrawables[r.index]); |
| 141 } else { |
| 142 fCanvas->drawPicture(fDrawablePicts[r.index]); |
| 143 } |
137 } | 144 } |
138 | 145 |
139 // This is an SkRecord visitor that fills an SkBBoxHierarchy. | 146 // This is an SkRecord visitor that fills an SkBBoxHierarchy. |
140 // | 147 // |
141 // The interesting part here is how to calculate bounds for ops which don't | 148 // The interesting part here is how to calculate bounds for ops which don't |
142 // have intrinsic bounds. What is the bounds of a Save or a Translate? | 149 // have intrinsic bounds. What is the bounds of a Save or a Translate? |
143 // | 150 // |
144 // We answer this by thinking about a particular definition of bounds: if I | 151 // We answer this by thinking about a particular definition of bounds: if I |
145 // don't execute this op, pixels in this rectangle might draw incorrectly. So | 152 // don't execute this op, pixels in this rectangle might draw incorrectly. So |
146 // the bounds of a Save, a Translate, a Restore, etc. are the union of the | 153 // the bounds of a Save, a Translate, a Restore, etc. are the union of the |
147 // bounds of Draw* ops that they might have an effect on. For any given | 154 // bounds of Draw* ops that they might have an effect on. For any given |
148 // Save/Restore block, the bounds of the Save, the Restore, and any other | 155 // Save/Restore block, the bounds of the Save, the Restore, and any other |
149 // non-drawing ("control") ops inside are exactly the union of the bounds of | 156 // non-drawing ("control") ops inside are exactly the union of the bounds of |
150 // the drawing ops inside that block. | 157 // the drawing ops inside that block. |
151 // | 158 // |
152 // To implement this, we keep a stack of active Save blocks. As we consume ops | 159 // To implement this, we keep a stack of active Save blocks. As we consume ops |
153 // inside the Save/Restore block, drawing ops are unioned with the bounds of | 160 // inside the Save/Restore block, drawing ops are unioned with the bounds of |
154 // the block, and control ops are stashed away for later. When we finish the | 161 // the block, and control ops are stashed away for later. When we finish the |
155 // block with a Restore, our bounds are complete, and we go back and fill them | 162 // block with a Restore, our bounds are complete, and we go back and fill them |
156 // in for all the control ops we stashed away. | 163 // in for all the control ops we stashed away. |
157 class FillBounds : SkNoncopyable { | 164 class FillBounds : SkNoncopyable { |
158 public: | 165 public: |
159 FillBounds(const SkRect& cullRect, const SkRecord& record) | 166 FillBounds(const SkRect& cullRect, const SkRecord& record) |
160 : fNumRecords(record.count()) | 167 : fNumRecords(record.count()) |
161 , fCullRect(cullRect) | 168 , fCullRect(cullRect) |
162 , fBounds(record.count()) { | 169 , fBounds(record.count()) |
| 170 { |
163 // Calculate bounds for all ops. This won't go quite in order, so we'll
need | 171 // Calculate bounds for all ops. This won't go quite in order, so we'll
need |
164 // to store the bounds separately then feed them in to the BBH later in
order. | 172 // to store the bounds separately then feed them in to the BBH later in
order. |
165 fCTM = &SkMatrix::I(); | 173 fCTM = &SkMatrix::I(); |
166 fCurrentClipBounds = fCullRect; | 174 fCurrentClipBounds = fCullRect; |
167 } | 175 } |
168 | 176 |
169 void setCurrentOp(unsigned currentOp) { fCurrentOp = currentOp; } | 177 void setCurrentOp(unsigned currentOp) { fCurrentOp = currentOp; } |
170 | 178 |
171 void cleanUp(SkBBoxHierarchy* bbh) { | 179 void cleanUp(SkBBoxHierarchy* bbh) { |
172 // If we have any lingering unpaired Saves, simulate restores to make | 180 // If we have any lingering unpaired Saves, simulate restores to make |
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
584 Bounds fCurrentClipBounds; | 592 Bounds fCurrentClipBounds; |
585 | 593 |
586 // Used to track the bounds of Save/Restore blocks and the control ops insid
e them. | 594 // Used to track the bounds of Save/Restore blocks and the control ops insid
e them. |
587 SkTDArray<SaveBounds> fSaveStack; | 595 SkTDArray<SaveBounds> fSaveStack; |
588 SkTDArray<unsigned> fControlIndices; | 596 SkTDArray<unsigned> fControlIndices; |
589 }; | 597 }; |
590 | 598 |
591 // SkRecord visitor to gather saveLayer/restore information. | 599 // SkRecord visitor to gather saveLayer/restore information. |
592 class CollectLayers : SkNoncopyable { | 600 class CollectLayers : SkNoncopyable { |
593 public: | 601 public: |
594 CollectLayers(const SkRect& cullRect, const SkRecord& record, SkLayerInfo* a
ccelData) | 602 CollectLayers(const SkRect& cullRect, const SkRecord& record, |
| 603 const SkPicture::SnapshotArray* pictList, SkLayerInfo* accelDa
ta) |
595 : fSaveLayersInStack(0) | 604 : fSaveLayersInStack(0) |
596 , fAccelData(accelData) | 605 , fAccelData(accelData) |
597 , fFillBounds(cullRect, record) { | 606 , fPictList(pictList) |
598 } | 607 , fFillBounds(cullRect, record) |
| 608 {} |
599 | 609 |
600 void setCurrentOp(unsigned currentOp) { fFillBounds.setCurrentOp(currentOp);
} | 610 void setCurrentOp(unsigned currentOp) { fFillBounds.setCurrentOp(currentOp);
} |
601 | 611 |
602 void cleanUp(SkBBoxHierarchy* bbh) { | 612 void cleanUp(SkBBoxHierarchy* bbh) { |
603 // fFillBounds must perform its cleanUp first so that all the bounding | 613 // fFillBounds must perform its cleanUp first so that all the bounding |
604 // boxes associated with unbalanced restores are updated (prior to | 614 // boxes associated with unbalanced restores are updated (prior to |
605 // fetching their bound in popSaveLayerInfo). | 615 // fetching their bound in popSaveLayerInfo). |
606 fFillBounds.cleanUp(bbh); | 616 fFillBounds.cleanUp(bbh); |
607 | 617 |
608 while (!fSaveLayerStack.isEmpty()) { | 618 while (!fSaveLayerStack.isEmpty()) { |
(...skipping 22 matching lines...) Expand all Loading... |
631 const SkPaint* fPaint; | 641 const SkPaint* fPaint; |
632 }; | 642 }; |
633 | 643 |
634 template <typename T> void trackSaveLayers(const T& op) { | 644 template <typename T> void trackSaveLayers(const T& op) { |
635 /* most ops aren't involved in saveLayers */ | 645 /* most ops aren't involved in saveLayers */ |
636 } | 646 } |
637 void trackSaveLayers(const Save& s) { this->pushSaveLayerInfo(false, NULL);
} | 647 void trackSaveLayers(const Save& s) { this->pushSaveLayerInfo(false, NULL);
} |
638 void trackSaveLayers(const SaveLayer& sl) { this->pushSaveLayerInfo(true, sl
.paint); } | 648 void trackSaveLayers(const SaveLayer& sl) { this->pushSaveLayerInfo(true, sl
.paint); } |
639 void trackSaveLayers(const Restore& r) { this->popSaveLayerInfo(); } | 649 void trackSaveLayers(const Restore& r) { this->popSaveLayerInfo(); } |
640 | 650 |
641 void trackSaveLayers(const DrawPicture& dp) { | 651 void trackSaveLayersForPicture(const SkPicture* picture, const SkPaint* pain
t) { |
642 // For sub-pictures, we wrap their layer information within the parent | 652 // For sub-pictures, we wrap their layer information within the parent |
643 // picture's rendering hierarchy | 653 // picture's rendering hierarchy |
644 SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey(); | 654 SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey(); |
645 | 655 |
646 const SkLayerInfo* childData = | 656 const SkLayerInfo* childData = |
647 static_cast<const SkLayerInfo*>(dp.picture->EXPERIMENTAL_getAccelDat
a(key)); | 657 static_cast<const SkLayerInfo*>(picture->EXPERIMENTAL_getAccelData(k
ey)); |
648 if (!childData) { | 658 if (!childData) { |
649 // If the child layer hasn't been generated with saveLayer data we | 659 // If the child layer hasn't been generated with saveLayer data we |
650 // assume the worst (i.e., that it does contain layers which nest | 660 // assume the worst (i.e., that it does contain layers which nest |
651 // inside existing layers). Layers within sub-pictures that don't | 661 // inside existing layers). Layers within sub-pictures that don't |
652 // have saveLayer data cannot be hoisted. | 662 // have saveLayer data cannot be hoisted. |
653 // TODO: could the analysis data be use to fine tune this? | 663 // TODO: could the analysis data be use to fine tune this? |
654 this->updateStackForSaveLayer(); | 664 this->updateStackForSaveLayer(); |
655 return; | 665 return; |
656 } | 666 } |
657 | 667 |
658 for (int i = 0; i < childData->numBlocks(); ++i) { | 668 for (int i = 0; i < childData->numBlocks(); ++i) { |
659 const SkLayerInfo::BlockInfo& src = childData->block(i); | 669 const SkLayerInfo::BlockInfo& src = childData->block(i); |
660 | 670 |
661 FillBounds::Bounds newBound = fFillBounds.adjustAndMap(src.fBounds,
dp.paint); | 671 FillBounds::Bounds newBound = fFillBounds.adjustAndMap(src.fBounds,
paint); |
662 if (newBound.isEmpty()) { | 672 if (newBound.isEmpty()) { |
663 continue; | 673 continue; |
664 } | 674 } |
665 | 675 |
666 this->updateStackForSaveLayer(); | 676 this->updateStackForSaveLayer(); |
667 | 677 |
668 SkLayerInfo::BlockInfo& dst = fAccelData->addBlock(); | 678 SkLayerInfo::BlockInfo& dst = fAccelData->addBlock(); |
669 | 679 |
670 // If src.fPicture is NULL the layer is in dp.picture; otherwise | 680 // If src.fPicture is NULL the layer is in dp.picture; otherwise |
671 // it belongs to a sub-picture. | 681 // it belongs to a sub-picture. |
672 dst.fPicture = src.fPicture ? src.fPicture : static_cast<const SkPic
ture*>(dp.picture); | 682 dst.fPicture = src.fPicture ? src.fPicture : picture; |
673 dst.fPicture->ref(); | 683 dst.fPicture->ref(); |
674 dst.fBounds = newBound; | 684 dst.fBounds = newBound; |
675 dst.fLocalMat = src.fLocalMat; | 685 dst.fLocalMat = src.fLocalMat; |
676 dst.fPreMat = src.fPreMat; | 686 dst.fPreMat = src.fPreMat; |
677 dst.fPreMat.postConcat(fFillBounds.ctm()); | 687 dst.fPreMat.postConcat(fFillBounds.ctm()); |
678 if (src.fPaint) { | 688 if (src.fPaint) { |
679 dst.fPaint = SkNEW_ARGS(SkPaint, (*src.fPaint)); | 689 dst.fPaint = SkNEW_ARGS(SkPaint, (*src.fPaint)); |
680 } | 690 } |
681 dst.fSaveLayerOpID = src.fSaveLayerOpID; | 691 dst.fSaveLayerOpID = src.fSaveLayerOpID; |
682 dst.fRestoreOpID = src.fRestoreOpID; | 692 dst.fRestoreOpID = src.fRestoreOpID; |
683 dst.fHasNestedLayers = src.fHasNestedLayers; | 693 dst.fHasNestedLayers = src.fHasNestedLayers; |
684 dst.fIsNested = fSaveLayersInStack > 0 || src.fIsNested; | 694 dst.fIsNested = fSaveLayersInStack > 0 || src.fIsNested; |
685 } | 695 } |
686 } | 696 } |
687 | 697 |
| 698 void trackSaveLayers(const DrawPicture& dp) { |
| 699 this->trackSaveLayersForPicture(dp.picture, dp.paint); |
| 700 } |
| 701 |
| 702 void trackSaveLayers(const DrawDrawable& dp) { |
| 703 SkASSERT(fPictList); |
| 704 SkASSERT(dp.index >= 0 && dp.index < fPictList->count()); |
| 705 const SkPaint* paint = NULL; // drawables don't get a side-car paint |
| 706 this->trackSaveLayersForPicture(fPictList->begin()[dp.index], paint); |
| 707 } |
| 708 |
688 // Inform all the saveLayers already on the stack that they now have a | 709 // Inform all the saveLayers already on the stack that they now have a |
689 // nested saveLayer inside them | 710 // nested saveLayer inside them |
690 void updateStackForSaveLayer() { | 711 void updateStackForSaveLayer() { |
691 for (int index = fSaveLayerStack.count() - 1; index >= 0; --index) { | 712 for (int index = fSaveLayerStack.count() - 1; index >= 0; --index) { |
692 if (fSaveLayerStack[index].fHasNestedSaveLayer) { | 713 if (fSaveLayerStack[index].fHasNestedSaveLayer) { |
693 break; | 714 break; |
694 } | 715 } |
695 fSaveLayerStack[index].fHasNestedSaveLayer = true; | 716 fSaveLayerStack[index].fHasNestedSaveLayer = true; |
696 if (fSaveLayerStack[index].fIsSaveLayer) { | 717 if (fSaveLayerStack[index].fIsSaveLayer) { |
697 break; | 718 break; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
736 block.fSaveLayerOpID = sli.fStartIndex; | 757 block.fSaveLayerOpID = sli.fStartIndex; |
737 block.fRestoreOpID = fFillBounds.currentOp(); | 758 block.fRestoreOpID = fFillBounds.currentOp(); |
738 block.fHasNestedLayers = sli.fHasNestedSaveLayer; | 759 block.fHasNestedLayers = sli.fHasNestedSaveLayer; |
739 block.fIsNested = fSaveLayersInStack > 0; | 760 block.fIsNested = fSaveLayersInStack > 0; |
740 } | 761 } |
741 | 762 |
742 // Used to collect saveLayer information for layer hoisting | 763 // Used to collect saveLayer information for layer hoisting |
743 int fSaveLayersInStack; | 764 int fSaveLayersInStack; |
744 SkTDArray<SaveLayerInfo> fSaveLayerStack; | 765 SkTDArray<SaveLayerInfo> fSaveLayerStack; |
745 SkLayerInfo* fAccelData; | 766 SkLayerInfo* fAccelData; |
| 767 const SkPicture::SnapshotArray* fPictList; |
746 | 768 |
747 SkRecords::FillBounds fFillBounds; | 769 SkRecords::FillBounds fFillBounds; |
748 }; | 770 }; |
749 | 771 |
750 } // namespace SkRecords | 772 } // namespace SkRecords |
751 | 773 |
752 void SkRecordFillBounds(const SkRect& cullRect, const SkRecord& record, SkBBoxHi
erarchy* bbh) { | 774 void SkRecordFillBounds(const SkRect& cullRect, const SkRecord& record, SkBBoxHi
erarchy* bbh) { |
753 SkRecords::FillBounds visitor(cullRect, record); | 775 SkRecords::FillBounds visitor(cullRect, record); |
754 | 776 |
755 for (unsigned curOp = 0; curOp < record.count(); curOp++) { | 777 for (unsigned curOp = 0; curOp < record.count(); curOp++) { |
756 visitor.setCurrentOp(curOp); | 778 visitor.setCurrentOp(curOp); |
757 record.visit<void>(curOp, visitor); | 779 record.visit<void>(curOp, visitor); |
758 } | 780 } |
759 | 781 |
760 visitor.cleanUp(bbh); | 782 visitor.cleanUp(bbh); |
761 } | 783 } |
762 | 784 |
763 void SkRecordComputeLayers(const SkRect& cullRect, const SkRecord& record, | 785 void SkRecordComputeLayers(const SkRect& cullRect, const SkRecord& record, |
764 SkBBoxHierarchy* bbh, SkLayerInfo* data) { | 786 const SkPicture::SnapshotArray* pictList, SkBBoxHiera
rchy* bbh, |
765 SkRecords::CollectLayers visitor(cullRect, record, data); | 787 SkLayerInfo* data) { |
| 788 SkRecords::CollectLayers visitor(cullRect, record, pictList, data); |
766 | 789 |
767 for (unsigned curOp = 0; curOp < record.count(); curOp++) { | 790 for (unsigned curOp = 0; curOp < record.count(); curOp++) { |
768 visitor.setCurrentOp(curOp); | 791 visitor.setCurrentOp(curOp); |
769 record.visit<void>(curOp, visitor); | 792 record.visit<void>(curOp, visitor); |
770 } | 793 } |
771 | 794 |
772 visitor.cleanUp(bbh); | 795 visitor.cleanUp(bbh); |
773 } | 796 } |
774 | 797 |
OLD | NEW |