diff --git a/gm/optimizations.cpp b/gm/optimizations.cpp deleted file mode 100644 index 85ce3e9d94..0000000000 --- a/gm/optimizations.cpp +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "gm.h" -#include "SkDebugCanvas.h" -#include "SkPictureFlat.h" -#include "SkPictureRecorder.h" - -#define WARN(msg) \ - SkDebugf("%s:%d: %s\n", __FILE__, __LINE__, msg); - -// Do the commands in 'input' match the supplied pattern? Note: this is a pretty -// heavy-weight operation since we are drawing the picture into a debug canvas -// to extract the commands. -static bool check_pattern(SkPicture& input, const SkTDArray &pattern) { - SkDebugCanvas debugCanvas(SkScalarCeilToInt(input.cullRect().width()), - SkScalarCeilToInt(input.cullRect().height())); - input.playback(&debugCanvas); - - if (pattern.count() != debugCanvas.getSize()) { - return false; - } - - for (int i = 0; i < pattern.count(); ++i) { - if (pattern[i] != debugCanvas.getDrawCommandAt(i)->getType()) { - return false; - } - } - - return true; -} - -// construct the pattern removed by the SkPictureRecord::remove_save_layer1 -// optimization, i.e.: -// SAVE_LAYER -// DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT -// RESTORE -// -// saveLayerHasPaint - control if the saveLayer has a paint (the optimization -// takes a different path if this is false) -// dbmr2rHasPaint - control if the dbmr2r has a paint (the optimization -// takes a different path if this is false) -// colorsMatch - control if the saveLayer and dbmr2r paint colors -// match (the optimization will fail if they do not) -static SkPicture* create_save_layer_opt_1(SkTDArray* preOptPattern, - SkTDArray* postOptPattern, - const SkBitmap& checkerBoard, - bool saveLayerHasPaint, - bool dbmr2rHasPaint, - bool colorsMatch) { - // Create the pattern that should trigger the optimization - preOptPattern->setCount(5); - (*preOptPattern)[0] = SAVE; - (*preOptPattern)[1] = SAVE_LAYER; - (*preOptPattern)[2] = DRAW_BITMAP_RECT_TO_RECT; - (*preOptPattern)[3] = RESTORE; - (*preOptPattern)[4] = RESTORE; - - if (colorsMatch) { - // Create the pattern that should appear after the optimization - postOptPattern->setCount(5); - (*postOptPattern)[0] = SAVE; // extra save/restore added by extra draw - (*postOptPattern)[1] = SAVE; - (*postOptPattern)[2] = DRAW_BITMAP_RECT_TO_RECT; - (*postOptPattern)[3] = RESTORE; - (*postOptPattern)[4] = RESTORE; - } else { - // Create the pattern that appears if the optimization doesn't fire - postOptPattern->setCount(7); - (*postOptPattern)[0] = SAVE; // extra save/restore added by extra draw - (*postOptPattern)[1] = SAVE; - (*postOptPattern)[2] = SAVE_LAYER; - (*postOptPattern)[3] = DRAW_BITMAP_RECT_TO_RECT; - (*postOptPattern)[4] = RESTORE; - (*postOptPattern)[5] = RESTORE; - (*postOptPattern)[6] = RESTORE; - } - - SkPictureRecorder recorder; - - SkCanvas* canvas = recorder.DEPRECATED_beginRecording(100, 100, NULL, 0); - // have to disable the optimizations while generating the picture - recorder.internalOnly_EnableOpts(false); - - SkPaint saveLayerPaint; - saveLayerPaint.setColor(0xCC000000); - - // saveLayer's 'bounds' parameter must be NULL for this optimization - if (saveLayerHasPaint) { - canvas->saveLayer(NULL, &saveLayerPaint); - } else { - canvas->saveLayer(NULL, NULL); - } - - SkRect rect = { 10, 10, 90, 90 }; - - // The dbmr2r's paint must be opaque - SkPaint dbmr2rPaint; - if (colorsMatch) { - dbmr2rPaint.setColor(0xFF000000); - } else { - dbmr2rPaint.setColor(0xFFFF0000); - } - - if (dbmr2rHasPaint) { - canvas->drawBitmapRectToRect(checkerBoard, NULL, rect, &dbmr2rPaint); - } else { - canvas->drawBitmapRectToRect(checkerBoard, NULL, rect, NULL); - } - canvas->restore(); - - return recorder.endRecording(); -} - -// straight-ahead version that is seen in the skps -static SkPicture* create_save_layer_opt_1_v1(SkTDArray* preOptPattern, - SkTDArray* postOptPattern, - const SkBitmap& checkerBoard) { - return create_save_layer_opt_1(preOptPattern, postOptPattern, checkerBoard, - true, // saveLayer has a paint - true, // dbmr2r has a paint - true); // and the colors match -} - -// alternate version that should still succeed -static SkPicture* create_save_layer_opt_1_v2(SkTDArray* preOptPattern, - SkTDArray* postOptPattern, - const SkBitmap& checkerBoard) { - return create_save_layer_opt_1(preOptPattern, postOptPattern, checkerBoard, - false, // saveLayer doesn't have a paint! - true, // dbmr2r has a paint - true); // color matching not really applicable -} - -// alternate version that should still succeed -static SkPicture* create_save_layer_opt_1_v3(SkTDArray* preOptPattern, - SkTDArray* postOptPattern, - const SkBitmap& checkerBoard) { - return create_save_layer_opt_1(preOptPattern, postOptPattern, checkerBoard, - true, // saveLayer has a paint - false, // dbmr2r doesn't have a paint! - true); // color matching not really applicable -} - -// version in which the optimization fails b.c. the colors don't match -static SkPicture* create_save_layer_opt_1_v4(SkTDArray* preOptPattern, - SkTDArray* postOptPattern, - const SkBitmap& checkerBoard) { - return create_save_layer_opt_1(preOptPattern, postOptPattern, checkerBoard, - true, // saveLayer has a paint - true, // dbmr2r has a paint - false); // and the colors don't match! -} - -// construct the pattern removed by the SkPictureRecord::remove_save_layer2 -// optimization, i.e.: -// SAVE_LAYER (with NULL == bounds) -// SAVE -// CLIP_RECT -// DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT -// RESTORE -// RESTORE -// -// saveLayerHasPaint - control if the saveLayer has a paint (the optimization -// takes a different path if this is false) -// dbmr2rHasPaint - control if the dbmr2r has a paint (the optimization -// takes a different path if this is false) -// colorsMatch - control if the saveLayer and dbmr2r paint colors -// match (the optimization will fail if they do not) -static SkPicture* create_save_layer_opt_2(SkTDArray* preOptPattern, - SkTDArray* postOptPattern, - const SkBitmap& checkerBoard, - bool saveLayerHasPaint, - bool dbmr2rHasPaint, - bool colorsMatch) { - // Create the pattern that should trigger the optimization - preOptPattern->setCount(8); - (*preOptPattern)[0] = SAVE; - (*preOptPattern)[1] = SAVE_LAYER; - (*preOptPattern)[2] = SAVE; - (*preOptPattern)[3] = CLIP_RECT; - (*preOptPattern)[4] = DRAW_BITMAP_RECT_TO_RECT; - (*preOptPattern)[5] = RESTORE; - (*preOptPattern)[6] = RESTORE; - (*preOptPattern)[7] = RESTORE; - - if (colorsMatch) { - // Create the pattern that should appear after the optimization - postOptPattern->setCount(8); - (*postOptPattern)[0] = SAVE; // extra save/restore added by extra draw - (*postOptPattern)[1] = SAVE; - (*postOptPattern)[2] = SAVE; - (*postOptPattern)[3] = CLIP_RECT; - (*postOptPattern)[4] = DRAW_BITMAP_RECT_TO_RECT; - (*postOptPattern)[5] = RESTORE; - (*postOptPattern)[6] = RESTORE; - (*postOptPattern)[7] = RESTORE; - } else { - // Create the pattern that appears if the optimization doesn't fire - postOptPattern->setCount(10); - (*postOptPattern)[0] = SAVE; // extra save/restore added by extra draw - (*postOptPattern)[1] = SAVE; - (*postOptPattern)[2] = SAVE_LAYER; - (*postOptPattern)[3] = SAVE; - (*postOptPattern)[4] = CLIP_RECT; - (*postOptPattern)[5] = DRAW_BITMAP_RECT_TO_RECT; - (*postOptPattern)[6] = RESTORE; - (*postOptPattern)[7] = RESTORE; - (*postOptPattern)[8] = RESTORE; - (*postOptPattern)[9] = RESTORE; - } - - SkPictureRecorder recorder; - - SkCanvas* canvas = recorder.DEPRECATED_beginRecording(100, 100, NULL, 0); - // have to disable the optimizations while generating the picture - recorder.internalOnly_EnableOpts(false); - - SkPaint saveLayerPaint; - saveLayerPaint.setColor(0xCC000000); - - // saveLayer's 'bounds' parameter must be NULL for this optimization - if (saveLayerHasPaint) { - canvas->saveLayer(NULL, &saveLayerPaint); - } else { - canvas->saveLayer(NULL, NULL); - } - - canvas->save(); - - SkRect rect = { 10, 10, 90, 90 }; - canvas->clipRect(rect); - - // The dbmr2r's paint must be opaque - SkPaint dbmr2rPaint; - if (colorsMatch) { - dbmr2rPaint.setColor(0xFF000000); - } else { - dbmr2rPaint.setColor(0xFFFF0000); - } - - if (dbmr2rHasPaint) { - canvas->drawBitmapRectToRect(checkerBoard, NULL, rect, &dbmr2rPaint); - } else { - canvas->drawBitmapRectToRect(checkerBoard, NULL, rect, NULL); - } - canvas->restore(); - canvas->restore(); - - return recorder.endRecording(); -} - -// straight-ahead version that is seen in the skps -static SkPicture* create_save_layer_opt_2_v1(SkTDArray* preOptPattern, - SkTDArray* postOptPattern, - const SkBitmap& checkerBoard) { - return create_save_layer_opt_2(preOptPattern, postOptPattern, checkerBoard, - true, // saveLayer has a paint - true, // dbmr2r has a paint - true); // and the colors match -} - -// alternate version that should still succeed -static SkPicture* create_save_layer_opt_2_v2(SkTDArray* preOptPattern, - SkTDArray* postOptPattern, - const SkBitmap& checkerBoard) { - return create_save_layer_opt_2(preOptPattern, postOptPattern, checkerBoard, - false, // saveLayer doesn't have a paint! - true, // dbmr2r has a paint - true); // color matching not really applicable -} - -// alternate version that should still succeed -static SkPicture* create_save_layer_opt_2_v3(SkTDArray* preOptPattern, - SkTDArray* postOptPattern, - const SkBitmap& checkerBoard) { - return create_save_layer_opt_2(preOptPattern, postOptPattern, checkerBoard, - true, // saveLayer has a paint - false, // dbmr2r doesn't have a paint! - true); // color matching not really applicable -} - -// version in which the optimization fails b.c. the colors don't match -static SkPicture* create_save_layer_opt_2_v4(SkTDArray* preOptPattern, - SkTDArray* postOptPattern, - const SkBitmap& checkerBoard) { - return create_save_layer_opt_2(preOptPattern, postOptPattern, checkerBoard, - true, // saveLayer has a paint - true, // dbmr2r has a paint - false); // and the colors don't match! -} - -// As our .skp optimizations get folded into the captured skps our code will -// no longer be locally exercised. This GM manually constructs the patterns -// our optimizations will remove to test them. It acts as both a GM and a unit -// test -class OptimizationsGM : public skiagm::GM { -public: - OptimizationsGM() { - this->makeCheckerboard(); - } - - static const int kWidth = 800; - static const int kHeight = 800; - -protected: - uint32_t onGetFlags() const SK_OVERRIDE { - // One optimization changes the color drawn slightly in a 565 target. - // We've decided it's innocuous, so we disable this GM when targeting 565. - // Revisit this if we get finer-grained control: it'd be nice to keep drawing directly. - // For more, see skia:1994. - return skiagm::GM::kSkip565_Flag; - } - - SkString onShortName() { - return SkString("optimizations"); - } - - SkISize onISize() { return SkISize::Make(kWidth, kHeight); } - - typedef SkPicture* (*PFCreateOpt)(SkTDArray *preOptPattern, - SkTDArray *postOptPattern, - const SkBitmap& checkerBoard); - - virtual void onDraw(SkCanvas* canvas) { - - PFCreateOpt gOpts[] = { - create_save_layer_opt_1_v1, - create_save_layer_opt_1_v2, - create_save_layer_opt_1_v3, - create_save_layer_opt_1_v4, - create_save_layer_opt_2_v1, - create_save_layer_opt_2_v2, - create_save_layer_opt_2_v3, - create_save_layer_opt_2_v4, - }; - - SkTDArray prePattern, postPattern; - SkScalar xPos = 0, yPos = 0; - - for (size_t i = 0; i < SK_ARRAY_COUNT(gOpts); ++i) { - SkAutoTUnref pre((*gOpts[i])(&prePattern, &postPattern, fCheckerboard)); - - if (!(check_pattern(*pre, prePattern))) { - WARN("Pre optimization pattern mismatch"); - SkASSERT(0); - } - - canvas->save(); - canvas->translate(xPos, yPos); - pre->playback(canvas); - xPos += pre->cullRect().width(); - canvas->restore(); - - // re-render the 'pre' picture and thus 'apply' the optimization - SkPictureRecorder recorder; - - SkCanvas* recordCanvas = - recorder.DEPRECATED_beginRecording(pre->cullRect().width(), - pre->cullRect().height(), - NULL, 0); - - pre->playback(recordCanvas); - - SkAutoTUnref post(recorder.endRecording()); - - if (!(check_pattern(*post, postPattern))) { - WARN("Post optimization pattern mismatch"); - SkASSERT(0); - } - - canvas->save(); - canvas->translate(xPos, yPos); - post->playback(canvas); - xPos += post->cullRect().width(); - canvas->restore(); - - if (xPos >= kWidth) { - // start a new line - xPos = 0; - yPos += post->cullRect().height(); - } - - // TODO: we could also render the pre and post pictures to bitmaps - // and manually compare them in this method - } - } - -private: - void makeCheckerboard() { - static const unsigned int kCheckerboardWidth = 16; - static const unsigned int kCheckerboardHeight = 16; - - fCheckerboard.allocN32Pixels(kCheckerboardWidth, kCheckerboardHeight); - for (unsigned int y = 0; y < kCheckerboardHeight; y += 2) { - SkPMColor* scanline = fCheckerboard.getAddr32(0, y); - for (unsigned int x = 0; x < kCheckerboardWidth; x += 2) { - *scanline++ = 0xFFFFFFFF; - *scanline++ = 0xFF000000; - } - scanline = fCheckerboard.getAddr32(0, y + 1); - for (unsigned int x = 0; x < kCheckerboardWidth; x += 2) { - *scanline++ = 0xFF000000; - *scanline++ = 0xFFFFFFFF; - } - } - } - - SkBitmap fCheckerboard; - - typedef skiagm::GM INHERITED; -}; - -////////////////////////////////////////////////////////////////////////////// - -DEF_GM( return new OptimizationsGM; ) diff --git a/gyp/core.gypi b/gyp/core.gypi index 6907d346cc..49027a91f2 100644 --- a/gyp/core.gypi +++ b/gyp/core.gypi @@ -14,10 +14,6 @@ '<(skia_src_path)/core/SkAntiRun.h', '<(skia_src_path)/core/SkBBHFactory.cpp', '<(skia_src_path)/core/SkBBoxHierarchy.h', - '<(skia_src_path)/core/SkBBoxRecord.cpp', - '<(skia_src_path)/core/SkBBoxRecord.h', - '<(skia_src_path)/core/SkBBoxHierarchyRecord.cpp', - '<(skia_src_path)/core/SkBBoxHierarchyRecord.h', '<(skia_src_path)/core/SkBitmap.cpp', '<(skia_src_path)/core/SkBitmapCache.cpp', '<(skia_src_path)/core/SkBitmapDevice.cpp', @@ -141,8 +137,6 @@ '<(skia_src_path)/core/SkPictureRecorder.cpp', '<(skia_src_path)/core/SkPictureShader.cpp', '<(skia_src_path)/core/SkPictureShader.h', - '<(skia_src_path)/core/SkPictureStateTree.cpp', - '<(skia_src_path)/core/SkPictureStateTree.h', '<(skia_src_path)/core/SkPixelRef.cpp', '<(skia_src_path)/core/SkPoint.cpp', '<(skia_src_path)/core/SkProcSpriteBlitter.cpp', diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi index 04301f4cf9..557cc4aa4b 100644 --- a/gyp/gmslides.gypi +++ b/gyp/gmslides.gypi @@ -127,7 +127,6 @@ '../gm/ninepatchstretch.cpp', '../gm/nonclosedpaths.cpp', '../gm/offsetimagefilter.cpp', - '../gm/optimizations.cpp', '../gm/ovals.cpp', '../gm/patch.cpp', '../gm/patchgrid.cpp', diff --git a/gyp/tests.gypi b/gyp/tests.gypi index a3197220ef..f50dc295cd 100644 --- a/gyp/tests.gypi +++ b/gyp/tests.gypi @@ -155,7 +155,6 @@ '../tests/PathTest.cpp', '../tests/PathUtilsTest.cpp', '../tests/PictureShaderTest.cpp', - '../tests/PictureStateTreeTest.cpp', '../tests/PictureTest.cpp', '../tests/PixelRefTest.cpp', '../tests/PointTest.cpp', diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h index c41709d4be..6e785d43da 100644 --- a/include/core/SkPicture.h +++ b/include/core/SkPicture.h @@ -253,8 +253,7 @@ private: mutable uint32_t fUniqueID; - // TODO: make SkPictureData const when clone method goes away - SkAutoTDelete fData; + SkAutoTDelete fData; const SkScalar fCullWidth; const SkScalar fCullHeight; mutable SkAutoTUnref fAccelData; @@ -270,30 +269,14 @@ private: SkPicture(SkScalar width, SkScalar height, const SkPictureRecord& record, bool deepCopyOps); - // An OperationList encapsulates a set of operation offsets into the picture byte - // stream along with the CTMs needed for those operation. - class OperationList : ::SkNoncopyable { - public: - // The following three entry points should only be accessed if - // 'valid' returns true. - int numOps() const { return fOps.count(); } - // The offset in the picture of the operation to execute. - uint32_t offset(int index) const; - // The CTM that must be installed for the operation to behave correctly - const SkMatrix& matrix(int index) const; - - SkTDArray fOps; - }; - void createHeader(SkPictInfo* info) const; static bool IsValidPictInfo(const SkPictInfo& info); - friend class SkPictureData; // to access OperationList friend class SkPictureRecorder; // just for SkPicture-based constructor friend class SkGpuDevice; // for fData access friend class GrLayerHoister; // access to fRecord friend class CollectLayers; // access to fRecord - friend class SkPicturePlayback; // to get fData & OperationList + friend class SkPicturePlayback; // to get fData friend void GrRecordReplaceDraw(const SkPicture* picture, SkCanvas* canvas, const GrReplacements* replacements, diff --git a/include/core/SkPictureRecorder.h b/include/core/SkPictureRecorder.h index 7951e5d396..8f3afb3a76 100644 --- a/include/core/SkPictureRecorder.h +++ b/include/core/SkPictureRecorder.h @@ -72,14 +72,6 @@ public: */ SkPicture* endRecording(); - /** Enable/disable all the picture recording optimizations (i.e., - those in SkPictureRecord). It is mainly intended for testing the - existing optimizations (i.e., to actually have the pattern - appear in an .skp we have to disable the optimization). Call right - after 'beginRecording'. - */ - void internalOnly_EnableOpts(bool enableOpts); - private: void reset(); diff --git a/src/core/SkBBoxHierarchyRecord.cpp b/src/core/SkBBoxHierarchyRecord.cpp deleted file mode 100644 index a9cd05d85f..0000000000 --- a/src/core/SkBBoxHierarchyRecord.cpp +++ /dev/null @@ -1,132 +0,0 @@ - -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkBBoxHierarchyRecord.h" -#include "SkPictureStateTree.h" - -SkBBoxHierarchyRecord::SkBBoxHierarchyRecord(const SkISize& size, - uint32_t recordFlags, - SkBBoxHierarchy* h) - : INHERITED(size, recordFlags) { - fStateTree = SkNEW(SkPictureStateTree); - fBoundingHierarchy = h; - fBoundingHierarchy->ref(); - fBoundingHierarchy->setClient(this); -} - -void SkBBoxHierarchyRecord::handleBBox(const SkRect& bounds) { - SkPictureStateTree::Draw* draw = fStateTree->appendDraw(this->writeStream().bytesWritten()); - fBoundingHierarchy->insert(draw, bounds, true); -} - -void SkBBoxHierarchyRecord::willSave() { - fStateTree->appendSave(); - this->INHERITED::willSave(); -} - -SkCanvas::SaveLayerStrategy SkBBoxHierarchyRecord::willSaveLayer(const SkRect* bounds, - const SkPaint* paint, - SaveFlags flags) { - // For now, assume all filters affect transparent black. - // FIXME: This could be made less conservative as an optimization. - bool paintAffectsTransparentBlack = paint && - ((paint->getImageFilter()) || - (paint->getColorFilter())); - bool needToHandleBBox = paintAffectsTransparentBlack; - if (!needToHandleBBox && paint) { - // Unusual Xfermodes require us to process a saved layer - // even with operations outisde the clip. - // For example, DstIn is used by masking layers. - // https://code.google.com/p/skia/issues/detail?id=1291 - SkXfermode* xfermode = paint->getXfermode(); - SkXfermode::Mode mode; - // SrcOver is the common case with a NULL xfermode, so we should - // make that the fast path and bypass the mode extraction and test. - if (xfermode && xfermode->asMode(&mode)) { - switch (mode) { - case SkXfermode::kClear_Mode: - case SkXfermode::kSrc_Mode: - case SkXfermode::kSrcIn_Mode: - case SkXfermode::kDstIn_Mode: - case SkXfermode::kSrcOut_Mode: - case SkXfermode::kDstATop_Mode: - case SkXfermode::kModulate_Mode: - needToHandleBBox = true; - break; - default: - break; - } - } - } - - SkRect drawBounds; - if (needToHandleBBox) { - SkIRect deviceBounds; - this->getClipDeviceBounds(&deviceBounds); - drawBounds.set(deviceBounds); - } - fStateTree->appendSaveLayer(this->writeStream().bytesWritten()); - SkCanvas::SaveLayerStrategy strategy = this->INHERITED::willSaveLayer(bounds, paint, flags); - if (needToHandleBBox) { - this->handleBBox(drawBounds); - this->addNoOp(); - } - return strategy; -} - -void SkBBoxHierarchyRecord::willRestore() { - fStateTree->appendRestore(); - this->INHERITED::willRestore(); -} - -void SkBBoxHierarchyRecord::didConcat(const SkMatrix& matrix) { - fStateTree->appendTransform(getTotalMatrix()); - INHERITED::didConcat(matrix); -} - -void SkBBoxHierarchyRecord::didSetMatrix(const SkMatrix& matrix) { - fStateTree->appendTransform(getTotalMatrix()); - INHERITED::didSetMatrix(matrix); -} - -void SkBBoxHierarchyRecord::onClipRect(const SkRect& rect, - SkRegion::Op op, - ClipEdgeStyle edgeStyle) { - fStateTree->appendClip(this->writeStream().bytesWritten()); - this->INHERITED::onClipRect(rect, op, edgeStyle); -} - -void SkBBoxHierarchyRecord::onClipRegion(const SkRegion& region, - SkRegion::Op op) { - fStateTree->appendClip(this->writeStream().bytesWritten()); - this->INHERITED::onClipRegion(region, op); -} - -void SkBBoxHierarchyRecord::onClipPath(const SkPath& path, - SkRegion::Op op, - ClipEdgeStyle edgeStyle) { - fStateTree->appendClip(this->writeStream().bytesWritten()); - this->INHERITED::onClipPath(path, op, edgeStyle); -} - -void SkBBoxHierarchyRecord::onClipRRect(const SkRRect& rrect, - SkRegion::Op op, - ClipEdgeStyle edgeStyle) { - fStateTree->appendClip(this->writeStream().bytesWritten()); - this->INHERITED::onClipRRect(rrect, op, edgeStyle); -} - -bool SkBBoxHierarchyRecord::shouldRewind(void* data) { - // SkBBoxHierarchy::rewindInserts is called by SkPicture after the - // SkPicture has rewound its command stream. To match that rewind in the - // BBH, we rewind all draws that reference commands that were recorded - // past the point to which the SkPicture has rewound, which is given by - // writeStream().bytesWritten(). - SkPictureStateTree::Draw* draw = static_cast(data); - return draw->fOffset >= writeStream().bytesWritten(); -} diff --git a/src/core/SkBBoxHierarchyRecord.h b/src/core/SkBBoxHierarchyRecord.h deleted file mode 100644 index 7db82d8369..0000000000 --- a/src/core/SkBBoxHierarchyRecord.h +++ /dev/null @@ -1,47 +0,0 @@ - -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkRTreeCanvas_DEFINED -#define SkRTreeCanvas_DEFINED - -#include "SkBBoxHierarchy.h" -#include "SkBBoxRecord.h" - -/** - * This records bounding box information into an SkBBoxHierarchy, and clip/transform information - * into an SkPictureStateTree to allow for efficient culling and correct playback of draws. - */ -class SkBBoxHierarchyRecord : public SkBBoxRecord, public SkBBoxHierarchyClient { -public: - /** This will take a ref of h */ - SkBBoxHierarchyRecord(const SkISize& size, uint32_t recordFlags, SkBBoxHierarchy* h); - virtual ~SkBBoxHierarchyRecord() { }; - - virtual void handleBBox(const SkRect& bounds) SK_OVERRIDE; - - // Implementation of the SkBBoxHierarchyClient interface - virtual bool shouldRewind(void* data) SK_OVERRIDE; - -protected: - virtual void willSave() SK_OVERRIDE; - virtual SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) SK_OVERRIDE; - virtual void willRestore() SK_OVERRIDE; - - virtual void didConcat(const SkMatrix&) SK_OVERRIDE; - virtual void didSetMatrix(const SkMatrix&) SK_OVERRIDE; - - virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE; - virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE; - virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE; - virtual void onClipRegion(const SkRegion&, SkRegion::Op) SK_OVERRIDE; - -private: - typedef SkBBoxRecord INHERITED; -}; - -#endif diff --git a/src/core/SkBBoxRecord.cpp b/src/core/SkBBoxRecord.cpp deleted file mode 100644 index 5fe42f99d6..0000000000 --- a/src/core/SkBBoxRecord.cpp +++ /dev/null @@ -1,380 +0,0 @@ - -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkBBoxRecord.h" -#include "SkPatchUtils.h" - -#include "SkTextBlob.h" - -SkBBoxRecord::~SkBBoxRecord() { - fSaveStack.deleteAll(); -} - -void SkBBoxRecord::drawOval(const SkRect& rect, const SkPaint& paint) { - if (this->transformBounds(rect, &paint)) { - INHERITED::drawOval(rect, paint); - } -} - -void SkBBoxRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) { - if (this->transformBounds(rrect.rect(), &paint)) { - INHERITED::drawRRect(rrect, paint); - } -} - -void SkBBoxRecord::drawRect(const SkRect& rect, const SkPaint& paint) { - if (this->transformBounds(rect, &paint)) { - INHERITED::drawRect(rect, paint); - } -} - -void SkBBoxRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, - const SkPaint& paint) { - if (this->transformBounds(outer.rect(), &paint)) { - this->INHERITED::onDrawDRRect(outer, inner, paint); - } -} - -void SkBBoxRecord::drawPath(const SkPath& path, const SkPaint& paint) { - if (path.isInverseFillType()) { - // If path is inverse filled, use the current clip bounds as the - // path's device-space bounding box. - SkIRect clipBounds; - if (this->getClipDeviceBounds(&clipBounds)) { - this->handleBBox(SkRect::Make(clipBounds)); - INHERITED::drawPath(path, paint); - } - } else if (this->transformBounds(path.getBounds(), &paint)) { - INHERITED::drawPath(path, paint); - } -} - -void SkBBoxRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[], - const SkPaint& paint) { - SkRect bbox; - bbox.set(pts, SkToInt(count)); - // Small min width value, just to ensure hairline point bounding boxes aren't empty. - // Even though we know hairline primitives are drawn one pixel wide, we do not use a - // minimum of 1 because the playback scale factor is unknown at record time. Later - // outsets will take care of adding additional padding for antialiasing and rounding out - // to integer device coordinates, guaranteeing that the rasterized pixels will be included - // in the computed bounds. - // Note: The device coordinate outset in SkBBoxHierarchyRecord::handleBBox is currently - // done in the recording coordinate space, which is wrong. - // http://code.google.com/p/skia/issues/detail?id=1021 - static const SkScalar kMinWidth = 0.01f; - SkScalar halfStrokeWidth = SkMaxScalar(paint.getStrokeWidth(), kMinWidth) / 2; - bbox.outset(halfStrokeWidth, halfStrokeWidth); - if (this->transformBounds(bbox, &paint)) { - INHERITED::drawPoints(mode, count, pts, paint); - } -} - -void SkBBoxRecord::drawPaint(const SkPaint& paint) { - SkRect bbox; - if (this->getClipBounds(&bbox)) { - if (this->transformBounds(bbox, &paint)) { - INHERITED::drawPaint(paint); - } - } -} - -void SkBBoxRecord::clear(SkColor color) { - SkISize size = this->getDeviceSize(); - SkRect bbox = {0, 0, SkIntToScalar(size.width()), SkIntToScalar(size.height())}; - this->handleBBox(bbox); - INHERITED::clear(color); -} - -void SkBBoxRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, - const SkPaint& paint) { - SkRect bbox; - paint.measureText(text, byteLength, &bbox); - SkPaint::FontMetrics metrics; - paint.getFontMetrics(&metrics); - - // Vertical and aligned text need to be offset - if (paint.isVerticalText()) { - SkScalar h = bbox.fBottom - bbox.fTop; - if (paint.getTextAlign() == SkPaint::kCenter_Align) { - bbox.fTop -= h / 2; - bbox.fBottom -= h / 2; - } - // Pad top and bottom with max extents from FontMetrics - bbox.fBottom += metrics.fBottom; - bbox.fTop += metrics.fTop; - } else { - SkScalar w = bbox.fRight - bbox.fLeft; - if (paint.getTextAlign() == SkPaint::kCenter_Align) { - bbox.fLeft -= w / 2; - bbox.fRight -= w / 2; - } else if (paint.getTextAlign() == SkPaint::kRight_Align) { - bbox.fLeft -= w; - bbox.fRight -= w; - } - // Set vertical bounds to max extents from font metrics - bbox.fTop = metrics.fTop; - bbox.fBottom = metrics.fBottom; - } - - // Pad horizontal bounds on each side by half of max vertical extents (this is sort of - // arbitrary, but seems to produce reasonable results, if there were a way of getting max - // glyph X-extents to pad by, that may be better here, but FontMetrics fXMin and fXMax seem - // incorrect on most platforms (too small in Linux, never even set in Windows). - SkScalar pad = (metrics.fBottom - metrics.fTop) / 2; - bbox.fLeft -= pad; - bbox.fRight += pad; - - bbox.fLeft += x; - bbox.fRight += x; - bbox.fTop += y; - bbox.fBottom += y; - if (this->transformBounds(bbox, &paint)) { - INHERITED::onDrawText(text, byteLength, x, y, paint); - } -} - -void SkBBoxRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, - const SkPaint* paint) { - SkRect bbox = {left, top, left + bitmap.width(), top + bitmap.height()}; - if (this->transformBounds(bbox, paint)) { - INHERITED::drawBitmap(bitmap, left, top, paint); - } -} - -void SkBBoxRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, - const SkRect& dst, const SkPaint* paint, - DrawBitmapRectFlags flags) { - if (this->transformBounds(dst, paint)) { - INHERITED::drawBitmapRectToRect(bitmap, src, dst, paint, flags); - } -} - -void SkBBoxRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& mat, - const SkPaint* paint) { - SkMatrix m = mat; - SkRect bbox = {0, 0, SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())}; - m.mapRect(&bbox); - if (this->transformBounds(bbox, paint)) { - INHERITED::drawBitmapMatrix(bitmap, mat, paint); - } -} - -void SkBBoxRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, - const SkRect& dst, const SkPaint* paint) { - if (this->transformBounds(dst, paint)) { - INHERITED::drawBitmapNine(bitmap, center, dst, paint); - } -} - -// Hack to work-around https://code.google.com/p/chromium/issues/detail?id=373785 -// This logic assums that 'pad' is enough to add to the left and right to account for -// big glyphs. For the font in question (a logo font) the glyphs is much wider than just -// the pointsize (approx 3x wider). -// As a temp work-around, we scale-up pad. -// A more correct fix might be to add fontmetrics.fMaxX, but we don't have that value in hand -// at the moment, and (possibly) the value in the font may not be accurate (but who knows). -// -static SkScalar hack_373785_amend_pad(SkScalar pad) { - return pad * 4; -} - -void SkBBoxRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], - const SkPaint& paint) { - SkRect bbox; - bbox.set(pos, paint.countText(text, byteLength)); - SkPaint::FontMetrics metrics; - paint.getFontMetrics(&metrics); - bbox.fTop += metrics.fTop; - bbox.fBottom += metrics.fBottom; - - // pad on left and right by half of max vertical glyph extents - SkScalar pad = (metrics.fTop - metrics.fBottom) / 2; - pad = hack_373785_amend_pad(pad); - bbox.fLeft += pad; - bbox.fRight -= pad; - - if (this->transformBounds(bbox, &paint)) { - INHERITED::onDrawPosText(text, byteLength, pos, paint); - } -} - -void SkBBoxRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], - SkScalar constY, const SkPaint& paint) { - size_t numChars = paint.countText(text, byteLength); - if (numChars == 0) { - return; - } - - const SkFlatData* flatPaintData = this->getFlatPaintData(paint); - WriteTopBot(paint, *flatPaintData); - - SkScalar top = flatPaintData->topBot()[0]; - SkScalar bottom = flatPaintData->topBot()[1]; - SkScalar pad = top - bottom; - - SkRect bbox; - bbox.fLeft = SK_ScalarMax; - bbox.fRight = SK_ScalarMin; - - for (size_t i = 0; i < numChars; ++i) { - if (xpos[i] < bbox.fLeft) { - bbox.fLeft = xpos[i]; - } - if (xpos[i] > bbox.fRight) { - bbox.fRight = xpos[i]; - } - } - - // pad horizontally by max glyph height - pad = hack_373785_amend_pad(pad); - bbox.fLeft += pad; - bbox.fRight -= pad; - - bbox.fTop = top + constY; - bbox.fBottom = bottom + constY; - - if (!this->transformBounds(bbox, &paint)) { - return; - } - // This is the equivalent of calling: - // INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint); - // but we filled our flat paint beforehand so that we could get font metrics. - drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData); -} - -void SkBBoxRecord::drawSprite(const SkBitmap& bitmap, int left, int top, - const SkPaint* paint) { - SkRect bbox; - bbox.set(SkIRect::MakeXYWH(left, top, bitmap.width(), bitmap.height())); - this->handleBBox(bbox); // directly call handleBBox, matrix is ignored - INHERITED::drawSprite(bitmap, left, top, paint); -} - -void SkBBoxRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, - const SkMatrix* matrix, const SkPaint& paint) { - SkRect bbox = path.getBounds(); - SkPaint::FontMetrics metrics; - paint.getFontMetrics(&metrics); - - // pad out all sides by the max glyph height above baseline - SkScalar pad = metrics.fTop; - bbox.fLeft += pad; - bbox.fRight -= pad; - bbox.fTop += pad; - bbox.fBottom -= pad; - - if (this->transformBounds(bbox, &paint)) { - INHERITED::onDrawTextOnPath(text, byteLength, path, matrix, paint); - } -} - -void SkBBoxRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, - const SkPaint& paint) { - SkRect bbox = blob->bounds(); - bbox.offset(x, y); - // FIXME: implement implicit blob bounds! - if (bbox.isEmpty()) { - this->getClipBounds(&bbox); - } - - if (this->transformBounds(bbox, &paint)) { - INHERITED::onDrawTextBlob(blob, x, y, paint); - } -} - -void SkBBoxRecord::drawVertices(VertexMode mode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xfer, - const uint16_t indices[], int indexCount, - const SkPaint& paint) { - SkRect bbox; - bbox.set(vertices, vertexCount); - if (this->transformBounds(bbox, &paint)) { - INHERITED::drawVertices(mode, vertexCount, vertices, texs, - colors, xfer, indices, indexCount, paint); - } -} - -void SkBBoxRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, - const SkPaint& paint) { - SkRect bbox; - bbox.set(cubics, SkPatchUtils::kNumCtrlPts); - if (this->transformBounds(bbox, &paint)) { - INHERITED::onDrawPatch(cubics, colors, texCoords, xmode, paint); - } -} - -void SkBBoxRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, - const SkPaint* paint) { - SkRect bounds = picture->cullRect(); - // todo: wonder if we should allow passing an optional matrix to transformBounds so we don't - // end up transforming the rect twice. - if (matrix) { - matrix->mapRect(&bounds); - } - if (this->transformBounds(bounds, paint)) { - this->INHERITED::onDrawPicture(picture, matrix, paint); - } -} - -void SkBBoxRecord::willSave() { - fSaveStack.push(NULL); - this->INHERITED::willSave(); -} - -SkCanvas::SaveLayerStrategy SkBBoxRecord::willSaveLayer(const SkRect* bounds, - const SkPaint* paint, - SaveFlags flags) { - // Image filters can affect the effective bounds of primitives drawn inside saveLayer(). - // Copy the paint so we can compute the modified bounds in transformBounds(). - fSaveStack.push(paint && paint->getImageFilter() ? new SkPaint(*paint) : NULL); - return this->INHERITED::willSaveLayer(bounds, paint, flags); -} - -void SkBBoxRecord::willRestore() { - delete fSaveStack.top(); - fSaveStack.pop(); - this->INHERITED::willRestore(); -} - -bool SkBBoxRecord::transformBounds(const SkRect& bounds, const SkPaint* paint) { - SkRect outBounds = bounds; - outBounds.sort(); - - if (paint) { - // account for stroking, path effects, shadows, etc - if (paint->canComputeFastBounds()) { - SkRect temp; - outBounds = paint->computeFastBounds(outBounds, &temp); - } else { - // set bounds to current clip - if (!this->getClipBounds(&outBounds)) { - // current clip is empty - return false; - } - } - } - - for (int i = fSaveStack.count() - 1; i >= 0; --i) { - const SkPaint* paint = fSaveStack.getAt(i); - if (paint && paint->canComputeFastBounds()) { - SkRect temp; - outBounds = paint->computeFastBounds(outBounds, &temp); - } - } - - if (!outBounds.isEmpty() && !this->quickReject(outBounds)) { - this->getTotalMatrix().mapRect(&outBounds); - this->handleBBox(outBounds); - return true; - } - - return false; -} diff --git a/src/core/SkBBoxRecord.h b/src/core/SkBBoxRecord.h deleted file mode 100644 index 4833452e73..0000000000 --- a/src/core/SkBBoxRecord.h +++ /dev/null @@ -1,96 +0,0 @@ - -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkBBoxRecord_DEFINED -#define SkBBoxRecord_DEFINED - -#include "SkPictureRecord.h" -#include "SkTDArray.h" - -/** - * This is an abstract SkPictureRecord subclass that intercepts draw calls and computes an - * axis-aligned bounding box for each draw that it sees, subclasses implement handleBBox() - * which will be called every time we get a new bounding box. - */ -class SkBBoxRecord : public SkPictureRecord { -public: - - SkBBoxRecord(const SkISize& size, uint32_t recordFlags) - : INHERITED(size, recordFlags) { - } - virtual ~SkBBoxRecord(); - - /** - * This is called each time we get a bounding box, it will be axis-aligned, - * in device coordinates, and expanded to include stroking, shadows, etc. - */ - virtual void handleBBox(const SkRect& bbox) = 0; - - virtual void drawOval(const SkRect& rect, const SkPaint& paint) SK_OVERRIDE; - virtual void drawRRect(const SkRRect& rrect, const SkPaint& paint) SK_OVERRIDE; - virtual void drawRect(const SkRect& rect, const SkPaint& paint) SK_OVERRIDE; - virtual void drawPath(const SkPath& path, const SkPaint& paint) SK_OVERRIDE; - virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[], - const SkPaint& paint) SK_OVERRIDE; - virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE; - virtual void clear(SkColor) SK_OVERRIDE; - virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, - const SkPaint* paint = NULL) SK_OVERRIDE; - virtual void drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, - const SkRect& dst, const SkPaint* paint, - DrawBitmapRectFlags flags) SK_OVERRIDE; - virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& mat, - const SkPaint* paint) SK_OVERRIDE; - virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, - const SkRect& dst, const SkPaint* paint) SK_OVERRIDE; - virtual void drawSprite(const SkBitmap& bitmap, int left, int top, - const SkPaint* paint) SK_OVERRIDE; - virtual void drawVertices(VertexMode mode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xfer, - const uint16_t indices[], int indexCount, - const SkPaint& paint) SK_OVERRIDE; - -protected: - virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) SK_OVERRIDE; - virtual void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, - const SkPaint&) SK_OVERRIDE; - virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], - const SkPaint&) SK_OVERRIDE; - virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], - SkScalar constY, const SkPaint&) SK_OVERRIDE; - virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, - const SkMatrix* matrix, const SkPaint&) SK_OVERRIDE; - virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, - const SkPaint& paint) SK_OVERRIDE; - virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, - const SkPaint& paint) SK_OVERRIDE; - virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) SK_OVERRIDE; - virtual void willSave() SK_OVERRIDE; - virtual SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) SK_OVERRIDE; - virtual void willRestore() SK_OVERRIDE; - -private: - /** - * Takes a bounding box in current canvas view space, accounts for stroking and effects, and - * computes an axis-aligned bounding box in device coordinates, then passes it to handleBBox() - * returns false if the draw is completely clipped out, and may safely be ignored. - **/ - bool transformBounds(const SkRect& bounds, const SkPaint* paint); - - /** - * Paints from currently-active saveLayers that need to be applied to bounding boxes of all - * primitives drawn inside them. We own these pointers. - **/ - SkTDArray fSaveStack; - - typedef SkPictureRecord INHERITED; -}; - -#endif diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp index 10bbbcedb3..def67e6571 100644 --- a/src/core/SkPicture.cpp +++ b/src/core/SkPicture.cpp @@ -12,7 +12,6 @@ #include "SkPicturePlayback.h" #include "SkPictureRecord.h" #include "SkPictureRecorder.h" -#include "SkPictureStateTree.h" #include "SkBitmapDevice.h" #include "SkCanvas.h" @@ -32,7 +31,6 @@ #include "SkReader32.h" #include "SkWriter32.h" #include "SkRTree.h" -#include "SkBBoxHierarchyRecord.h" #if SK_SUPPORT_GPU #include "GrContext.h" @@ -307,32 +305,21 @@ SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() { /////////////////////////////////////////////////////////////////////////////// -uint32_t SkPicture::OperationList::offset(int index) const { - SkASSERT(index < fOps.count()); - return ((SkPictureStateTree::Draw*)fOps[index])->fOffset; -} - -const SkMatrix& SkPicture::OperationList::matrix(int index) const { - SkASSERT(index < fOps.count()); - return *((SkPictureStateTree::Draw*)fOps[index])->fMatrix; -} - // fRecord OK void SkPicture::playback(SkCanvas* canvas, SkDrawPictureCallback* callback) const { SkASSERT(canvas); SkASSERT(fData.get() || fRecord.get()); - // If the query contains the whole picture, don't bother with the BBH. - SkRect clipBounds = { 0, 0, 0, 0 }; - (void)canvas->getClipBounds(&clipBounds); - const bool useBBH = !clipBounds.contains(this->cullRect()); - if (fData.get()) { SkPicturePlayback playback(this); - playback.setUseBBH(useBBH); playback.draw(canvas, callback); } if (fRecord.get()) { + // If the query contains the whole picture, don't bother with the BBH. + SkRect clipBounds = { 0, 0, 0, 0 }; + (void)canvas->getClipBounds(&clipBounds); + const bool useBBH = !clipBounds.contains(this->cullRect()); + SkRecordDraw(*fRecord, canvas, useBBH ? fBBH.get() : NULL, callback); } } diff --git a/src/core/SkPictureData.cpp b/src/core/SkPictureData.cpp index 877c3f4c33..896c2e6bf3 100644 --- a/src/core/SkPictureData.cpp +++ b/src/core/SkPictureData.cpp @@ -46,17 +46,8 @@ SkPictureData::SkPictureData(const SkPictureRecord& record, fOpData = record.opData(deepCopyOps); - fBoundingHierarchy = record.fBoundingHierarchy; - fStateTree = record.fStateTree; - - SkSafeRef(fBoundingHierarchy); - SkSafeRef(fStateTree); fContentInfo.set(record.fContentInfo); - if (fBoundingHierarchy) { - fBoundingHierarchy->flushDeferredInserts(); - } - // copy over the refcnt dictionary to our reader record.fFlattenableHeap.setupPlaybacks(); @@ -98,8 +89,6 @@ void SkPictureData::init() { fTextBlobCount = 0; fOpData = NULL; fFactoryPlayback = NULL; - fBoundingHierarchy = NULL; - fStateTree = NULL; } SkPictureData::~SkPictureData() { @@ -107,8 +96,6 @@ SkPictureData::~SkPictureData() { SkSafeUnref(fBitmaps); SkSafeUnref(fPaints); - SkSafeUnref(fBoundingHierarchy); - SkSafeUnref(fStateTree); for (int i = 0; i < fPictureCount; i++) { fPictureRefs[i]->unref(); @@ -578,16 +565,6 @@ bool SkPictureData::parseBuffer(SkReadBuffer& buffer) { /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -const SkPicture::OperationList* SkPictureData::getActiveOps(const SkRect& query) const { - if (NULL == fStateTree || NULL == fBoundingHierarchy) { - return NULL; - } - - SkPicture::OperationList* activeOps = SkNEW(SkPicture::OperationList); - fBoundingHierarchy->search(query, &(activeOps->fOps)); - return activeOps; -} - #if SK_SUPPORT_GPU bool SkPictureData::suitableForGpuRasterization(GrContext* context, const char **reason, int sampleCount) const { diff --git a/src/core/SkPictureData.h b/src/core/SkPictureData.h index b875151b50..02529938ab 100644 --- a/src/core/SkPictureData.h +++ b/src/core/SkPictureData.h @@ -13,7 +13,6 @@ #include "SkPicture.h" #include "SkPictureContentInfo.h" #include "SkPictureFlat.h" -#include "SkPictureStateTree.h" class SkData; class SkPictureRecord; @@ -24,7 +23,6 @@ class SkBBoxHierarchy; class SkMatrix; class SkPaint; class SkPath; -class SkPictureStateTree; class SkReadBuffer; class SkTextBlob; @@ -67,8 +65,6 @@ public: virtual ~SkPictureData(); - const SkPicture::OperationList* getActiveOps(const SkRect& queryRect) const; - void serialize(SkWStream*, SkPicture::EncodeBitmap) const; void flatten(SkWriteBuffer&) const; @@ -123,14 +119,6 @@ public: return fTextBlobRefs[index - 1]; } - void initIterator(SkPictureStateTree::Iterator* iter, - const SkTDArray& draws, - SkCanvas* canvas) const { - if (fStateTree) { - fStateTree->initIterator(iter, draws, canvas); - } - } - #if SK_SUPPORT_GPU /** * sampleCount is the number of samples-per-pixel or zero if non-MSAA. @@ -175,9 +163,6 @@ private: const SkTextBlob** fTextBlobRefs; int fTextBlobCount; - SkBBoxHierarchy* fBoundingHierarchy; - SkPictureStateTree* fStateTree; - SkPictureContentInfo fContentInfo; SkTypefacePlayback fTFPlayback; diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp index 308ce9ec3f..661115e41a 100644 --- a/src/core/SkPicturePlayback.cpp +++ b/src/core/SkPicturePlayback.cpp @@ -10,7 +10,6 @@ #include "SkPictureData.h" #include "SkPicturePlayback.h" #include "SkPictureRecord.h" -#include "SkPictureStateTree.h" #include "SkReader32.h" #include "SkTextBlob.h" #include "SkTDArray.h" @@ -66,84 +65,12 @@ static SkBitmap shallow_copy(const SkBitmap& bitmap) { return bitmap; } -const SkPicture::OperationList* SkPicturePlayback::getActiveOps(const SkCanvas* canvas) { - - if (fUseBBH) { - SkRect clipBounds; - if (canvas->getClipBounds(&clipBounds)) { - return fPictureData->getActiveOps(clipBounds); - } - } - - return NULL; -} - -// Initialize the state tree iterator. Return false if there is nothing left to draw. -bool SkPicturePlayback::initIterator(SkPictureStateTree::Iterator* iter, - SkCanvas* canvas, - const SkPicture::OperationList *activeOpsList) { - - if (activeOpsList) { - if (0 == activeOpsList->numOps()) { - return false; // nothing to draw - } - - fPictureData->initIterator(iter, activeOpsList->fOps, canvas); - } - - return true; -} - -// If 'iter' is valid use it to skip forward through the picture. -void SkPicturePlayback::StepIterator(SkPictureStateTree::Iterator* iter, SkReader32* reader) { - if (iter->isValid()) { - uint32_t skipTo = iter->nextDraw(); - if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) { - reader->setOffset(reader->size()); // skip to end - } else { - reader->setOffset(skipTo); - } - } -} - -// Update the iterator and state tree to catch up with the skipped ops. -void SkPicturePlayback::SkipIterTo(SkPictureStateTree::Iterator* iter, - SkReader32* reader, - uint32_t skipTo) { - SkASSERT(skipTo <= reader->size()); - SkASSERT(reader->offset() <= skipTo); // should only be skipping forward - - if (iter->isValid()) { - // If using a bounding box hierarchy, advance the state tree - // iterator until at or after skipTo - uint32_t adjustedSkipTo; - do { - adjustedSkipTo = iter->nextDraw(); - } while (adjustedSkipTo < skipTo); - skipTo = adjustedSkipTo; - } - if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) { - reader->setOffset(reader->size()); // skip to end - } else { - reader->setOffset(skipTo); - } -} - void SkPicturePlayback::draw(SkCanvas* canvas, SkDrawPictureCallback* callback) { AutoResetOpID aroi(this); SkASSERT(0 == fCurOffset); - SkAutoTDelete activeOpsList(this->getActiveOps(canvas)); - SkPictureStateTree::Iterator it; - - if (!this->initIterator(&it, canvas, activeOpsList.get())) { - return; // nothing to draw - } - SkReader32 reader(fPictureData->opData()->bytes(), fPictureData->opData()->size()); - StepIterator(&it, &reader); - // Record this, so we can concat w/ it if we encounter a setMatrix() SkMatrix initialMatrix = canvas->getTotalMatrix(); @@ -157,15 +84,8 @@ void SkPicturePlayback::draw(SkCanvas* canvas, SkDrawPictureCallback* callback) fCurOffset = reader.offset(); uint32_t size; DrawType op = ReadOpAndSize(&reader, &size); - if (NOOP == op) { - // NOOPs are to be ignored - do not propagate them any further - SkipIterTo(&it, &reader, fCurOffset + size); - continue; - } this->handleOp(&reader, op, size, canvas, initialMatrix); - - StepIterator(&it, &reader); } } @@ -175,6 +95,10 @@ void SkPicturePlayback::handleOp(SkReader32* reader, SkCanvas* canvas, const SkMatrix& initialMatrix) { switch (op) { + case NOOP: { + SkASSERT(size >= 4); + reader->skip(size - 4); + } break; case CLIP_PATH: { const SkPath& path = fPictureData->getPath(reader); uint32_t packed = reader->readInt(); @@ -518,7 +442,7 @@ void SkPicturePlayback::handleOp(SkReader32* reader, canvas->translate(dx, dy); } break; default: - SkASSERT(0); + SkASSERTF(false, "Unknown draw type: %d", op); } } diff --git a/src/core/SkPicturePlayback.h b/src/core/SkPicturePlayback.h index cdfa8efe18..9e5db08c63 100644 --- a/src/core/SkPicturePlayback.h +++ b/src/core/SkPicturePlayback.h @@ -9,7 +9,6 @@ #define SkPicturePlayback_DEFINED #include "SkPictureFlat.h" // for DrawType -#include "SkPictureStateTree.h" class SkBitmap; class SkCanvas; @@ -18,14 +17,11 @@ class SkPaint; class SkPictureData; // The basic picture playback class replays the provided picture into a canvas. -// If the picture was generated with a BBH it is used to accelerate drawing -// unless disabled via setUseBBH. class SkPicturePlayback : SkNoncopyable { public: SkPicturePlayback(const SkPicture* picture) : fPictureData(picture->fData.get()) - , fCurOffset(0) - , fUseBBH(true) { + , fCurOffset(0) { } virtual ~SkPicturePlayback() { } @@ -37,31 +33,18 @@ public: size_t curOpID() const { return fCurOffset; } void resetOpID() { fCurOffset = 0; } - // TODO: remove setUseBBH after cleaning up GrGatherCanvas - void setUseBBH(bool useBBH) { fUseBBH = useBBH; } - protected: const SkPictureData* fPictureData; // The offset of the current operation when within the draw method size_t fCurOffset; - bool fUseBBH; - - void handleOp(SkReader32* reader, - DrawType op, - uint32_t size, + void handleOp(SkReader32* reader, + DrawType op, + uint32_t size, SkCanvas* canvas, const SkMatrix& initialMatrix); - const SkPicture::OperationList* getActiveOps(const SkCanvas* canvas); - bool initIterator(SkPictureStateTree::Iterator* iter, - SkCanvas* canvas, - const SkPicture::OperationList *activeOpsList); - static void StepIterator(SkPictureStateTree::Iterator* iter, SkReader32* reader); - static void SkipIterTo(SkPictureStateTree::Iterator* iter, - SkReader32* reader, uint32_t skipTo); - static DrawType ReadOpAndSize(SkReader32* reader, uint32_t* size); class AutoResetOpID { diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp index 5b28468898..16cb3b5a1b 100644 --- a/src/core/SkPictureRecord.cpp +++ b/src/core/SkPictureRecord.cpp @@ -6,10 +6,8 @@ */ #include "SkPictureRecord.h" -#include "SkBBoxHierarchy.h" #include "SkDevice.h" #include "SkPatchUtils.h" -#include "SkPictureStateTree.h" #include "SkPixelRef.h" #include "SkRRect.h" #include "SkTextBlob.h" @@ -17,15 +15,6 @@ #define HEAP_BLOCK_SIZE 4096 -// If SK_RECORD_LITERAL_PICTURES is defined, record our inputs as literally as possible. -// Otherwise, we can be clever and record faster equivalents. kBeClever is normally true. -static const bool kBeClever = -#ifdef SK_RECORD_LITERAL_PICTURES - false; -#else - true; -#endif - enum { // just need a value that save or getSaveCount would never return kNoInitialSave = -1, @@ -40,12 +29,9 @@ static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags) : INHERITED(dimensions.width(), dimensions.height()) - , fBoundingHierarchy(NULL) - , fStateTree(NULL) , fFlattenableHeap(HEAP_BLOCK_SIZE) , fPaints(&fFlattenableHeap) - , fRecordFlags(flags) - , fOptsEnabled(kBeClever) { + , fRecordFlags(flags) { fBitmapHeap = SkNEW(SkBitmapHeap); fFlattenableHeap.setBitmapStorage(fBitmapHeap); @@ -56,8 +42,6 @@ SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags) SkPictureRecord::~SkPictureRecord() { SkSafeUnref(fBitmapHeap); - SkSafeUnref(fBoundingHierarchy); - SkSafeUnref(fStateTree); fFlattenableHeap.setBitmapStorage(NULL); fPictureRefs.unrefAll(); fTextBlobRefs.unrefAll(); @@ -211,15 +195,7 @@ bool SkPictureRecord::isDrawingToLayer() const { return fFirstSavedLayerIndex != kNoSavedLayerIndex; } -/* - * Read the op code from 'offset' in 'writer'. - */ #ifdef SK_DEBUG -static DrawType peek_op(SkWriter32* writer, size_t offset) { - return (DrawType)(writer->readTAt(offset) >> 24); -} -#endif - /* * Read the op code from 'offset' in 'writer' and extract the size too. */ @@ -234,346 +210,7 @@ static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* si } return (DrawType) op; } - -// Is the supplied paint simply a color? -static bool is_simple(const SkPaint& p) { - intptr_t orAccum = (intptr_t)p.getPathEffect() | - (intptr_t)p.getShader() | - (intptr_t)p.getXfermode() | - (intptr_t)p.getMaskFilter() | - (intptr_t)p.getColorFilter() | - (intptr_t)p.getRasterizer() | - (intptr_t)p.getLooper() | - (intptr_t)p.getImageFilter(); - return 0 == orAccum; -} - -// CommandInfos are fed to the 'match' method and filled in with command -// information. -struct CommandInfo { - DrawType fActualOp; - uint32_t fOffset; - uint32_t fSize; -}; - -/* - * Attempt to match the provided pattern of commands starting at 'offset' - * in the byte stream and stopping at the end of the stream. Upon success, - * return true with all the pattern information filled out in the result - * array (i.e., actual ops, offsets and sizes). - * Note this method skips any NOOPs seen in the stream - */ -static bool match(SkWriter32* writer, uint32_t offset, - int* pattern, CommandInfo* result, int numCommands) { - SkASSERT(offset < writer->bytesWritten()); - - uint32_t curOffset = offset; - uint32_t curSize = 0; - int numMatched; - for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) { - DrawType op = peek_op_and_size(writer, curOffset, &curSize); - while (NOOP == op) { - curOffset += curSize; - if (curOffset >= writer->bytesWritten()) { - return false; - } - op = peek_op_and_size(writer, curOffset, &curSize); - } - - if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) { - if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op && - DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) { - return false; - } - } else if (op != pattern[numMatched]) { - return false; - } - - result[numMatched].fActualOp = op; - result[numMatched].fOffset = curOffset; - result[numMatched].fSize = curSize; - - curOffset += curSize; - } - - if (numMatched != numCommands) { - return false; - } - - if (curOffset < writer->bytesWritten()) { - // Something else between the last command and the end of the stream - return false; - } - - return true; -} - -// temporarily here to make code review easier -static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer, - SkPaintDictionary* paintDict, - const CommandInfo& saveLayerInfo, - const CommandInfo& dbmInfo); - -/* - * Restore has just been called (but not recorded), look back at the - * matching save* and see if we are in the configuration: - * SAVE_LAYER - * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT - * RESTORE - * where the saveLayer's color can be moved into the drawBitmap*'s paint - */ -static bool remove_save_layer1(SkWriter32* writer, int32_t offset, - SkPaintDictionary* paintDict) { - // back up to the save block - // TODO: add a stack to track save*/restore offsets rather than searching backwards - while (offset > 0) { - offset = writer->readTAt(offset); - } - - int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ }; - CommandInfo result[SK_ARRAY_COUNT(pattern)]; - - if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) { - return false; - } - - if (kSaveLayerWithBoundsSize == result[0].fSize) { - // The saveLayer's bound can offset where the dbm is drawn - return false; - } - - return merge_savelayer_paint_into_drawbitmp(writer, paintDict, - result[0], result[1]); -} - -/* - * Convert the command code located at 'offset' to a NOOP. Leave the size - * field alone so the NOOP can be skipped later. - */ -static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) { - uint32_t command = writer->readTAt(offset); - writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24)); -} - -/* - * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint. - * Return true on success; false otherwise. - */ -static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer, - SkPaintDictionary* paintDict, - const CommandInfo& saveLayerInfo, - const CommandInfo& dbmInfo) { - SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp); - SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp || - DRAW_BITMAP_MATRIX == dbmInfo.fActualOp || - DRAW_BITMAP_NINE == dbmInfo.fActualOp || - DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp); - - size_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize); - size_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize); - - // we have a match, now we need to get the paints involved - uint32_t dbmPaintId = writer->readTAt(dbmInfo.fOffset + dbmPaintOffset); - uint32_t saveLayerPaintId = writer->readTAt(saveLayerInfo.fOffset + slPaintOffset); - - if (0 == saveLayerPaintId) { - // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer - // and signal the caller (by returning true) to not add the RESTORE op - convert_command_to_noop(writer, saveLayerInfo.fOffset); - return true; - } - - if (0 == dbmPaintId) { - // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer - // and signal the caller (by returning true) to not add the RESTORE op - convert_command_to_noop(writer, saveLayerInfo.fOffset); - writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId); - return true; - } - - SkAutoTDelete saveLayerPaint(paintDict->unflatten(saveLayerPaintId)); - if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) { - return false; - } - - // For this optimization we only fold the saveLayer and drawBitmapRect - // together if the saveLayer's draw is simple (i.e., no fancy effects) and - // and the only difference in the colors is that the saveLayer's can have - // an alpha while the drawBitmapRect's is opaque. - // TODO: it should be possible to fold them together even if they both - // have different non-255 alphas - SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque - - SkAutoTDelete dbmPaint(paintDict->unflatten(dbmPaintId)); - if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor || !is_simple(*dbmPaint)) { - return false; - } - - SkColor newColor = SkColorSetA(dbmPaint->getColor(), - SkColorGetA(saveLayerPaint->getColor())); - dbmPaint->setColor(newColor); - - const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint); - if (NULL == data) { - return false; - } - - // kill the saveLayer and alter the DBMR2R's paint to be the modified one - convert_command_to_noop(writer, saveLayerInfo.fOffset); - writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index()); - return true; -} - -/* - * Restore has just been called (but not recorded), look back at the - * matching save* and see if we are in the configuration: - * SAVE_LAYER (with NULL == bounds) - * SAVE - * CLIP_RECT - * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT - * RESTORE - * RESTORE - * where the saveLayer's color can be moved into the drawBitmap*'s paint - */ -static bool remove_save_layer2(SkWriter32* writer, int32_t offset, - SkPaintDictionary* paintDict) { - // back up to the save block - // TODO: add a stack to track save*/restore offsets rather than searching backwards - while (offset > 0) { - offset = writer->readTAt(offset); - } - - int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ }; - CommandInfo result[SK_ARRAY_COUNT(pattern)]; - - if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) { - return false; - } - - if (kSaveLayerWithBoundsSize == result[0].fSize) { - // The saveLayer's bound can offset where the dbm is drawn - return false; - } - - return merge_savelayer_paint_into_drawbitmp(writer, paintDict, - result[0], result[3]); -} - -static bool is_drawing_op(DrawType op) { - - // FIXME: yuck. convert to a lookup table? - return (op > CONCAT && op < ROTATE) - || DRAW_DRRECT == op - || DRAW_PATCH == op - || DRAW_PICTURE_MATRIX_PAINT == op - || DRAW_TEXT_BLOB == op; -} - -/* - * Restore has just been called (but not recorded), so look back at the - * matching save(), and see if we can eliminate the pair of them, due to no - * intervening matrix/clip calls. - * - * If so, update the writer and return true, in which case we won't even record - * the restore() call. If we still need the restore(), return false. - */ -static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset, - SkPaintDictionary* paintDict) { - int32_t restoreOffset = (int32_t)writer->bytesWritten(); - - // back up to the save block - while (offset > 0) { - offset = writer->readTAt(offset); - } - - // now offset points to a save - offset = -offset; - uint32_t opSize; - DrawType op = peek_op_and_size(writer, offset, &opSize); - if (SAVE_LAYER == op) { - // not ready to cull these out yet (mrr) - return false; - } - SkASSERT(SAVE == op); - SkASSERT(kSaveSize == opSize); - - // Walk forward until we get back to either a draw-verb (abort) or we hit - // our restore (success). - int32_t saveOffset = offset; - - offset += opSize; - while (offset < restoreOffset) { - op = peek_op_and_size(writer, offset, &opSize); - if (is_drawing_op(op) || (SAVE_LAYER == op)) { - // drawing verb, abort - return false; - } - offset += opSize; - } - - writer->rewindToOffset(saveOffset); - return true; -} - -typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset, - SkPaintDictionary* paintDict); -enum PictureRecordOptType { - kRewind_OptType, // Optimization rewinds the command stream - kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair -}; - -enum PictureRecordOptFlags { - kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the - // SkPicture has a bounding box hierarchy. - kRescindLastSave_Flag = 0x2, - kRescindLastSaveLayer_Flag = 0x4, -}; - -struct PictureRecordOpt { - PictureRecordOptProc fProc; - PictureRecordOptType fType; - unsigned fFlags; -}; -/* - * A list of the optimizations that are tried upon seeing a restore - * TODO: add a real API for such optimizations - * Add the ability to fire optimizations on any op (not just RESTORE) - */ -static const PictureRecordOpt gPictureRecordOpts[] = { - // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy - // because it is redundant with the state traversal optimization in - // SkPictureStateTree, and applying the optimization introduces significant - // record time overhead because it requires rewinding contents that were - // recorded into the BBoxHierarchy. - { collapse_save_clip_restore, kRewind_OptType, - kSkipIfBBoxHierarchy_Flag|kRescindLastSave_Flag }, - { remove_save_layer1, kCollapseSaveLayer_OptType, kRescindLastSaveLayer_Flag }, - { remove_save_layer2, kCollapseSaveLayer_OptType, kRescindLastSaveLayer_Flag } -}; - -// This is called after an optimization has been applied to the command stream -// in order to adjust the contents and state of the bounding box hierarchy and -// state tree to reflect the optimization. -static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree, - SkBBoxHierarchy* boundingHierarchy) { - switch (opt) { - case kCollapseSaveLayer_OptType: - if (stateTree) { - stateTree->saveCollapsed(); - } - break; - case kRewind_OptType: - if (boundingHierarchy) { - boundingHierarchy->rewindInserts(); - } - // Note: No need to touch the state tree for this to work correctly. - // Unused branches do not burden the playback, and pruning the tree - // would be O(N^2), so it is best to leave it alone. - break; - default: - SkASSERT(0); - } -} +#endif//SK_DEBUG void SkPictureRecord::willRestore() { // FIXME: SkDeferredCanvas needs to be refactored to respect @@ -592,31 +229,7 @@ void SkPictureRecord::willRestore() { fFirstSavedLayerIndex = kNoSavedLayerIndex; } - size_t opt = 0; - if (fOptsEnabled) { - for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) { - if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag) - && fBoundingHierarchy) { - continue; - } - if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) { - // Some optimization fired so don't add the RESTORE - apply_optimization_to_bbh(gPictureRecordOpts[opt].fType, - fStateTree, fBoundingHierarchy); - if (gPictureRecordOpts[opt].fFlags & kRescindLastSave_Flag) { - fContentInfo.rescindLastSave(); - } else if (gPictureRecordOpts[opt].fFlags & kRescindLastSaveLayer_Flag) { - fContentInfo.rescindLastSaveLayer(); - } - break; - } - } - } - - if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) { - // No optimization fired so add the RESTORE - this->recordRestore(); - } + this->recordRestore(); fRestoreOffsetStack.pop(); @@ -905,19 +518,13 @@ void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) { } void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) { - if (rrect.isRect() && kBeClever) { - this->SkPictureRecord::drawRect(rrect.getBounds(), paint); - } else if (rrect.isOval() && kBeClever) { - this->SkPictureRecord::drawOval(rrect.getBounds(), paint); - } else { - // op + paint index + rrect - size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory; - size_t initialOffset = this->addDraw(DRAW_RRECT, &size); - SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten()); - this->addPaint(paint); - this->addRRect(rrect); - this->validate(initialOffset, size); - } + // op + paint index + rrect + size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory; + size_t initialOffset = this->addDraw(DRAW_RRECT, &size); + SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten()); + this->addPaint(paint); + this->addRRect(rrect); + this->validate(initialOffset, size); } void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, @@ -946,10 +553,6 @@ void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) { void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint* paint = NULL) { - if (bitmap.drawsNothing() && kBeClever) { - return; - } - // op + paint index + bitmap index + left + top size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); size_t initialOffset = this->addDraw(DRAW_BITMAP, &size); @@ -964,10 +567,6 @@ void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, const SkPaint* paint, DrawBitmapRectFlags flags) { - if (bitmap.drawsNothing() && kBeClever) { - return; - } - // id + paint index + bitmap index + bool for 'src' + flags size_t size = 5 * kUInt32Size; if (src) { @@ -988,10 +587,6 @@ void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { - if (bitmap.drawsNothing() && kBeClever) { - return; - } - // id + paint index + bitmap index + matrix size_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL); size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size); @@ -1004,10 +599,6 @@ void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint) { - if (bitmap.drawsNothing() && kBeClever) { - return; - } - // op + paint index + bitmap id + center + dst rect size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst); size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size); @@ -1021,10 +612,6 @@ void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& cent void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint = NULL) { - if (bitmap.drawsNothing() && kBeClever) { - return; - } - // op + paint index + bitmap index + left + top size_t size = 5 * kUInt32Size; size_t initialOffset = this->addDraw(DRAW_SPRITE, &size); @@ -1036,160 +623,52 @@ void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top, this->validate(initialOffset, size); } -void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) { - SkPaint::FontMetrics metrics; - paint.getFontMetrics(&metrics); - SkRect bounds; - // construct a rect so we can see any adjustments from the paint. - // we use 0,1 for left,right, just so the rect isn't empty - bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom); - (void)paint.computeFastBounds(bounds, &bounds); - topbot[0] = bounds.fTop; - topbot[1] = bounds.fBottom; -} - -void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat, - SkScalar minY, SkScalar maxY) { - WriteTopBot(paint, flat); - this->addScalar(flat.topBot()[0] + minY); - this->addScalar(flat.topBot()[1] + maxY); -} - void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { - bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever; - // op + paint index + length + 'length' worth of chars + x + y size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar); - if (fast) { - size += 2 * sizeof(SkScalar); // + top & bottom - } - DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT; + DrawType op = DRAW_TEXT; size_t initialOffset = this->addDraw(op, &size); SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten()); - const SkFlatData* flatPaintData = addPaint(paint); - SkASSERT(flatPaintData); + this->addPaint(paint); this->addText(text, byteLength); this->addScalar(x); this->addScalar(y); - if (fast) { - this->addFontMetricsTopBottom(paint, *flatPaintData, y, y); - } this->validate(initialOffset, size); } void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint) { int points = paint.countText(text, byteLength); - if (0 == points) - return; - bool canUseDrawH = true; - SkScalar minY = pos[0].fY; - SkScalar maxY = pos[0].fY; - // check if the caller really should have used drawPosTextH() - { - const SkScalar firstY = pos[0].fY; - for (int index = 1; index < points; index++) { - if (pos[index].fY != firstY) { - canUseDrawH = false; - if (pos[index].fY < minY) { - minY = pos[index].fY; - } else if (pos[index].fY > maxY) { - maxY = pos[index].fY; - } - } - } - } + // op + paint index + length + 'length' worth of data + num points + x&y point data + size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + points * sizeof(SkPoint); - bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever; - bool fast = canUseDrawH && fastBounds && kBeClever; + DrawType op = DRAW_POS_TEXT; - // op + paint index + length + 'length' worth of data + num points - size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; - if (canUseDrawH) { - if (fast) { - size += 2 * sizeof(SkScalar); // + top & bottom - } - // + y-pos + actual x-point data - size += sizeof(SkScalar) + points * sizeof(SkScalar); - } else { - // + x&y point data - size += points * sizeof(SkPoint); - if (fastBounds) { - size += 2 * sizeof(SkScalar); // + top & bottom - } - } - - DrawType op; - if (fast) { - op = DRAW_POS_TEXT_H_TOP_BOTTOM; - } else if (canUseDrawH) { - op = DRAW_POS_TEXT_H; - } else if (fastBounds) { - op = DRAW_POS_TEXT_TOP_BOTTOM; - } else { - op = DRAW_POS_TEXT; - } size_t initialOffset = this->addDraw(op, &size); SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten()); - const SkFlatData* flatPaintData = this->addPaint(paint); - SkASSERT(flatPaintData); + this->addPaint(paint); this->addText(text, byteLength); this->addInt(points); - - if (canUseDrawH) { - if (fast) { - this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY); - } - this->addScalar(pos[0].fY); - SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar)); - for (int index = 0; index < points; index++) - *xptr++ = pos[index].fX; - } else { - fWriter.writeMul4(pos, points * sizeof(SkPoint)); - if (fastBounds) { - this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY); - } - } + fWriter.writeMul4(pos, points * sizeof(SkPoint)); this->validate(initialOffset, size); } void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint& paint) { - const SkFlatData* flatPaintData = this->getFlatPaintData(paint); - this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData); -} - -void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength, - const SkScalar xpos[], SkScalar constY, - const SkPaint& paint, const SkFlatData* flatPaintData) { int points = paint.countText(text, byteLength); - if (0 == points && kBeClever) { - return; - } - - bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever; // op + paint index + length + 'length' worth of data + num points size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; - if (fast) { - size += 2 * sizeof(SkScalar); // + top & bottom - } // + y + the actual points size += 1 * kUInt32Size + points * sizeof(SkScalar); - size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H, - &size); - SkASSERT(flatPaintData); - this->addFlatPaint(flatPaintData); + size_t initialOffset = this->addDraw(DRAW_POS_TEXT_H, &size); + this->addPaint(paint); this->addText(text, byteLength); this->addInt(points); - - if (fast) { - this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY); - } this->addScalar(constY); fWriter.writeMul4(xpos, points * sizeof(SkScalar)); this->validate(initialOffset, size); @@ -1331,13 +810,13 @@ void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors size += kUInt32Size; } } - + size_t initialOffset = this->addDraw(DRAW_PATCH, &size); SkASSERT(initialOffset+getPaintOffset(DRAW_PATCH, size) == fWriter.bytesWritten()); this->addPaint(paint); this->addPatch(cubics); this->addInt(flag); - + // write optional parameters if (colors) { fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor)); @@ -1409,14 +888,6 @@ void SkPictureRecord::onPopCull() { uint32_t cullSkipOffset = fCullOffsetStack.top(); fCullOffsetStack.pop(); - // Collapse empty push/pop pairs. - if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten() && kBeClever) { - SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize); - SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize)); - fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize); - return; - } - // op only size_t size = kUInt32Size; size_t initialOffset = this->addDraw(POP_CULL, &size); @@ -1447,21 +918,16 @@ void SkPictureRecord::addMatrix(const SkMatrix& matrix) { fWriter.writeMatrix(matrix); } -const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) { - return fPaints.findAndReturnFlat(paint); -} - -const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) { +void SkPictureRecord::addPaintPtr(const SkPaint* paint) { fContentInfo.onAddPaintPtr(paint); - const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL; - this->addFlatPaint(data); - return data; -} - -void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) { - int index = flatPaint ? flatPaint->index() : 0; - this->addInt(index); + if (paint) { + const SkFlatData* flat = fPaints.findAndReturnFlat(*paint); + SkASSERT(flat && flat->index() != 0); + this->addInt(flat->index()); + } else { + this->addInt(0); + } } int SkPictureRecord::addPathToHeap(const SkPath& path) { diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h index f8895c950e..ca2aecd678 100644 --- a/src/core/SkPictureRecord.h +++ b/src/core/SkPictureRecord.h @@ -17,9 +17,6 @@ #include "SkTemplates.h" #include "SkWriter32.h" -class SkBBoxHierarchy; -class SkPictureStateTree; - // These macros help with packing and unpacking a single byte value and // a 3 byte value into/out of a uint32_t #define MASK_24 0x00FFFFFF @@ -64,9 +61,6 @@ public: virtual void endCommentGroup() SK_OVERRIDE; virtual bool isDrawingToLayer() const SK_OVERRIDE; - void addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData&, - SkScalar minY, SkScalar maxY); - const SkTDArray& getPictureRefs() const { return fPictureRefs; } @@ -108,10 +102,6 @@ public: void beginRecording(); void endRecording(); - void internalOnly_EnableOpts(bool optsEnabled) { - fOptsEnabled = optsEnabled; - } - protected: void addNoOp(); @@ -170,9 +160,8 @@ private: // The command at 'offset' in the skp uses the specified bitmap int addBitmap(const SkBitmap& bitmap); void addMatrix(const SkMatrix& matrix); - const SkFlatData* addPaint(const SkPaint& paint) { return this->addPaintPtr(&paint); } - const SkFlatData* addPaintPtr(const SkPaint* paint); - void addFlatPaint(const SkFlatData* flatPaint); + void addPaint(const SkPaint& paint) { this->addPaintPtr(&paint); } + void addPaintPtr(const SkPaint* paint); void addPatch(const SkPoint cubics[12]); void addPath(const SkPath& path); void addPicture(const SkPicture* picture); @@ -220,7 +209,7 @@ protected: const SkMatrix* matrix, const SkPaint&) SK_OVERRIDE; virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) SK_OVERRIDE; - + virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) SK_OVERRIDE; @@ -232,27 +221,6 @@ protected: virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) SK_OVERRIDE; - // Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been - // tweaked by paint.computeFastBounds(). - static void ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]); - - // Make sure that flat has fTopBot written. - static void WriteTopBot(const SkPaint& paint, const SkFlatData& flat) { - if (!flat.isTopBotWritten()) { - ComputeFontMetricsTopBottom(paint, flat.writableTopBot()); - SkASSERT(flat.isTopBotWritten()); - } - } - // Will return a cached version when possible. - const SkFlatData* getFlatPaintData(const SkPaint& paint); - /** - * SkBBoxRecord::drawPosTextH gets a flat paint and uses it, - * then it calls this, using the extra parameter, to avoid duplication. - */ - void drawPosTextHImpl(const void* text, size_t byteLength, - const SkScalar xpos[], SkScalar constY, - const SkPaint& paint, const SkFlatData* flatPaintData); - int addPathToHeap(const SkPath& path); // does not write to ops stream // These entry points allow the writing of matrices, clips, saves & @@ -269,11 +237,6 @@ protected: void recordSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags); void recordRestore(bool fillInSkips = true); - // These are set to NULL in our constructor, but may be changed by - // subclasses, in which case they will be SkSafeUnref'd in our destructor. - SkBBoxHierarchy* fBoundingHierarchy; - SkPictureStateTree* fStateTree; - // Allocated in the constructor and managed by this class. SkBitmapHeap* fBitmapHeap; @@ -292,7 +255,6 @@ private: SkTDArray fTextBlobRefs; uint32_t fRecordFlags; - bool fOptsEnabled; int fInitialSaveCount; friend class SkPictureData; // for SkPictureData's SkPictureRecord-based constructor diff --git a/src/core/SkPictureRecorder.cpp b/src/core/SkPictureRecorder.cpp index 43111a5c6c..81c39e36f0 100644 --- a/src/core/SkPictureRecorder.cpp +++ b/src/core/SkPictureRecorder.cpp @@ -5,7 +5,6 @@ * found in the LICENSE file. */ -#include "SkBBoxHierarchyRecord.h" #include "SkPictureRecord.h" #include "SkPictureRecorder.h" #include "SkRecord.h" @@ -26,20 +25,11 @@ SkCanvas* SkPictureRecorder::beginRecording(SkScalar width, SkScalar height, SkCanvas* SkPictureRecorder::DEPRECATED_beginRecording(SkScalar width, SkScalar height, SkBBHFactory* bbhFactory /* = NULL */, uint32_t recordFlags /* = 0 */) { + SkASSERT(!bbhFactory); // No longer suppported with this backend. + fCullWidth = width; fCullHeight = height; - - const SkISize size = SkISize::Make(width, height); - - if (bbhFactory) { - // We don't need to hold a ref on the BBH ourselves, but might as well for - // consistency with EXPERIMENTAL_beginRecording(), which does need to. - fBBH.reset((*bbhFactory)(width, height)); - SkASSERT(fBBH.get()); - fPictureRecord.reset(SkNEW_ARGS(SkBBoxHierarchyRecord, (size, recordFlags, fBBH.get()))); - } else { - fPictureRecord.reset(SkNEW_ARGS(SkPictureRecord, (size, recordFlags))); - } + fPictureRecord.reset(SkNEW_ARGS(SkPictureRecord, (SkISize::Make(width, height), recordFlags))); fPictureRecord->beginRecording(); return this->getRecordingCanvas(); @@ -85,12 +75,6 @@ SkPicture* SkPictureRecorder::endRecording() { return picture; } -void SkPictureRecorder::internalOnly_EnableOpts(bool enableOpts) { - if (fPictureRecord.get()) { - fPictureRecord->internalOnly_EnableOpts(enableOpts); - } -} - void SkPictureRecorder::partialReplay(SkCanvas* canvas) const { if (NULL == canvas) { return; diff --git a/src/core/SkPictureStateTree.cpp b/src/core/SkPictureStateTree.cpp deleted file mode 100644 index 704a04ebee..0000000000 --- a/src/core/SkPictureStateTree.cpp +++ /dev/null @@ -1,218 +0,0 @@ - -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkPictureStateTree.h" -#include "SkCanvas.h" - -SkPictureStateTree::SkPictureStateTree() - : fAlloc(2048) - , fLastRestoredNode(NULL) - , fStateStack(sizeof(Draw), 16) { - 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(fStateStack.push_back()) = fCurrentState; -} - -SkPictureStateTree::~SkPictureStateTree() { -} - -SkPictureStateTree::Draw* SkPictureStateTree::appendDraw(size_t offset) { - Draw* draw = static_cast(fAlloc.allocThrow(sizeof(Draw))); - *draw = fCurrentState; - draw->fOffset = SkToU32(offset); - return draw; -} - -void SkPictureStateTree::appendSave() { - *static_cast(fStateStack.push_back()) = fCurrentState; - fCurrentState.fNode->fFlags |= Node::kSave_Flag; -} - -void SkPictureStateTree::appendSaveLayer(size_t offset) { - *static_cast(fStateStack.push_back()) = fCurrentState; - this->appendNode(offset); - fCurrentState.fNode->fFlags |= Node::kSaveLayer_Flag; -} - -void SkPictureStateTree::saveCollapsed() { - SkASSERT(fLastRestoredNode); - SkASSERT(SkToBool(fLastRestoredNode->fFlags & \ - (Node::kSaveLayer_Flag | Node::kSave_Flag))); - SkASSERT(fLastRestoredNode->fParent == fCurrentState.fNode); - // The structure of the tree is not modified here. We just turn off - // the save or saveLayer flag to prevent the iterator from making state - // changing calls on the playback canvas when traversing a save or - // saveLayerNode node. - fLastRestoredNode->fFlags = 0; -} - -void SkPictureStateTree::appendRestore() { - fLastRestoredNode = fCurrentState.fNode; - fCurrentState = *static_cast(fStateStack.back()); - fStateStack.pop_back(); -} - -void SkPictureStateTree::appendTransform(const SkMatrix& trans) { - SkMatrix* m = static_cast(fAlloc.allocThrow(sizeof(SkMatrix))); - *m = trans; - fCurrentState.fMatrix = m; -} - -void SkPictureStateTree::appendClip(size_t offset) { - this->appendNode(offset); -} - -void SkPictureStateTree::initIterator(SkPictureStateTree::Iterator* iter, - const SkTDArray& draws, - SkCanvas* canvas) { - iter->init(draws, canvas, &fRoot); -} - -void SkPictureStateTree::appendNode(size_t offset) { - Node* n = static_cast(fAlloc.allocThrow(sizeof(Node))); - n->fOffset = SkToU32(offset); - n->fFlags = 0; - n->fParent = fCurrentState.fNode; - n->fLevel = fCurrentState.fNode->fLevel + 1; - n->fMatrix = fCurrentState.fMatrix; - fCurrentState.fNode = n; -} - -void SkPictureStateTree::Iterator::init(const SkTDArray& 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(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::nextDraw() { - SkASSERT(this->isValid()); - if (fPlaybackIndex >= fDraws->count()) { - return this->finish(); - } - - Draw* draw = static_cast((*fDraws)[fPlaybackIndex]); - Node* targetNode = draw->fNode; - - if (fSave) { - fCanvas->save(); - fSave = false; - } - - if (fCurrentNode != targetNode) { - // If we're not at the target and we don't have a list of nodes to get there, we need to - // figure out the path from our current node, to the target - if (fNodes.count() == 0) { - // Trace back up to a common ancestor, restoring to get our current state to match that - // of the ancestor, and saving a list of nodes whose state we need to apply to get to - // the target (we can restore up to the ancestor immediately, but we'll need to return - // an offset for each node on the way down to the target, to apply the desired clips and - // saveLayers, so it may take several draw() calls before the next draw actually occurs) - Node* tmp = fCurrentNode; - Node* ancestor = targetNode; - while (tmp != ancestor) { - uint16_t currentLevel = tmp->fLevel; - uint16_t targetLevel = ancestor->fLevel; - if (currentLevel >= targetLevel) { - 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) { - fNodes.push(ancestor); - ancestor = ancestor->fParent; - } - } - - if (ancestor->fFlags & Node::kSave_Flag) { - if (fCurrentNode != ancestor) { - fCanvas->restore(); - // restore() may change the matrix, so we need to reapply. - fCurrentMatrix = NULL; - } - if (targetNode != ancestor) { - fCanvas->save(); - } - } - fCurrentNode = ancestor; - } - - // 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) { - 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. - this->setCurrentMatrix(draw->fMatrix); - - ++fPlaybackIndex; - return draw->fOffset; -} diff --git a/src/core/SkPictureStateTree.h b/src/core/SkPictureStateTree.h deleted file mode 100644 index 15bb02f354..0000000000 --- a/src/core/SkPictureStateTree.h +++ /dev/null @@ -1,162 +0,0 @@ - -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkPictureStateTree_DEFINED -#define SkPictureStateTree_DEFINED - -#include "SkTDArray.h" -#include "SkChunkAlloc.h" -#include "SkDeque.h" -#include "SkMatrix.h" -#include "SkRefCnt.h" - -class SkCanvas; - -/** - * Provides an interface that, given a sequence of draws into an SkPicture with corresponding - * offsets, allows for playback of an arbitrary subset of the draws (note that Z-order is only - * guaranteed if the draws are explicitly sorted). - */ -class SkPictureStateTree : public SkRefCnt { -private: - struct Node; -public: - SK_DECLARE_INST_COUNT(SkPictureStateTree) - - /** - * A draw call, stores offset into command buffer, a pointer to the matrix, and a pointer to - * the node in the tree that corresponds to its clip/layer state - */ - struct Draw { - SkMatrix* fMatrix; - Node* fNode; - uint32_t fOffset; - bool operator<(const Draw& other) const { return fOffset < other.fOffset; } - }; - - class Iterator; - - SkPictureStateTree(); - ~SkPictureStateTree(); - - /** - * Creates and returns a struct representing a draw at the given offset. - */ - Draw* appendDraw(size_t offset); - - /** - * Given a list of draws, and a canvas, initialize an iterator that produces the correct - * sequence of offsets into the command buffer to carry out those calls with correct - * matrix/clip state. This handles saves/restores, and does all necessary matrix setup. - */ - void initIterator(SkPictureStateTree::Iterator* iter, - const SkTDArray& draws, - SkCanvas* canvas); - - void appendSave(); - void appendSaveLayer(size_t offset); - void appendRestore(); - void appendTransform(const SkMatrix& trans); - void appendClip(size_t offset); - - /** - * Call this immediately after an appendRestore call that is associated - * a save or saveLayer that was removed from the command stream - * due to a command pattern optimization in SkPicture. - */ - void saveCollapsed(); - - /** - * Playback helper - */ - class Iterator { - public: - /** Returns the next op offset needed to create the drawing state - required by the queued up draw operation or the offset of the queued - up draw operation itself. In the latter case, the next draw operation - will move into the queued up slot. - It retuns kDrawComplete when done. - TODO: this might be better named nextOp - */ - uint32_t nextDraw(); - static const uint32_t kDrawComplete = SK_MaxU32; - Iterator() : fValid(false) { } - bool isValid() const { return fValid; } - - private: - void init(const SkTDArray& draws, SkCanvas* canvas, Node* root); - - void setCurrentMatrix(const SkMatrix*); - - // The draws this iterator is associated with - const SkTDArray* fDraws; - - // canvas this is playing into (so we can insert saves/restores as necessary) - SkCanvas* fCanvas; - - // current state node - Node* fCurrentNode; - - // List of nodes whose state we need to apply to reach TargetNode - SkTDArray fNodes; - - // The matrix of the canvas we're playing back into - SkMatrix fPlaybackMatrix; - - // Cache of current matrix, so we can avoid redundantly setting it - const SkMatrix* fCurrentMatrix; - - // current position in the array of draws - int fPlaybackIndex; - // Whether or not we need to do a save next iteration - bool fSave; - - // Whether or not this is a valid iterator (the default public constructor sets this false) - bool fValid; - - uint32_t finish(); - - friend class SkPictureStateTree; - }; - -private: - - void appendNode(size_t offset); - - SkChunkAlloc fAlloc; - // Needed by saveCollapsed() because nodes do not currently store - // references to their children. If they did, we could just retrieve the - // last added child. - Node* fLastRestoredNode; - - // The currently active state - Draw fCurrentState; - // A stack of states for tracking save/restores - SkDeque fStateStack; - - // Represents a notable piece of state that requires an offset into the command buffer, - // corresponding to a clip/saveLayer/etc call, to apply. - struct Node { - Node* fParent; - uint32_t fOffset; - uint16_t fLevel; - uint16_t fFlags; - SkMatrix* fMatrix; - enum Flags { - kSave_Flag = 0x1, - kSaveLayer_Flag = 0x2 - }; - }; - - Node fRoot; - SkMatrix fRootMatrix; - - typedef SkRefCnt INHERITED; -}; - -#endif diff --git a/tests/PictureStateTreeTest.cpp b/tests/PictureStateTreeTest.cpp deleted file mode 100644 index cb154def96..0000000000 --- a/tests/PictureStateTreeTest.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkBBHFactory.h" -#include "SkCanvas.h" -#include "SkPictureRecorder.h" -#include "SkPictureStateTree.h" -#include "Test.h" - -static SkPicture* draw_scene(SkBBHFactory* bbhFactory) { - SkPictureRecorder recorder; - SkCanvas* canvas = recorder.beginRecording(200, 200, bbhFactory, 0); - - SkPaint p1, p2; - p1.setStyle(SkPaint::kFill_Style); - p1.setARGB(0x80, 0, 0xff, 0); - p2.setStyle(SkPaint::kFill_Style); - p2.setARGB(0x80, 0xff, 0, 0); - - canvas->drawColor(SK_ColorWHITE); - - // This is intended to exercise some tricky SkPictureStateTree code paths when - // played back with various clips: - // - // * cleanup/rewind when the last draw is not at the root of the state tree. - // * state nodes with both kSave_Flag & kSaveLayer_Flag set. - // * state tree transitions which implicitly reset the matrix via. restore(). - - canvas->save(); - canvas->translate(10, 10); - - canvas->drawRect(SkRect::MakeWH(100, 50), p1); - canvas->drawRect(SkRect::MakeWH(50, 100), p2); - - SkRect layerBounds = SkRect::MakeXYWH(0, 0, 90, 90); - canvas->saveLayer(&layerBounds, NULL); - canvas->save(); - canvas->clipRect(layerBounds); - - canvas->save(); - canvas->clipRect(SkRect::MakeWH(25, 25)); - canvas->rotate(90); - canvas->drawRect(SkRect::MakeWH(100, 50), p1); - canvas->restore(); - - canvas->save(); - canvas->clipRect(SkRect::MakeWH(25, 25)); - canvas->save(); - canvas->rotate(90); - canvas->drawRect(SkRect::MakeWH(50, 100), p2); - canvas->restore(); - canvas->drawRect(SkRect::MakeWH(100, 50), p1); - canvas->restore(); - canvas->drawRect(SkRect::MakeXYWH(99, 99, 1, 1), p1); - canvas->restore(); - canvas->restore(); - - canvas->restore(); - - return recorder.endRecording(); -} - -static void check_bms(skiatest::Reporter* reporter, const SkBitmap& bm1, const SkBitmap& bm2) { - SkASSERT(bm1.getSize() == bm2.getSize()); - REPORTER_ASSERT(reporter, 0 == memcmp(bm1.getAddr(0, 0), bm2.getAddr(0, 0), bm1.getSize())); -} - -static void test_reference_picture(skiatest::Reporter* reporter) { - SkRTreeFactory bbhFactory; - - SkAutoTUnref bbhPicture(draw_scene(&bbhFactory)); - SkAutoTUnref referencePicture(draw_scene(NULL)); - - SkBitmap referenceBitmap; - referenceBitmap.allocN32Pixels(100, 100); - SkCanvas referenceCanvas(referenceBitmap); - - SkBitmap bbhBitmap; - bbhBitmap.allocN32Pixels(100, 100); - SkCanvas bbhCanvas(bbhBitmap); - - referenceCanvas.drawColor(SK_ColorTRANSPARENT); - referenceCanvas.drawPicture(referencePicture.get()); - bbhCanvas.drawColor(SK_ColorTRANSPARENT); - bbhCanvas.drawPicture(bbhPicture.get()); - REPORTER_ASSERT(reporter, - referenceCanvas.getSaveCount() == bbhCanvas.getSaveCount()); - REPORTER_ASSERT(reporter, - referenceCanvas.getTotalMatrix() == bbhCanvas.getTotalMatrix()); - check_bms(reporter, referenceBitmap, bbhBitmap); - - referenceCanvas.drawColor(SK_ColorTRANSPARENT); - referenceCanvas.clipRect(SkRect::MakeWH(50, 50)); - referenceCanvas.drawPicture(referencePicture.get()); - bbhCanvas.drawColor(SK_ColorTRANSPARENT); - bbhCanvas.clipRect(SkRect::MakeWH(50, 50)); - bbhCanvas.drawPicture(bbhPicture.get()); - REPORTER_ASSERT(reporter, - referenceCanvas.getSaveCount() == bbhCanvas.getSaveCount()); - REPORTER_ASSERT(reporter, - referenceCanvas.getTotalMatrix() == bbhCanvas.getTotalMatrix()); - check_bms(reporter, referenceBitmap, bbhBitmap); - - referenceCanvas.drawColor(SK_ColorTRANSPARENT); - referenceCanvas.clipRect(SkRect::MakeWH(10, 10)); - referenceCanvas.drawPicture(referencePicture.get()); - bbhCanvas.drawColor(SK_ColorTRANSPARENT); - bbhCanvas.clipRect(SkRect::MakeWH(10, 10)); - bbhCanvas.drawPicture(bbhPicture.get()); - REPORTER_ASSERT(reporter, - referenceCanvas.getSaveCount() == bbhCanvas.getSaveCount()); - REPORTER_ASSERT(reporter, - referenceCanvas.getTotalMatrix() == bbhCanvas.getTotalMatrix()); - check_bms(reporter, referenceBitmap, bbhBitmap); -} - -DEF_TEST(PictureStateTree, reporter) { - test_reference_picture(reporter); -} diff --git a/tests/RecordingXfermodeTest.cpp b/tests/RecordingXfermodeTest.cpp index 8da81b3680..aa6bf687a1 100644 --- a/tests/RecordingXfermodeTest.cpp +++ b/tests/RecordingXfermodeTest.cpp @@ -20,20 +20,17 @@ // This arose from http://crbug.com/401593 which has // https://code.google.com/p/skia/issues/detail?id=1291 as its root cause. - namespace { class Drawer { public: - explicit Drawer() - : fImageInfo(SkImageInfo::MakeN32Premul(200,100)) - { - fCircleBM.allocPixels( SkImageInfo::MakeN32Premul(100,100) ); + explicit Drawer() : fImageInfo(SkImageInfo::MakeN32Premul(200, 100)) { + fCircleBM.allocPixels(SkImageInfo::MakeN32Premul(100, 100)); SkCanvas canvas(fCircleBM); canvas.clear(0xffffffff); SkPaint circlePaint; circlePaint.setColor(0xff000000); - canvas.drawCircle(50,50,50,circlePaint); + canvas.drawCircle(50, 50, 50, circlePaint); } const SkImageInfo& imageInfo() const { return fImageInfo; } @@ -48,15 +45,16 @@ class Drawer { SkPaint layerPaint; layerPaint.setColor(0xff000000); layerPaint.setXfermodeMode(mode); - SkRect canvasRect(SkRect::MakeWH(SkIntToScalar(fImageInfo.width()),SkIntToScalar(fImageInfo.height()))); + SkRect canvasRect(SkRect::MakeWH(SkIntToScalar(fImageInfo.width()), + SkIntToScalar(fImageInfo.height()))); canvas->clipRect(clipRect); canvas->clear(0xff000000); - canvas->saveLayer(NULL,&blackPaint); - canvas->drawRect(canvasRect,greenPaint); - canvas->saveLayer(NULL,&layerPaint); - canvas->drawBitmapRect(fCircleBM,SkRect::MakeXYWH(20,20,60,60),&blackPaint); + canvas->saveLayer(NULL, &blackPaint); + canvas->drawRect(canvasRect, greenPaint); + canvas->saveLayer(NULL, &layerPaint); + canvas->drawBitmapRect(fCircleBM, SkRect::MakeXYWH(20,20,60,60), &blackPaint); canvas->restore(); canvas->restore(); } @@ -69,7 +67,6 @@ class Drawer { class RecordingStrategy { public: virtual ~RecordingStrategy() {} - virtual void init(const SkImageInfo&) = 0; virtual const SkBitmap& recordAndReplay(const Drawer& drawer, const SkRect& intoClip, SkXfermode::Mode) = 0; @@ -78,9 +75,7 @@ class RecordingStrategy { class BitmapBackedCanvasStrategy : public RecordingStrategy { // This version just draws into a bitmap-backed canvas. public: - BitmapBackedCanvasStrategy() {} - - virtual void init(const SkImageInfo& imageInfo) { + BitmapBackedCanvasStrategy(const SkImageInfo& imageInfo) { fBitmap.allocPixels(imageInfo); } @@ -99,18 +94,15 @@ class BitmapBackedCanvasStrategy : public RecordingStrategy { SkBitmap fBitmap; }; -class DeprecatedRecorderStrategy : public RecordingStrategy { - // This version draws the entire scene into an SkPictureRecorder, - // using the deprecated recording backend. +class PictureStrategy : public RecordingStrategy { + // This version draws the entire scene into an SkPictureRecorder. // Then it then replays the scene through a clip rectangle. // This backend proved to be buggy. public: - DeprecatedRecorderStrategy() {} - - virtual void init(const SkImageInfo& imageInfo) { + PictureStrategy(const SkImageInfo& imageInfo) { fBitmap.allocPixels(imageInfo); - fWidth = imageInfo.width(); - fHeight= imageInfo.height(); + fWidth = imageInfo.width(); + fHeight = imageInfo.height(); } virtual const SkBitmap& recordAndReplay(const Drawer& drawer, @@ -120,47 +112,9 @@ class DeprecatedRecorderStrategy : public RecordingStrategy { SkTileGridFactory factory(tileGridInfo); SkPictureRecorder recorder; SkRect canvasRect(SkRect::MakeWH(SkIntToScalar(fWidth),SkIntToScalar(fHeight))); - SkCanvas* canvas = recorder.DEPRECATED_beginRecording( SkIntToScalar(fWidth), SkIntToScalar(fHeight), &factory); - drawer.draw(canvas, canvasRect, mode); - SkAutoTDelete picture(recorder.endRecording()); - - SkCanvas replayCanvas(fBitmap); - replayCanvas.clear(0xffffffff); - replayCanvas.clipRect(intoClip); - picture->playback(&replayCanvas); - - return fBitmap; - } - - private: - SkBitmap fBitmap; - int fWidth; - int fHeight; -}; - -class NewRecordingStrategy : public RecordingStrategy { - // This version draws the entire scene into an SkPictureRecorder, - // using the new recording backend. - // Then it then replays the scene through a clip rectangle. - // This backend proved to be buggy. - public: - NewRecordingStrategy() {} - - virtual void init(const SkImageInfo& imageInfo) { - fBitmap.allocPixels(imageInfo); - fWidth = imageInfo.width(); - fHeight= imageInfo.height(); - } - - virtual const SkBitmap& recordAndReplay(const Drawer& drawer, - const SkRect& intoClip, - SkXfermode::Mode mode) { - SkTileGridFactory::TileGridInfo tileGridInfo = { {100,100}, {0,0}, {0,0} }; - SkTileGridFactory factory(tileGridInfo); - SkPictureRecorder recorder; - SkRect canvasRect(SkRect::MakeWH(SkIntToScalar(fWidth),SkIntToScalar(fHeight))); - SkCanvas* canvas = recorder.EXPERIMENTAL_beginRecording( SkIntToScalar(fWidth), SkIntToScalar(fHeight), &factory); - + SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(fWidth), + SkIntToScalar(fHeight), + &factory); drawer.draw(canvas, canvasRect, mode); SkAutoTDelete picture(recorder.endRecording()); @@ -177,64 +131,45 @@ class NewRecordingStrategy : public RecordingStrategy { int fHeight; }; -} - +} // namespace DEF_TEST(SkRecordingAccuracyXfermode, reporter) { #define FINEGRAIN 0 - const Drawer drawer; - BitmapBackedCanvasStrategy golden; // This is the expected result. - DeprecatedRecorderStrategy deprecatedRecording; - NewRecordingStrategy newRecording; - - golden.init(drawer.imageInfo()); - deprecatedRecording.init(drawer.imageInfo()); - newRecording.init(drawer.imageInfo()); + BitmapBackedCanvasStrategy golden(drawer.imageInfo()); + PictureStrategy picture(drawer.imageInfo()); #if !FINEGRAIN unsigned numErrors = 0; SkString errors; #endif - for (int iMode = 0; iMode < int(SkXfermode::kLastMode) ; iMode++ ) { - const SkRect& clip = SkRect::MakeXYWH(100,0,100,100); + for (int iMode = 0; iMode < int(SkXfermode::kLastMode); iMode++) { + const SkRect& clip = SkRect::MakeXYWH(100, 0, 100, 100); SkXfermode::Mode mode = SkXfermode::Mode(iMode); const SkBitmap& goldenBM = golden.recordAndReplay(drawer, clip, mode); - const SkBitmap& deprecatedBM = deprecatedRecording.recordAndReplay(drawer, clip, mode); - const SkBitmap& newRecordingBM = newRecording.recordAndReplay(drawer, clip, mode); + const SkBitmap& pictureBM = picture.recordAndReplay(drawer, clip, mode); size_t pixelsSize = goldenBM.getSize(); - REPORTER_ASSERT( reporter, pixelsSize == deprecatedBM.getSize() ); - REPORTER_ASSERT( reporter, pixelsSize == newRecordingBM.getSize() ); + REPORTER_ASSERT(reporter, pixelsSize == pictureBM.getSize()); // The pixel arrays should match. #if FINEGRAIN - REPORTER_ASSERT_MESSAGE( reporter, - 0==memcmp( goldenBM.getPixels(), deprecatedBM.getPixels(), pixelsSize ), - "Tiled bitmap is wrong"); - REPORTER_ASSERT_MESSAGE( reporter, - 0==memcmp( goldenBM.getPixels(), recordingBM.getPixels(), pixelsSize ), - "SkRecorder bitmap is wrong"); + REPORTER_ASSERT(reporter, + 0 == memcmp(goldenBM.getPixels(), pictureBM.getPixels(), pixelsSize)); #else - if ( memcmp( goldenBM.getPixels(), deprecatedBM.getPixels(), pixelsSize ) ) { + if (memcmp(goldenBM.getPixels(), pictureBM.getPixels(), pixelsSize)) { numErrors++; - SkString str; - str.printf("For SkXfermode %d %s: Deprecated recorder bitmap is wrong\n", iMode, SkXfermode::ModeName(mode)); - errors.append(str); - } - if ( memcmp( goldenBM.getPixels(), newRecordingBM.getPixels(), pixelsSize ) ) { - numErrors++; - SkString str; - str.printf("For SkXfermode %d %s: SkPictureRecorder bitmap is wrong\n", iMode, SkXfermode::ModeName(mode)); - errors.append(str); + errors.appendf("For SkXfermode %d %s: SkPictureRecorder bitmap is wrong\n", + iMode, SkXfermode::ModeName(mode)); } #endif } + #if !FINEGRAIN - REPORTER_ASSERT_MESSAGE( reporter, 0==numErrors, errors.c_str() ); + REPORTER_ASSERT_MESSAGE(reporter, 0 == numErrors, errors.c_str()); #endif }