OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 #include "SkPicturePlayback.h" | 8 #include "SkPicturePlayback.h" |
9 #include "SkPictureRecord.h" | 9 #include "SkPictureRecord.h" |
10 #include "SkTypeface.h" | 10 #include "SkTypeface.h" |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 for (int i = 0; i < fPictureCount; i++) { | 117 for (int i = 0; i < fPictureCount; i++) { |
118 if (deepCopy) { | 118 if (deepCopy) { |
119 fPictureRefs[i] = pictures[i]->clone(); | 119 fPictureRefs[i] = pictures[i]->clone(); |
120 } else { | 120 } else { |
121 fPictureRefs[i] = pictures[i]; | 121 fPictureRefs[i] = pictures[i]; |
122 fPictureRefs[i]->ref(); | 122 fPictureRefs[i]->ref(); |
123 } | 123 } |
124 } | 124 } |
125 } | 125 } |
126 | 126 |
| 127 #if SK_RECORD_BOUNDS_IN_PICTURE |
| 128 fHasRecordedBounds = true; |
| 129 #else |
| 130 fHasRecordedBounds = false; |
| 131 #endif |
| 132 |
127 #ifdef SK_DEBUG_SIZE | 133 #ifdef SK_DEBUG_SIZE |
128 int overall = fPlayback->size(&overallBytes); | 134 int overall = fPlayback->size(&overallBytes); |
129 bitmaps = fPlayback->bitmaps(&bitmapBytes); | 135 bitmaps = fPlayback->bitmaps(&bitmapBytes); |
130 paints = fPlayback->paints(&paintBytes); | 136 paints = fPlayback->paints(&paintBytes); |
131 paths = fPlayback->paths(&pathBytes); | 137 paths = fPlayback->paths(&pathBytes); |
132 pictures = fPlayback->pictures(&pictureBytes); | 138 pictures = fPlayback->pictures(&pictureBytes); |
133 regions = fPlayback->regions(®ionBytes); | 139 regions = fPlayback->regions(®ionBytes); |
134 SkDebugf("playback size %zd (objects:%d) ", overallBytes, overall); | 140 SkDebugf("playback size %zd (objects:%d) ", overallBytes, overall); |
135 if (bitmaps != 0) | 141 if (bitmaps != 0) |
136 SkDebugf("bitmaps size %zd (bitmaps:%d) ", bitmapBytes, bitmaps); | 142 SkDebugf("bitmaps size %zd (bitmaps:%d) ", bitmapBytes, bitmaps); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 | 175 |
170 fBitmapHeap.reset(SkSafeRef(src.fBitmapHeap.get())); | 176 fBitmapHeap.reset(SkSafeRef(src.fBitmapHeap.get())); |
171 fPathHeap.reset(SkSafeRef(src.fPathHeap.get())); | 177 fPathHeap.reset(SkSafeRef(src.fPathHeap.get())); |
172 | 178 |
173 fMatrices = SkSafeRef(src.fMatrices); | 179 fMatrices = SkSafeRef(src.fMatrices); |
174 fRegions = SkSafeRef(src.fRegions); | 180 fRegions = SkSafeRef(src.fRegions); |
175 fOpData = SkSafeRef(src.fOpData); | 181 fOpData = SkSafeRef(src.fOpData); |
176 | 182 |
177 fBoundingHierarchy = src.fBoundingHierarchy; | 183 fBoundingHierarchy = src.fBoundingHierarchy; |
178 fStateTree = src.fStateTree; | 184 fStateTree = src.fStateTree; |
179 | 185 fHasRecordedBounds = src.fHasRecordedBounds; |
180 SkSafeRef(fBoundingHierarchy); | 186 SkSafeRef(fBoundingHierarchy); |
181 SkSafeRef(fStateTree); | 187 SkSafeRef(fStateTree); |
182 | 188 |
183 if (deepCopyInfo) { | 189 if (deepCopyInfo) { |
184 int paintCount = SafeCount(src.fPaints); | 190 int paintCount = SafeCount(src.fPaints); |
185 | 191 |
186 if (src.fBitmaps) { | 192 if (src.fBitmaps) { |
187 fBitmaps = SkTRefArray<SkBitmap>::Create(src.fBitmaps->begin(), src.
fBitmaps->count()); | 193 fBitmaps = SkTRefArray<SkBitmap>::Create(src.fBitmaps->begin(), src.
fBitmaps->count()); |
188 } | 194 } |
189 | 195 |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 fBitmaps = NULL; | 269 fBitmaps = NULL; |
264 fMatrices = NULL; | 270 fMatrices = NULL; |
265 fPaints = NULL; | 271 fPaints = NULL; |
266 fPictureRefs = NULL; | 272 fPictureRefs = NULL; |
267 fRegions = NULL; | 273 fRegions = NULL; |
268 fPictureCount = 0; | 274 fPictureCount = 0; |
269 fOpData = NULL; | 275 fOpData = NULL; |
270 fFactoryPlayback = NULL; | 276 fFactoryPlayback = NULL; |
271 fBoundingHierarchy = NULL; | 277 fBoundingHierarchy = NULL; |
272 fStateTree = NULL; | 278 fStateTree = NULL; |
| 279 fHasRecordedBounds = false; |
273 } | 280 } |
274 | 281 |
275 SkPicturePlayback::~SkPicturePlayback() { | 282 SkPicturePlayback::~SkPicturePlayback() { |
276 fOpData->unref(); | 283 fOpData->unref(); |
277 | 284 |
278 SkSafeUnref(fBitmaps); | 285 SkSafeUnref(fBitmaps); |
279 SkSafeUnref(fMatrices); | 286 SkSafeUnref(fMatrices); |
280 SkSafeUnref(fPaints); | 287 SkSafeUnref(fPaints); |
281 SkSafeUnref(fRegions); | 288 SkSafeUnref(fRegions); |
282 SkSafeUnref(fBoundingHierarchy); | 289 SkSafeUnref(fBoundingHierarchy); |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
579 for (size_t i = 0; i < size; ++i) { | 586 for (size_t i = 0; i < size; ++i) { |
580 buffer.readRegion(&fRegions->writableAt(i)); | 587 buffer.readRegion(&fRegions->writableAt(i)); |
581 } | 588 } |
582 } break; | 589 } break; |
583 } | 590 } |
584 } | 591 } |
585 | 592 |
586 SkPicturePlayback::SkPicturePlayback(SkStream* stream, const SkPictInfo& info, | 593 SkPicturePlayback::SkPicturePlayback(SkStream* stream, const SkPictInfo& info, |
587 SkPicture::InstallPixelRefProc proc) { | 594 SkPicture::InstallPixelRefProc proc) { |
588 this->init(); | 595 this->init(); |
589 | 596 #if SK_RECORD_BOUNDS_IN_PICTURE |
| 597 fHasRecordedBounds = SkToBool(info.fFlags & SkPictInfo::kHasRecordedBounds_F
lag); |
| 598 #else |
| 599 // Can't handle skps with recorded bounds in a build that does support them. |
| 600 SkASSERT(false == SkToBool(info.fFlags & SkPictInfo::kHasRecordedBounds_Flag
)); |
| 601 fHasRecordedBounds = false; |
| 602 #endif |
590 for (;;) { | 603 for (;;) { |
591 uint32_t tag = stream->readU32(); | 604 uint32_t tag = stream->readU32(); |
592 if (PICT_EOF_TAG == tag) { | 605 if (PICT_EOF_TAG == tag) { |
593 break; | 606 break; |
594 } | 607 } |
595 | 608 |
596 uint32_t size = stream->readU32(); | 609 uint32_t size = stream->readU32(); |
597 this->parseStreamTag(stream, info, tag, size, proc); | 610 this->parseStreamTag(stream, info, tag, size, proc); |
598 } | 611 } |
599 } | 612 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
643 *size = 0; | 656 *size = 0; |
644 } else { | 657 } else { |
645 UNPACK_8_24(temp, op, *size); | 658 UNPACK_8_24(temp, op, *size); |
646 if (MASK_24 == *size) { | 659 if (MASK_24 == *size) { |
647 *size = reader->readInt(); | 660 *size = reader->readInt(); |
648 } | 661 } |
649 } | 662 } |
650 return (DrawType) op; | 663 return (DrawType) op; |
651 } | 664 } |
652 | 665 |
| 666 // Sets 'bounds' to represent the clip bounds of the playback canvas, |
| 667 // expressed in the recording device's coordinate space. |
| 668 // returns true if the bounds are not empty. |
| 669 static inline bool get_intial_clip_bounds(const SkCanvas& canvas, SkIRect* bound
s) { |
| 670 SkASSERT(NULL != bounds); |
| 671 SkRect clipBounds; |
| 672 if (canvas.getClipBounds(&clipBounds)) { |
| 673 clipBounds.roundOut(bounds); |
| 674 } else { |
| 675 bounds->setEmpty(); |
| 676 return false; |
| 677 } |
| 678 return !bounds->isEmpty(); |
| 679 } |
| 680 |
653 void SkPicturePlayback::draw(SkCanvas& canvas) { | 681 void SkPicturePlayback::draw(SkCanvas& canvas) { |
654 #ifdef ENABLE_TIME_DRAW | 682 #ifdef ENABLE_TIME_DRAW |
655 SkAutoTime at("SkPicture::draw", 50); | 683 SkAutoTime at("SkPicture::draw", 50); |
656 #endif | 684 #endif |
657 | 685 |
658 #ifdef SPEW_CLIP_SKIPPING | 686 #ifdef SPEW_CLIP_SKIPPING |
659 SkipClipRec skipRect, skipRRect, skipRegion, skipPath; | 687 SkipClipRec skipRect, skipRRect, skipRegion, skipPath; |
660 #endif | 688 #endif |
661 | 689 |
662 #ifdef SK_BUILD_FOR_ANDROID | 690 #ifdef SK_BUILD_FOR_ANDROID |
663 SkAutoMutexAcquire autoMutex(fDrawMutex); | 691 SkAutoMutexAcquire autoMutex(fDrawMutex); |
664 #endif | 692 #endif |
665 | 693 |
666 // kDrawComplete will be the signal that we have reached the end of | 694 // kDrawComplete will be the signal that we have reached the end of |
667 // the command stream | 695 // the command stream |
668 static const uint32_t kDrawComplete = SK_MaxU32; | 696 static const uint32_t kDrawComplete = SK_MaxU32; |
669 | 697 |
670 SkReader32 reader(fOpData->bytes(), fOpData->size()); | 698 SkReader32 reader(fOpData->bytes(), fOpData->size()); |
671 TextContainer text; | 699 TextContainer text; |
672 SkTDArray<void*> results; | 700 SkTDArray<void*> results; |
673 | 701 |
| 702 bool initialClipBoundsSet = false; |
| 703 SkIRect initialClipBounds; // only computed if needed |
674 if (NULL != fStateTree && NULL != fBoundingHierarchy) { | 704 if (NULL != fStateTree && NULL != fBoundingHierarchy) { |
675 SkRect clipBounds; | 705 if (!get_intial_clip_bounds(canvas, &initialClipBounds)) { |
676 if (canvas.getClipBounds(&clipBounds)) { | 706 return; |
677 SkIRect query; | |
678 clipBounds.roundOut(&query); | |
679 fBoundingHierarchy->search(query, &results); | |
680 if (results.count() == 0) { | |
681 return; | |
682 } | |
683 SkTQSort<SkPictureStateTree::Draw>( | |
684 reinterpret_cast<SkPictureStateTree::Draw**>(results.begin()), | |
685 reinterpret_cast<SkPictureStateTree::Draw**>(results.end()-1)); | |
686 } | 707 } |
| 708 fBoundingHierarchy->search(initialClipBounds, &results); |
| 709 if (results.count() == 0) { |
| 710 return; |
| 711 } |
| 712 initialClipBoundsSet = true; |
| 713 SkTQSort<SkPictureStateTree::Draw>( |
| 714 reinterpret_cast<SkPictureStateTree::Draw**>(results.begin()), |
| 715 reinterpret_cast<SkPictureStateTree::Draw**>(results.end()-1)); |
687 } | 716 } |
688 | 717 |
| 718 #if SK_RECORD_BOUNDS_IN_PICTURE |
| 719 if (fHasRecordedBounds) { |
| 720 // TODO(junov): temporarily disable quickReject testing on 'canvas' |
| 721 // because it is redundant with early bounds check. |
| 722 if (!initialClipBoundsSet && !get_intial_clip_bounds(canvas, &initialCli
pBounds)) { |
| 723 return; |
| 724 } |
| 725 initialClipBoundsSet = true; |
| 726 } |
| 727 #endif |
| 728 |
689 SkPictureStateTree::Iterator it = (NULL == fStateTree) ? | 729 SkPictureStateTree::Iterator it = (NULL == fStateTree) ? |
690 SkPictureStateTree::Iterator() : | 730 SkPictureStateTree::Iterator() : |
691 fStateTree->getIterator(results, &canvas); | 731 fStateTree->getIterator(results, &canvas); |
692 | 732 |
693 if (it.isValid()) { | 733 if (it.isValid()) { |
694 uint32_t skipTo = it.draw(); | 734 uint32_t skipTo = it.draw(); |
695 if (kDrawComplete == skipTo) { | 735 if (kDrawComplete == skipTo) { |
696 return; | 736 return; |
697 } | 737 } |
698 reader.setOffset(skipTo); | 738 reader.setOffset(skipTo); |
699 } | 739 } |
700 | 740 |
701 // Record this, so we can concat w/ it if we encounter a setMatrix() | 741 // Record this, so we can concat w/ it if we encounter a setMatrix() |
702 SkMatrix initialMatrix = canvas.getTotalMatrix(); | 742 SkMatrix initialMatrix = canvas.getTotalMatrix(); |
703 | 743 |
704 #ifdef SK_BUILD_FOR_ANDROID | 744 #ifdef SK_BUILD_FOR_ANDROID |
705 fAbortCurrentPlayback = false; | 745 fAbortCurrentPlayback = false; |
706 #endif | 746 #endif |
707 | 747 |
708 while (!reader.eof()) { | 748 while (!reader.eof()) { |
709 #ifdef SK_BUILD_FOR_ANDROID | 749 #ifdef SK_BUILD_FOR_ANDROID |
710 if (fAbortCurrentPlayback) { | 750 if (fAbortCurrentPlayback) { |
711 return; | 751 return; |
712 } | 752 } |
713 #endif | 753 #endif |
714 | 754 |
715 size_t curOffset = reader.offset(); | 755 size_t curOffset = reader.offset(); |
716 uint32_t size; | 756 uint32_t size; |
717 DrawType op = read_op_and_size(&reader, &size); | 757 DrawType op = read_op_and_size(&reader, &size); |
718 if (NOOP == op) { | 758 size_t skipTo = 0; |
719 // NOOPs are to be ignored - do not propagate them any further | 759 #ifdef SK_DEVELOPER |
720 reader.setOffset(curOffset+size); | 760 // TODO: once chunk sizes are in all .skps just use |
721 continue; | 761 // "curOffset + size" |
| 762 skipTo = this->preDraw(curOffset, op); |
| 763 #endif |
| 764 if (0 == skipTo) { |
| 765 if (NOOP == op) { |
| 766 // NOOPs are to be ignored - do not propagate them any further |
| 767 skipTo = curOffset + size; |
| 768 } |
| 769 #if SK_RECORD_BOUNDS_IN_PICTURE |
| 770 else if (fHasRecordedBounds && SkPictureRecord::canRecordBounds(op))
{ |
| 771 const SkIRect& clippedBounds = reader.skipT<SkIRect>(); |
| 772 // recording canvas device bounds are in the same coordinate spa
ce |
| 773 // as local clip bounds at start of playback. |
| 774 SkASSERT(initialClipBoundsSet); |
| 775 if (!SkIRect::Intersects(clippedBounds, initialClipBounds)) { |
| 776 skipTo = curOffset + size; |
| 777 } |
| 778 } |
| 779 #endif |
722 } | 780 } |
723 | 781 |
724 #ifdef SK_DEVELOPER | |
725 // TODO: once chunk sizes are in all .skps just use "curOffset + size" | |
726 size_t skipTo = this->preDraw(curOffset, op); | |
727 if (0 != skipTo) { | 782 if (0 != skipTo) { |
| 783 if (it.isValid()) { |
| 784 // If using a bounding box hierarchy, advance the state tree |
| 785 // iterator until at or after skipTo |
| 786 uint32_t adjustedSkipTo; |
| 787 do { |
| 788 adjustedSkipTo = it.draw(); |
| 789 } while (adjustedSkipTo < skipTo); |
| 790 skipTo = adjustedSkipTo; |
| 791 } |
728 if (kDrawComplete == skipTo) { | 792 if (kDrawComplete == skipTo) { |
729 break; | 793 break; |
730 } | 794 } |
731 reader.setOffset(skipTo); | 795 reader.setOffset(skipTo); |
732 continue; | 796 continue; |
733 } | 797 } |
734 #endif | 798 |
735 switch (op) { | 799 switch (op) { |
736 case CLIP_PATH: { | 800 case CLIP_PATH: { |
737 const SkPath& path = getPath(reader); | 801 const SkPath& path = getPath(reader); |
738 uint32_t packed = reader.readInt(); | 802 uint32_t packed = reader.readInt(); |
739 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed); | 803 SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed); |
740 bool doAA = ClipParams_unpackDoAA(packed); | 804 bool doAA = ClipParams_unpackDoAA(packed); |
741 size_t offsetToRestore = reader.readInt(); | 805 size_t offsetToRestore = reader.readInt(); |
742 SkASSERT(!offsetToRestore || \ | 806 SkASSERT(!offsetToRestore || \ |
743 offsetToRestore >= reader.offset()); | 807 offsetToRestore >= reader.offset()); |
744 if (!canvas.clipPath(path, regionOp, doAA) && offsetToRestore) { | 808 if (!canvas.clipPath(path, regionOp, doAA) && offsetToRestore) { |
(...skipping 825 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1570 for (index = 0; index < fRegionCount; index++) | 1634 for (index = 0; index < fRegionCount; index++) |
1571 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer
), | 1635 bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer
), |
1572 "region%p, ", &fRegions[index]); | 1636 "region%p, ", &fRegions[index]); |
1573 if (fRegionCount > 0) | 1637 if (fRegionCount > 0) |
1574 SkDebugf("%s0};\n", pBuffer); | 1638 SkDebugf("%s0};\n", pBuffer); |
1575 | 1639 |
1576 const_cast<SkPicturePlayback*>(this)->dumpStream(); | 1640 const_cast<SkPicturePlayback*>(this)->dumpStream(); |
1577 } | 1641 } |
1578 | 1642 |
1579 #endif | 1643 #endif |
OLD | NEW |