diff options
Diffstat (limited to 'skia/sgl')
78 files changed, 1169 insertions, 771 deletions
diff --git a/skia/sgl/SkAlphaRuns.cpp b/skia/sgl/SkAlphaRuns.cpp index 35fcfd6..46b0206 100644 --- a/skia/sgl/SkAlphaRuns.cpp +++ b/skia/sgl/SkAlphaRuns.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkAlphaRuns.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkAntiRun.h b/skia/sgl/SkAntiRun.h index 32814f1..12930e66 100644 --- a/skia/sgl/SkAntiRun.h +++ b/skia/sgl/SkAntiRun.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkAntiRun.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkAutoKern.h b/skia/sgl/SkAutoKern.h index 644ad85..023cb6b 100644 --- a/skia/sgl/SkAutoKern.h +++ b/skia/sgl/SkAutoKern.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkAutoKern.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkBitmap.cpp b/skia/sgl/SkBitmap.cpp index 914fc77..5ca3601 100644 --- a/skia/sgl/SkBitmap.cpp +++ b/skia/sgl/SkBitmap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2008 Google Inc. + * Copyright (C) 2006-2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ #include "SkColorPriv.h" #include "SkDither.h" #include "SkFlattenable.h" +#include "SkMallocPixelRef.h" #include "SkMask.h" #include "SkPixelRef.h" #include "SkThread.h" @@ -33,8 +34,8 @@ struct MipLevel { }; struct SkBitmap::MipMap : SkNoncopyable { - int fRefCnt; - int fLevelCount; + int32_t fRefCnt; + int fLevelCount; // MipLevel fLevel[fLevelCount]; // Pixels[] @@ -203,6 +204,20 @@ int SkBitmap::ComputeRowBytes(Config c, int width) { return rowBytes; } +Sk64 SkBitmap::ComputeSize64(Config c, int width, int height) { + Sk64 size; + size.setMul(SkBitmap::ComputeRowBytes(c, width), height); + return size; +} + +size_t SkBitmap::ComputeSize(Config c, int width, int height) { + Sk64 size = SkBitmap::ComputeSize64(c, width, height); + if (size.isNeg() || !size.is32()) { + return 0; + } + return size.get32(); +} + void SkBitmap::setConfig(Config c, int width, int height, int rowBytes) { this->freePixels(); @@ -334,40 +349,6 @@ void SkBitmap::notifyPixelsChanged() const { /////////////////////////////////////////////////////////////////////////////// -/** We explicitly use the same allocator for our pixels that SkMask does, - so that we can freely assign memory allocated by one class to the other. - */ -class SkMallocPixelRef : public SkPixelRef { -public: - /** Allocate the specified buffer for pixels. The memory is freed when the - last owner of this pixelref is gone. - */ - SkMallocPixelRef(void* addr, size_t size, SkColorTable* ctable); - virtual ~SkMallocPixelRef(); - - virtual void flatten(SkFlattenableWriteBuffer&) const; - virtual Factory getFactory() const { - return Create; - } - static SkPixelRef* Create(SkFlattenableReadBuffer& buffer) { - return SkNEW_ARGS(SkMallocPixelRef, (buffer)); - } - -protected: - // overrides from SkPixelRef - virtual void* onLockPixels(SkColorTable**); - virtual void onUnlockPixels(); - - SkMallocPixelRef(SkFlattenableReadBuffer& buffer); - -private: - void* fStorage; - size_t fSize; - SkColorTable* fCTable; - - typedef SkPixelRef INHERITED; -}; - SkMallocPixelRef::SkMallocPixelRef(void* storage, size_t size, SkColorTable* ctable) { SkASSERT(storage); @@ -416,7 +397,7 @@ SkMallocPixelRef::SkMallocPixelRef(SkFlattenableReadBuffer& buffer) : INHERITED( } static SkPixelRef::Registrar reg("SkMallocPixelRef", - SkMallocPixelRef::Create); + SkMallocPixelRef::Create); /** We explicitly use the same allocator for our pixels that SkMask does, so that we can freely assign memory allocated by one class to the other. @@ -534,7 +515,7 @@ void SkBitmap::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const { SkAutoLockPixels alp(*this); // perform this check after the lock call - if (NULL == fPixels) { + if (!this->readyToDraw()) { return; } @@ -648,6 +629,8 @@ bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const { if (kRLE_Index8_Config == fConfig) { SkAutoLockPixels alp(*this); + // don't call readyToDraw(), since we can operate w/o a colortable + // at this stage if (this->getPixels() == NULL) { return false; } @@ -725,7 +708,7 @@ bool SkBitmap::copyTo(SkBitmap* dst, Config dstConfig, Allocator* alloc) const { SkAutoLockPixels srclock(*this); SkAutoLockPixels dstlock(tmp); - if (NULL == this->getPixels() || NULL == tmp.getPixels()) { + if (!this->readyToDraw() || !tmp.readyToDraw()) { // allocator/lock failed return false; } @@ -1257,6 +1240,7 @@ void SkBitmap::validate() const { SkASSERT(NULL == fColorTable || (unsigned)fColorTable->getRefCnt() < 10000); SkASSERT((uint8_t)ComputeBytesPerPixel((Config)fConfig) == fBytesPerPixel); +#if 0 // these asserts are not thread-correct, so disable for now if (fPixelRef) { if (fPixelLockCount > 0) { SkASSERT(fPixelRef->getLockCount() > 0); @@ -1265,6 +1249,7 @@ void SkBitmap::validate() const { SkASSERT(NULL == fColorTable); } } +#endif } #endif diff --git a/skia/sgl/SkBitmapProcShader.h b/skia/sgl/SkBitmapProcShader.h index 6d7d0d9..ed790c8 100644 --- a/skia/sgl/SkBitmapProcShader.h +++ b/skia/sgl/SkBitmapProcShader.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkBitmapShader.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkBitmapProcState.cpp b/skia/sgl/SkBitmapProcState.cpp index aff7e9d..428921d 100644 --- a/skia/sgl/SkBitmapProcState.cpp +++ b/skia/sgl/SkBitmapProcState.cpp @@ -296,9 +296,8 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { } const SkMatrix* m; - if (inv.getType() <= SkMatrix::kTranslate_Mask || - (SkShader::kClamp_TileMode == fTileModeX && - SkShader::kClamp_TileMode == fTileModeY)) { + if (SkShader::kClamp_TileMode == fTileModeX && + SkShader::kClamp_TileMode == fTileModeY) { m = &inv; } else { fUnitInvMatrix = inv; @@ -331,16 +330,6 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { fInvMatrix = m; fInvProc = m->getMapXYProc(); fInvType = m->getType(); - if (fInvType <= SkMatrix::kTranslate_Mask && - inv.getType() > SkMatrix::kTranslate_Mask) { - SkASSERT(inv.getType() <= - (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)); - // It is possible that by the calculation of fUnitInvMatrix, we have - // eliminated the scale transformation of the matrix (e.g., if inv^(-1) - // scales fOrigBitmap into an 1X1 rect). We add the scale flag back so - // that we don't make wrong choice in chooseMatrixProc(). - fInvType |= SkMatrix::kScale_Mask; - } fInvSx = SkScalarToFixed(m->getScaleX()); fInvSy = SkScalarToFixed(m->getScaleY()); fInvKy = SkScalarToFixed(m->getSkewY()); diff --git a/skia/sgl/SkBitmapProcState.h b/skia/sgl/SkBitmapProcState.h index e48a8c3..1366d3b 100644 --- a/skia/sgl/SkBitmapProcState.h +++ b/skia/sgl/SkBitmapProcState.h @@ -1,5 +1,5 @@ /* -** Copyright 2007, Google Inc. +** Copyright 2007, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -39,9 +39,8 @@ struct SkBitmapProcState { int count, uint16_t colors[]); - typedef SkFixed (*FixedTileProc)(SkFixed, int); - typedef int (*IntTileProc)(int, int); - + typedef U16CPU (*FixedTileProc)(SkFixed); // returns 0..0xFFFF + MatrixProc fMatrixProc; // chooseProcs SampleProc32 fSampleProc32; // chooseProcs SampleProc16 fSampleProc16; // chooseProcs @@ -49,8 +48,6 @@ struct SkBitmapProcState { SkMatrix fUnitInvMatrix; // chooseProcs FixedTileProc fTileProcX; // chooseProcs FixedTileProc fTileProcY; // chooseProcs - IntTileProc iTileProcX; // chooseProcs - IntTileProc iTileProcY; // chooseProcs SkFixed fFilterOneX; SkFixed fFilterOneY; diff --git a/skia/sgl/SkBitmapProcState_matrix.h b/skia/sgl/SkBitmapProcState_matrix.h index fe551c2..1212a41 100644 --- a/skia/sgl/SkBitmapProcState_matrix.h +++ b/skia/sgl/SkBitmapProcState_matrix.h @@ -1,5 +1,4 @@ -#define TRANSLATE_NOFILTER_NAME MAKENAME(_nofilter_translate) #define SCALE_NOFILTER_NAME MAKENAME(_nofilter_scale) #define SCALE_FILTER_NAME MAKENAME(_filter_scale) #define AFFINE_NOFILTER_NAME MAKENAME(_nofilter_affine) @@ -18,38 +17,6 @@ #define PREAMBLE_ARG_Y #endif -#ifndef PREAMBLE_TRANS - #define PREAMBLE_TRANS(state) -#endif - -static void TRANSLATE_NOFILTER_NAME(const SkBitmapProcState& s, - uint32_t xy[], int count, int x, int y) -{ - SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0); - - PREAMBLE_TRANS(s); - - x += SkScalarFloor(s.fInvMatrix->getTranslateX()); - y += SkScalarFloor(s.fInvMatrix->getTranslateY()); - - *xy++ = (uint32_t)TILEY_TRANS(y, (s.fBitmap->height() - 1)); - - int maxX = s.fBitmap->width() - 1; - int i; - uint16_t* xx = (uint16_t*)xy; - for (i = (count >> 2); i > 0; --i) - { - *xx++ = (uint16_t)TILEX_TRANS(x, maxX); x++; - *xx++ = (uint16_t)TILEX_TRANS(x, maxX); x++; - *xx++ = (uint16_t)TILEX_TRANS(x, maxX); x++; - *xx++ = (uint16_t)TILEX_TRANS(x, maxX); x++; - } - for (i = (count & 3); i > 0; --i) - { - *xx++ = (uint16_t)TILEX_TRANS(x, maxX); x++; - } -} - static void SCALE_NOFILTER_NAME(const SkBitmapProcState& s, uint32_t xy[], int count, int x, int y) { SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | @@ -274,9 +241,6 @@ static void PERSP_FILTER_NAME(const SkBitmapProcState& s, } static SkBitmapProcState::MatrixProc MAKENAME(_Procs)[] = { - TRANSLATE_NOFILTER_NAME, - TRANSLATE_NOFILTER_NAME, // No need to do filtering if the matrix is no - // more complex than identity/translate. SCALE_NOFILTER_NAME, SCALE_FILTER_NAME, AFFINE_NOFILTER_NAME, @@ -291,10 +255,7 @@ static SkBitmapProcState::MatrixProc MAKENAME(_Procs)[] = { #ifdef CHECK_FOR_DECAL #undef CHECK_FOR_DECAL #endif -#undef TILEX_TRANS -#undef TILEY_TRANS - -#undef TRANSLATE_NOFILTER_NAME + #undef SCALE_NOFILTER_NAME #undef SCALE_FILTER_NAME #undef AFFINE_NOFILTER_NAME @@ -307,7 +268,6 @@ static SkBitmapProcState::MatrixProc MAKENAME(_Procs)[] = { #undef PREAMBLE_PARAM_Y #undef PREAMBLE_ARG_X #undef PREAMBLE_ARG_Y -#undef PREAMBLE_TRANS #undef TILEX_LOW_BITS #undef TILEY_LOW_BITS diff --git a/skia/sgl/SkBitmapProcState_matrixProcs.cpp b/skia/sgl/SkBitmapProcState_matrixProcs.cpp index 369f9ff..beb21c8 100644 --- a/skia/sgl/SkBitmapProcState_matrixProcs.cpp +++ b/skia/sgl/SkBitmapProcState_matrixProcs.cpp @@ -28,8 +28,6 @@ void decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count); #define TILEX_LOW_BITS(fx, max) (((fx) >> 12) & 0xF) #define TILEY_LOW_BITS(fy, max) (((fy) >> 12) & 0xF) #define CHECK_FOR_DECAL -#define TILEX_TRANS(x, max) SkClampMax(x, max) -#define TILEY_TRANS(y, max) SkClampMax(y, max) #include "SkBitmapProcState_matrix.h" #define MAKENAME(suffix) RepeatX_RepeatY ## suffix @@ -37,9 +35,6 @@ void decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count); #define TILEY_PROCF(fy, max) (((fy) & 0xFFFF) * ((max) + 1) >> 16) #define TILEX_LOW_BITS(fx, max) ((((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF) #define TILEY_LOW_BITS(fy, max) ((((fy) & 0xFFFF) * ((max) + 1) >> 12) & 0xF) -#define REAL_MOD(val, modulus) (((val)%(modulus)) + (modulus)*( (val)<0 )) -#define TILEX_TRANS(x, max) (REAL_MOD((x), ((max) + 1))) -#define TILEY_TRANS(y, max) (REAL_MOD((y), ((max) + 1))) #include "SkBitmapProcState_matrix.h" #define MAKENAME(suffix) GeneralXY ## suffix @@ -49,17 +44,13 @@ void decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count); #define PREAMBLE_PARAM_Y , SkBitmapProcState::FixedTileProc tileProcY #define PREAMBLE_ARG_X , tileProcX #define PREAMBLE_ARG_Y , tileProcY -#define TILEX_PROCF(fx, max) (tileProcX(fx, max) >> 16) -#define TILEY_PROCF(fy, max) (tileProcY(fy, max) >> 16) -#define TILEX_LOW_BITS(fx, max) ((tileProcX(fx, max) >> 14) & 0x3) -#define TILEY_LOW_BITS(fy, max) ((tileProcY(fy, max) >> 14) & 0x3) -#define PREAMBLE_TRANS(state) SkBitmapProcState::IntTileProc tileProcX = (state).iTileProcX; \ - SkBitmapProcState::IntTileProc tileProcY = (state).iTileProcY -#define TILEX_TRANS(x, max) tileProcX(x, max) -#define TILEY_TRANS(y, max) tileProcY(y, max) +#define TILEX_PROCF(fx, max) (tileProcX(fx) * ((max) + 1) >> 16) +#define TILEY_PROCF(fy, max) (tileProcY(fy) * ((max) + 1) >> 16) +#define TILEX_LOW_BITS(fx, max) ((tileProcX(fx) * ((max) + 1) >> 12) & 0xF) +#define TILEY_LOW_BITS(fy, max) ((tileProcY(fy) * ((max) + 1) >> 12) & 0xF) #include "SkBitmapProcState_matrix.h" -static inline SkFixed fixed_clamp(SkFixed x, int max) +static inline U16CPU fixed_clamp(SkFixed x) { #ifdef SK_CPU_HAS_CONDITIONAL_INSTR if (x >> 16) @@ -75,20 +66,19 @@ static inline SkFixed fixed_clamp(SkFixed x, int max) x = 0xFFFF; } #endif - return x * (max + 1); + return x; } -static inline SkFixed fixed_repeat(SkFixed x, int max) +static inline U16CPU fixed_repeat(SkFixed x) { - return (x & 0xFFFF) * (max + 1); + return x & 0xFFFF; } -static inline SkFixed fixed_mirror(SkFixed x, int max) +static inline U16CPU fixed_mirror(SkFixed x) { SkFixed s = x << 15 >> 31; // s is FFFFFFFF if we're on an odd interval, or 0 if an even interval - x = ((x ^ s) & 0xFFFF) * (max + 1); - return s ? (x ^ 0xFFFF) : x; + return (x ^ s) & 0xFFFF; } static SkBitmapProcState::FixedTileProc choose_tile_proc(unsigned m) @@ -100,41 +90,6 @@ static SkBitmapProcState::FixedTileProc choose_tile_proc(unsigned m) SkASSERT(SkShader::kMirror_TileMode == m); return fixed_mirror; } - -static inline int int_clamp(int x, int max) -{ - SkASSERT(max >= 0); - - return SkClampMax(x, max); -} - -static inline int int_repeat(int x, int max) -{ - SkASSERT(max >= 0); - - return x % (max + 1); -} - -static inline int int_mirror(int x, int max) -{ - SkASSERT(max >= 0); - - int dx = x % (max + 1); - if (dx < 0) - dx = -dx - 1; - - return (x / (max + 1) % 2) ? max - dx : dx; -} - -static SkBitmapProcState::IntTileProc choose_int_tile_proc(unsigned m) -{ - if (SkShader::kClamp_TileMode == m) - return int_clamp; - if (SkShader::kRepeat_TileMode == m) - return int_repeat; - SkASSERT(SkShader::kMirror_TileMode == m); - return int_mirror; -} SkBitmapProcState::MatrixProc SkBitmapProcState::chooseMatrixProc() { @@ -142,10 +97,8 @@ SkBitmapProcState::MatrixProc SkBitmapProcState::chooseMatrixProc() if (fDoFilter) index = 1; if (fInvType & SkMatrix::kPerspective_Mask) - index |= 6; - else if (fInvType & SkMatrix::kAffine_Mask) index |= 4; - else if (fInvType & SkMatrix::kScale_Mask) + else if (fInvType & SkMatrix::kAffine_Mask) index |= 2; if (SkShader::kClamp_TileMode == fTileModeX && @@ -170,8 +123,6 @@ SkBitmapProcState::MatrixProc SkBitmapProcState::chooseMatrixProc() // only general needs these procs fTileProcX = choose_tile_proc(fTileModeX); fTileProcY = choose_tile_proc(fTileModeY); - iTileProcX = choose_int_tile_proc(fTileModeX); - iTileProcY = choose_int_tile_proc(fTileModeY); return GeneralXY_Procs[index]; } diff --git a/skia/sgl/SkBitmapSampler.cpp b/skia/sgl/SkBitmapSampler.cpp index 924aeaa..045efd1 100644 --- a/skia/sgl/SkBitmapSampler.cpp +++ b/skia/sgl/SkBitmapSampler.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkBitmapSampler.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkBitmapSampler.h b/skia/sgl/SkBitmapSampler.h index b31bb9f..eeef3b3 100644 --- a/skia/sgl/SkBitmapSampler.h +++ b/skia/sgl/SkBitmapSampler.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkBitmapSampler.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkBitmapSamplerTemplate.h b/skia/sgl/SkBitmapSamplerTemplate.h index d9680d6..00df10c 100644 --- a/skia/sgl/SkBitmapSamplerTemplate.h +++ b/skia/sgl/SkBitmapSamplerTemplate.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkBitmapSamplerTemplate.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkBitmapShader.cpp b/skia/sgl/SkBitmapShader.cpp index 939080d..5d70dd3 100644 --- a/skia/sgl/SkBitmapShader.cpp +++ b/skia/sgl/SkBitmapShader.cpp @@ -1,4 +1,4 @@ -/* Copyright 2006, Google Inc. +/* Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkBitmapShader.h b/skia/sgl/SkBitmapShader.h index d64274c..8d40a4b 100644 --- a/skia/sgl/SkBitmapShader.h +++ b/skia/sgl/SkBitmapShader.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkBitmapShader.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkBitmapShader16BilerpTemplate.h b/skia/sgl/SkBitmapShader16BilerpTemplate.h index 555d587..b70801e 100644 --- a/skia/sgl/SkBitmapShader16BilerpTemplate.h +++ b/skia/sgl/SkBitmapShader16BilerpTemplate.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkBitmapShader16BilerpTemplate.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkBitmapShaderTemplate.h b/skia/sgl/SkBitmapShaderTemplate.h index b24168c..0174138 100644 --- a/skia/sgl/SkBitmapShaderTemplate.h +++ b/skia/sgl/SkBitmapShaderTemplate.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkBitmapShaderTemplate.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkBitmap_scroll.cpp b/skia/sgl/SkBitmap_scroll.cpp index eb2abc8..f9f197d 100644 --- a/skia/sgl/SkBitmap_scroll.cpp +++ b/skia/sgl/SkBitmap_scroll.cpp @@ -64,6 +64,7 @@ bool SkBitmap::scrollRect(const SkIRect* subset, int dx, int dy, SkAutoLockPixels alp(*this); // if we have no pixels, just return (inval is already updated) + // don't call readyToDraw(), since we don't require a colortable per se if (this->getPixels() == NULL) { return true; } diff --git a/skia/sgl/SkBlitBWMaskTemplate.h b/skia/sgl/SkBlitBWMaskTemplate.h index f7767fb..e433d36 100644 --- a/skia/sgl/SkBlitBWMaskTemplate.h +++ b/skia/sgl/SkBlitBWMaskTemplate.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkBlitBWMaskTemplate.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkBlitter.cpp b/skia/sgl/SkBlitter.cpp index 95a67c7..9208429 100644 --- a/skia/sgl/SkBlitter.cpp +++ b/skia/sgl/SkBlitter.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkBlitter.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkBlitter.h b/skia/sgl/SkBlitter.h index 56d69c9..11b84fd 100644 --- a/skia/sgl/SkBlitter.h +++ b/skia/sgl/SkBlitter.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkBlitter.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkBlitter_4444.cpp b/skia/sgl/SkBlitter_4444.cpp index de42312..cce94c5 100644 --- a/skia/sgl/SkBlitter_4444.cpp +++ b/skia/sgl/SkBlitter_4444.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkBlitter_ARGB32.cpp ** - ** Copyright 2006, Google Inc. + ** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -379,11 +379,14 @@ class SkARGB4444_Shader_Blitter : public SkShaderBlitter { SkBlitRow::Proc fOpaqueProc; SkBlitRow::Proc fAlphaProc; SkPMColor* fBuffer; + uint8_t* fAAExpand; public: SkARGB4444_Shader_Blitter(const SkBitmap& device, const SkPaint& paint) : INHERITED(device, paint) { - fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor))); + const int width = device.width(); + fBuffer = (SkPMColor*)sk_malloc_throw(width * sizeof(SkPMColor) + width); + fAAExpand = (uint8_t*)(fBuffer + width); (fXfermode = paint.getXfermode())->safeRef(); @@ -423,7 +426,8 @@ virtual void blitH(int x, int y, int width) virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) { - SkPMColor* span = fBuffer; + SkPMColor* SK_RESTRICT span = fBuffer; + uint8_t* SK_RESTRICT aaExpand = fAAExpand; SkPMColor16* device = fDevice.getAddr16(x, y); SkShader* shader = fShader; SkXfermode* xfer = fXfermode; @@ -439,10 +443,12 @@ virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t ru if (255 == aa) { xfer->xfer4444(device, span, count, NULL); } else { - // count is almost always 1 - for (int i = count - 1; i >= 0; --i) { - xfer->xfer4444(&device[i], &span[i], count, antialias); + const uint8_t* aaBuffer = antialias; + if (count > 1) { + memset(aaExpand, aa, count); + aaBuffer = aaExpand; } + xfer->xfer4444(device, span, count, aaBuffer); } } device += count; diff --git a/skia/sgl/SkBlitter_A1.cpp b/skia/sgl/SkBlitter_A1.cpp index 61d9cf6..1a91a26 100644 --- a/skia/sgl/SkBlitter_A1.cpp +++ b/skia/sgl/SkBlitter_A1.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkBlitter_A1.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkBlitter_A8.cpp b/skia/sgl/SkBlitter_A8.cpp index 23f7f01..18b0881 100644 --- a/skia/sgl/SkBlitter_A8.cpp +++ b/skia/sgl/SkBlitter_A8.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkBlitter_A8.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkBlitter_ARGB32.cpp b/skia/sgl/SkBlitter_ARGB32.cpp index 0fa0e0b..ed2fc0e 100644 --- a/skia/sgl/SkBlitter_ARGB32.cpp +++ b/skia/sgl/SkBlitter_ARGB32.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkBlitter_ARGB32.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkBlitter_RGB16.cpp b/skia/sgl/SkBlitter_RGB16.cpp index aca515d..b253662 100644 --- a/skia/sgl/SkBlitter_RGB16.cpp +++ b/skia/sgl/SkBlitter_RGB16.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkBlitter_RGB16.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -161,6 +161,7 @@ SkRGB16_Blitter::SkRGB16_Blitter(const SkBitmap& device, const SkPaint& paint) : INHERITED(device) { SkColor color = paint.getColor(); + fSrcColor32 = SkPreMultiplyColor(color); fScale = SkAlpha255To256(SkColorGetA(color)); int r = SkColorGetR(color); @@ -210,9 +211,9 @@ void SkRGB16_Blitter::blitH(int x, int y, int width) SK_RESTRICT { } } else { // TODO: respect fDoDither - unsigned scale = 256 - fScale; + SkPMColor src32 = fSrcColor32; do { - *device = srcColor + SkAlphaMulRGB16(*device, scale); + *device = SkSrcOver32To16(src32, *device); device += 1; } while (--width != 0); } @@ -467,11 +468,10 @@ void SkRGB16_Blitter::blitRect(int x, int y, int width, int height) { } } } else { - unsigned dst_scale = 256 - fScale; // apply it to the dst - + SkPMColor src32 = fSrcColor32; while (--height >= 0) { for (int i = width - 1; i >= 0; --i) { - device[i] = color16 + SkAlphaMulRGB16(device[i], dst_scale); + device[i] = SkSrcOver32To16(src32, device[i]); } device = (uint16_t*)((char*)device + deviceRB); } diff --git a/skia/sgl/SkBlitter_Sprite.cpp b/skia/sgl/SkBlitter_Sprite.cpp index 6ce8f13..f0da166 100644 --- a/skia/sgl/SkBlitter_Sprite.cpp +++ b/skia/sgl/SkBlitter_Sprite.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkBlitter_Sprite.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkCanvas.cpp b/skia/sgl/SkCanvas.cpp index a657023..4088416 100644 --- a/skia/sgl/SkCanvas.cpp +++ b/skia/sgl/SkCanvas.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2008 Google Inc. + * Copyright (C) 2006-2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ #include "SkDrawFilter.h" #include "SkDrawLooper.h" #include "SkPicture.h" +#include "SkScalarCompare.h" #include "SkTemplates.h" #include "SkUtils.h" #include <new> @@ -49,6 +50,14 @@ #endif /////////////////////////////////////////////////////////////////////////////// +// Helpers for computing fast bounds for quickReject tests + +static SkCanvas::EdgeType paint2EdgeType(const SkPaint* paint) { + return paint != NULL && paint->isAntiAlias() ? + SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType; +} + +/////////////////////////////////////////////////////////////////////////////// /* This is the record we keep for each SkDevice that the user installs. The clip/matrix/proc are fields that reflect the top of the save/restore @@ -229,6 +238,7 @@ public: fBitmap = &fDevice->accessBitmap(true); fLayerX = rec->fX; fLayerY = rec->fY; + fPaint = rec->fPaint; SkDEBUGCODE(this->validate();) fCurrLayer = rec->fNext; @@ -249,10 +259,11 @@ public: SkDevice* getDevice() const { return fDevice; } const SkMatrix& getMatrix() const { return *fMatrix; } const SkRegion& getClip() const { return *fClip; } - + const SkPaint* getPaint() const { return fPaint; } private: SkCanvas* fCanvas; const DeviceCM* fCurrLayer; + const SkPaint* fPaint; // May be null. int fLayerX; int fLayerY; SkBool8 fSkipEmptyClips; @@ -377,7 +388,8 @@ private: SkDevice* SkCanvas::init(SkDevice* device) { fBounder = NULL; - + fLocalBoundsCompareTypeDirty = true; + fMCRec = (MCRec*)fMCStack.push_back(); new (fMCRec) MCRec(NULL, 0); @@ -668,6 +680,7 @@ void SkCanvas::internalRestore() { SkASSERT(fMCStack.count() != 0); fDeviceCMDirty = true; + fLocalBoundsCompareTypeDirty = true; // reserve our layer (if any) DeviceCM* layer = fMCRec->fLayer; // may be null @@ -750,31 +763,37 @@ void SkCanvas::drawDevice(SkDevice* device, int x, int y, bool SkCanvas::translate(SkScalar dx, SkScalar dy) { fDeviceCMDirty = true; + fLocalBoundsCompareTypeDirty = true; return fMCRec->fMatrix->preTranslate(dx, dy); } bool SkCanvas::scale(SkScalar sx, SkScalar sy) { fDeviceCMDirty = true; + fLocalBoundsCompareTypeDirty = true; return fMCRec->fMatrix->preScale(sx, sy); } bool SkCanvas::rotate(SkScalar degrees) { fDeviceCMDirty = true; + fLocalBoundsCompareTypeDirty = true; return fMCRec->fMatrix->preRotate(degrees); } bool SkCanvas::skew(SkScalar sx, SkScalar sy) { fDeviceCMDirty = true; + fLocalBoundsCompareTypeDirty = true; return fMCRec->fMatrix->preSkew(sx, sy); } bool SkCanvas::concat(const SkMatrix& matrix) { fDeviceCMDirty = true; + fLocalBoundsCompareTypeDirty = true; return fMCRec->fMatrix->preConcat(matrix); } void SkCanvas::setMatrix(const SkMatrix& matrix) { fDeviceCMDirty = true; + fLocalBoundsCompareTypeDirty = true; *fMCRec->fMatrix = matrix; } @@ -791,6 +810,8 @@ void SkCanvas::resetMatrix() { bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) { fDeviceCMDirty = true; + fLocalBoundsCompareTypeDirty = true; + if (fMCRec->fMatrix->rectStaysRect()) { SkRect r; SkIRect ir; @@ -808,6 +829,7 @@ bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) { bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op) { fDeviceCMDirty = true; + fLocalBoundsCompareTypeDirty = true; SkPath devPath; path.transform(*fMCRec->fMatrix, &devPath); @@ -831,24 +853,52 @@ bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op) { bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { fDeviceCMDirty = true; + fLocalBoundsCompareTypeDirty = true; + return fMCRec->fRegion->op(rgn, op); } -bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const { - if (fMCRec->fRegion->isEmpty() || rect.isEmpty()) { - return true; +void SkCanvas::computeLocalClipBoundsCompareType() const { + SkRect r; + + if (!this->getClipBounds(&r, kAA_EdgeType)) { + fLocalBoundsCompareType.setEmpty(); + } else { + fLocalBoundsCompareType.set(SkScalarToCompareType(r.fLeft), + SkScalarToCompareType(r.fTop), + SkScalarToCompareType(r.fRight), + SkScalarToCompareType(r.fBottom)); } +} - SkRect r; - SkIRect ir; +bool SkCanvas::quickReject(const SkRect& rect, EdgeType) const { + /* current impl ignores edgetype, and relies on + getLocalClipBoundsCompareType(), which always returns a value assuming + antialiasing (worst case) + */ - fMCRec->fMatrix->mapRect(&r, rect); - if (kAA_EdgeType == et) { - r.roundOut(&ir); - } else { - r.round(&ir); + if (fMCRec->fRegion->isEmpty()) { + return true; } - return fMCRec->fRegion->quickReject(ir); + + // check for empty user rect (horizontal) + SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft); + SkScalarCompareType userR = SkScalarToCompareType(rect.fRight); + if (userL >= userR) { + return true; + } + + // check for empty user rect (vertical) + SkScalarCompareType userT = SkScalarToCompareType(rect.fTop); + SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom); + if (userT >= userB) { + return true; + } + + // check if we are completely outside of the local clip bounds + const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(); + return userL >= clipR.fRight || userT >= clipR.fBottom || + userR <= clipR.fLeft || userB <= clipR.fTop; } bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const { @@ -858,7 +908,7 @@ bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const { if (fMCRec->fMatrix->rectStaysRect()) { SkRect r; - path.computeBounds(&r, SkPath::kExact_BoundsType); + path.computeBounds(&r, SkPath::kFast_BoundsType); return this->quickReject(r, et); } @@ -867,55 +917,38 @@ bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const { SkIRect ir; path.transform(*fMCRec->fMatrix, &dstPath); - dstPath.computeBounds(&r, SkPath::kExact_BoundsType); + dstPath.computeBounds(&r, SkPath::kFast_BoundsType); + r.round(&ir); if (kAA_EdgeType == et) { - r.roundOut(&ir); - } else { - r.round(&ir); + ir.inset(-1, -1); } return fMCRec->fRegion->quickReject(ir); } bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const { - if (fMCRec->fRegion->isEmpty() || top >= bottom) { + /* current impl ignores edgetype, and relies on + getLocalClipBoundsCompareType(), which always returns a value assuming + antialiasing (worst case) + */ + + if (fMCRec->fRegion->isEmpty()) { return true; } - const SkMatrix& matrix = *fMCRec->fMatrix; - - // if we're rotated/skewed/perspective, give up (for now) - // TODO: cache this attribute of the matrix? or specialized query method? - // TODO: if rotate=90 or 270 is common, we can handle those too... - if (matrix.getType() & ~(SkMatrix::kTranslate_Mask | - SkMatrix::kScale_Mask)) { - return false; - } - // transform top/botttom into device coordinates - const SkScalar sy = matrix[SkMatrix::kMScaleY]; - const SkScalar ty = matrix[SkMatrix::kMTransY]; - top = SkScalarMulAdd(top, sy, ty); - bottom = SkScalarMulAdd(bottom, sy, ty); - - // if the scale flipped us, flip back - if (top > bottom) { - SkTSwap<SkScalar>(top, bottom); - } - // now round based on the edge type - int ymin, ymax; - if (kAA_EdgeType == et) { - ymin = SkScalarFloor(top); - ymax = SkScalarCeil(bottom); - } else { - ymin = SkScalarRound(top); - ymax = SkScalarRound(bottom); + SkScalarCompareType userT = SkScalarAs2sCompliment(top); + SkScalarCompareType userB = SkScalarAs2sCompliment(bottom); + + // check for invalid user Y coordinates (i.e. empty) + if (userT >= userB) { + return true; } - // now compare against the bounds of the clip - const SkIRect& bounds = fMCRec->fRegion->getBounds(); - return ymin >= bounds.fBottom || ymax <= bounds.fTop; + // check if we are above or below the local clip bounds + const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(); + return userT >= clipR.fBottom || userB <= clipR.fTop; } -bool SkCanvas::getClipBounds(SkRect* bounds) const { +bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const { const SkRegion& clip = *fMCRec->fRegion; if (clip.isEmpty()) { if (bounds) { @@ -928,9 +961,16 @@ bool SkCanvas::getClipBounds(SkRect* bounds) const { SkMatrix inverse; SkRect r; - // TODO: should we cache the inverse (with a dirty bit)? fMCRec->fMatrix->invert(&inverse); - r.set(clip.getBounds()); + + // get the clip's bounds + const SkIRect& ibounds = clip.getBounds(); + // adjust it outwards if we are antialiasing + int inset = (kAA_EdgeType == et); + r.iset(ibounds.fLeft - inset, ibounds.fTop - inset, + ibounds.fRight + inset, ibounds.fBottom + inset); + + // invert into local coordinates inverse.mapRect(bounds, r); } return true; @@ -994,6 +1034,14 @@ void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], } void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { + if (paint.canComputeFastBounds()) { + SkRect storage; + if (this->quickReject(paint.computeFastBounds(r, &storage), + paint2EdgeType(&paint))) { + return; + } + } + ITER_BEGIN(paint, SkDrawFilter::kRect_Type) while (iter.next()) { @@ -1004,6 +1052,15 @@ void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { } void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { + if (paint.canComputeFastBounds()) { + SkRect r; + path.computeBounds(&r, SkPath::kFast_BoundsType); + if (this->quickReject(paint.computeFastBounds(r, &r), + paint2EdgeType(&paint))) { + return; + } + } + ITER_BEGIN(paint, SkDrawFilter::kPath_Type) while (iter.next()) { @@ -1016,7 +1073,17 @@ void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) { SkDEBUGCODE(bitmap.validate();) - + + if (NULL == paint || (paint->getMaskFilter() == NULL)) { + SkRect fastBounds; + fastBounds.set(x, y, + x + SkIntToScalar(bitmap.width()), + y + SkIntToScalar(bitmap.height())); + if (this->quickReject(fastBounds, paint2EdgeType(paint))) { + return; + } + } + SkMatrix matrix; matrix.setTranslate(x, y); this->internalDrawBitmap(bitmap, matrix, paint); @@ -1029,8 +1096,7 @@ void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, } // do this now, to avoid the cost of calling extract for RLE bitmaps - if (this->quickReject(dst, paint != NULL && paint->isAntiAlias() ? - kAA_EdgeType : kBW_EdgeType)) { + if (this->quickReject(dst, paint2EdgeType(paint))) { return; } @@ -1229,10 +1295,18 @@ void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, radius = 0; } - SkPath path; SkRect r; - r.set(cx - radius, cy - radius, cx + radius, cy + radius); + + if (paint.canComputeFastBounds()) { + SkRect storage; + if (this->quickReject(paint.computeFastBounds(r, &storage), + paint2EdgeType(&paint))) { + return; + } + } + + SkPath path; path.addOval(r); this->drawPath(path, paint); } @@ -1240,6 +1314,14 @@ void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, const SkPaint& paint) { if (rx > 0 && ry > 0) { + if (paint.canComputeFastBounds()) { + SkRect storage; + if (this->quickReject(paint.computeFastBounds(r, &storage), + paint2EdgeType(&paint))) { + return; + } + } + SkPath path; path.addRoundRect(r, rx, ry, SkPath::kCW_Direction); this->drawPath(path, paint); @@ -1249,6 +1331,14 @@ void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, } void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { + if (paint.canComputeFastBounds()) { + SkRect storage; + if (this->quickReject(paint.computeFastBounds(oval, &storage), + paint2EdgeType(&paint))) { + return; + } + } + SkPath path; path.addOval(oval); this->drawPath(path, paint); @@ -1316,8 +1406,15 @@ const SkMatrix& SkCanvas::LayerIter::matrix() const { return fImpl->getMatrix(); } +const SkPaint& SkCanvas::LayerIter::paint() const { + const SkPaint* paint = fImpl->getPaint(); + if (NULL == paint) { + paint = &fDefaultPaint; + } + return *paint; +} + const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } int SkCanvas::LayerIter::x() const { return fImpl->getX(); } int SkCanvas::LayerIter::y() const { return fImpl->getY(); } - diff --git a/skia/sgl/SkColor.cpp b/skia/sgl/SkColor.cpp index 1e7aa70..4256179 100644 --- a/skia/sgl/SkColor.cpp +++ b/skia/sgl/SkColor.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkColor.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -66,7 +66,9 @@ void SkRGBToHSV(U8CPU r, U8CPU g, U8CPU b, SkScalar hsv[3]) { SkASSERT(v >= 0 && v <= SK_Scalar1); if (0 == delta) { // we're a shade of gray - hsv[0] = hsv[1] = hsv[2] = v; + hsv[0] = 0; + hsv[1] = 0; + hsv[2] = v; return; } diff --git a/skia/sgl/SkColorFilter.cpp b/skia/sgl/SkColorFilter.cpp index d9034c6..bb4be48 100644 --- a/skia/sgl/SkColorFilter.cpp +++ b/skia/sgl/SkColorFilter.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkColorFilter.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkColorTable.cpp b/skia/sgl/SkColorTable.cpp index b8edf18..f991da3 100644 --- a/skia/sgl/SkColorTable.cpp +++ b/skia/sgl/SkColorTable.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkColorTable.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkCoreBlitters.h b/skia/sgl/SkCoreBlitters.h index e1692f0..5b3497e 100644 --- a/skia/sgl/SkCoreBlitters.h +++ b/skia/sgl/SkCoreBlitters.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkCoreBlitters.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -162,6 +162,7 @@ public: virtual const SkBitmap* justAnOpaqueColor(uint32_t*); private: + SkPMColor fSrcColor32; unsigned fScale; uint16_t fColor16; // already scaled by fScale uint16_t fRawColor16; // unscaled diff --git a/skia/sgl/SkDeque.cpp b/skia/sgl/SkDeque.cpp index e424817..4f15051 100644 --- a/skia/sgl/SkDeque.cpp +++ b/skia/sgl/SkDeque.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkDeque.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkDraw.cpp b/skia/sgl/SkDraw.cpp index 106543a..2f0ddff 100644 --- a/skia/sgl/SkDraw.cpp +++ b/skia/sgl/SkDraw.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkDraw.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -37,6 +37,27 @@ //#define TRACE_BITMAP_DRAWS +class SkAutoRestoreBounder : SkNoncopyable { +public: + // note: initializing fBounder is done only to fix a warning + SkAutoRestoreBounder() : fDraw(NULL), fBounder(NULL) {} + ~SkAutoRestoreBounder() { + if (fDraw) { + fDraw->fBounder = fBounder; + } + } + + void clearBounder(const SkDraw* draw) { + fDraw = const_cast<SkDraw*>(draw); + fBounder = draw->fBounder; + fDraw->fBounder = NULL; + } + +private: + SkDraw* fDraw; + SkBounder* fBounder; +}; + static SkPoint* rect_points(SkRect& r, int index) { SkASSERT((unsigned)index < 2); return &((SkPoint*)(void*)&r)[index]; @@ -182,7 +203,7 @@ static BitmapXferProc ChooseBitmapXferProc(const SkBitmap& bitmap, return D_Dst_BitmapXferProc; // ignore data case SkPorterDuff::kSrc_Mode: { /* - should I worry about dithering for the lower depths? <reed> + should I worry about dithering for the lower depths? */ SkPMColor pmc = SkPreMultiplyColor(color); switch (bitmap.config()) { @@ -496,6 +517,21 @@ PtProcRec::Proc PtProcRec::chooseProc(SkBlitter* blitter) { return proc; } +static bool bounder_points(SkBounder* bounder, SkCanvas::PointMode mode, + size_t count, const SkPoint pts[], + const SkPaint& paint, const SkMatrix& matrix) { + SkIRect ibounds; + SkRect bounds; + SkScalar inset = paint.getStrokeWidth(); + + bounds.set(pts, count); + bounds.inset(-inset, -inset); + matrix.mapRect(&bounds); + + bounds.roundOut(&ibounds); + return bounder->doIRect(ibounds); +} + // each of these costs 8-bytes of stack space, so don't make it too large // must be even for lines/polygon to work #define MAX_DEV_PTS 32 @@ -510,6 +546,18 @@ void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count, if ((long)count <= 0) { return; } + + SkAutoRestoreBounder arb; + + if (fBounder) { + if (!bounder_points(fBounder, mode, count, pts, paint, *fMatrix)) { + return; + } + // clear the bounder for the rest of this function, so we don't call it + // again later if we happen to call ourselves for drawRect, drawPath, + // etc. + arb.clearBounder(this); + } SkASSERT(pts != NULL); SkDEBUGCODE(this->validate();) @@ -749,7 +797,7 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& paint, SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) /* - If the device thickness <= 1.0, then make it a hairline, and + If the device thickness < 1.0, then make it a hairline, and modulate alpha if the thickness is even smaller (e.g. thickness == 0.5 should modulate the alpha by 1/2) */ @@ -762,7 +810,7 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& paint, SkScalar width = paint.getStrokeWidth(); if (width > 0) { width = matrix->mapRadius(paint.getStrokeWidth()); - if (width <= SK_Scalar1) { + if (width < SK_Scalar1) { int scale = (int)SkScalarMul(width, 256); int alpha = paint.getAlpha() * scale >> 8; @@ -931,15 +979,15 @@ void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, return; } - // do I need to call the bounder first??? <reed> + // do I need to call the bounder first??? if (clipped_out(matrix, *fClip, bitmap.width(), bitmap.height())) { return; } // only lock the pixels if we passed the clip test SkAutoLockPixels alp(bitmap); - // after the lock, check if we have valid pixels - if (bitmap.getPixels() == NULL) { + // after the lock, check if we are valid + if (!bitmap.readyToDraw()) { return; } @@ -988,7 +1036,7 @@ void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, SkRect r; r.set(0, 0, SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())); - // is this ok if paint has a rasterizer? <reed> + // is this ok if paint has a rasterizer? draw.drawRect(r, paint); } } @@ -1053,7 +1101,7 @@ void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, matrix.reset(); draw.fMatrix = &matrix; // call ourself with a rect - // is this OK if paint has a rasterizer? <reed> + // is this OK if paint has a rasterizer? draw.drawRect(r, paint); } @@ -2298,4 +2346,3 @@ bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds, return true; } - diff --git a/skia/sgl/SkEdge.cpp b/skia/sgl/SkEdge.cpp index 3a9474c..b079bef 100644 --- a/skia/sgl/SkEdge.cpp +++ b/skia/sgl/SkEdge.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkEdge.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -77,7 +77,12 @@ int SkEdge::setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip, fX = SkFDot6ToFixed(x0 + SkFixedMul(slope, (32 - y0) & 63)); // + SK_Fixed1/2 fDX = slope; - fFirstY = (int16_t)(top); // inlined skToS16() +#if 0 + // CHANGED FOR CHROME + fFirstY = top; + fLastY = bot - 1; +#else + fFirstY = top; if (top != (long)fFirstY) { if (fFirstY < top) { fFirstY = std::numeric_limits<int16_t>::max(); @@ -86,7 +91,7 @@ int SkEdge::setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip, } fX -= fDX * (top - (long)fFirstY); } - fLastY = (int16_t)(bot - 1); // inlined SkToS16() + fLastY = bot - 1; if (bot-1 != (long)fLastY) { if (fLastY < bot-1) { fLastY = std::numeric_limits<int16_t>::max(); @@ -94,6 +99,7 @@ int SkEdge::setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip, fLastY = std::numeric_limits<int16_t>::min(); } } +#endif fCurveCount = 0; fWinding = SkToS8(winding); fCurveShift = 0; @@ -109,7 +115,7 @@ int SkEdge::updateLine(SkFixed x0, SkFixed y0, SkFixed x1, SkFixed y1) { SkASSERT(fWinding == 1 || fWinding == -1); SkASSERT(fCurveCount != 0); - SkASSERT(fCurveShift != 0); +// SkASSERT(fCurveShift != 0); y0 >>= 10; y1 >>= 10; @@ -132,8 +138,8 @@ int SkEdge::updateLine(SkFixed x0, SkFixed y0, SkFixed x1, SkFixed y1) fX = SkFDot6ToFixed(x0 + SkFixedMul(slope, (32 - y0) & 63)); // + SK_Fixed1/2 fDX = slope; - fFirstY = SkToS16(top); - fLastY = SkToS16(bot - 1); + fFirstY = top; + fLastY = bot - 1; return 1; } @@ -153,7 +159,14 @@ void SkEdge::chopLineWithClip(const SkIRect& clip) } } -///////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +/* We store 1<<shift in a (signed) byte, so its maximum value is 1<<6 == 64. + Note that this limits the number of lines we use to approximate a curve. + If we need to increase this, we need to store fCurveCount in something + larger than int8_t. +*/ +#define MAX_COEFF_SHIFT 6 static inline SkFDot6 cheap_distance(SkFDot6 dx, SkFDot6 dy) { @@ -176,7 +189,7 @@ static inline int diff_to_shift(SkFDot6 dx, SkFDot6 dy) // down by 5 should give us 1/2 pixel accuracy (assuming our dist is accurate...) // this is chosen by heuristic: make it as big as possible (to minimize segments) // ... but small enough so that our curves still look smooth - dist >>= 5; + dist = (dist + (1 << 4)) >> 5; // each subdivision (shift value) cuts this dist (error) by 1/4 return (32 - SkCLZ(dist)) >> 1; @@ -230,14 +243,19 @@ int SkQuadraticEdge::setQuadratic(const SkPoint pts[3], const SkIRect* clip, int SkFDot6 dx = ((x1 << 1) - x0 - x2) >> 2; SkFDot6 dy = ((y1 << 1) - y0 - y2) >> 2; shift = diff_to_shift(dx, dy); + SkASSERT(shift >= 0); } // need at least 1 subdivision for our bias trick - if (shift == 0) + if (shift == 0) { shift = 1; - + } else if (shift > MAX_COEFF_SHIFT) { + shift = MAX_COEFF_SHIFT; + } + fWinding = SkToS8(winding); fCurveShift = SkToU8(shift); - fCurveCount = SkToS16(1 << shift); + //fCubicDShift only set for cubics + fCurveCount = SkToS8(1 << shift); SkFixed A = SkFDot6ToFixed(x0 - x1 - x1 + x2); SkFixed B = SkFDot6ToFixed(x1 - x0 + x1 - x0); @@ -309,6 +327,11 @@ int SkQuadraticEdge::updateQuadratic() ///////////////////////////////////////////////////////////////////////// +static inline int SkFDot6UpShift(SkFDot6 x, int upShift) { + SkASSERT((x << upShift >> upShift) == x); + return x << upShift; +} + /* f(1/3) = (8a + 12b + 6c + d) / 27 f(2/3) = (a + 6b + 12c + 8d) / 27 @@ -386,23 +409,38 @@ int SkCubicEdge::setCubic(const SkPoint pts[4], const SkIRect* clip, int shift) } // need at least 1 subdivision for our bias trick SkASSERT(shift > 0); + if (shift > MAX_COEFF_SHIFT) { + shift = MAX_COEFF_SHIFT; + } + + /* Since our in coming data is initially shifted down by 10 (or 8 in + antialias). That means the most we can shift up is 8. However, we + compute coefficients with a 3*, so the safest upshift is really 6 + */ + int upShift = 6; // largest safe value + int downShift = shift + upShift - 10; + if (downShift < 0) { + downShift = 0; + upShift = 10 - shift; + } fWinding = SkToS8(winding); + fCurveCount = SkToS8(-1 << shift); fCurveShift = SkToU8(shift); - fCurveCount = SkToS16(-1 << shift); + fCubicDShift = SkToU8(downShift); - SkFixed B = SkFDot6ToFixed(3 * (x1 - x0)); - SkFixed C = SkFDot6ToFixed(3 * (x0 - x1 - x1 + x2)); - SkFixed D = SkFDot6ToFixed(x3 + 3 * (x1 - x2) - x0); + SkFixed B = SkFDot6UpShift(3 * (x1 - x0), upShift); + SkFixed C = SkFDot6UpShift(3 * (x0 - x1 - x1 + x2), upShift); + SkFixed D = SkFDot6UpShift(x3 + 3 * (x1 - x2) - x0, upShift); fCx = SkFDot6ToFixed(x0); fCDx = B + (C >> shift) + (D >> 2*shift); // biased by shift fCDDx = 2*C + (3*D >> (shift - 1)); // biased by 2*shift fCDDDx = 3*D >> (shift - 1); // biased by 2*shift - B = SkFDot6ToFixed(3 * (y1 - y0)); - C = SkFDot6ToFixed(3 * (y0 - y1 - y1 + y2)); - D = SkFDot6ToFixed(y3 + 3 * (y1 - y2) - y0); + B = SkFDot6UpShift(3 * (y1 - y0), upShift); + C = SkFDot6UpShift(3 * (y0 - y1 - y1 + y2), upShift); + D = SkFDot6UpShift(y3 + 3 * (y1 - y2) - y0, upShift); fCy = SkFDot6ToFixed(y0); fCDy = B + (C >> shift) + (D >> 2*shift); // biased by shift @@ -431,19 +469,20 @@ int SkCubicEdge::updateCubic() SkFixed oldx = fCx; SkFixed oldy = fCy; SkFixed newx, newy; - int shift = fCurveShift; + const int ddshift = fCurveShift; + const int dshift = fCubicDShift; SkASSERT(count < 0); do { if (++count < 0) { - newx = oldx + (fCDx >> shift); - fCDx += fCDDx >> shift; + newx = oldx + (fCDx >> dshift); + fCDx += fCDDx >> ddshift; fCDDx += fCDDDx; - newy = oldy + (fCDy >> shift); - fCDy += fCDDy >> shift; + newy = oldy + (fCDy >> dshift); + fCDy += fCDDy >> ddshift; fCDDy += fCDDDy; } else // last segment diff --git a/skia/sgl/SkEdge.h b/skia/sgl/SkEdge.h index 086e5a6..5b0cc75 100644 --- a/skia/sgl/SkEdge.h +++ b/skia/sgl/SkEdge.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkEdge.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -32,10 +32,11 @@ struct SkEdge { SkFixed fX; SkFixed fDX; - int16_t fFirstY; - int16_t fLastY; - int16_t fCurveCount; // only used by kQuad(+) and kCubic(-) - uint8_t fCurveShift; + int32_t fFirstY; + int32_t fLastY; + int8_t fCurveCount; // only used by kQuad(+) and kCubic(-) + uint8_t fCurveShift; // appled to all Dx/DDx/DDDx except for fCubicDShift exception + uint8_t fCubicDShift; // applied to fCDx and fCDy only in cubic int8_t fWinding; // 1 or -1 int setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip, diff --git a/skia/sgl/SkFP.h b/skia/sgl/SkFP.h index b95cba2..6c0c526 100644 --- a/skia/sgl/SkFP.h +++ b/skia/sgl/SkFP.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkFP.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkFilterProc.cpp b/skia/sgl/SkFilterProc.cpp index 8082a34..814bafe 100644 --- a/skia/sgl/SkFilterProc.cpp +++ b/skia/sgl/SkFilterProc.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkFilterProc.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkFilterProc.h b/skia/sgl/SkFilterProc.h index 5aa59ab..9af4ed5 100644 --- a/skia/sgl/SkFilterProc.h +++ b/skia/sgl/SkFilterProc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2008 Google Inc. + * Copyright (C) 2006-2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -70,7 +70,7 @@ typedef unsigned (*SkFilter32Proc)(uint32_t x00, uint32_t x01, const SkFilter32Proc* SkGetFilter32ProcTable(); -inline SkFilter32Proc SkGetFilter32Proc22(const SkFilterProc* table, +inline SkFilter32Proc SkGetFilter32Proc22(const SkFilter32Proc* table, unsigned x, unsigned y) { SkASSERT(table); @@ -81,7 +81,7 @@ inline SkFilter32Proc SkGetFilter32Proc22(const SkFilterProc* table, return table[(y << 2) | x]; } -inline const SkFilter32Proc* SkGetFilter32Proc22Row(const SkFilterProc* table, +inline const SkFilter32Proc* SkGetFilter32Proc22Row(const SkFilter32Proc* table, unsigned y) { SkASSERT(table); @@ -89,7 +89,7 @@ inline const SkFilter32Proc* SkGetFilter32Proc22Row(const SkFilterProc* table, return &table[y << 30 >> 28]; } -inline SkFilter32Proc SkGetFilter32Proc22RowProc(const SkFilterProc* row, +inline SkFilter32Proc SkGetFilter32Proc22RowProc(const SkFilter32Proc* row, unsigned x) { SkASSERT(row); diff --git a/skia/sgl/SkGeometry.cpp b/skia/sgl/SkGeometry.cpp index 3c72f4b..4f22e92 100644 --- a/skia/sgl/SkGeometry.cpp +++ b/skia/sgl/SkGeometry.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkGeometry.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -260,6 +260,14 @@ static void flatten_double_quad_extrema(SkScalar coords[14]) coords[2] = coords[6] = coords[4]; } +static void force_quad_monotonic_in_y(SkPoint pts[3]) +{ + // zap pts[1].fY to the nearest value + SkScalar ab = SkScalarAbs(pts[0].fY - pts[1].fY); + SkScalar bc = SkScalarAbs(pts[1].fY - pts[2].fY); + pts[1].fY = ab < bc ? pts[0].fY : pts[2].fY; +} + /* Returns 0 for 1 quad, and 1 for two quads, either way the answer is stored in dst[]. Guarantees that the 1/2 quads will be monotonic. */ diff --git a/skia/sgl/SkGeometry.h b/skia/sgl/SkGeometry.h index d4547a5..571159f 100644 --- a/skia/sgl/SkGeometry.h +++ b/skia/sgl/SkGeometry.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkGeometry.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkGlobals.cpp b/skia/sgl/SkGlobals.cpp index fb1c948..bc72b97 100644 --- a/skia/sgl/SkGlobals.cpp +++ b/skia/sgl/SkGlobals.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkGlobals.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkGlyphCache.cpp b/skia/sgl/SkGlyphCache.cpp index f67223d..6b214df 100644 --- a/skia/sgl/SkGlyphCache.cpp +++ b/skia/sgl/SkGlyphCache.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkGlyphCache.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -21,7 +21,33 @@ #include "SkTemplates.h" #define SPEW_PURGE_STATUS -#define USE_CACHE_HASHxxxxx +//#define USE_CACHE_HASH +//#define RECORD_HASH_EFFICIENCY + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef RECORD_HASH_EFFICIENCY + static uint32_t gHashSuccess; + static uint32_t gHashCollision; + + static void RecordHashSuccess() { + gHashSuccess += 1; + } + + static void RecordHashCollisionIf(bool pred) { + if (pred) { + gHashCollision += 1; + + uint32_t total = gHashSuccess + gHashCollision; + SkDebugf("Font Cache Hash success rate: %d%%\n", + 100 * gHashSuccess / total); + } + } +#else + #define RecordHashSuccess() (void)0 + #define RecordHashCollisionIf(pred) (void)0 +#endif +#define RecordHashCollision() RecordHashCollisionIf(true) /////////////////////////////////////////////////////////////////////////////// @@ -70,26 +96,40 @@ SkGlyphCache::~SkGlyphCache() { /////////////////////////////////////////////////////////////////////////////// #ifdef SK_DEBUG - class AutoCheckForNull { - public: - AutoCheckForNull(const SkTDArray<SkGlyph*>& array) : fArray(array) { - for (int i = 0; i < array.count(); i++) - SkASSERT(array[i]); - } - ~AutoCheckForNull() { - const SkTDArray<SkGlyph*>& array = fArray; - for (int i = 0; i < array.count(); i++) { - SkASSERT(array[i]); - } +class AutoCheckForNull { +public: + AutoCheckForNull(const SkTDArray<SkGlyph*>& array) : fArray(array) { + for (int i = 0; i < array.count(); i++) + SkASSERT(array[i]); + } + ~AutoCheckForNull() { + const SkTDArray<SkGlyph*>& array = fArray; + for (int i = 0; i < array.count(); i++) { + SkASSERT(array[i]); } - private: - const SkTDArray<SkGlyph*>& fArray; - }; - #define VALIDATE() AutoCheckForNull acfn(fGlyphArray) + } +private: + const SkTDArray<SkGlyph*>& fArray; +}; +#define VALIDATE() AutoCheckForNull acfn(fGlyphArray) #else - #define VALIDATE() +#define VALIDATE() #endif +uint16_t SkGlyphCache::unicharToGlyph(SkUnichar charCode) { + VALIDATE(); + uint32_t id = SkGlyph::MakeID(charCode); + const CharGlyphRec& rec = fCharToGlyphHash[ID2HashIndex(id)]; + + if (rec.fID == id) { + return rec.fGlyph->getGlyphID(); + } else { + return fScalerContext->charToGlyphID(charCode); + } +} + +/////////////////////////////////////////////////////////////////////////////// + const SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) { VALIDATE(); uint32_t id = SkGlyph::MakeID(charCode); @@ -126,12 +166,14 @@ const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode) { CharGlyphRec* rec = &fCharToGlyphHash[ID2HashIndex(id)]; if (rec->fID != id) { + RecordHashCollisionIf(rec->fGlyph != NULL); // this ID is based on the UniChar rec->fID = id; // this ID is based on the glyph index id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode)); rec->fGlyph = this->lookupMetrics(id, kFull_MetricsType); } else { + RecordHashSuccess(); if (rec->fGlyph->isJustAdvance()) { fScalerContext->getMetrics(rec->fGlyph); } @@ -147,12 +189,14 @@ const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode, CharGlyphRec* rec = &fCharToGlyphHash[ID2HashIndex(id)]; if (rec->fID != id) { + RecordHashCollisionIf(rec->fGlyph != NULL); // this ID is based on the UniChar rec->fID = id; // this ID is based on the glyph index id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode), x, y); rec->fGlyph = this->lookupMetrics(id, kFull_MetricsType); } else { + RecordHashSuccess(); if (rec->fGlyph->isJustAdvance()) { fScalerContext->getMetrics(rec->fGlyph); } @@ -168,9 +212,11 @@ const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID) { SkGlyph* glyph = fGlyphHash[index]; if (NULL == glyph || glyph->fID != id) { + RecordHashCollisionIf(glyph != NULL); glyph = this->lookupMetrics(glyphID, kFull_MetricsType); fGlyphHash[index] = glyph; } else { + RecordHashSuccess(); if (glyph->isJustAdvance()) { fScalerContext->getMetrics(glyph); } @@ -185,11 +231,13 @@ const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID, uint32_t id = SkGlyph::MakeID(glyphID, x, y); unsigned index = ID2HashIndex(id); SkGlyph* glyph = fGlyphHash[index]; - + if (NULL == glyph || glyph->fID != id) { + RecordHashCollisionIf(glyph != NULL); glyph = this->lookupMetrics(id, kFull_MetricsType); fGlyphHash[index] = glyph; } else { + RecordHashSuccess(); if (glyph->isJustAdvance()) { fScalerContext->getMetrics(glyph); } @@ -406,6 +454,23 @@ public: #define GET_GC_GLOBALS() gGCGlobals #endif +void SkGlyphCache::VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), + void* context) { + SkGlyphCache_Globals& globals = FIND_GC_GLOBALS(); + SkAutoMutexAcquire ac(globals.fMutex); + SkGlyphCache* cache; + + globals.validate(); + + for (cache = globals.fHead; cache != NULL; cache = cache->fNext) { + if (proc(cache, context)) { + break; + } + } + + globals.validate(); +} + /* This guy calls the visitor from within the mutext lock, so the visitor cannot: - take too much time @@ -434,7 +499,6 @@ SkGlyphCache* SkGlyphCache::VisitCache(const SkDescriptor* desc, } #endif - cache = globals.fHead; for (cache = globals.fHead; cache != NULL; cache = cache->fNext) { if (cache->fDesc->equals(*desc)) { cache->detach(&globals.fHead); diff --git a/skia/sgl/SkGlyphCache.h b/skia/sgl/SkGlyphCache.h index 6aef173..2462ea5 100644 --- a/skia/sgl/SkGlyphCache.h +++ b/skia/sgl/SkGlyphCache.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkGlyphCache.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -66,6 +66,12 @@ public: const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y); const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y); + /** Return the glyphID for the specified Unichar. If the char has already + been seen, use the existing cache entry. If not, ask the scalercontext + to compute it for us. + */ + uint16_t unicharToGlyph(SkUnichar); + /** Return the image associated with the glyph. If it has not been generated this will trigger that. */ @@ -98,6 +104,12 @@ public: // call the proc) void removeAuxProc(void (*auxProc)(void*)); + /** Call proc on all cache entries, stopping early if proc returns true. + The proc should not create or delete caches, since it could produce + deadlock. + */ + static void VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), void* ctx); + /** Find a matching cache entry, and call proc() with it. If none is found create a new one. If the proc() returns true, detach the cache and return it, otherwise leave it and return NULL. @@ -176,7 +188,7 @@ private: SkPaint::FontMetrics fFontMetricsY; enum { - kHashBits = 6, + kHashBits = 8, kHashCount = 1 << kHashBits, kHashMask = kHashCount - 1 }; diff --git a/skia/sgl/SkGraphics.cpp b/skia/sgl/SkGraphics.cpp index 1bb3cb3..ed9ab02 100644 --- a/skia/sgl/SkGraphics.cpp +++ b/skia/sgl/SkGraphics.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkGraphics.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -149,10 +149,132 @@ static void test_drawText(SkBitmap::Config config, SkColor color) #endif +#include "SkFloatBits.h" + +static inline float fast_inc(float x) { + SkFloatIntUnion data; + data.fFloat = x; + data.fSignBitInt += 1; + return data.fFloat; +} + +extern float dummy(); +int time_math() { + SkMSec now; + int i; + int sum = 0; + const int repeat = 1000000; + float f; + + f = dummy(); + now = SkTime::GetMSecs(); + for (i = repeat - 1; i >= 0; --i) { + sum += (int)f; f = fast_inc(f); + sum += (int)f; f = fast_inc(f); + sum += (int)f; f = fast_inc(f); + sum += (int)f; f = fast_inc(f); + } + SkDebugf("---- native cast %d\n", SkTime::GetMSecs() - now); + + f = dummy(); + now = SkTime::GetMSecs(); + for (i = repeat - 1; i >= 0; --i) { + sum += SkFloatToIntCast(f); f = fast_inc(f); + sum += SkFloatToIntCast(f); f = fast_inc(f); + sum += SkFloatToIntCast(f); f = fast_inc(f); + sum += SkFloatToIntCast(f); f = fast_inc(f); + } + SkDebugf("---- hack cast %d\n", SkTime::GetMSecs() - now); + + f = dummy(); + now = SkTime::GetMSecs(); + for (i = repeat - 1; i >= 0; --i) { + sum += (int)floorf(f + 0.5f); f = fast_inc(f); + sum += (int)floorf(f + 0.5f); f = fast_inc(f); + sum += (int)floorf(f + 0.5f); f = fast_inc(f); + sum += (int)floorf(f + 0.5f); f = fast_inc(f); + } + SkDebugf("---- native round %d\n", SkTime::GetMSecs() - now); + + f = dummy(); + now = SkTime::GetMSecs(); + for (i = repeat - 1; i >= 0; --i) { + sum += SkFloatToIntRound(f); f = fast_inc(f); + sum += SkFloatToIntRound(f); f = fast_inc(f); + sum += SkFloatToIntRound(f); f = fast_inc(f); + sum += SkFloatToIntRound(f); f = fast_inc(f); + } + SkDebugf("---- hack round %d\n", SkTime::GetMSecs() - now); + + f = dummy(); + now = SkTime::GetMSecs(); + for (i = repeat - 1; i >= 0; --i) { + sum += SkFloat2Bits(floorf(f)); f = fast_inc(f); + sum += SkFloat2Bits(floorf(f)); f = fast_inc(f); + sum += SkFloat2Bits(floorf(f)); f = fast_inc(f); + sum += SkFloat2Bits(floorf(f)); f = fast_inc(f); + } + SkDebugf("---- native floor %d\n", SkTime::GetMSecs() - now); + + f = dummy(); + now = SkTime::GetMSecs(); + for (i = repeat - 1; i >= 0; --i) { + sum += SkFloatToIntFloor(f); f = fast_inc(f); + sum += SkFloatToIntFloor(f); f = fast_inc(f); + sum += SkFloatToIntFloor(f); f = fast_inc(f); + sum += SkFloatToIntFloor(f); f = fast_inc(f); + } + SkDebugf("---- hack floor %d\n", SkTime::GetMSecs() - now); + + return sum; +} + +static float time_intToFloat() { + const int repeat = 1000000; + int i, n; + SkMSec now; + float sum = 0; + + n = (int)dummy(); + now = SkTime::GetMSecs(); + for (i = repeat - 1; i >= 0; --i) { + sum += (float)n; n += 1; + sum += (float)n; n += 1; + sum += (float)n; n += 1; + sum += (float)n; n += 1; + } + SkDebugf("---- native i2f %d\n", SkTime::GetMSecs() - now); + + n = (int)dummy(); + now = SkTime::GetMSecs(); + for (i = repeat - 1; i >= 0; --i) { + sum += SkIntToFloatCast(n); n += 1; + sum += SkIntToFloatCast(n); n += 1; + sum += SkIntToFloatCast(n); n += 1; + sum += SkIntToFloatCast(n); n += 1; + } + SkDebugf("---- check i2f %d\n", SkTime::GetMSecs() - now); + + n = (int)dummy(); + now = SkTime::GetMSecs(); + for (i = repeat - 1; i >= 0; --i) { + sum += SkIntToFloatCast_NoOverflowCheck(n); n += 1; + sum += SkIntToFloatCast_NoOverflowCheck(n); n += 1; + sum += SkIntToFloatCast_NoOverflowCheck(n); n += 1; + sum += SkIntToFloatCast_NoOverflowCheck(n); n += 1; + } + SkDebugf("---- nocheck i2f %d\n", SkTime::GetMSecs() - now); + + return sum; +} + void SkGraphics::Init(bool runUnitTests) { SkGlobals::Init(); +// time_math(); +// time_intToFloat(); + #ifdef BUILD_EMBOSS_TABLE SkEmbossMask_BuildTable(); #endif @@ -221,11 +343,12 @@ void SkGraphics::Init(bool runUnitTests) unittestline(SkMath), unittestline(SkUtils), unittestline(SkString), - unittestline(SkFloat), unittestline(SkMatrix), unittestline(SkGeometry), unittestline(SkPath), - unittestline(SkPathMeasure) + unittestline(SkPathMeasure), + unittestline(SkStream), + unittestline(SkWStream), }; for (i = 0; i < (int)SK_ARRAY_COUNT(gUnitTests); i++) @@ -402,3 +525,4 @@ bool SkGraphics::SetFontCacheUsed(size_t usageInBytes) { return SkGlyphCache::SetCacheUsed(usageInBytes); } +float dummy() { return 1.25f; } diff --git a/skia/sgl/SkMask.cpp b/skia/sgl/SkMask.cpp index edc3b0a..b237639 100644 --- a/skia/sgl/SkMask.cpp +++ b/skia/sgl/SkMask.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkMask.cpp ** -** Copyright 2007, Google Inc. +** Copyright 2007, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkMaskFilter.cpp b/skia/sgl/SkMaskFilter.cpp index 9040cfd..56fff97 100644 --- a/skia/sgl/SkMaskFilter.cpp +++ b/skia/sgl/SkMaskFilter.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkMaskFilter.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkPaint.cpp b/skia/sgl/SkPaint.cpp index ef23f09..bb6b31e 100644 --- a/skia/sgl/SkPaint.cpp +++ b/skia/sgl/SkPaint.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkPaint.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -301,40 +301,26 @@ SkDrawLooper* SkPaint::setLooper(SkDrawLooper* looper) return looper; } -/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// #include "SkGlyphCache.h" #include "SkUtils.h" -class SkAutoRestoreFlags { -public: - SkAutoRestoreFlags(SkPaint* paint) : fPaint(paint) - { - fFlags = paint->getFlags(); - } - ~SkAutoRestoreFlags() - { - fPaint->setFlags(fFlags); - } -private: - SkPaint* fPaint; - uint32_t fFlags; -}; - -int SkPaint::textToGlyphs(const void* textData, size_t byteLength, uint16_t glyphs[]) const -{ - if (byteLength == 0) +int SkPaint::textToGlyphs(const void* textData, size_t byteLength, + uint16_t glyphs[]) const { + if (byteLength == 0) { return 0; + } SkASSERT(textData != NULL); - if (NULL == glyphs) - { + if (NULL == glyphs) { switch (this->getTextEncoding()) { case kUTF8_TextEncoding: return SkUTF8_CountUnichars((const char*)textData, byteLength); case kUTF16_TextEncoding: - return SkUTF16_CountUnichars((const uint16_t*)textData, byteLength >> 1); + return SkUTF16_CountUnichars((const uint16_t*)textData, + byteLength >> 1); case kGlyphID_TextEncoding: return byteLength >> 1; default: @@ -345,33 +331,60 @@ int SkPaint::textToGlyphs(const void* textData, size_t byteLength, uint16_t glyp // if we get here, we have a valid glyphs[] array, so time to fill it in - if (this->getTextEncoding() == kGlyphID_TextEncoding) - { + // handle this encoding before the setup for the glyphcache + if (this->getTextEncoding() == kGlyphID_TextEncoding) { // we want to ignore the low bit of byteLength memcpy(glyphs, textData, byteLength >> 1 << 1); return byteLength >> 1; } - SkAutoRestoreFlags autoRestore((SkPaint*)this); - ((SkPaint*)this)->fFlags &= ~kSubpixelText_Flag; - - SkAutoGlyphCache autoCache(*this, NULL); - SkGlyphCache* cache = autoCache.getCache(); - SkMeasureCacheProc proc; - proc = this->getMeasureCacheProc(kForward_TextBufferDirection, false); + SkAutoGlyphCache autoCache(*this, NULL); + SkGlyphCache* cache = autoCache.getCache(); - const char* text = (const char*)textData; - const char* stop = text + byteLength; - uint16_t* gptr = glyphs; + const char* text = (const char*)textData; + const char* stop = text + byteLength; + uint16_t* gptr = glyphs; - while (text < stop) - { - // no need to provide x, y - *gptr++ = proc(cache, &text).getGlyphID(); + switch (this->getTextEncoding()) { + case SkPaint::kUTF8_TextEncoding: + while (text < stop) { + *gptr++ = cache->unicharToGlyph(SkUTF8_NextUnichar(&text)); + } + break; + case SkPaint::kUTF16_TextEncoding: { + const uint16_t* text16 = (const uint16_t*)text; + const uint16_t* stop16 = (const uint16_t*)stop; + while (text16 < stop16) { + *gptr++ = cache->unicharToGlyph(SkUTF16_NextUnichar(&text16)); + } + break; + } + default: + SkASSERT(!"unknown text encoding"); } return gptr - glyphs; } +/////////////////////////////////////////////////////////////////////////////// + +static uint32_t sk_glyphID_next(const char** text) +{ + const uint16_t* glyph = (const uint16_t*)text; + int32_t value = *glyph; + glyph += 1; + *text = (const char*)glyph; + return value; +} + +static uint32_t sk_glyphID_prev(const char** text) +{ + const uint16_t* glyph = (const uint16_t*)text; + glyph -= 1; + int32_t value = *glyph; + *text = (const char*)glyph; + return value; +} + ////////////////////////////////////////////////////////////////////////////// static const SkGlyph& sk_getMetrics_utf8_next(SkGlyphCache* cache, const char** text) @@ -1231,7 +1244,7 @@ void SkPaint::descriptorProc(const SkMatrix* deviceMatrix, descSize += peBuffer.size(); entryCount += 1; rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion - // seems like we could support kLCD as well at this point <reed>... + // seems like we could support kLCD as well at this point... } if (mf) { mfBuffer.writeFlattenable(mf); @@ -1431,6 +1444,38 @@ bool SkPaint::getFillPath(const SkPath& src, SkPath* dst) const return width != 0; // return true if we're filled, or false if we're hairline (width == 0) } +bool SkPaint::canComputeFastBounds() const { + // use bit-or since no need for early exit + return (reinterpret_cast<uintptr_t>(this->getMaskFilter()) | + reinterpret_cast<uintptr_t>(this->getLooper()) | + reinterpret_cast<uintptr_t>(this->getRasterizer()) | + reinterpret_cast<uintptr_t>(this->getPathEffect())) == 0; +} + +const SkRect& SkPaint::computeFastBounds(const SkRect& src, + SkRect* storage) const { + SkASSERT(storage); + + if (this->getStyle() != SkPaint::kFill_Style) { + // if we're stroked, outset the rect by the radius (and join type) + SkScalar radius = SkScalarHalf(this->getStrokeWidth()); + + if (0 == radius) { // hairline + radius = SK_Scalar1; + } else if (this->getStrokeJoin() == SkPaint::kMiter_Join) { + SkScalar scale = this->getStrokeMiter(); + if (scale > SK_Scalar1) { + radius = SkScalarMul(radius, scale); + } + } + storage->set(src.fLeft - radius, src.fTop - radius, + src.fRight + radius, src.fBottom + radius); + return *storage; + } + // no adjustments needed, just return the original rect + return src; +} + //////////////////////////////////////////////////////////////////////////////////////// static bool has_thick_frame(const SkPaint& paint) @@ -1524,4 +1569,3 @@ const SkPath* SkTextToPathIter::next(SkScalar* xpos) } return NULL; } - diff --git a/skia/sgl/SkPath.cpp b/skia/sgl/SkPath.cpp index afe8662..5d6882e 100644 --- a/skia/sgl/SkPath.cpp +++ b/skia/sgl/SkPath.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkPath.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -19,6 +19,63 @@ #include "SkFlattenable.h" #include "SkMath.h" +//////////////////////////////////////////////////////////////////////////// + +/* This guy's constructor/destructor bracket a path editing operation. It is + used when we know the bounds of the amount we are going to add to the path + (usually a new contour, but not required). + + It captures some state about the path up front (i.e. if it already has a + cached bounds), and the if it can, it updates the cache bounds explicitly, + avoiding the need to revisit all of the points in computeBounds(). + */ +class SkAutoPathBoundsUpdate { +public: + SkAutoPathBoundsUpdate(SkPath* path, const SkRect& r) : fRect(r) { + this->init(path); + } + + SkAutoPathBoundsUpdate(SkPath* path, SkScalar left, SkScalar top, + SkScalar right, SkScalar bottom) { + fRect.set(left, top, right, bottom); + this->init(path); + } + + ~SkAutoPathBoundsUpdate() { + if (fEmpty) { + fPath->fFastBounds = fRect; + fPath->fFastBoundsIsDirty = false; + } else if (!fDirty) { + fPath->fFastBounds.join(fRect); + fPath->fFastBoundsIsDirty = false; + } + } + +private: + const SkPath* fPath; + SkRect fRect; + bool fDirty; + bool fEmpty; + + // returns true if we should proceed + void init(const SkPath* path) { + fPath = path; + fDirty = path->fFastBoundsIsDirty; + fEmpty = path->isEmpty(); + } +}; + +static void compute_fast_bounds(SkRect* bounds, const SkTDArray<SkPoint>& pts) { + if (pts.count() <= 1) { // we ignore just 1 point (moveto) + bounds->set(0, 0, 0, 0); + } else { + bounds->set(pts.begin(), pts.count()); +// SkDebugf("------- compute bounds %p %d", &pts, pts.count()); + } +} + +//////////////////////////////////////////////////////////////////////////// + /* Stores the verbs and points as they are given to us, with exceptions: - we only record "Close" if it was immediately preceeded by Line | Quad | Cubic @@ -145,24 +202,8 @@ void SkPath::computeBounds(SkRect* bounds, BoundsType bt) const { if (fFastBoundsIsDirty) { fFastBoundsIsDirty = false; - if (fPts.count() <= 1) { // we ignore just 1 point (moveto) - fFastBounds.set(0, 0, 0, 0); - } else { - fFastBounds.set(fPts.begin(), fPts.count()); - } + compute_fast_bounds(&fFastBounds, fPts); } -#ifdef SK_DEBUG - else { // check that our cache is correct - SkRect r; - if (fPts.count() <= 1) { // we ignore just 1 point (moveto) - r.set(0, 0, 0, 0); - } else { - r.set(fPts.begin(), fPts.count()); - } - SkASSERT(r == fFastBounds); - } -#endif - *bounds = fFastBounds; } @@ -286,13 +327,15 @@ void SkPath::close() { } /////////////////////////////////////////////////////////////////////////////// - + void SkPath::addRect(const SkRect& rect, Direction dir) { this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir); } void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, Direction dir) { + SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom); + this->incReserve(5); this->moveTo(left, top); @@ -312,6 +355,8 @@ void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right, void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, Direction dir) { + SkAutoPathBoundsUpdate apbu(this, rect); + SkScalar w = rect.width(); SkScalar halfW = SkScalarHalf(w); SkScalar h = rect.height(); @@ -395,7 +440,7 @@ void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, static void add_corner_arc(SkPath* path, const SkRect& rect, SkScalar rx, SkScalar ry, int startAngle, - bool ccw, bool forceMoveTo = false) { + SkPath::Direction dir, bool forceMoveTo) { rx = SkMinScalar(SkScalarHalf(rect.width()), rx); ry = SkMinScalar(SkScalarHalf(rect.height()), ry); @@ -416,7 +461,7 @@ static void add_corner_arc(SkPath* path, const SkRect& rect, SkScalar start = SkIntToScalar(startAngle); SkScalar sweep = SkIntToScalar(90); - if (ccw) { + if (SkPath::kCCW_Direction == dir) { start += sweep; sweep = -sweep; } @@ -426,26 +471,30 @@ static void add_corner_arc(SkPath* path, const SkRect& rect, void SkPath::addRoundRect(const SkRect& rect, const SkScalar rad[], Direction dir) { + SkAutoPathBoundsUpdate apbu(this, rect); if (kCW_Direction == dir) { - add_corner_arc(this, rect, rad[0], rad[1], 180, false, true); - add_corner_arc(this, rect, rad[2], rad[3], 270, false); - add_corner_arc(this, rect, rad[4], rad[5], 0, false); - add_corner_arc(this, rect, rad[6], rad[7], 90, false); + add_corner_arc(this, rect, rad[0], rad[1], 180, dir, true); + add_corner_arc(this, rect, rad[2], rad[3], 270, dir, false); + add_corner_arc(this, rect, rad[4], rad[5], 0, dir, false); + add_corner_arc(this, rect, rad[6], rad[7], 90, dir, false); } else { - add_corner_arc(this, rect, rad[0], rad[1], 180, true, true); - add_corner_arc(this, rect, rad[6], rad[7], 90, true); - add_corner_arc(this, rect, rad[4], rad[5], 0, true); - add_corner_arc(this, rect, rad[2], rad[3], 270, true); + add_corner_arc(this, rect, rad[0], rad[1], 180, dir, true); + add_corner_arc(this, rect, rad[6], rad[7], 90, dir, false); + add_corner_arc(this, rect, rad[4], rad[5], 0, dir, false); + add_corner_arc(this, rect, rad[2], rad[3], 270, dir, false); } + this->close(); } void SkPath::addOval(const SkRect& oval, Direction dir) { + SkAutoPathBoundsUpdate apbu(this, oval); + SkScalar cx = oval.centerX(); SkScalar cy = oval.centerY(); SkScalar rx = SkScalarHalf(oval.width()); SkScalar ry = SkScalarHalf(oval.height()); -#if 1 // these seem faster than using quads (1/2 the number of edges) +#if 0 // these seem faster than using quads (1/2 the number of edges) SkScalar sx = SkScalarMul(rx, CUBIC_ARC_FACTOR); SkScalar sy = SkScalarMul(ry, CUBIC_ARC_FACTOR); @@ -468,7 +517,7 @@ void SkPath::addOval(const SkRect& oval, Direction dir) { SkScalar mx = SkScalarMul(rx, SK_ScalarRoot2Over2); SkScalar my = SkScalarMul(ry, SK_ScalarRoot2Over2); - this->incReserve(16); + this->incReserve(17); // 8 quads + close this->moveTo(cx + rx, cy); if (dir == kCCW_Direction) { this->quadTo(cx + rx, cy - sy, cx + mx, cy - my); @@ -547,7 +596,7 @@ void SkPath::addArc(const SkRect& oval, SkScalar startAngle, if (oval.isEmpty() || 0 == sweepAngle) { return; } - + const SkScalar kFullCircleAngle = SkIntToScalar(360); if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) { @@ -792,6 +841,7 @@ static void subdivide_cubic_to(SkPath* path, const SkPoint pts[4], } void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const { + SkDEBUGCODE(this->validate();) if (dst == NULL) { dst = (SkPath*)this; } @@ -846,6 +896,7 @@ void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const { dst->fFillType = fFillType; } matrix.mapPoints(dst->fPts.begin(), fPts.begin(), fPts.count()); + SkDEBUGCODE(dst->validate();) } } @@ -1211,11 +1262,18 @@ void SkPath::toString(SkString* str) const { void SkPath::validate() const { SkASSERT(this != NULL); SkASSERT((fFillType & ~3) == 0); - if (!fFastBoundsIsDirty) { - SkASSERT(fFastBounds.width() >= 0 && fFastBounds.height() >= 0); - } fPts.validate(); fVerbs.validate(); + + if (!fFastBoundsIsDirty) { + SkRect bounds; + compute_fast_bounds(&bounds, fPts); + // can't call contains(), since it returns false if the rect is empty + SkASSERT(fFastBounds.fLeft <= bounds.fLeft); + SkASSERT(fFastBounds.fTop <= bounds.fTop); + SkASSERT(fFastBounds.fRight >= bounds.fRight); + SkASSERT(fFastBounds.fBottom >= bounds.fBottom); + } } #if 0 // test to ensure that the iterator returns the same data as the path diff --git a/skia/sgl/SkPathEffect.cpp b/skia/sgl/SkPathEffect.cpp index 8321fca..2905895 100644 --- a/skia/sgl/SkPathEffect.cpp +++ b/skia/sgl/SkPathEffect.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkPathEffect.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkPathMeasure.cpp b/skia/sgl/SkPathMeasure.cpp index e877d0f..ec1510d 100644 --- a/skia/sgl/SkPathMeasure.cpp +++ b/skia/sgl/SkPathMeasure.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2008 Google Inc. + * Copyright (C) 2006-2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkPicture.cpp b/skia/sgl/SkPicture.cpp deleted file mode 100644 index 0847004..0000000 --- a/skia/sgl/SkPicture.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/* -** -** Copyright 2007, Google Inc. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#include "SkPictureFlat.h" -#include "SkPicturePlayback.h" -#include "SkPictureRecord.h" - -#include "SkCanvas.h" -#include "SkChunkAlloc.h" -#include "SkPicture.h" -#include "SkRegion.h" -#include "SkStream.h" -#include "SkTDArray.h" -#include "SkTSearch.h" -#include "SkTime.h" - -#include "SkReader32.h" -#include "SkWriter32.h" - -#define DUMP_BUFFER_SIZE 65536 - -//#define ENABLE_TIME_DRAW // dumps milliseconds for each draw - - -#ifdef SK_DEBUG -// enable SK_DEBUG_TRACE to trace DrawType elements when -// recorded and played back -// #define SK_DEBUG_TRACE -// enable SK_DEBUG_SIZE to see the size of picture components -// #define SK_DEBUG_SIZE -// enable SK_DEBUG_DUMP to see the contents of recorded elements -// #define SK_DEBUG_DUMP -// enable SK_DEBUG_VALIDATE to check internal structures for consistency -// #define SK_DEBUG_VALIDATE -#endif - -#if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP -const char* DrawTypeToString(DrawType drawType) { - switch (drawType) { - case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break; - case CLIP_PATH: return "CLIP_PATH"; - case CLIP_REGION: return "CLIP_REGION"; - case CLIP_RECT: return "CLIP_RECT"; - case CONCAT: return "CONCAT"; - case DRAW_BITMAP: return "DRAW_BITMAP"; - case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX"; - case DRAW_BITMAP_RECT: return "DRAW_BITMAP_RECT"; - case DRAW_PAINT: return "DRAW_PAINT"; - case DRAW_PATH: return "DRAW_PATH"; - case DRAW_PICTURE: return "DRAW_PICTURE"; - case DRAW_POINTS: return "DRAW_POINTS"; - case DRAW_POS_TEXT: return "DRAW_POS_TEXT"; - case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H"; - case DRAW_RECT_GENERAL: return "DRAW_RECT_GENERAL"; - case DRAW_RECT_SIMPLE: return "DRAW_RECT_SIMPLE"; - case DRAW_SPRITE: return "DRAW_SPRITE"; - case DRAW_TEXT: return "DRAW_TEXT"; - case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH"; - case RESTORE: return "RESTORE"; - case ROTATE: return "ROTATE"; - case SAVE: return "SAVE"; - case SAVE_LAYER: return "SAVE_LAYER"; - case SCALE: return "SCALE"; - case SKEW: return "SKEW"; - case TRANSLATE: return "TRANSLATE"; - default: - SkDebugf("DrawType error 0x%08x\n", drawType); - SkASSERT(0); - break; - } - SkASSERT(0); - return NULL; -} -#endif - -#ifdef SK_DEBUG_VALIDATE -static void validateMatrix(const SkMatrix* matrix) { - SkScalar scaleX = matrix->getScaleX(); - SkScalar scaleY = matrix->getScaleY(); - SkScalar skewX = matrix->getSkewX(); - SkScalar skewY = matrix->getSkewY(); - SkScalar perspX = matrix->getPerspX(); - SkScalar perspY = matrix->getPerspY(); - if (scaleX != 0 && skewX != 0) - SkDebugf("scaleX != 0 && skewX != 0\n"); - SkASSERT(scaleX == 0 || skewX == 0); - SkASSERT(scaleY == 0 || skewY == 0); - SkASSERT(perspX == 0); - SkASSERT(perspY == 0); -} -#endif - - -/////////////////////////////////////////////////////////////////////////////// - -SkPicture::SkPicture() { - fRecord = NULL; - fPlayback = NULL; - fWidth = fHeight = 0; -} - -SkPicture::SkPicture(const SkPicture& src) : SkRefCnt() { - fWidth = src.fWidth; - fHeight = src.fHeight; - fRecord = NULL; - - /* We want to copy the src's playback. However, if that hasn't been built - yet, we need to fake a call to endRecording() without actually calling - it (since it is destructive, and we don't want to change src). - */ - if (src.fPlayback) { - fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback)); - } else if (src.fRecord) { - // here we do a fake src.endRecording() - fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fRecord)); - } else { - fPlayback = NULL; - } -} - -SkPicture::~SkPicture() { - fRecord->safeUnref(); - SkDELETE(fPlayback); -} - -void SkPicture::swap(SkPicture& other) { - SkTSwap(fRecord, other.fRecord); - SkTSwap(fPlayback, other.fPlayback); - SkTSwap(fWidth, other.fWidth); - SkTSwap(fHeight, other.fHeight); -} - -/////////////////////////////////////////////////////////////////////////////// - -SkCanvas* SkPicture::beginRecording(int width, int height) { - if (fPlayback) { - SkDELETE(fPlayback); - fPlayback = NULL; - } - - if (NULL != fRecord) { - fRecord->unref(); - fRecord = NULL; - } - - fRecord = SkNEW(SkPictureRecord); - - fWidth = width; - fHeight = height; - - SkBitmap bm; - bm.setConfig(SkBitmap::kNo_Config, width, height); - fRecord->setBitmapDevice(bm); - - return fRecord; -} - -SkCanvas* SkPicture::getRecordingCanvas() const { - // will be null if we are not recording - return fRecord; -} - -void SkPicture::endRecording() { - if (NULL == fPlayback) { - if (NULL != fRecord) { - fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); - fRecord->unref(); - fRecord = NULL; - } - } - SkASSERT(NULL == fRecord); -} - -void SkPicture::draw(SkCanvas* surface) { - this->endRecording(); - if (fPlayback) { - fPlayback->draw(*surface); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -#include "SkStream.h" - -#define PICTURE_VERSION 1 - -SkPicture::SkPicture(SkStream* stream) : SkRefCnt() { - if (stream->readU32() != PICTURE_VERSION) { - sk_throw(); - } - - fWidth = stream->readU32(); - fHeight = stream->readU32(); - - fRecord = NULL; - fPlayback = NULL; - - if (stream->readBool()) { - fPlayback = SkNEW_ARGS(SkPicturePlayback, (stream)); - } -} - -void SkPicture::serialize(SkWStream* stream) const { - SkPicturePlayback* playback = fPlayback; - - if (NULL == playback && fRecord) { - playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord)); - } - - stream->write32(PICTURE_VERSION); - stream->write32(fWidth); - stream->write32(fHeight); - if (playback) { - stream->writeBool(true); - playback->serialize(stream); - // delete playback if it is a local version (i.e. cons'd up just now) - if (playback != fPlayback) { - SkDELETE(playback); - } - } else { - stream->writeBool(false); - } -} - diff --git a/skia/sgl/SkProcSpriteBlitter.cpp b/skia/sgl/SkProcSpriteBlitter.cpp index 822c218..f727581e 100644 --- a/skia/sgl/SkProcSpriteBlitter.cpp +++ b/skia/sgl/SkProcSpriteBlitter.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkProcSpriteBlitter.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkRasterizer.cpp b/skia/sgl/SkRasterizer.cpp index 8a46bad..f1d087d 100644 --- a/skia/sgl/SkRasterizer.cpp +++ b/skia/sgl/SkRasterizer.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkRasterizer.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkRefCnt.cpp b/skia/sgl/SkRefCnt.cpp index 2f0babc..fea1005 100644 --- a/skia/sgl/SkRefCnt.cpp +++ b/skia/sgl/SkRefCnt.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkRefCnt.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkRegion_path.cpp b/skia/sgl/SkRegion_path.cpp index 11e19b9..d00baf9 100644 --- a/skia/sgl/SkRegion_path.cpp +++ b/skia/sgl/SkRegion_path.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkRegion_path.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -25,7 +25,8 @@ class SkRgnBuilder : public SkBlitter { public: virtual ~SkRgnBuilder(); - void init(int maxHeight, int maxTransitions); + // returns true if it could allocate the working storage needed + bool init(int maxHeight, int maxTransitions); void done() { if (fCurrScanline != NULL) { @@ -96,15 +97,33 @@ SkRgnBuilder::~SkRgnBuilder() { sk_free(fStorage); } -void SkRgnBuilder::init(int maxHeight, int maxTransitions) { - int count = maxHeight * (3 + maxTransitions); +bool SkRgnBuilder::init(int maxHeight, int maxTransitions) { + if ((maxHeight | maxTransitions) < 0) { + return false; + } + + Sk64 count, size; + + // compute the count with +1 and +3 slop for the working buffer + count.setMul(maxHeight + 1, 3 + maxTransitions); + if (!count.is32() || count.isNeg()) { + return false; + } + fStorageCount = count.get32(); - // add maxTransitions to have slop for working buffer - fStorageCount = count + 3 + maxTransitions; - fStorage = (SkRegion::RunType*)sk_malloc_throw(fStorageCount * sizeof(SkRegion::RunType)); + size.setMul(fStorageCount, sizeof(SkRegion::RunType)); + if (!size.is32() || size.isNeg()) { + return false; + } + + fStorage = (SkRegion::RunType*)sk_malloc_flags(size.get32(), 0); + if (NULL == fStorage) { + return false; + } fCurrScanline = NULL; // signal empty collection fPrevScanline = NULL; // signal first scanline + return true; } void SkRgnBuilder::blitH(int x, int y, int width) { @@ -275,7 +294,11 @@ bool SkRegion::setPath(const SkPath& path, const SkRegion& clip) { SkRgnBuilder builder; - builder.init(bot - top, SkMax32(pathTransitions, clipTransitions)); + if (!builder.init(bot - top, SkMax32(pathTransitions, clipTransitions))) { + // can't allocate working space, so return false + return this->setEmpty(); + } + SkScan::FillPath(path, clip, &builder); builder.done(); diff --git a/skia/sgl/SkScalerContext.cpp b/skia/sgl/SkScalerContext.cpp index 0289312..854c4de 100644 --- a/skia/sgl/SkScalerContext.cpp +++ b/skia/sgl/SkScalerContext.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkScalerContext.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -182,6 +182,17 @@ SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) const { return ctx; } +static int plus_minus_pin(int value, int max) { + SkASSERT(max >= 0); + + if (value > max) { + value = max; + } else if (value < -max) { + value = -max; + } + return value; +} + void SkScalerContext::getAdvance(SkGlyph* glyph) { // mark us as just having a valid advance glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE; @@ -384,18 +395,19 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) { // check to see if we should filter the alpha channel - if (fRec.fMaskFormat != SkMask::kBW_Format && + if (NULL == fMaskFilter && + fRec.fMaskFormat != SkMask::kBW_Format && (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0) { const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable; if (NULL != table) { - uint8_t* dst = (uint8_t*)glyph->fImage; - unsigned rowBytes = glyph->rowBytes(); + uint8_t* dst = (uint8_t*)origGlyph.fImage; + unsigned rowBytes = origGlyph.rowBytes(); - for (int y = glyph->fHeight - 1; y >= 0; --y) + for (int y = origGlyph.fHeight - 1; y >= 0; --y) { - for (int x = glyph->fWidth - 1; x >= 0; --x) + for (int x = origGlyph.fWidth - 1; x >= 0; --x) dst[x] = table[dst[x]]; dst += rowBytes; } diff --git a/skia/sgl/SkScan.cpp b/skia/sgl/SkScan.cpp index 1d80bb1..013b0ea 100644 --- a/skia/sgl/SkScan.cpp +++ b/skia/sgl/SkScan.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkScan.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -65,10 +65,10 @@ void SkScan::FillXRect(const SkXRect& xr, const SkRegion* clip, void SkScan::FillRect(const SkRect& r, const SkRegion* clip, SkBlitter* blitter) { - SkXRect xr; + SkIRect ir; - XRect_set(&xr, r); - SkScan::FillXRect(xr, clip, blitter); + r.round(&ir); + SkScan::FillIRect(ir, clip, blitter); } #endif diff --git a/skia/sgl/SkScan.h b/skia/sgl/SkScan.h index f5b12fb..379c016 100644 --- a/skia/sgl/SkScan.h +++ b/skia/sgl/SkScan.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkScan.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -83,7 +83,7 @@ public: from int to SkFixed. Does not check for overflow if the src coordinates exceed 32K */ -static inline void XRect_set(SkXRect* xr, const SkIRect& src) { +static void XRect_set(SkXRect* xr, const SkIRect& src) { xr->fLeft = SkIntToFixed(src.fLeft); xr->fTop = SkIntToFixed(src.fTop); xr->fRight = SkIntToFixed(src.fRight); @@ -94,7 +94,7 @@ static inline void XRect_set(SkXRect* xr, const SkIRect& src) { from SkScalar to SkFixed. Does not check for overflow if the src coordinates exceed 32K */ -static inline void XRect_set(SkXRect* xr, const SkRect& src) { +static void XRect_set(SkXRect* xr, const SkRect& src) { xr->fLeft = SkScalarToFixed(src.fLeft); xr->fTop = SkScalarToFixed(src.fTop); xr->fRight = SkScalarToFixed(src.fRight); @@ -103,7 +103,7 @@ static inline void XRect_set(SkXRect* xr, const SkRect& src) { /** Round the SkXRect coordinates, and store the result in the SkIRect. */ -static inline void XRect_round(const SkXRect& xr, SkIRect* dst) { +static void XRect_round(const SkXRect& xr, SkIRect* dst) { dst->fLeft = SkFixedRound(xr.fLeft); dst->fTop = SkFixedRound(xr.fTop); dst->fRight = SkFixedRound(xr.fRight); @@ -113,7 +113,7 @@ static inline void XRect_round(const SkXRect& xr, SkIRect* dst) { /** Round the SkXRect coordinates out (i.e. use floor for left/top, and ceiling for right/bottom), and store the result in the SkIRect. */ -static inline void XRect_roundOut(const SkXRect& xr, SkIRect* dst) { +static void XRect_roundOut(const SkXRect& xr, SkIRect* dst) { dst->fLeft = SkFixedFloor(xr.fLeft); dst->fTop = SkFixedFloor(xr.fTop); dst->fRight = SkFixedCeil(xr.fRight); diff --git a/skia/sgl/SkScanPriv.h b/skia/sgl/SkScanPriv.h index de7e3e7..43dfdef 100644 --- a/skia/sgl/SkScanPriv.h +++ b/skia/sgl/SkScanPriv.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkScanPriv.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkScan_AntiPath.cpp b/skia/sgl/SkScan_AntiPath.cpp index b603f15..9cdeeaa 100644 --- a/skia/sgl/SkScan_AntiPath.cpp +++ b/skia/sgl/SkScan_AntiPath.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkScan_AntiPath.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkScan_Antihair.cpp b/skia/sgl/SkScan_Antihair.cpp index ca36739..04e4690 100644 --- a/skia/sgl/SkScan_Antihair.cpp +++ b/skia/sgl/SkScan_Antihair.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkScan_Antihair.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -23,6 +23,12 @@ #define HLINE_STACK_BUFFER 100 +static inline int SmallDot6Scale(int value, int dot6) { + SkASSERT((int16_t)value == value); + SkASSERT((unsigned)dot6 <= 64); + return SkMulS16(value, dot6) >> 6; +} + //#define TEST_GAMMA #ifdef TEST_GAMMA @@ -52,8 +58,9 @@ #define ApplyGamma(table, alpha) SkToU8(alpha) #endif +/////////////////////////////////////////////////////////////////////////////// -static void call_hline_blitter(SkBlitter* blitter, int x, int y, int count, uint8_t alpha) +static void call_hline_blitter(SkBlitter* blitter, int x, int y, int count, U8CPU alpha) { SkASSERT(count > 0); @@ -74,7 +81,7 @@ static void call_hline_blitter(SkBlitter* blitter, int x, int y, int count, uint } while (count > 0); } -static void hline(int x, int stopx, SkFixed fy, SkFixed /*slope*/, SkBlitter* blitter) +static SkFixed hline(int x, int stopx, SkFixed fy, SkFixed /*slope*/, SkBlitter* blitter, int mod64) { SkASSERT(x < stopx); int count = stopx - x; @@ -84,16 +91,21 @@ static void hline(int x, int stopx, SkFixed fy, SkFixed /*slope*/, SkBlitter* bl uint8_t a = (uint8_t)(fy >> 8); // lower line - if (a) - call_hline_blitter(blitter, x, y, count, a); + unsigned ma = SmallDot6Scale(a, mod64); + if (ma) { + call_hline_blitter(blitter, x, y, count, ma); + } // upper line - a = (uint8_t)(255 - a); - if (a) - call_hline_blitter(blitter, x, y - 1, count, a); + ma = SmallDot6Scale(255 - a, mod64); + if (ma) { + call_hline_blitter(blitter, x, y - 1, count, ma); + } + + return fy - SK_Fixed1/2; } -static void horish(int x, int stopx, SkFixed fy, SkFixed dy, SkBlitter* blitter) +static SkFixed horish(int x, int stopx, SkFixed fy, SkFixed dy, SkBlitter* blitter, int mod64) { SkASSERT(x < stopx); @@ -110,19 +122,19 @@ static void horish(int x, int stopx, SkFixed fy, SkFixed dy, SkBlitter* blitter) do { int lower_y = fy >> 16; uint8_t a = (uint8_t)(fy >> 8); - - if (a) + unsigned ma = SmallDot6Scale(a, mod64); + if (ma) { - aa[0] = ApplyGamma(gamma, a); + aa[0] = ApplyGamma(gamma, ma); blitter->blitAntiH(x, lower_y, aa, runs); // the clipping blitters might edit runs, but should not affect us SkASSERT(runs[0] == 1); SkASSERT(runs[1] == 0); } - a = (uint8_t)(255 - a); - if (a) + ma = SmallDot6Scale(255 - a, mod64); + if (ma) { - aa[0] = ApplyGamma(gamma, a); + aa[0] = ApplyGamma(gamma, ma); blitter->blitAntiH(x, lower_y - 1, aa, runs); // the clipping blitters might edit runs, but should not affect us SkASSERT(runs[0] == 1); @@ -130,9 +142,11 @@ static void horish(int x, int stopx, SkFixed fy, SkFixed dy, SkBlitter* blitter) } fy += dy; } while (++x < stopx); + + return fy - SK_Fixed1/2; } -static void vline(int y, int stopy, SkFixed fx, SkFixed /*slope*/, SkBlitter* blitter) +static SkFixed vline(int y, int stopy, SkFixed fx, SkFixed /*slope*/, SkBlitter* blitter, int mod64) { SkASSERT(y < stopy); fx += SK_Fixed1/2; @@ -140,14 +154,17 @@ static void vline(int y, int stopy, SkFixed fx, SkFixed /*slope*/, SkBlitter* bl int x = fx >> 16; int a = (uint8_t)(fx >> 8); - if (a) - blitter->blitV(x, y, stopy - y, ApplyGamma(gGammaTable, a)); - a = 255 - a; - if (a) - blitter->blitV(x - 1, y, stopy - y, ApplyGamma(gGammaTable, a)); + unsigned ma = SmallDot6Scale(a, mod64); + if (ma) + blitter->blitV(x, y, stopy - y, ApplyGamma(gGammaTable, ma)); + ma = SmallDot6Scale(255 - a, mod64); + if (ma) + blitter->blitV(x - 1, y, stopy - y, ApplyGamma(gGammaTable, ma)); + + return fx - SK_Fixed1/2; } -static void vertish(int y, int stopy, SkFixed fx, SkFixed dx, SkBlitter* blitter) +static SkFixed vertish(int y, int stopy, SkFixed fx, SkFixed dx, SkBlitter* blitter, int mod64) { SkASSERT(y < stopy); #ifdef TEST_GAMMA @@ -164,8 +181,8 @@ static void vertish(int y, int stopy, SkFixed fx, SkFixed dx, SkBlitter* blitter int x = fx >> 16; uint8_t a = (uint8_t)(fx >> 8); - aa[0] = ApplyGamma(gamma, 255 - a); - aa[1] = ApplyGamma(gamma, a); + aa[0] = ApplyGamma(gamma, SmallDot6Scale(255 - a, mod64)); + aa[1] = ApplyGamma(gamma, SmallDot6Scale(a, mod64)); // the clippng blitters might overwrite this guy, so we have to reset it each time runs[1] = 1; blitter->blitAntiH(x - 1, y, aa, runs); @@ -174,9 +191,11 @@ static void vertish(int y, int stopy, SkFixed fx, SkFixed dx, SkBlitter* blitter SkASSERT(runs[2] == 0); fx += dx; } while (++y < stopy); + + return fx - SK_Fixed1/2; } -typedef void (*LineProc)(int istart, int istop, SkFixed fstart, SkFixed slope, SkBlitter*); +typedef SkFixed (*LineProc)(int istart, int istop, SkFixed fstart, SkFixed slope, SkBlitter*, int); static inline SkFixed fastfixdiv(SkFDot6 a, SkFDot6 b) { @@ -184,11 +203,6 @@ static inline SkFixed fastfixdiv(SkFDot6 a, SkFDot6 b) SkASSERT(b != 0); return (a << 16) / b; } -static inline SkFDot6 fastfixmul(SkFixed fixed, SkFDot6 b) -{ - SkASSERT(SkAbs32(fixed) <= SK_Fixed1 && SkAbs32(b) <= SkIntToFDot6(511)); - return (fixed * b + 0x8000) >> 16; -} static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1, const SkIRect* clip, SkBlitter* blitter) @@ -205,35 +219,40 @@ static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1, return; } + int scaleStart, scaleStop; int istart, istop; SkFixed fstart, slope; LineProc proc; if (SkAbs32(x1 - x0) > SkAbs32(y1 - y0)) // mostly horizontal { - if (x0 > x1) // we want to go left-to-right - { + if (x0 > x1) { // we want to go left-to-right SkTSwap<SkFDot6>(x0, x1); SkTSwap<SkFDot6>(y0, y1); } - istart = SkFDot6Round(x0); - istop = SkFDot6Round(x1); - if (istart == istop) // too short to draw - return; - if (y0 == y1) // completely horizontal, take fast case - { + istart = SkFDot6Floor(x0); + istop = SkFDot6Ceil(x1); + fstart = SkFDot6ToFixed(y0); + if (y0 == y1) { // completely horizontal, take fast case slope = 0; - fstart = SkFDot6ToFixed(y0); proc = hline; - } - else - { + } else { slope = fastfixdiv(y1 - y0, x1 - x0); SkASSERT(slope >= -SK_Fixed1 && slope <= SK_Fixed1); - fstart = SkFDot6ToFixed(y0 + fastfixmul(slope, (32 - x0) & 63)); + fstart += (slope * (32 - (x0 & 63)) + 32) >> 6; proc = horish; } + + SkASSERT(istop > istart); + if (istop - istart == 1) { + scaleStart = x1 - x0; + SkASSERT(scaleStart >= 0 && scaleStart <= 64); + scaleStop = 0; + } else { + scaleStart = 64 - (x0 & 63); + scaleStop = x1 & 63; + } if (clip) { @@ -243,12 +262,16 @@ static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1, { fstart += slope * (clip->fLeft - istart); istart = clip->fLeft; + scaleStart = 64; } - if (istop > clip->fRight) + if (istop > clip->fRight) { istop = clip->fRight; + scaleStop = 64; + } SkASSERT(istart <= istop); if (istart == istop) return; + // now test if our Y values are completely inside the clip int top, bottom; if (slope >= 0) // T2B @@ -274,25 +297,36 @@ static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1, SkTSwap<SkFDot6>(x0, x1); SkTSwap<SkFDot6>(y0, y1); } - istart = SkFDot6Round(y0); - istop = SkFDot6Round(y1); - if (istart == istop) // too short to draw - return; + istart = SkFDot6Floor(y0); + istop = SkFDot6Ceil(y1); + fstart = SkFDot6ToFixed(x0); if (x0 == x1) { + if (y0 == y1) { // are we zero length? + return; // nothing to do + } slope = 0; - fstart = SkFDot6ToFixed(x0); proc = vline; } else { slope = fastfixdiv(x1 - x0, y1 - y0); SkASSERT(slope <= SK_Fixed1 && slope >= -SK_Fixed1); - fstart = SkFDot6ToFixed(x0 + fastfixmul(slope, (32 - y0) & 63)); + fstart += (slope * (32 - (y0 & 63)) + 32) >> 6; proc = vertish; } + SkASSERT(istop > istart); + if (istop - istart == 1) { + scaleStart = y1 - y0; + SkASSERT(scaleStart >= 0 && scaleStart <= 64); + scaleStop = 0; + } else { + scaleStart = 64 - (y0 & 63); + scaleStop = y1 & 63; + } + if (clip) { if (istart >= clip->fBottom || istop <= clip->fTop) @@ -301,12 +335,16 @@ static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1, { fstart += slope * (clip->fTop - istart); istart = clip->fTop; + scaleStart = 64; } - if (istop > clip->fBottom) + if (istop > clip->fBottom) { istop = clip->fBottom; + scaleStop = 64; + } SkASSERT(istart <= istop); if (istart == istop) return; + // now test if our X values are completely inside the clip int left, right; if (slope >= 0) // L2R @@ -332,7 +370,16 @@ static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1, rectClipper.init(blitter, *clip); blitter = &rectClipper; } - proc(istart, istop, fstart, slope, blitter); + + fstart = proc(istart, istart + 1, fstart, slope, blitter, scaleStart); + istart += 1; + int fullSpans = istop - istart - 1; + if (fullSpans > 0) { + fstart = proc(istart, istart + fullSpans, fstart, slope, blitter, 64); + } + if (scaleStop > 0) { + proc(istop - 1, istop, fstart, slope, blitter, scaleStop); + } } void SkScan::AntiHairLine(const SkPoint& pt0, const SkPoint& pt1, @@ -360,10 +407,10 @@ void SkScan::AntiHairLine(const SkPoint& pt0, const SkPoint& pt1, SkFDot6 bottom = SkMax32(y0, y1); SkIRect ir; - ir.set( SkFDot6Round(left) - 1, - SkFDot6Round(top) - 1, - SkFDot6Round(right) + 1, - SkFDot6Round(bottom) + 1); + ir.set( SkFDot6Floor(left) - 1, + SkFDot6Floor(top) - 1, + SkFDot6Ceil(right) + 1, + SkFDot6Ceil(bottom) + 1); if (clip->quickReject(ir)) return; @@ -536,12 +583,61 @@ void SkScan::AntiFillXRect(const SkXRect& xr, const SkRegion* clip, #ifdef SK_SCALAR_IS_FLOAT -void SkScan::AntiFillRect(const SkRect& r, const SkRegion* clip, - SkBlitter* blitter) { +/* This guy takes a float-rect, but with the key improvement that it has + already been clipped, so we know that it is safe to convert it into a + XRect (fixedpoint), as it won't overflow. +*/ +static void antifillrect(const SkRect& r, SkBlitter* blitter) { SkXRect xr; XRect_set(&xr, r); - SkScan::AntiFillXRect(xr, clip, blitter); + antifillrect(xr, blitter); +} + +/* We repeat the clipping logic of AntiFillXRect because the float rect might + overflow if we blindly converted it to an XRect. This sucks that we have to + repeat the clipping logic, but I don't see how to share the code/logic. + + We clip r (as needed) into one or more (smaller) float rects, and then pass + those to our version of antifillrect, which converts it into an XRect and + then calls the blit. +*/ +void SkScan::AntiFillRect(const SkRect& r, const SkRegion* clip, + SkBlitter* blitter) { + if (clip) { + SkIRect outerBounds; + r.roundOut(&outerBounds); + + if (clip->isRect()) { + const SkIRect& clipBounds = clip->getBounds(); + + if (clipBounds.contains(outerBounds)) { + antifillrect(r, blitter); + } else { + SkRect tmpR; + // this keeps our original edges fractional + tmpR.set(clipBounds); + if (tmpR.intersect(r)) { + antifillrect(tmpR, blitter); + } + } + } else { + SkRegion::Cliperator clipper(*clip, outerBounds); + const SkIRect& rr = clipper.rect(); + + while (!clipper.done()) { + SkRect tmpR; + // this keeps our original edges fractional + tmpR.set(rr); + if (tmpR.intersect(r)) { + antifillrect(tmpR, blitter); + } + clipper.next(); + } + } + } else { + antifillrect(r, blitter); + } } #endif diff --git a/skia/sgl/SkScan_Hairline.cpp b/skia/sgl/SkScan_Hairline.cpp index 5312f25..6a66754 100644 --- a/skia/sgl/SkScan_Hairline.cpp +++ b/skia/sgl/SkScan_Hairline.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkScan_Hairline.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -95,7 +95,7 @@ void SkScan::HairLine(const SkPoint& pt0, const SkPoint& pt1, const SkRegion* cl return; SkFixed slope = SkFixedDiv(dy, dx); - SkFixed startY = SkFDot6ToFixed(y0 + SkFixedMul(slope, (32 - x0) & 63)); + SkFixed startY = SkFDot6ToFixed(y0) + (slope * ((32 - x0) & 63) >> 6); horiline(ix0, ix1, startY, slope, blitter); } @@ -112,7 +112,7 @@ void SkScan::HairLine(const SkPoint& pt0, const SkPoint& pt1, const SkRegion* cl return; SkFixed slope = SkFixedDiv(dx, dy); - SkFixed startX = SkFDot6ToFixed(x0 + SkFixedMul(slope, (32 - y0) & 63)); + SkFixed startX = SkFDot6ToFixed(x0) + (slope * ((32 - y0) & 63) >> 6); vertline(iy0, iy1, startX, slope, blitter); } @@ -165,6 +165,25 @@ static bool quad_too_curvy(const SkPoint pts[3]) return true; } +static int compute_int_quad_dist(const SkPoint pts[3]) { + // compute the vector between the control point ([1]) and the middle of the + // line connecting the start and end ([0] and [2]) + SkScalar dx = SkScalarHalf(pts[0].fX + pts[2].fX) - pts[1].fX; + SkScalar dy = SkScalarHalf(pts[0].fY + pts[2].fY) - pts[1].fY; + // we want everyone to be positive + dx = SkScalarAbs(dx); + dy = SkScalarAbs(dy); + // convert to whole pixel values (use ceiling to be conservative) + int idx = SkScalarCeil(dx); + int idy = SkScalarCeil(dy); + // use the cheap approx for distance + if (idx > idy) { + return idx + (idy >> 1); + } else { + return idy + (idx >> 1); + } +} + static void hairquad(const SkPoint pts[3], const SkRegion* clip, SkBlitter* blitter, int level, void (*lineproc)(const SkPoint&, const SkPoint&, const SkRegion* clip, SkBlitter*)) { @@ -180,8 +199,19 @@ static void hairquad(const SkPoint pts[3], const SkRegion* clip, SkBlitter* blit else lineproc(pts[0], pts[2], clip, blitter); #else - lineproc(pts[0], pts[1], clip, blitter); - lineproc(pts[1], pts[2], clip, blitter); + int count = 1 << level; + const SkScalar dt = SkFixedToScalar(SK_Fixed1 >> level); + SkScalar t = dt; + SkPoint prevPt = pts[0]; + for (int i = 1; i < count; i++) { + SkPoint nextPt; + SkEvalQuadAt(pts, t, &nextPt); + lineproc(prevPt, nextPt, clip, blitter); + t += dt; + prevPt = nextPt; + } + // draw the last line explicitly to 1.0, in case t didn't match that exactly + lineproc(prevPt, pts[2], clip, blitter); #endif } @@ -244,9 +274,22 @@ static void hair_path(const SkPath& path, const SkRegion* clip, SkBlitter* blitt case SkPath::kLine_Verb: lineproc(pts[0], pts[1], clip, blitter); break; - case SkPath::kQuad_Verb: - hairquad(pts, clip, blitter, kMaxQuadSubdivideLevel, lineproc); + case SkPath::kQuad_Verb: { + int d = compute_int_quad_dist(pts); + /* quadratics approach the line connecting their start and end points + 4x closer with each subdivision, so we compute the number of + subdivisions to be the minimum need to get that distance to be less + than a pixel. + */ + int level = (33 - SkCLZ(d)) >> 1; +// SkDebugf("----- distance %d computedLevel %d\n", d, computedLevel); + // sanity check on level (from the previous version) + if (level > kMaxQuadSubdivideLevel) { + level = kMaxQuadSubdivideLevel; + } + hairquad(pts, clip, blitter, level, lineproc); break; + } case SkPath::kCubic_Verb: haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc); break; diff --git a/skia/sgl/SkScan_Path.cpp b/skia/sgl/SkScan_Path.cpp index 43a61bd..8b58991 100644 --- a/skia/sgl/SkScan_Path.cpp +++ b/skia/sgl/SkScan_Path.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkScan_Path.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -23,15 +23,15 @@ #include "SkRegion.h" #include "SkTemplates.h" -#define kEDGE_HEAD_Y SK_MinS16 -#define kEDGE_TAIL_Y SK_MaxS16 +#define kEDGE_HEAD_Y SK_MinS32 +#define kEDGE_TAIL_Y SK_MaxS32 #ifdef SK_DEBUG static void validate_sort(const SkEdge* edge) { int y = kEDGE_HEAD_Y; - while (edge->fFirstY != SK_MaxS16) + while (edge->fFirstY != SK_MaxS32) { edge->validate(); SkASSERT(y <= edge->fFirstY); @@ -368,7 +368,7 @@ extern "C" { valuea = edgea->fX; valueb = edgeb->fX; } - return valuea > valueb ? 1 : valuea < valueb ? -1 : 0; + return valuea - valueb; } } @@ -387,7 +387,6 @@ static SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last) return list[0]; } -#ifdef SK_DEBUG /* 'quick' computation of the max sized needed to allocated for our edgelist. */ @@ -423,7 +422,6 @@ static int worst_case_edge_count(const SkPath& path, size_t* storage) *storage = size; return edgeCount; } -#endif /* Much faster than worst_case_edge_count, but over estimates even more */ diff --git a/skia/sgl/SkShader.cpp b/skia/sgl/SkShader.cpp index 9a90959..dd9c859 100644 --- a/skia/sgl/SkShader.cpp +++ b/skia/sgl/SkShader.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkShader.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkSpriteBlitter.h b/skia/sgl/SkSpriteBlitter.h index 7447389..9f7764d 100644 --- a/skia/sgl/SkSpriteBlitter.h +++ b/skia/sgl/SkSpriteBlitter.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkSpriteBlitter.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkSpriteBlitterTemplate.h b/skia/sgl/SkSpriteBlitterTemplate.h index 267931e..2ab2b3a 100644 --- a/skia/sgl/SkSpriteBlitterTemplate.h +++ b/skia/sgl/SkSpriteBlitterTemplate.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkSpriteBlitterTemplate.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkSpriteBlitter_ARGB32.cpp b/skia/sgl/SkSpriteBlitter_ARGB32.cpp index ede7450..6addde7 100644 --- a/skia/sgl/SkSpriteBlitter_ARGB32.cpp +++ b/skia/sgl/SkSpriteBlitter_ARGB32.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkSpriteBlitter_ARGB32.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkSpriteBlitter_RGB16.cpp b/skia/sgl/SkSpriteBlitter_RGB16.cpp index 3ffea44..a158637 100644 --- a/skia/sgl/SkSpriteBlitter_RGB16.cpp +++ b/skia/sgl/SkSpriteBlitter_RGB16.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkSpriteBlitter_RGB16.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -24,12 +24,7 @@ #define D16_S32A_Opaque_Pixel(dst, sc) \ do { \ if (sc) { \ - unsigned sa = SkGetPackedA32(sc); \ - unsigned result = SkPixel32ToPixel16(sc); \ - if (sa != 0xFF) { \ - result += SkAlphaMulRGB16_ToU16(*dst, SkAlpha255To256(255 - sa)); \ - } \ - *dst = SkToU16(result); \ + *dst = SkSrcOver32To16(sc, *dst); \ } \ } while (0) diff --git a/skia/sgl/SkString.cpp b/skia/sgl/SkString.cpp index 839f5c4..c683e35 100644 --- a/skia/sgl/SkString.cpp +++ b/skia/sgl/SkString.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkString.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -107,7 +107,10 @@ char* SkStrAppendScalar(char string[], SkScalar value) const uint16_t* tens = gTens; x = SkFixedRound(frac * 10000); - SkASSERT(x < 10000); + SkASSERT(x <= 10000); + if (x == 10000) { + x -= 1; + } *string++ = '.'; do { unsigned powerOfTen = *tens++; diff --git a/skia/sgl/SkStroke.cpp b/skia/sgl/SkStroke.cpp index 530f0fa..86dff48 100644 --- a/skia/sgl/SkStroke.cpp +++ b/skia/sgl/SkStroke.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2008 Google Inc. + * Copyright (C) 2006-2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -528,15 +528,61 @@ void SkStroke::setJoin(SkPaint::Join join) { fJoin = SkToU8(join); } +/////////////////////////////////////////////////////////////////////////////// + +#ifdef SK_SCALAR_IS_FIXED + /* return non-zero if the path is too big, and should be shrunk to avoid + overflows during intermediate calculations. Note that we compute the + bounds for this. If we had a custom callback/walker for paths, we could + perhaps go faster by using that, and just perform the abs | in that + routine + */ + static int needs_to_shrink(const SkPath& path) { + SkRect r; + path.computeBounds(&r, SkPath::kFast_BoundsType); + SkFixed mask = SkAbs32(r.fLeft); + mask |= SkAbs32(r.fTop); + mask |= SkAbs32(r.fRight); + mask |= SkAbs32(r.fBottom); + // we need the top 3 bits clear (after abs) to avoid overflow + return mask >> 29; + } + + static void identity_proc(SkPoint pts[], int count) {} + static void shift_down_2_proc(SkPoint pts[], int count) { + for (int i = 0; i < count; i++) { + pts->fX >>= 2; + pts->fY >>= 2; + pts += 1; + } + } + #define APPLY_PROC(proc, pts, count) proc(pts, count) +#else // float does need any of this + #define APPLY_PROC(proc, pts, count) +#endif + void SkStroke::strokePath(const SkPath& src, SkPath* dst) const { SkASSERT(&src != NULL && dst != NULL); + SkScalar radius = SkScalarHalf(fWidth); + dst->reset(); - if (SkScalarHalf(fWidth) <= 0) { + if (radius <= 0) { return; } + +#ifdef SK_SCALAR_IS_FIXED + void (*proc)(SkPoint pts[], int count) = identity_proc; + if (needs_to_shrink(src)) { + proc = shift_down_2_proc; + radius >>= 2; + if (radius == 0) { + return; + } + } +#endif - SkPathStroker stroker(SkScalarHalf(fWidth), fMiterLimit, this->getCap(), + SkPathStroker stroker(radius, fMiterLimit, this->getCap(), this->getJoin()); SkPath::Iter iter(src, false); @@ -546,17 +592,21 @@ void SkStroke::strokePath(const SkPath& src, SkPath* dst) const { while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { switch (verb) { case SkPath::kMove_Verb: + APPLY_PROC(proc, &pts[0], 1); stroker.moveTo(pts[0]); break; case SkPath::kLine_Verb: + APPLY_PROC(proc, &pts[1], 1); stroker.lineTo(pts[1]); lastSegment = verb; break; case SkPath::kQuad_Verb: + APPLY_PROC(proc, &pts[1], 2); stroker.quadTo(pts[1], pts[2]); lastSegment = verb; break; case SkPath::kCubic_Verb: + APPLY_PROC(proc, &pts[1], 3); stroker.cubicTo(pts[1], pts[2], pts[3]); lastSegment = verb; break; @@ -569,6 +619,16 @@ void SkStroke::strokePath(const SkPath& src, SkPath* dst) const { } stroker.done(dst, lastSegment == SkPath::kLine_Verb); +#ifdef SK_SCALAR_IS_FIXED + // undo our previous down_shift + if (shift_down_2_proc == proc) { + // need a real shift methid on path. antialias paths could use this too + SkMatrix matrix; + matrix.setScale(SkIntToScalar(4), SkIntToScalar(4)); + dst->transform(matrix); + } +#endif + if (fDoFill) { dst->addPath(src); } diff --git a/skia/sgl/SkStrokerPriv.cpp b/skia/sgl/SkStrokerPriv.cpp index 28276cb..07833ca 100644 --- a/skia/sgl/SkStrokerPriv.cpp +++ b/skia/sgl/SkStrokerPriv.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkStrokerPriv.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkStrokerPriv.h b/skia/sgl/SkStrokerPriv.h index 1d1eb89..ecb9bde 100644 --- a/skia/sgl/SkStrokerPriv.h +++ b/skia/sgl/SkStrokerPriv.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkStrokerPriv.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkTSearch.cpp b/skia/sgl/SkTSearch.cpp index 3a1a7d4..bab348f 100644 --- a/skia/sgl/SkTSearch.cpp +++ b/skia/sgl/SkTSearch.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkTSearch.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkTSort.h b/skia/sgl/SkTSort.h index 660b689..fba49e2 100644 --- a/skia/sgl/SkTSort.h +++ b/skia/sgl/SkTSort.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkTSort.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkTemplatesPriv.h b/skia/sgl/SkTemplatesPriv.h index 91ecd51..b0a95a0 100644 --- a/skia/sgl/SkTemplatesPriv.h +++ b/skia/sgl/SkTemplatesPriv.h @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkTemplatesPriv.h ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/skia/sgl/SkUtils.cpp b/skia/sgl/SkUtils.cpp index 94834fd..4f5ba6ea 100644 --- a/skia/sgl/SkUtils.cpp +++ b/skia/sgl/SkUtils.cpp @@ -1,6 +1,6 @@ /* libs/graphics/sgl/SkUtils.cpp ** -** Copyright 2006, Google Inc. +** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -427,12 +427,10 @@ size_t SkUTF16_ToUTF8(const uint16_t utf16[], int numberOf16BitValues, char utf8 #include <stdlib.h> -#if 0 static int round_to_K(size_t bytes) { return (bytes + 512) >> 10; } -#endif SkAutoMemoryUsageProbe::SkAutoMemoryUsageProbe(const char label[]) : fLabel(label) diff --git a/skia/sgl/SkWriter32.cpp b/skia/sgl/SkWriter32.cpp index 819803f..61d0051 100644 --- a/skia/sgl/SkWriter32.cpp +++ b/skia/sgl/SkWriter32.cpp @@ -37,6 +37,15 @@ struct SkWriter32::Block { } }; +static size_t compute_block_size(size_t currSize, size_t minSize) +{ + if (currSize < minSize) + currSize = minSize; + + currSize += (currSize >> 1); + return SkAlign4(currSize); +} + /////////////////////////////////////////////////////////////////////////////// SkWriter32::~SkWriter32() diff --git a/skia/sgl/SkXfermode.cpp b/skia/sgl/SkXfermode.cpp index 6225e6e..e8a202d 100644 --- a/skia/sgl/SkXfermode.cpp +++ b/skia/sgl/SkXfermode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Google Inc. + * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,19 @@ static SkPMColor SkFourByteInterp(SkPMColor src, SkPMColor dst, U8CPU alpha) { return SkPackARGB32(a, r, g, b); } +// idea for higher precision blends in xfer procs (and slightly faster) +// see DstATop as a probable caller +static U8CPU mulmuldiv255round(U8CPU a, U8CPU b, U8CPU c, U8CPU d) { + SkASSERT(a <= 255); + SkASSERT(b <= 255); + SkASSERT(c <= 255); + SkASSERT(d <= 255); + unsigned prod = SkMulS16(a, b) + SkMulS16(c, d) + 128; + unsigned result = (prod + (prod >> 8)) >> 8; + SkASSERT(result <= 255); + return result; +} + /////////////////////////////////////////////////////////////////////////////// bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) { |