diff options
author | Mike Reed <reed@google.com> | 2009-08-13 15:45:50 -0400 |
---|---|---|
committer | Mike Reed <reed@google.com> | 2009-08-13 15:45:50 -0400 |
commit | 9a5843c9b6ef01f25513bef72a91936f75cc4458 (patch) | |
tree | 8107cbc8443f3026d338a4a473026db596a1fee8 | |
parent | d0fdbc18b77dc2602c83b046c7dff59fc05d88db (diff) | |
download | external_skia-9a5843c9b6ef01f25513bef72a91936f75cc4458.zip external_skia-9a5843c9b6ef01f25513bef72a91936f75cc4458.tar.gz external_skia-9a5843c9b6ef01f25513bef72a91936f75cc4458.tar.bz2 |
special case no scale in the matrixprocs for tiled bitmaps
yields ~10% overall speedup
also, refresh misc fixes in freetype and antipath from trunk
-rw-r--r-- | bench/Android.mk | 1 | ||||
-rw-r--r-- | bench/RepeatTileBench.cpp | 138 | ||||
-rw-r--r-- | include/core/SkMask.h | 1 | ||||
-rw-r--r-- | src/core/SkBitmapProcShader.cpp | 2 | ||||
-rw-r--r-- | src/core/SkBitmapProcState.cpp | 22 | ||||
-rw-r--r-- | src/core/SkBitmapProcState.h | 28 | ||||
-rw-r--r-- | src/core/SkBitmapProcState_matrixProcs.cpp | 367 | ||||
-rw-r--r-- | src/core/SkPath.cpp | 15 | ||||
-rw-r--r-- | src/core/SkPictureFlat.h | 2 | ||||
-rw-r--r-- | src/core/SkScan_AntiPath.cpp | 4 | ||||
-rw-r--r-- | src/ports/SkFontHost_FreeType.cpp | 16 |
11 files changed, 500 insertions, 96 deletions
diff --git a/bench/Android.mk b/bench/Android.mk index 117fb38..ba29622 100644 --- a/bench/Android.mk +++ b/bench/Android.mk @@ -5,6 +5,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ BitmapBench.cpp \ RectBench.cpp \ + RepeatTileBench.cpp \ TextBench.cpp \ SkBenchmark.cpp \ benchmain.cpp diff --git a/bench/RepeatTileBench.cpp b/bench/RepeatTileBench.cpp new file mode 100644 index 0000000..48c1f6f --- /dev/null +++ b/bench/RepeatTileBench.cpp @@ -0,0 +1,138 @@ +#include "SkBenchmark.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkPaint.h" +#include "SkShader.h" +#include "SkString.h" + +static const char* gConfigName[] = { + "ERROR", "a1", "a8", "index8", "565", "4444", "8888" +}; + +static void drawIntoBitmap(const SkBitmap& bm) { + const int w = bm.width(); + const int h = bm.height(); + + SkCanvas canvas(bm); + SkPaint p; + p.setAntiAlias(true); + p.setColor(SK_ColorRED); + canvas.drawCircle(SkIntToScalar(w)/2, SkIntToScalar(h)/2, + SkIntToScalar(SkMin32(w, h))*3/8, p); + + SkRect r; + r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h)); + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(SkIntToScalar(4)); + p.setColor(SK_ColorBLUE); + canvas.drawRect(r, p); +} + +static int conv6ToByte(int x) { + return x * 0xFF / 5; +} + +static int convByteTo6(int x) { + return x * 5 / 255; +} + +static uint8_t compute666Index(SkPMColor c) { + int r = SkGetPackedR32(c); + int g = SkGetPackedG32(c); + int b = SkGetPackedB32(c); + + return convByteTo6(r) * 36 + convByteTo6(g) * 6 + convByteTo6(b); +} + +static void convertToIndex666(const SkBitmap& src, SkBitmap* dst) { + SkColorTable* ctable = new SkColorTable(216); + SkPMColor* colors = ctable->lockColors(); + // rrr ggg bbb + for (int r = 0; r < 6; r++) { + int rr = conv6ToByte(r); + for (int g = 0; g < 6; g++) { + int gg = conv6ToByte(g); + for (int b = 0; b < 6; b++) { + int bb = conv6ToByte(b); + *colors++ = SkPreMultiplyARGB(0xFF, rr, gg, bb); + } + } + } + ctable->unlockColors(true); + dst->setConfig(SkBitmap::kIndex8_Config, src.width(), src.height()); + dst->allocPixels(ctable); + ctable->unref(); + + SkAutoLockPixels alps(src); + SkAutoLockPixels alpd(*dst); + + for (int y = 0; y < src.height(); y++) { + const SkPMColor* srcP = src.getAddr32(0, y); + uint8_t* dstP = dst->getAddr8(0, y); + for (int x = src.width() - 1; x >= 0; --x) { + *dstP++ = compute666Index(*srcP++); + } + } +} + +class RepeatTileBench : public SkBenchmark { + SkPaint fPaint; + SkString fName; + enum { N = 20 }; +public: + RepeatTileBench(SkBitmap::Config c) { + const int w = 50; + const int h = 50; + SkBitmap bm; + + if (SkBitmap::kIndex8_Config == c) { + bm.setConfig(SkBitmap::kARGB_8888_Config, w, h); + } else { + bm.setConfig(c, w, h); + } + bm.allocPixels(); + bm.eraseColor(0); + + drawIntoBitmap(bm); + + if (SkBitmap::kIndex8_Config == c) { + SkBitmap tmp; + convertToIndex666(bm, &tmp); + bm = tmp; + } + + SkShader* s = SkShader::CreateBitmapShader(bm, + SkShader::kRepeat_TileMode, + SkShader::kRepeat_TileMode); + fPaint.setShader(s)->unref(); + fName.printf("repeatTile_%s", gConfigName[bm.config()]); + } + +protected: + virtual const char* onGetName() { + return fName.c_str(); + } + + virtual void onDraw(SkCanvas* canvas) { + SkPaint paint(fPaint); + this->setupPaint(&paint); + + for (int i = 0; i < N; i++) { + canvas->drawPaint(paint); + } + } + +private: + typedef SkBenchmark INHERITED; +}; + +static SkBenchmark* Fact0(void*) { return new RepeatTileBench(SkBitmap::kARGB_8888_Config); } +static SkBenchmark* Fact1(void*) { return new RepeatTileBench(SkBitmap::kRGB_565_Config); } +static SkBenchmark* Fact2(void*) { return new RepeatTileBench(SkBitmap::kARGB_4444_Config); } +static SkBenchmark* Fact3(void*) { return new RepeatTileBench(SkBitmap::kIndex8_Config); } + +static BenchRegistry gReg0(Fact0); +static BenchRegistry gReg1(Fact1); +static BenchRegistry gReg2(Fact2); +static BenchRegistry gReg3(Fact3); diff --git a/include/core/SkMask.h b/include/core/SkMask.h index 6cbf37a..608010d 100644 --- a/include/core/SkMask.h +++ b/include/core/SkMask.h @@ -100,7 +100,6 @@ struct SkMask { */ const uint32_t* getAddrLCD(int x, int y) const { SkASSERT(fFormat == kHorizontalLCD_Format || fFormat == kVerticalLCD_Format); - SkASSERT(fBounds.contains(x, y)); SkASSERT(fImage != NULL); return reinterpret_cast<const uint32_t*>(fImage + SkAlign4(fRowBytes * fBounds.height())) + diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp index b396c68..44af0cc 100644 --- a/src/core/SkBitmapProcShader.cpp +++ b/src/core/SkBitmapProcShader.cpp @@ -140,7 +140,7 @@ void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { return; } - uint32_t buffer[BUF_MAX]; + uint32_t buffer[BUF_MAX + 1]; SkBitmapProcState::MatrixProc mproc = state.fMatrixProc; SkBitmapProcState::SampleProc32 sproc = state.fSampleProc32; int max = fState.fDoFilter ? (BUF_MAX >> 1) : BUF_MAX; diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp index 3c5833d..b999a0c 100644 --- a/src/core/SkBitmapProcState.cpp +++ b/src/core/SkBitmapProcState.cpp @@ -5,14 +5,6 @@ #include "SkPaint.h" #include "SkShader.h" // for tilemodes -#ifdef SK_CPU_BENDIAN - #define UNPACK_PRIMARY_SHORT(packed) ((uint32_t)(packed) >> 16) - #define UNPACK_SECONDARY_SHORT(packed) ((packed) & 0xFFFF) -#else - #define UNPACK_PRIMARY_SHORT(packed) ((packed) & 0xFFFF) - #define UNPACK_SECONDARY_SHORT(packed) ((uint32_t)(packed) >> 16) -#endif - // returns expanded * 5bits static inline uint32_t Filter_565_Expanded(unsigned x, unsigned y, uint32_t a00, uint32_t a01, @@ -334,20 +326,20 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { if (fOrigBitmap.width() == 0 || fOrigBitmap.height() == 0) { return false; } + const SkMatrix* m; - bool clamp_clamp; + bool trivial_matrix = (inv.getType() & ~SkMatrix::kTranslate_Mask) == 0; + bool clamp_clamp = SkShader::kClamp_TileMode == fTileModeX && + SkShader::kClamp_TileMode == fTileModeY; - if (SkShader::kClamp_TileMode == fTileModeX && - SkShader::kClamp_TileMode == fTileModeY) { + if (clamp_clamp || trivial_matrix) { m = &inv; - clamp_clamp = true; } else { fUnitInvMatrix = inv; fUnitInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height()); m = &fUnitInvMatrix; - clamp_clamp = false; } - + fBitmap = &fOrigBitmap; if (fOrigBitmap.hasMipMap()) { int shift = fOrigBitmap.extractMipLevel(&fMipBitmap, @@ -390,7 +382,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { fSampleProc32 = NULL; fSampleProc16 = NULL; - fMatrixProc = this->chooseMatrixProc(); + fMatrixProc = this->chooseMatrixProc(trivial_matrix); if (NULL == fMatrixProc) { return false; } diff --git a/src/core/SkBitmapProcState.h b/src/core/SkBitmapProcState.h index 7962579..2790a6c 100644 --- a/src/core/SkBitmapProcState.h +++ b/src/core/SkBitmapProcState.h @@ -46,6 +46,7 @@ struct SkBitmapProcState { uint16_t colors[]); typedef U16CPU (*FixedTileProc)(SkFixed); // returns 0..0xFFFF + typedef U16CPU (*IntTileProc)(int value, int count); // returns 0..count-1 // If a shader proc is present, then the corresponding matrix/sample procs // are ignored @@ -62,6 +63,7 @@ struct SkBitmapProcState { FixedTileProc fTileProcX; // chooseProcs FixedTileProc fTileProcY; // chooseProcs + IntTileProc fIntTileProcY; // chooseProcs SkFixed fFilterOneX; SkFixed fFilterOneY; @@ -96,8 +98,32 @@ private: SkBitmap fOrigBitmap; // CONSTRUCTOR SkBitmap fMipBitmap; - MatrixProc chooseMatrixProc(); + MatrixProc chooseMatrixProc(bool trivial_matrix); bool chooseProcs(const SkMatrix& inv, const SkPaint&); }; +/* Macros for packing and unpacking pairs of 16bit values in a 32bit uint. + Used to allow access to a stream of uint16_t either one at a time, or + 2 at a time by unpacking a uint32_t + */ +#ifdef SK_CPU_BENDIAN + #define PACK_TWO_SHORTS(pri, sec) ((pri) << 16 | (sec)) + #define UNPACK_PRIMARY_SHORT(packed) ((uint32_t)(packed) >> 16) + #define UNPACK_SECONDARY_SHORT(packed) ((packed) & 0xFFFF) +#else + #define PACK_TWO_SHORTS(pri, sec) ((pri) | ((sec) << 16)) + #define UNPACK_PRIMARY_SHORT(packed) ((packed) & 0xFFFF) + #define UNPACK_SECONDARY_SHORT(packed) ((uint32_t)(packed) >> 16) +#endif + +#ifdef SK_DEBUG + static inline uint32_t pack_two_shorts(U16CPU pri, U16CPU sec) { + SkASSERT((uint16_t)pri == pri); + SkASSERT((uint16_t)sec == sec); + return PACK_TWO_SHORTS(pri, sec); + } +#else + #define pack_two_shorts(pri, sec) PACK_TWO_SHORTS(pri, sec) +#endif + #endif diff --git a/src/core/SkBitmapProcState_matrixProcs.cpp b/src/core/SkBitmapProcState_matrixProcs.cpp index beb21c8..cf32d9b 100644 --- a/src/core/SkBitmapProcState_matrixProcs.cpp +++ b/src/core/SkBitmapProcState_matrixProcs.cpp @@ -1,27 +1,30 @@ #include "SkBitmapProcState.h" #include "SkPerspIter.h" #include "SkShader.h" +#include "SkUtils.h" + +/* returns 0...(n-1) given any x (positive or negative). + + As an example, if n (which is always positive) is 5... + + x: -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 + returns: 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 + */ +static inline int sk_int_mod(int x, int n) { + SkASSERT(n > 0); + if ((unsigned)x >= (unsigned)n) { + if (x < 0) { + x = n + ~(~x % n); + } else { + x = x % n; + } + } + return x; +} void decal_nofilter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count); void decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count); -#ifdef SK_CPU_BENDIAN - #define PACK_TWO_SHORTS(pri, sec) ((pri) << 16 | (sec)) -#else - #define PACK_TWO_SHORTS(pri, sec) ((pri) | ((sec) << 16)) -#endif - -#ifdef SK_DEBUG - static uint32_t pack_two_shorts(U16CPU pri, U16CPU sec) - { - SkASSERT((uint16_t)pri == pri); - SkASSERT((uint16_t)sec == sec); - return PACK_TWO_SHORTS(pri, sec); - } -#else - #define pack_two_shorts(pri, sec) PACK_TWO_SHORTS(pri, sec) -#endif - #define MAKENAME(suffix) ClampX_ClampY ## suffix #define TILEX_PROCF(fx, max) SkClampMax((fx) >> 16, max) #define TILEY_PROCF(fy, max) SkClampMax((fy) >> 16, max) @@ -91,39 +94,51 @@ static SkBitmapProcState::FixedTileProc choose_tile_proc(unsigned m) return fixed_mirror; } -SkBitmapProcState::MatrixProc SkBitmapProcState::chooseMatrixProc() -{ - int index = 0; - if (fDoFilter) - index = 1; - if (fInvType & SkMatrix::kPerspective_Mask) - index |= 4; - else if (fInvType & SkMatrix::kAffine_Mask) - index |= 2; +static inline U16CPU int_clamp(int x, int n) { +#ifdef SK_CPU_HAS_CONDITIONAL_INSTR + if (x >= n) + x = n - 1; + if (x < 0) + x = 0; +#else + if ((unsigned)x >= (unsigned)n) { + if (x < 0) { + x = 0; + } else { + x = n - 1; + } + } +#endif + return x; +} - if (SkShader::kClamp_TileMode == fTileModeX && - SkShader::kClamp_TileMode == fTileModeY) - { - // clamp gets special version of filterOne - fFilterOneX = SK_Fixed1; - fFilterOneY = SK_Fixed1; - return ClampX_ClampY_Procs[index]; +static inline U16CPU int_repeat(int x, int n) { + return sk_int_mod(x, n); +} + +static inline U16CPU int_mirror(int x, int n) { + x = sk_int_mod(x, 2 * n); + if (x >= n) { + x = n + ~(x - n); } - - // all remaining procs use this form for filterOne - fFilterOneX = SK_Fixed1 / fBitmap->width(); - fFilterOneY = SK_Fixed1 / fBitmap->height(); + return x; +} - if (SkShader::kRepeat_TileMode == fTileModeX && - SkShader::kRepeat_TileMode == fTileModeY) - { - return RepeatX_RepeatY_Procs[index]; +#if 0 +static void test_int_tileprocs() { + for (int i = -8; i <= 8; i++) { + SkDebugf(" int_mirror(%2d, 3) = %d\n", i, int_mirror(i, 3)); } +} +#endif - // only general needs these procs - fTileProcX = choose_tile_proc(fTileModeX); - fTileProcY = choose_tile_proc(fTileModeY); - return GeneralXY_Procs[index]; +static SkBitmapProcState::IntTileProc choose_int_tile_proc(unsigned tm) { + if (SkShader::kClamp_TileMode == tm) + return int_clamp; + if (SkShader::kRepeat_TileMode == tm) + return int_repeat; + SkASSERT(SkShader::kMirror_TileMode == tm); + return int_mirror; } ////////////////////////////////////////////////////////////////////////////// @@ -166,34 +181,248 @@ void decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count) } } -/////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// stores the same as SCALE, but is cheaper to compute. Also since there is no +// scale, we don't need/have a FILTER version -void repeat_nofilter_identity(uint32_t dst[], int x, int width, int count) -{ - if (x >= width) - x %= width; +static void fill_sequential(uint16_t xptr[], int start, int count) { +#if 1 + if (reinterpret_cast<intptr_t>(xptr) & 0x2) { + *xptr++ = start++; + count -= 1; + } + if (count > 3) { + uint32_t* xxptr = reinterpret_cast<uint32_t*>(xptr); + uint32_t pattern0 = PACK_TWO_SHORTS(start + 0, start + 1); + uint32_t pattern1 = PACK_TWO_SHORTS(start + 2, start + 3); + start += count & ~3; + int qcount = count >> 2; + do { + *xxptr++ = pattern0; + pattern0 += 0x40004; + *xxptr++ = pattern1; + pattern1 += 0x40004; + } while (--qcount >= 0); + xptr = reinterpret_cast<uint16_t*>(xxptr); + count &= 3; + } + while (--count >= 0) { + *xptr++ = start++; + } +#else + for (int i = 0; i < count; i++) { + *xptr++ = start++; + } +#endif +} - int i; - uint16_t* xx = (uint16_t*)dst; +static int nofilter_trans_preamble(const SkBitmapProcState& s, uint32_t** xy, + int x, int y) { + SkPoint pt; + s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf, + SkIntToScalar(y) + SK_ScalarHalf, &pt); + **xy = s.fIntTileProcY(SkScalarToFixed(pt.fY) >> 16, + s.fBitmap->height()); + *xy += 1; // bump the ptr + // return our starting X position + return SkScalarToFixed(pt.fX) >> 16; +} - // do the first partial run - int n = width - x; - if (n > count) - n = count; +static void clampx_nofilter_trans(const SkBitmapProcState& s, + uint32_t xy[], int count, int x, int y) { + SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0); + + int xpos = nofilter_trans_preamble(s, &xy, x, y); + const int width = s.fBitmap->width(); + if (1 == width) { + // all of the following X values must be 0 + memset(xy, 0, count * sizeof(uint16_t)); + return; + } + uint16_t* xptr = reinterpret_cast<uint16_t*>(xy); + int n; + + // fill before 0 as needed + if (xpos < 0) { + n = -xpos; + if (n > count) { + n = count; + } + memset(xptr, 0, n * sizeof(uint16_t)); + count -= n; + if (0 == count) { + return; + } + xptr += n; + xpos = 0; + } + + // fill in 0..width-1 if needed + if (xpos < width) { + n = width - xpos; + if (n > count) { + n = count; + } + fill_sequential(xptr, xpos, n); + count -= n; + if (0 == count) { + return; + } + xptr += n; + } + + // fill the remaining with the max value + sk_memset16(xptr, width - 1, count * sizeof(uint16_t)); +} + +static void repeatx_nofilter_trans(const SkBitmapProcState& s, + uint32_t xy[], int count, int x, int y) { + SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0); + + int xpos = nofilter_trans_preamble(s, &xy, x, y); + const int width = s.fBitmap->width(); + if (1 == width) { + // all of the following X values must be 0 + memset(xy, 0, count * sizeof(uint16_t)); + return; + } + + uint16_t* xptr = reinterpret_cast<uint16_t*>(xy); + int start = sk_int_mod(xpos, width); + int n = width - start; + if (n > count) { + n = count; + } + fill_sequential(xptr, start, n); + xptr += n; + count -= n; + + while (count >= width) { + fill_sequential(xptr, 0, width); + xptr += width; + count -= width; + } + + if (count > 0) { + fill_sequential(xptr, 0, count); + } +} + +static void fill_backwards(uint16_t xptr[], int pos, int count) { + for (int i = 0; i < count; i++) { + SkASSERT(pos >= 0); + xptr[i] = pos--; + } +} + +static void mirrorx_nofilter_trans(const SkBitmapProcState& s, + uint32_t xy[], int count, int x, int y) { + SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0); + + int xpos = nofilter_trans_preamble(s, &xy, x, y); + const int width = s.fBitmap->width(); + if (1 == width) { + // all of the following X values must be 0 + memset(xy, 0, count * sizeof(uint16_t)); + return; + } + + uint16_t* xptr = reinterpret_cast<uint16_t*>(xy); + // need to know our start, and our initial phase (forward or backward) + bool forward; + int n; + int start = sk_int_mod(xpos, 2 * width); + if (start >= width) { + start = width + ~(start - width); + forward = false; + n = start + 1; // [start .. 0] + } else { + forward = true; + n = width - start; // [start .. width) + } + if (n > count) { + n = count; + } + if (forward) { + fill_sequential(xptr, start, n); + } else { + fill_backwards(xptr, start, n); + } + forward = !forward; + xptr += n; count -= n; - n += x; - for (i = x; i < n; i++) - *xx++ = SkToU16(i); - - // do all the full-width runs - while ((count -= width) >= 0) - for (i = 0; i < width; i++) - *xx++ = SkToU16(i); - - // final cleanup run - count += width; - for (i = 0; i < count; i++) - *xx++ = SkToU16(i); + + while (count >= width) { + if (forward) { + fill_sequential(xptr, 0, width); + } else { + fill_backwards(xptr, width - 1, width); + } + forward = !forward; + xptr += width; + count -= width; + } + + if (count > 0) { + if (forward) { + fill_sequential(xptr, 0, count); + } else { + fill_backwards(xptr, width - 1, count); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +SkBitmapProcState::MatrixProc +SkBitmapProcState::chooseMatrixProc(bool trivial_matrix) { +// test_int_tileprocs(); + // check for our special case when there is no scale/affine/perspective + if (trivial_matrix) { + SkASSERT(!fDoFilter); + fIntTileProcY = choose_int_tile_proc(fTileModeY); + switch (fTileModeX) { + case SkShader::kClamp_TileMode: + return clampx_nofilter_trans; + case SkShader::kRepeat_TileMode: + return repeatx_nofilter_trans; + case SkShader::kMirror_TileMode: + return mirrorx_nofilter_trans; + } + } + + int index = 0; + if (fDoFilter) { + index = 1; + } + if (fInvType & SkMatrix::kPerspective_Mask) { + index += 4; + } else if (fInvType & SkMatrix::kAffine_Mask) { + index += 4; + } + + if (SkShader::kClamp_TileMode == fTileModeX && + SkShader::kClamp_TileMode == fTileModeY) + { + // clamp gets special version of filterOne + fFilterOneX = SK_Fixed1; + fFilterOneY = SK_Fixed1; + return ClampX_ClampY_Procs[index]; + } + + // all remaining procs use this form for filterOne + fFilterOneX = SK_Fixed1 / fBitmap->width(); + fFilterOneY = SK_Fixed1 / fBitmap->height(); + + if (SkShader::kRepeat_TileMode == fTileModeX && + SkShader::kRepeat_TileMode == fTileModeY) + { + return RepeatX_RepeatY_Procs[index]; + } + + fTileProcX = choose_tile_proc(fTileModeX); + fTileProcY = choose_tile_proc(fTileModeY); + return GeneralXY_Procs[index]; } diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp index 794681c..63c3eb0 100644 --- a/src/core/SkPath.cpp +++ b/src/core/SkPath.cpp @@ -1233,11 +1233,16 @@ void SkPath::validate() const { if (!fBoundsIsDirty) { SkRect bounds; compute_pt_bounds(&bounds, fPts); - // can't call contains(), since it returns false if the rect is empty - SkASSERT(fBounds.fLeft <= bounds.fLeft); - SkASSERT(fBounds.fTop <= bounds.fTop); - SkASSERT(fBounds.fRight >= bounds.fRight); - SkASSERT(fBounds.fBottom >= bounds.fBottom); + if (fPts.count() <= 1) { + // if we're empty, fBounds may be empty but translated, so we can't + // necessarily compare to bounds directly + // try path.addOval(2, 2, 2, 2) which is empty, but the bounds will + // be [2, 2, 2, 2] + SkASSERT(bounds.isEmpty()); + SkASSERT(fBounds.isEmpty()); + } else { + fBounds.contains(bounds); + } } } diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h index a4856a2..86a161d 100644 --- a/src/core/SkPictureFlat.h +++ b/src/core/SkPictureFlat.h @@ -71,8 +71,6 @@ protected: class SkTypefacePlayback : public SkRefCntPlayback { public: - virtual ~SkTypefacePlayback() {} - virtual void setupBuffer(SkFlattenableReadBuffer& buffer) const { buffer.setTypefaceArray((SkTypeface**)fArray, fCount); } diff --git a/src/core/SkScan_AntiPath.cpp b/src/core/SkScan_AntiPath.cpp index f2f117a..922c0ab 100644 --- a/src/core/SkScan_AntiPath.cpp +++ b/src/core/SkScan_AntiPath.cpp @@ -319,11 +319,15 @@ void MaskSuperBlitter::blitH(int x, int y, int width) if (n < 0) { + SkASSERT(row >= fMask.fImage); + SkASSERT(row < fMask.fImage + kMAX_STORAGE + 1); add_aa_span(row, coverage_to_alpha(fe - fb)); } else { fb = (1 << SHIFT) - fb; + SkASSERT(row >= fMask.fImage); + SkASSERT(row + n + 1 < fMask.fImage + kMAX_STORAGE + 1); add_aa_span(row, coverage_to_alpha(fb), n, coverage_to_alpha(fe), (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT)); } diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp index 77f4b23..c7e310e 100644 --- a/src/ports/SkFontHost_FreeType.cpp +++ b/src/ports/SkFontHost_FreeType.cpp @@ -376,6 +376,13 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc) break; } + if (fRec.fMaskFormat != SkMask::kBW_Format) { + // If the user requested anti-aliasing then we don't use bitmap + // strikes in the font. The consensus among our Japanese users is + // that this results in the best quality. + loadFlags |= FT_LOAD_NO_BITMAP; + } + fLoadGlyphFlags = loadFlags; } @@ -686,7 +693,9 @@ void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) { const uint8_t* src = (const uint8_t*)fFace->glyph->bitmap.buffer; uint8_t* dst = (uint8_t*)glyph.fImage; - if (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) { + if (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY || + (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO && + glyph.fMaskFormat == SkMask::kBW_Format)) { unsigned srcRowBytes = fFace->glyph->bitmap.pitch; unsigned dstRowBytes = glyph.rowBytes(); unsigned minRowBytes = SkMin32(srcRowBytes, dstRowBytes); @@ -698,7 +707,8 @@ void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) { src += srcRowBytes; dst += dstRowBytes; } - } else if (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { + } else if (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO && + glyph.fMaskFormat == SkMask::kA8_Format) { for (int y = 0; y < fFace->glyph->bitmap.rows; ++y) { uint8_t byte = 0; int bits = 0; @@ -719,6 +729,8 @@ void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) { src += fFace->glyph->bitmap.pitch; dst += glyph.rowBytes(); } + } else { + SkASSERT(!"unknown glyph bitmap transform needed"); } if (lcdRenderMode) |