From 42cb6c0247894b631976fd361d46be9260b27c3b Mon Sep 17 00:00:00 2001 From: "reed@google.com" Date: Tue, 27 Aug 2013 17:53:52 +0000 Subject: [PATCH] add SkDeviceLooper to handle larger-than-fixedpoint BUG= Review URL: https://codereview.chromium.org/23392006 git-svn-id: http://skia.googlecode.com/svn/trunk@10943 2bbb7eff-a529-9590-31e7-b0007b416f81 --- gyp/core.gypi | 1 + src/core/SkDeviceLooper.cpp | 97 +++++++++++++++++++++++++++++++++++++++++++++ src/core/SkDeviceLooper.h | 69 ++++++++++++++++++++++++++++++++ src/core/SkDraw.cpp | 91 +++++++++++++++++++++++------------------- tests/DrawPathTest.cpp | 5 +-- 5 files changed, 218 insertions(+), 45 deletions(-) create mode 100644 src/core/SkDeviceLooper.cpp create mode 100644 src/core/SkDeviceLooper.h diff --git a/gyp/core.gypi b/gyp/core.gypi index e4631af..dbc3291 100644 --- a/gyp/core.gypi +++ b/gyp/core.gypi @@ -70,6 +70,7 @@ '<(skia_src_path)/core/SkDebug.cpp', '<(skia_src_path)/core/SkDeque.cpp', '<(skia_src_path)/core/SkDevice.cpp', + '<(skia_src_path)/core/SkDeviceLooper.cpp', '<(skia_src_path)/core/SkDeviceProfile.cpp', '<(skia_src_path)/core/SkDither.cpp', '<(skia_src_path)/core/SkDraw.cpp', diff --git a/src/core/SkDeviceLooper.cpp b/src/core/SkDeviceLooper.cpp new file mode 100644 index 0000000..7870239 --- /dev/null +++ b/src/core/SkDeviceLooper.cpp @@ -0,0 +1,97 @@ +/* + * 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 "SkDeviceLooper.h" + +SkDeviceLooper::SkDeviceLooper(const SkBitmap& base, + const SkRasterClip& rc, + const SkIRect& bounds, bool aa) +: fBaseBitmap(base) +, fBaseRC(rc) +, fDelta(aa ? kAA_Delta : kBW_Delta) +{ + SkIRect bitmapBounds = SkIRect::MakeWH(base.width(), base.height()); + if (!fClippedBounds.intersect(bounds, bitmapBounds)) { + fState = kDone_State; + } else if (this->fitsInDelta(bounds)) { + fCurrBitmap = &fBaseBitmap; + fCurrRC = &fBaseRC; + fState = kSimple_State; + } else { + fCurrBitmap = &fSubsetBitmap; + fCurrRC = &fSubsetRC; + // back up by 1 DX, so that next() will put us in a correct starting + // position. + fCurrOffset.set(fClippedBounds.left() - fDelta, + fClippedBounds.top()); + fState = kComplex_State; + } +} + +SkDeviceLooper::~SkDeviceLooper() { +} + +void SkDeviceLooper::mapRect(SkRect* dst, const SkRect& src) const { + SkASSERT(kDone_State != fState); + *dst = src; + dst->offset(SkIntToScalar(-fCurrOffset.fX), + SkIntToScalar(-fCurrOffset.fY)); +} + +void SkDeviceLooper::mapMatrix(SkMatrix* dst, const SkMatrix& src) const { + SkASSERT(kDone_State != fState); + *dst = src; + dst->postTranslate(SkIntToScalar(-fCurrOffset.fX), + SkIntToScalar(-fCurrOffset.fY)); +} + +bool SkDeviceLooper::computeCurrBitmapAndClip() { + SkASSERT(kComplex_State == fState); + + SkIRect r = SkIRect::MakeXYWH(fCurrOffset.x(), fCurrOffset.y(), + fDelta, fDelta); + if (!fBaseBitmap.extractSubset(&fSubsetBitmap, r)) { + fState = kDone_State; + return false; + } + fSubsetBitmap.lockPixels(); + + fBaseRC.translate(-r.left(), -r.top(), &fSubsetRC); + (void)fSubsetRC.op(SkIRect::MakeWH(fDelta, fDelta), SkRegion::kIntersect_Op); + return true; +} + +bool SkDeviceLooper::next() { + if (kDone_State == fState) { + return false; + } + + if (kSimple_State == fState) { + fCurrBitmap = &fBaseBitmap; + fCurrRC = &fBaseRC; + fCurrOffset.set(0, 0); + fState = kDone_State; + return true; + } + + SkASSERT(kComplex_State == fState); + + // need to propogate fCurrOffset through clippedbounds + // left to right, until we wrap around and move down + + if (fCurrOffset.x() + fDelta < fClippedBounds.right()) { + fCurrOffset.fX += fDelta; + return this->computeCurrBitmapAndClip(); + } + fCurrOffset.fX = fClippedBounds.left(); + if (fCurrOffset.y() + fDelta < fClippedBounds.bottom()) { + fCurrOffset.fY += fDelta; + return this->computeCurrBitmapAndClip(); + } + fState = kDone_State; + return false; +} diff --git a/src/core/SkDeviceLooper.h b/src/core/SkDeviceLooper.h new file mode 100644 index 0000000..fae03be --- /dev/null +++ b/src/core/SkDeviceLooper.h @@ -0,0 +1,69 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkDeviceLooper_DEFINED +#define SkDeviceLooper_DEFINED + +#include "SkBitmap.h" +#include "SkMatrix.h" +#include "SkRasterClip.h" + +class SkDeviceLooper { +public: + SkDeviceLooper(const SkBitmap& base, const SkRasterClip&, + const SkIRect& bounds, bool aa); + ~SkDeviceLooper(); + + const SkBitmap& getBitmap() const { + SkASSERT(kDone_State != fState); + return *fCurrBitmap; + } + + const SkRasterClip& getRC() const { + SkASSERT(kDone_State != fState); + return *fCurrRC; + } + + void mapRect(SkRect* dst, const SkRect& src) const; + void mapMatrix(SkMatrix* dst, const SkMatrix& src) const; + + bool next(); + +private: + const SkBitmap& fBaseBitmap; + const SkRasterClip& fBaseRC; + + enum State { + kDone_State, // iteration is complete, getters will assert + kSimple_State, // no translate/clip mods needed + kComplex_State + }; + + // storage for our tiled versions. Perhaps could use SkTLazy + SkBitmap fSubsetBitmap; + SkRasterClip fSubsetRC; + + const SkBitmap* fCurrBitmap; + const SkRasterClip* fCurrRC; + SkIRect fClippedBounds; + SkIPoint fCurrOffset; + int fDelta; + State fState; + + enum Delta { + kBW_Delta = 1 << 14, // 16K, gives room to spare for fixedpoint + kAA_Delta = kBW_Delta >> 2 // supersample 4x + }; + + bool fitsInDelta(const SkIRect& r) const { + return r.right() < fDelta && r.bottom() < fDelta; + } + + bool computeCurrBitmapAndClip(); +}; + +#endif diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index 671da49..a9d5fbb 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -5,13 +5,13 @@ * found in the LICENSE file. */ - #include "SkDraw.h" #include "SkBlitter.h" #include "SkBounder.h" #include "SkCanvas.h" #include "SkColorPriv.h" #include "SkDevice.h" +#include "SkDeviceLooper.h" #include "SkFixed.h" #include "SkMaskFilter.h" #include "SkPaint.h" @@ -873,48 +873,56 @@ void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const { } // look for the quick exit, before we build a blitter - if (true) { - SkIRect ir; - devRect.roundOut(&ir); - if (paint.getStyle() != SkPaint::kFill_Style) { - // extra space for hairlines - ir.inset(-1, -1); - } - if (fRC->quickReject(ir)) - return; + SkIRect ir; + devRect.roundOut(&ir); + if (paint.getStyle() != SkPaint::kFill_Style) { + // extra space for hairlines + ir.inset(-1, -1); + } + if (fRC->quickReject(ir)) { + return; } - SkAutoBlitterChoose blitterStorage(*fBitmap, matrix, paint); - const SkRasterClip& clip = *fRC; - SkBlitter* blitter = blitterStorage.get(); - - // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter - // case we are also hairline (if we've gotten to here), which devolves to - // effectively just kFill - switch (rtype) { - case kFill_RectType: - if (paint.isAntiAlias()) { - SkScan::AntiFillRect(devRect, clip, blitter); - } else { - SkScan::FillRect(devRect, clip, blitter); - } - break; - case kStroke_RectType: - if (paint.isAntiAlias()) { - SkScan::AntiFrameRect(devRect, strokeSize, clip, blitter); - } else { - SkScan::FrameRect(devRect, strokeSize, clip, blitter); - } - break; - case kHair_RectType: - if (paint.isAntiAlias()) { - SkScan::AntiHairRect(devRect, clip, blitter); - } else { - SkScan::HairRect(devRect, clip, blitter); - } - break; - default: - SkDEBUGFAIL("bad rtype"); + SkDeviceLooper looper(*fBitmap, *fRC, ir, paint.isAntiAlias()); + while (looper.next()) { + SkRect localDevRect; + looper.mapRect(&localDevRect, devRect); + SkMatrix localMatrix; + looper.mapMatrix(&localMatrix, matrix); + + SkAutoBlitterChoose blitterStorage(looper.getBitmap(), localMatrix, + paint); + const SkRasterClip& clip = looper.getRC(); + SkBlitter* blitter = blitterStorage.get(); + + // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter + // case we are also hairline (if we've gotten to here), which devolves to + // effectively just kFill + switch (rtype) { + case kFill_RectType: + if (paint.isAntiAlias()) { + SkScan::AntiFillRect(localDevRect, clip, blitter); + } else { + SkScan::FillRect(localDevRect, clip, blitter); + } + break; + case kStroke_RectType: + if (paint.isAntiAlias()) { + SkScan::AntiFrameRect(localDevRect, strokeSize, clip, blitter); + } else { + SkScan::FrameRect(localDevRect, strokeSize, clip, blitter); + } + break; + case kHair_RectType: + if (paint.isAntiAlias()) { + SkScan::AntiHairRect(localDevRect, clip, blitter); + } else { + SkScan::HairRect(localDevRect, clip, blitter); + } + break; + default: + SkDEBUGFAIL("bad rtype"); + } } } @@ -2825,3 +2833,4 @@ bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds, return true; } + diff --git a/tests/DrawPathTest.cpp b/tests/DrawPathTest.cpp index f47b8c3..9f440f6 100644 --- a/tests/DrawPathTest.cpp +++ b/tests/DrawPathTest.cpp @@ -320,10 +320,7 @@ static void TestDrawPath(skiatest::Reporter* reporter) { if (false) test_crbug131181(); test_infinite_dash(reporter); test_crbug_165432(reporter); - - if (false) { // working on a fix - test_big_aa_rect(reporter); - } + test_big_aa_rect(reporter); } #include "TestClassDef.h" -- 2.7.4