summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2013-12-18 16:25:41 +0000
committerTorne (Richard Coles) <torne@google.com>2013-12-18 16:25:41 +0000
commit13b628ac69a70ac0044585997f16633af83c353a (patch)
tree3c0229f3d6163ee2f43fb32a886cb15deb58227d
parentea135c1c1fb61ba5ff8063bdf74ffbd3c84f1942 (diff)
parent24df3e66d89fff6e91ba76a9fe1a4f1e7c413402 (diff)
downloadsrc-13b628ac69a70ac0044585997f16633af83c353a.tar.gz
Merge from Chromium at DEPS revision 240154
This commit was generated by merge_to_master.py. Change-Id: I46e962d43e6d822150c4556f33ed018d9f4225e3
-rw-r--r--animator/SkDrawBitmap.cpp9
-rw-r--r--animator/SkScript.cpp6
-rw-r--r--core/SkAdvancedTypefaceMetrics.cpp2
-rw-r--r--core/SkBBoxHierarchy.cpp11
-rw-r--r--core/SkBitmap.cpp122
-rw-r--r--core/SkBitmapDevice.cpp22
-rw-r--r--core/SkBitmapHeap.cpp3
-rw-r--r--core/SkBitmapProcShader.cpp31
-rw-r--r--core/SkBitmapProcState.cpp3
-rw-r--r--core/SkBlitter.cpp5
-rw-r--r--core/SkBlitter_A1.cpp50
-rw-r--r--core/SkCanvas.cpp4
-rw-r--r--core/SkColorFilter.cpp2
-rw-r--r--core/SkColorTable.cpp2
-rw-r--r--core/SkCoreBlitters.h16
-rw-r--r--core/SkData.cpp2
-rw-r--r--core/SkDataTable.cpp2
-rw-r--r--core/SkDevice.cpp2
-rw-r--r--core/SkDeviceProfile.cpp2
-rw-r--r--core/SkDiscardableMemory.h13
-rw-r--r--core/SkDrawLooper.cpp2
-rw-r--r--core/SkFlattenable.cpp2
-rw-r--r--core/SkFontHost.cpp4
-rw-r--r--core/SkGlyphCache.cpp4
-rw-r--r--core/SkGlyphCache.h2
-rw-r--r--core/SkImageFilter.cpp12
-rw-r--r--core/SkImageInfo.cpp29
-rw-r--r--core/SkMaskFilter.cpp2
-rw-r--r--core/SkMaskGamma.h7
-rw-r--r--core/SkMatrix.cpp64
-rw-r--r--core/SkOnce.h40
-rw-r--r--core/SkPaint.cpp12
-rw-r--r--core/SkPath.cpp57
-rw-r--r--core/SkPathEffect.cpp2
-rw-r--r--core/SkPathHeap.cpp2
-rw-r--r--core/SkPathRef.cpp55
-rw-r--r--core/SkPicture.cpp26
-rw-r--r--core/SkPictureFlat.cpp2
-rw-r--r--core/SkPicturePlayback.cpp13
-rw-r--r--core/SkPictureStateTree.cpp2
-rw-r--r--core/SkPixelRef.cpp30
-rw-r--r--core/SkPtrRecorder.cpp3
-rw-r--r--core/SkRTree.cpp2
-rw-r--r--core/SkRasterizer.cpp2
-rw-r--r--core/SkRefCnt.cpp13
-rw-r--r--core/SkScaledImageCache.cpp214
-rw-r--r--core/SkScaledImageCache.h38
-rw-r--r--core/SkScalerContext.cpp109
-rw-r--r--core/SkScalerContext.h57
-rw-r--r--core/SkShader.cpp2
-rw-r--r--core/SkStream.cpp9
-rw-r--r--core/SkString.cpp12
-rw-r--r--core/SkTypeface.cpp2
-rw-r--r--core/SkValidatingReadBuffer.cpp6
-rw-r--r--core/SkValidatingReadBuffer.h1
-rw-r--r--core/SkXfermode.cpp11
-rw-r--r--doc/SkDocument.cpp2
-rw-r--r--effects/SkBitmapAlphaThresholdShader.cpp2
-rw-r--r--effects/SkBitmapSource.cpp56
-rw-r--r--effects/SkBlurImageFilter.cpp4
-rw-r--r--effects/SkBlurMaskFilter.cpp16
-rwxr-xr-xeffects/SkColorFilterImageFilter.cpp3
-rw-r--r--effects/SkColorFilters.cpp6
-rw-r--r--effects/SkColorMatrixFilter.cpp6
-rw-r--r--effects/SkDropShadowImageFilter.cpp40
-rw-r--r--effects/SkEmbossMaskFilter.cpp16
-rw-r--r--effects/SkGpuBlurUtils.cpp4
-rw-r--r--effects/SkLayerDrawLooper.cpp2
-rw-r--r--effects/SkLightingImageFilter.cpp9
-rw-r--r--effects/SkMagnifierImageFilter.cpp20
-rw-r--r--effects/SkMatrixConvolutionImageFilter.cpp3
-rwxr-xr-xeffects/SkMergeImageFilter.cpp14
-rw-r--r--effects/SkMorphologyImageFilter.cpp6
-rw-r--r--effects/SkOffsetImageFilter.cpp3
-rw-r--r--effects/SkRectShaderImageFilter.cpp3
-rw-r--r--effects/SkTileImageFilter.cpp26
-rw-r--r--effects/SkTransparentShader.cpp3
-rw-r--r--effects/SkXfermodeImageFilter.cpp3
-rw-r--r--fonts/SkGScalerContext.cpp2
-rw-r--r--gpu/GrAARectRenderer.cpp2
-rwxr-xr-xgpu/GrAllocator.h33
-rw-r--r--gpu/GrBinHashKey.h74
-rwxr-xr-xgpu/GrBitmapTextContext.cpp5
-rw-r--r--gpu/GrClipMaskManager.cpp10
-rw-r--r--gpu/GrContext.cpp21
-rw-r--r--gpu/GrDrawTarget.cpp4
-rw-r--r--gpu/GrEffect.cpp4
-rw-r--r--gpu/GrGeometryBuffer.cpp10
-rw-r--r--gpu/GrOvalRenderer.cpp2
-rw-r--r--gpu/GrPath.cpp2
-rw-r--r--gpu/GrPathRenderer.cpp2
-rw-r--r--gpu/GrPathRendererChain.cpp2
-rw-r--r--gpu/GrPathUtils.cpp59
-rw-r--r--gpu/GrRenderTarget.cpp2
-rw-r--r--gpu/GrResource.cpp2
-rw-r--r--gpu/GrResourceCache.h67
-rw-r--r--gpu/GrStencilBuffer.cpp2
-rw-r--r--gpu/GrSurface.cpp2
-rw-r--r--gpu/GrTHashTable.h24
-rw-r--r--gpu/GrTextStrike.cpp51
-rw-r--r--gpu/GrTextStrike.h11
-rw-r--r--gpu/GrTextStrike_impl.h8
-rw-r--r--gpu/GrTexture.cpp2
-rw-r--r--gpu/SkGpuDevice.cpp113
-rw-r--r--gpu/SkGrFontScaler.cpp6
-rw-r--r--gpu/SkGrPixelRef.cpp17
-rw-r--r--gpu/effects/GrBicubicEffect.cpp27
-rw-r--r--gpu/effects/GrBicubicEffect.h48
-rw-r--r--gpu/effects/GrTextureDomain.cpp (renamed from gpu/effects/GrTextureDomainEffect.cpp)241
-rw-r--r--gpu/effects/GrTextureDomain.h169
-rw-r--r--gpu/effects/GrTextureDomainEffect.h89
-rw-r--r--gpu/effects/GrTextureStripAtlas.h17
-rw-r--r--gpu/gl/GrGLCaps.cpp2
-rw-r--r--gpu/gl/GrGLEffect.h1
-rw-r--r--gpu/gl/GrGLInterface.cpp2
-rw-r--r--gpu/gl/GrGLProgram.cpp2
-rw-r--r--gpu/gl/GrGLShaderBuilder.h19
-rw-r--r--gpu/gl/GrGLTexture.cpp2
-rw-r--r--gpu/gl/GrGpuGL.cpp25
-rw-r--r--gpu/gl/GrGpuGL_program.cpp2
-rw-r--r--gpu/gl/SkGLContextHelper.cpp2
-rw-r--r--gpu/gl/debug/GrGLCreateDebugInterface.cpp2
-rw-r--r--gpu/gl/win/GrGLCreateNativeInterface_win.cpp2
-rw-r--r--gpu/gl/win/SkNativeGLContext_win.cpp2
-rw-r--r--gpu/gr_unittests.cpp80
-rw-r--r--image/SkDataPixelRef.cpp4
-rw-r--r--image/SkDataPixelRef.h1
-rw-r--r--image/SkImage.cpp2
-rw-r--r--image/SkImagePriv.cpp50
-rw-r--r--image/SkImagePriv.h7
-rw-r--r--image/SkImage_Gpu.cpp2
-rw-r--r--image/SkSurface.cpp2
-rw-r--r--image/SkSurface_Gpu.cpp2
-rw-r--r--images/SkDecodingImageGenerator.cpp196
-rw-r--r--images/SkDecodingImageGenerator.h81
-rw-r--r--images/SkImageDecoder.cpp164
-rw-r--r--images/SkMovie.cpp2
-rw-r--r--lazy/SkBitmapFactory.cpp80
-rw-r--r--lazy/SkCachingPixelRef.cpp101
-rw-r--r--lazy/SkCachingPixelRef.h76
-rw-r--r--lazy/SkDiscardableMemoryPool.cpp203
-rw-r--r--lazy/SkDiscardableMemoryPool.h70
-rw-r--r--lazy/SkDiscardablePixelRef.cpp31
-rw-r--r--lazy/SkDiscardablePixelRef.h30
-rw-r--r--lazy/SkLazyCachingPixelRef.cpp61
-rw-r--r--lazy/SkLazyCachingPixelRef.h98
-rw-r--r--lazy/SkLazyPixelRef.cpp311
-rw-r--r--lazy/SkLazyPixelRef.h96
-rw-r--r--lazy/SkLruImageCache.cpp206
-rw-r--r--lazy/SkPurgeableImageCache.cpp160
-rw-r--r--opts/SkBlitMask_opts_arm.cpp27
-rw-r--r--opts/SkBlitMask_opts_arm_neon.cpp254
-rw-r--r--opts/SkBlitMask_opts_arm_neon.h16
-rw-r--r--opts/SkBlurImage_opts_neon.cpp101
-rw-r--r--opts/SkBlurImage_opts_neon.h13
-rw-r--r--opts/SkColor_opts_neon.h46
-rw-r--r--opts/SkXfermode_opts_arm.cpp10
-rw-r--r--opts/SkXfermode_opts_arm_neon.cpp174
-rw-r--r--opts/SkXfermode_opts_arm_neon.h6
-rw-r--r--opts/SkXfermode_opts_none.cpp8
-rw-r--r--opts/opts_check_arm.cpp17
-rw-r--r--pdf/SkPDFDevice.cpp56
-rw-r--r--pdf/SkPDFFont.cpp5
-rw-r--r--pdf/SkPDFFont.h2
-rw-r--r--pdf/SkPDFGraphicState.h2
-rw-r--r--pdf/SkPDFImage.cpp56
-rw-r--r--pdf/SkPDFPage.h2
-rw-r--r--pdf/SkPDFResourceDict.cpp2
-rw-r--r--pdf/SkPDFResourceDict.h1
-rw-r--r--pdf/SkPDFShader.cpp2
-rw-r--r--pdf/SkPDFStream.h1
-rw-r--r--pdf/SkPDFTypes.cpp10
-rw-r--r--ports/SkDebug_win.cpp2
-rw-r--r--ports/SkDiscardableMemory_ashmem.cpp114
-rw-r--r--ports/SkDiscardableMemory_none.cpp52
-rw-r--r--ports/SkFontConfigInterface_direct.cpp2
-rw-r--r--ports/SkFontHost_FreeType.cpp336
-rw-r--r--ports/SkFontHost_FreeType_common.cpp484
-rwxr-xr-xports/SkFontHost_mac.cpp8
-rw-r--r--ports/SkFontHost_win_dw.cpp91
-rw-r--r--ports/SkImageDecoder_empty.cpp6
-rw-r--r--text/SkTextLayout.cpp2
-rw-r--r--utils/SkBoundaryPatch.cpp2
-rw-r--r--utils/SkCanvasStack.cpp2
-rw-r--r--utils/SkDumpCanvas.cpp2
-rw-r--r--utils/SkLayer.cpp2
-rw-r--r--utils/SkUnitMappers.cpp2
-rw-r--r--utils/android/ashmem.h6
-rw-r--r--utils/debugger/SkDebugCanvas.cpp28
-rw-r--r--utils/debugger/SkDebugCanvas.h12
-rw-r--r--utils/debugger/SkObjectParser.cpp4
-rw-r--r--utils/win/SkAutoCoInitialize.cpp2
-rw-r--r--utils/win/SkIStream.cpp2
-rw-r--r--views/SkEventSink.cpp2
-rw-r--r--views/SkView.cpp3
-rw-r--r--views/animated/SkWidgetViews.cpp2
-rw-r--r--views/win/skia_win.cpp2
197 files changed, 3741 insertions, 2955 deletions
diff --git a/animator/SkDrawBitmap.cpp b/animator/SkDrawBitmap.cpp
index 568401d0..327e8136 100644
--- a/animator/SkDrawBitmap.cpp
+++ b/animator/SkDrawBitmap.cpp
@@ -75,11 +75,10 @@ void SkDrawBitmap::dump(SkAnimateMaker* maker) {
const char* formatName;
switch (format) {
case 0: formatName = "none"; break;
- case 1: formatName = "A1"; break;
- case 2: formatName = "A8"; break;
- case 3: formatName = "Index8"; break;
- case 4: formatName = "RGB16"; break;
- case 5: formatName = "RGB32"; break;
+ case 1: formatName = "A8"; break;
+ case 2: formatName = "Index8"; break;
+ case 3: formatName = "RGB16"; break;
+ case 4: formatName = "RGB32"; break;
}
SkDebugf("format=\"%s\" />\n", formatName);
}
diff --git a/animator/SkScript.cpp b/animator/SkScript.cpp
index c74b195f..934b0abe 100644
--- a/animator/SkScript.cpp
+++ b/animator/SkScript.cpp
@@ -1532,11 +1532,11 @@ bool SkScriptEngine::ConvertTo(SkScriptEngine* engine, SkDisplayTypes toType, Sk
SkString* strPtr = new SkString();
SkASSERT(engine);
engine->track(strPtr);
- if (type == SkType_Int)
+ if (type == SkType_Int) {
strPtr->appendS32(operand.fS32);
- else if (type == SkType_Displayable)
+ } else if (type == SkType_Displayable) {
SkASSERT(0); // must call through instance version instead of static version
- else {
+ } else {
if (type != SkType_Float) {
success = false;
break;
diff --git a/core/SkAdvancedTypefaceMetrics.cpp b/core/SkAdvancedTypefaceMetrics.cpp
index c7ed34df..ce64a42d 100644
--- a/core/SkAdvancedTypefaceMetrics.cpp
+++ b/core/SkAdvancedTypefaceMetrics.cpp
@@ -10,8 +10,6 @@
#include "SkAdvancedTypefaceMetrics.h"
#include "SkTypes.h"
-SK_DEFINE_INST_COUNT(SkAdvancedTypefaceMetrics)
-
#if defined(SK_BUILD_FOR_WIN)
#include <dwrite.h>
#endif
diff --git a/core/SkBBoxHierarchy.cpp b/core/SkBBoxHierarchy.cpp
deleted file mode 100644
index 5232fb7c..00000000
--- a/core/SkBBoxHierarchy.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkBBoxHierarchy.h"
-
-SK_DEFINE_INST_COUNT(SkBBoxHierarchy)
diff --git a/core/SkBitmap.cpp b/core/SkBitmap.cpp
index 429d0921..25a6b1db 100644
--- a/core/SkBitmap.cpp
+++ b/core/SkBitmap.cpp
@@ -24,8 +24,6 @@
#include "SkPackBits.h"
#include <new>
-SK_DEFINE_INST_COUNT(SkBitmap::Allocator)
-
static bool isPos32Bits(const Sk64& value) {
return !value.isNeg() && value.is32();
}
@@ -161,7 +159,6 @@ int SkBitmap::ComputeBytesPerPixel(SkBitmap::Config config) {
int bpp;
switch (config) {
case kNo_Config:
- case kA1_Config:
bpp = 0; // not applicable
break;
case kA8_Config:
@@ -194,11 +191,6 @@ size_t SkBitmap::ComputeRowBytes(Config c, int width) {
switch (c) {
case kNo_Config:
break;
- case kA1_Config:
- rowBytes.set(width);
- rowBytes.add(7);
- rowBytes.shiftRight(3);
- break;
case kA8_Config:
case kIndex8_Config:
rowBytes.set(width);
@@ -275,7 +267,6 @@ static bool validate_alphaType(SkBitmap::Config config, SkAlphaType alphaType,
case SkBitmap::kNo_Config:
alphaType = kIgnore_SkAlphaType;
break;
- case SkBitmap::kA1_Config:
case SkBitmap::kA8_Config:
if (kUnpremul_SkAlphaType == alphaType) {
alphaType = kPremul_SkAlphaType;
@@ -291,6 +282,8 @@ static bool validate_alphaType(SkBitmap::Config config, SkAlphaType alphaType,
case SkBitmap::kRGB_565_Config:
alphaType = kOpaque_SkAlphaType;
break;
+ default:
+ return false;
}
if (canonical) {
*canonical = alphaType;
@@ -368,6 +361,48 @@ void SkBitmap::updatePixelsFromRef() const {
}
}
+static bool config_to_colorType(SkBitmap::Config config, SkColorType* ctOut) {
+ SkColorType ct;
+ switch (config) {
+ case SkBitmap::kA8_Config:
+ ct = kAlpha_8_SkColorType;
+ break;
+ case SkBitmap::kIndex8_Config:
+ ct = kIndex_8_SkColorType;
+ break;
+ case SkBitmap::kRGB_565_Config:
+ ct = kRGB_565_SkColorType;
+ break;
+ case SkBitmap::kARGB_4444_Config:
+ ct = kARGB_4444_SkColorType;
+ break;
+ case SkBitmap::kARGB_8888_Config:
+ ct = kPMColor_SkColorType;
+ break;
+ case SkBitmap::kNo_Config:
+ default:
+ return false;
+ }
+ if (ctOut) {
+ *ctOut = ct;
+ }
+ return true;
+}
+
+bool SkBitmap::asImageInfo(SkImageInfo* info) const {
+ SkColorType ct;
+ if (!config_to_colorType(this->config(), &ct)) {
+ return false;
+ }
+ if (info) {
+ info->fWidth = fWidth;
+ info->fHeight = fHeight;
+ info->fAlphaType = this->alphaType();
+ info->fColorType = ct;
+ }
+ return true;
+}
+
SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, size_t offset) {
// do this first, we that we never have a non-zero offset with a null ref
if (NULL == pr) {
@@ -606,8 +641,6 @@ void* SkBitmap::getAddr(int x, int y) const {
case SkBitmap::kIndex8_Config:
base += x;
break;
- case SkBitmap::kA1_Config:
- base += x >> 3;
break;
default:
SkDEBUGFAIL("Can't return addr for config");
@@ -623,15 +656,6 @@ SkColor SkBitmap::getColor(int x, int y) const {
SkASSERT((unsigned)y < (unsigned)this->height());
switch (this->config()) {
- case SkBitmap::kA1_Config: {
- uint8_t* addr = this->getAddr1(x, y);
- uint8_t mask = 1 << (7 - (x % 8));
- if (addr[0] & mask) {
- return SK_ColorBLACK;
- } else {
- return 0;
- }
- }
case SkBitmap::kA8_Config: {
uint8_t* addr = this->getAddr8(x, y);
return SkColorSetA(0, addr[0]);
@@ -654,6 +678,7 @@ SkColor SkBitmap::getColor(int x, int y) const {
return SkUnPreMultiply::PMColorToColor(addr[0]);
}
case kNo_Config:
+ default:
SkASSERT(false);
return 0;
}
@@ -671,9 +696,6 @@ bool SkBitmap::ComputeIsOpaque(const SkBitmap& bm) {
const int width = bm.width();
switch (bm.config()) {
- case SkBitmap::kA1_Config: {
- // TODO
- } break;
case SkBitmap::kA8_Config: {
unsigned a = 0xFF;
for (int y = 0; y < height; ++y) {
@@ -779,38 +801,6 @@ void SkBitmap::internalErase(const SkIRect& area,
}
switch (fConfig) {
- case kA1_Config: {
- uint8_t* p = this->getAddr1(area.fLeft, area.fTop);
- const int left = area.fLeft >> 3;
- const int right = area.fRight >> 3;
-
- int middle = right - left - 1;
-
- uint8_t leftMask = 0xFF >> (area.fLeft & 7);
- uint8_t rightMask = ~(0xFF >> (area.fRight & 7));
- if (left == right) {
- leftMask &= rightMask;
- rightMask = 0;
- }
-
- a = (a >> 7) ? 0xFF : 0;
- while (--height >= 0) {
- uint8_t* startP = p;
-
- *p = (*p & ~leftMask) | (a & leftMask);
- p++;
- if (middle > 0) {
- memset(p, a, middle);
- p += middle;
- }
- if (rightMask) {
- *p = (*p & ~rightMask) | (a & rightMask);
- }
-
- p = startP + rowBytes;
- }
- break;
- }
case kA8_Config: {
uint8_t* p = this->getAddr8(area.fLeft, area.fTop);
while (--height >= 0) {
@@ -896,7 +886,6 @@ static size_t get_sub_offset(const SkBitmap& bm, int x, int y) {
break;
case SkBitmap::kNo_Config:
- case SkBitmap::kA1_Config:
default:
return SUB_OFFSET_FAILURE;
}
@@ -939,8 +928,6 @@ bool get_upper_left_from_offset(SkBitmap::Config config, size_t offset, size_t r
case SkBitmap::kNo_Config:
// Fall through.
- case SkBitmap::kA1_Config:
- // Fall through.
default:
return false;
}
@@ -1021,7 +1008,6 @@ bool SkBitmap::canCopyTo(Config dstConfig) const {
case kRGB_565_Config:
case kARGB_8888_Config:
break;
- case kA1_Config:
case kIndex8_Config:
if (!sameConfigs) {
return false;
@@ -1032,12 +1018,6 @@ bool SkBitmap::canCopyTo(Config dstConfig) const {
default:
return false;
}
-
- // do not copy src if srcConfig == kA1_Config while dstConfig != kA1_Config
- if (this->config() == kA1_Config && !sameConfigs) {
- return false;
- }
-
return true;
}
@@ -1619,7 +1599,11 @@ void SkBitmap::unflatten(SkFlattenableReadBuffer& buffer) {
buffer.validate((width >= 0) && (height >= 0) && (rowBytes >= 0) &&
SkIsValidConfig(config) && validate_alphaType(config, alphaType));
- this->setConfig(config, width, height, rowBytes, alphaType);
+ bool configIsValid = this->setConfig(config, width, height, rowBytes, alphaType);
+ // Note : Using (fRowBytes >= (fWidth * fBytesPerPixel)) in the following test can create false
+ // positives if the multiplication causes an integer overflow. Use the division instead.
+ buffer.validate(configIsValid && (fBytesPerPixel > 0) &&
+ ((fRowBytes / fBytesPerPixel) >= fWidth));
int reftype = buffer.readInt();
if (buffer.validate((SERIALIZE_PIXELTYPE_REF_DATA == reftype) ||
@@ -1628,6 +1612,10 @@ void SkBitmap::unflatten(SkFlattenableReadBuffer& buffer) {
case SERIALIZE_PIXELTYPE_REF_DATA: {
size_t offset = buffer.readUInt();
SkPixelRef* pr = buffer.readPixelRef();
+ if (!buffer.validate((NULL == pr) ||
+ (pr->getAllocatedSizeInBytes() >= (offset + this->getSafeSize())))) {
+ offset = 0;
+ }
SkSafeUnref(this->setPixelRef(pr, offset));
break;
}
@@ -1683,7 +1671,7 @@ void SkBitmap::validate() const {
void SkBitmap::toString(SkString* str) const {
static const char* gConfigNames[kConfigCount] = {
- "NONE", "A1", "A8", "INDEX8", "565", "4444", "8888"
+ "NONE", "A8", "INDEX8", "565", "4444", "8888"
};
str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(),
diff --git a/core/SkBitmapDevice.cpp b/core/SkBitmapDevice.cpp
index 369f10c1..1668618c 100644
--- a/core/SkBitmapDevice.cpp
+++ b/core/SkBitmapDevice.cpp
@@ -11,8 +11,6 @@
#include "SkRasterClip.h"
#include "SkShader.h"
-SK_DEFINE_INST_COUNT(SkBitmapDevice)
-
#define CHECK_FOR_ANNOTATION(paint) \
do { if (paint.getAnnotation()) { return; } } while (0)
@@ -29,7 +27,10 @@ SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties&
SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque) {
fBitmap.setConfig(config, width, height, 0, isOpaque ?
kOpaque_SkAlphaType : kPremul_SkAlphaType);
- fBitmap.allocPixels();
+ if (!fBitmap.allocPixels()) {
+ fBitmap.setConfig(config, 0, 0, 0, isOpaque ?
+ kOpaque_SkAlphaType : kPremul_SkAlphaType);
+ }
if (!isOpaque) {
fBitmap.eraseColor(SK_ColorTRANSPARENT);
}
@@ -41,7 +42,10 @@ SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, b
fBitmap.setConfig(config, width, height, 0, isOpaque ?
kOpaque_SkAlphaType : kPremul_SkAlphaType);
- fBitmap.allocPixels();
+ if (!fBitmap.allocPixels()) {
+ fBitmap.setConfig(config, 0, 0, 0, isOpaque ?
+ kOpaque_SkAlphaType : kPremul_SkAlphaType);
+ }
if (!isOpaque) {
fBitmap.eraseColor(SK_ColorTRANSPARENT);
}
@@ -61,8 +65,14 @@ SkBaseDevice* SkBitmapDevice::onCreateCompatibleDevice(SkBitmap::Config config,
int width, int height,
bool isOpaque,
Usage usage) {
- return SkNEW_ARGS(SkBitmapDevice,(config, width, height, isOpaque,
- this->getDeviceProperties()));
+ SkBitmapDevice* device = SkNEW_ARGS(SkBitmapDevice,(config, width, height,
+ isOpaque, this->getDeviceProperties()));
+ // Check if allocation failed and delete device if it did fail
+ if ((device->width() != width) || (device->height() != height)) {
+ SkDELETE(device);
+ device = NULL;
+ }
+ return device;
}
void SkBitmapDevice::lockPixels() {
diff --git a/core/SkBitmapHeap.cpp b/core/SkBitmapHeap.cpp
index a1711384..1f2f3dcf 100644
--- a/core/SkBitmapHeap.cpp
+++ b/core/SkBitmapHeap.cpp
@@ -12,9 +12,6 @@
#include "SkFlattenableBuffers.h"
#include "SkTSearch.h"
-SK_DEFINE_INST_COUNT(SkBitmapHeapReader)
-SK_DEFINE_INST_COUNT(SkBitmapHeap::ExternalStorage)
-
SkBitmapHeapEntry::SkBitmapHeapEntry()
: fSlot(-1)
, fRefCount(0)
diff --git a/core/SkBitmapProcShader.cpp b/core/SkBitmapProcShader.cpp
index ded1b720..bb161192 100644
--- a/core/SkBitmapProcShader.cpp
+++ b/core/SkBitmapProcShader.cpp
@@ -358,13 +358,12 @@ GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint&
SkMatrix matrix;
matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
- if (this->hasLocalMatrix()) {
- SkMatrix inverse;
- if (!this->getLocalMatrix().invert(&inverse)) {
- return NULL;
- }
- matrix.preConcat(inverse);
+ SkMatrix inverse;
+ if (!this->getLocalMatrix().invert(&inverse)) {
+ return NULL;
}
+ matrix.preConcat(inverse);
+
SkShader::TileMode tm[] = {
(TileMode)fState.fTileModeX,
(TileMode)fState.fTileModeY,
@@ -384,9 +383,21 @@ GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint&
textureFilterMode = GrTextureParams::kMipMap_FilterMode;
break;
case SkPaint::kHigh_FilterLevel:
- // fall back to no filtering here; we will install another
- // shader that will do the HQ filtering.
- textureFilterMode = GrTextureParams::kNone_FilterMode;
+ // Minification can look bad with the bicubic effect. This is an overly aggressive
+ // check for MIP fallbacks. It doesn't consider the fact that minification in the local
+ // matrix could be offset by the view matrix and vice versa. We also don't know whether
+ // the draw has explicit local coords (e.g. drawVertices) where the scale factor is
+ // unknown and varies.
+ if (context->getMatrix().getMinStretch() >= SK_Scalar1 &&
+ this->getLocalMatrix().getMaxStretch() <= SK_Scalar1) {
+ // fall back to no filtering here; we will install another
+ // shader that will do the HQ filtering.
+ textureFilterMode = GrTextureParams::kNone_FilterMode;
+ } else {
+ // Fall back to mip-mapping.
+ paintFilterLevel = SkPaint::kMedium_FilterLevel;
+ textureFilterMode = GrTextureParams::kMipMap_FilterMode;
+ }
break;
default:
SkErrorInternals::SetError( kInvalidPaint_SkError,
@@ -408,7 +419,7 @@ GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint&
GrEffectRef* effect = NULL;
if (paintFilterLevel == SkPaint::kHigh_FilterLevel) {
- effect = GrBicubicEffect::Create(texture, matrix, params);
+ effect = GrBicubicEffect::Create(texture, matrix, tm);
} else {
effect = GrSimpleTextureEffect::Create(texture, matrix, params);
}
diff --git a/core/SkBitmapProcState.cpp b/core/SkBitmapProcState.cpp
index 59483d66..c93a2b5c 100644
--- a/core/SkBitmapProcState.cpp
+++ b/core/SkBitmapProcState.cpp
@@ -147,7 +147,8 @@ bool SkBitmapProcState::possiblyScaleImage() {
SkBitmapScaler::RESIZE_BEST,
dest_width,
dest_height,
- simd)) {
+ simd,
+ SkScaledImageCache::GetAllocator())) {
// we failed to create fScaledBitmap, so just return and let
// the scanline proc handle it.
return false;
diff --git a/core/SkBlitter.cpp b/core/SkBlitter.cpp
index dc7946a4..9682d557 100644
--- a/core/SkBlitter.cpp
+++ b/core/SkBlitter.cpp
@@ -945,11 +945,6 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device,
switch (device.config()) {
- case SkBitmap::kA1_Config:
- SK_PLACEMENT_NEW_ARGS(blitter, SkA1_Blitter,
- storage, storageSize, (device, *paint));
- break;
-
case SkBitmap::kA8_Config:
if (drawCoverage) {
SkASSERT(NULL == shader);
diff --git a/core/SkBlitter_A1.cpp b/core/SkBlitter_A1.cpp
deleted file mode 100644
index b64afe2a..00000000
--- a/core/SkBlitter_A1.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#include "SkCoreBlitters.h"
-
-SkA1_Blitter::SkA1_Blitter(const SkBitmap& device, const SkPaint& paint)
- : INHERITED(device) {
- fSrcA = paint.getAlpha();
-}
-
-void SkA1_Blitter::blitH(int x, int y, int width) {
- SkASSERT(x >= 0 && y >= 0 &&
- (unsigned)(x + width) <= (unsigned)fDevice.width());
-
- if (fSrcA <= 0x7F) {
- return;
- }
- uint8_t* dst = fDevice.getAddr1(x, y);
- int right = x + width;
-
- int left_mask = 0xFF >> (x & 7);
- int rite_mask = 0xFF << (8 - (right & 7));
- int full_runs = (right >> 3) - ((x + 7) >> 3);
-
- // check for empty right mask, so we don't read off the end
- // (or go slower than we need to)
- if (rite_mask == 0) {
- SkASSERT(full_runs >= 0);
- full_runs -= 1;
- rite_mask = 0xFF;
- }
- if (left_mask == 0xFF) {
- full_runs -= 1;
- }
- if (full_runs < 0) {
- SkASSERT((left_mask & rite_mask) != 0);
- *dst |= (left_mask & rite_mask);
- } else {
- *dst++ |= left_mask;
- memset(dst, 0xFF, full_runs);
- dst += full_runs;
- *dst |= rite_mask;
- }
-}
diff --git a/core/SkCanvas.cpp b/core/SkCanvas.cpp
index 4eaea11b..47d3cca8 100644
--- a/core/SkCanvas.cpp
+++ b/core/SkCanvas.cpp
@@ -30,10 +30,6 @@
#include "GrRenderTarget.h"
#endif
-SK_DEFINE_INST_COUNT(SkBounder)
-SK_DEFINE_INST_COUNT(SkCanvas)
-SK_DEFINE_INST_COUNT(SkDrawFilter)
-
// experimental for faster tiled drawing...
//#define SK_ENABLE_CLIP_QUICKREJECT
diff --git a/core/SkColorFilter.cpp b/core/SkColorFilter.cpp
index abf191e1..ef0bda74 100644
--- a/core/SkColorFilter.cpp
+++ b/core/SkColorFilter.cpp
@@ -12,8 +12,6 @@
#include "SkUnPreMultiply.h"
#include "SkString.h"
-SK_DEFINE_INST_COUNT(SkColorFilter)
-
bool SkColorFilter::asColorMode(SkColor* color, SkXfermode::Mode* mode) const {
return false;
}
diff --git a/core/SkColorTable.cpp b/core/SkColorTable.cpp
index 38a46c51..c719defe 100644
--- a/core/SkColorTable.cpp
+++ b/core/SkColorTable.cpp
@@ -12,8 +12,6 @@
#include "SkStream.h"
#include "SkTemplates.h"
-SK_DEFINE_INST_COUNT(SkColorTable)
-
// As copy constructor is hidden in the class hierarchy, we need to call
// default constructor explicitly to suppress a compiler warning.
SkColorTable::SkColorTable(const SkColorTable& src) : INHERITED() {
diff --git a/core/SkCoreBlitters.h b/core/SkCoreBlitters.h
index 673b8745..1605a527 100644
--- a/core/SkCoreBlitters.h
+++ b/core/SkCoreBlitters.h
@@ -162,22 +162,6 @@ private:
///////////////////////////////////////////////////////////////////////////////
-class SkA1_Blitter : public SkRasterBlitter {
-public:
- SkA1_Blitter(const SkBitmap& device, const SkPaint& paint);
- virtual void blitH(int x, int y, int width) SK_OVERRIDE;
-
-private:
- uint8_t fSrcA;
-
- // illegal
- SkA1_Blitter& operator=(const SkA1_Blitter&);
-
- typedef SkRasterBlitter INHERITED;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
/* These return the correct subclass of blitter for their device config.
Currently, they make the following assumptions about the state of the
diff --git a/core/SkData.cpp b/core/SkData.cpp
index 56c1256d..fd963a9f 100644
--- a/core/SkData.cpp
+++ b/core/SkData.cpp
@@ -10,8 +10,6 @@
#include "SkOSFile.h"
#include "SkOnce.h"
-SK_DEFINE_INST_COUNT(SkData)
-
SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) {
fPtr = ptr;
fSize = size;
diff --git a/core/SkDataTable.cpp b/core/SkDataTable.cpp
index 917445c9..e2644a05 100644
--- a/core/SkDataTable.cpp
+++ b/core/SkDataTable.cpp
@@ -8,8 +8,6 @@
#include "SkData.h"
#include "SkDataTable.h"
-SK_DEFINE_INST_COUNT(SkDataTable)
-
static void malloc_freeproc(void* context) {
sk_free(context);
}
diff --git a/core/SkDevice.cpp b/core/SkDevice.cpp
index c0d4ad36..0c9e9d66 100644
--- a/core/SkDevice.cpp
+++ b/core/SkDevice.cpp
@@ -9,8 +9,6 @@
#include "SkDevice.h"
#include "SkMetaData.h"
-SK_DEFINE_INST_COUNT(SkBaseDevice)
-
#if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
const SkCanvas::Config8888 SkBaseDevice::kPMColorAlias = SkCanvas::kBGRA_Premul_Config8888;
#elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
diff --git a/core/SkDeviceProfile.cpp b/core/SkDeviceProfile.cpp
index a15069a1..8d60151f 100644
--- a/core/SkDeviceProfile.cpp
+++ b/core/SkDeviceProfile.cpp
@@ -9,8 +9,6 @@
#include "SkDeviceProfile.h"
#include "SkThread.h"
-SK_DEFINE_INST_COUNT(SkDeviceProfile)
-
#define DEFAULT_GAMMAEXP 2.2f
#define DEFAULT_CONTRASTSCALE 0.5f
#define DEFAULT_LCDCONFIG SkDeviceProfile::kNone_LCDConfig
diff --git a/core/SkDiscardableMemory.h b/core/SkDiscardableMemory.h
index e1634eef..f3159fe2 100644
--- a/core/SkDiscardableMemory.h
+++ b/core/SkDiscardableMemory.h
@@ -8,6 +8,7 @@
#ifndef SkDiscardableMemory_DEFINED
#define SkDiscardableMemory_DEFINED
+#include "SkRefCnt.h"
#include "SkTypes.h"
/**
@@ -15,7 +16,6 @@
* embedder.
*/
class SK_API SkDiscardableMemory {
-
public:
/**
* Factory method that creates, initializes and locks an SkDiscardableMemory
@@ -23,6 +23,17 @@ public:
*/
static SkDiscardableMemory* Create(size_t bytes);
+ /**
+ * Factory class that creates, initializes and locks an SkDiscardableMemory
+ * object. If either of these steps fails, a NULL pointer will be returned.
+ */
+ class Factory : public SkRefCnt {
+ public:
+ virtual SkDiscardableMemory* create(size_t bytes) = 0;
+ private:
+ typedef SkRefCnt INHERITED;
+ };
+
/** Must not be called while locked.
*/
virtual ~SkDiscardableMemory() {}
diff --git a/core/SkDrawLooper.cpp b/core/SkDrawLooper.cpp
index 0277986a..bac2d969 100644
--- a/core/SkDrawLooper.cpp
+++ b/core/SkDrawLooper.cpp
@@ -11,8 +11,6 @@
#include "SkPaint.h"
#include "SkRect.h"
-SK_DEFINE_INST_COUNT(SkDrawLooper)
-
bool SkDrawLooper::canComputeFastBounds(const SkPaint& paint) {
SkCanvas canvas;
diff --git a/core/SkFlattenable.cpp b/core/SkFlattenable.cpp
index 6cebb225..877fa0a8 100644
--- a/core/SkFlattenable.cpp
+++ b/core/SkFlattenable.cpp
@@ -8,8 +8,6 @@
#include "SkFlattenable.h"
#include "SkPtrRecorder.h"
-SK_DEFINE_INST_COUNT(SkFlattenable)
-
///////////////////////////////////////////////////////////////////////////////
void SkFlattenable::flatten(SkFlattenableWriteBuffer&) const
diff --git a/core/SkFontHost.cpp b/core/SkFontHost.cpp
index f3d30e85..a209b970 100644
--- a/core/SkFontHost.cpp
+++ b/core/SkFontHost.cpp
@@ -69,8 +69,6 @@ SkFontStyle::SkFontStyle(int weight, int width, Slant slant) {
#include "SkFontMgr.h"
-SK_DEFINE_INST_COUNT(SkFontStyleSet)
-
class SkEmptyFontStyleSet : public SkFontStyleSet {
public:
virtual int count() SK_OVERRIDE { return 0; }
@@ -92,8 +90,6 @@ SkFontStyleSet* SkFontStyleSet::CreateEmpty() {
///////////////////////////////////////////////////////////////////////////////
-SK_DEFINE_INST_COUNT(SkFontMgr)
-
class SkEmptyFontMgr : public SkFontMgr {
protected:
virtual int onCountFamilies() SK_OVERRIDE {
diff --git a/core/SkGlyphCache.cpp b/core/SkGlyphCache.cpp
index faa3f890..a78b197a 100644
--- a/core/SkGlyphCache.cpp
+++ b/core/SkGlyphCache.cpp
@@ -87,8 +87,6 @@ SkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc, SkSca
fGlyphArray.setReserve(kMinGlyphCount);
- fMetricsCount = 0;
- fAdvanceCount = 0;
fAuxProcList = NULL;
}
@@ -320,11 +318,9 @@ SkGlyph* SkGlyphCache::lookupMetrics(uint32_t id, MetricsType mtype) {
if (kJustAdvance_MetricsType == mtype) {
fScalerContext->getAdvance(glyph);
- fAdvanceCount += 1;
} else {
SkASSERT(kFull_MetricsType == mtype);
fScalerContext->getMetrics(glyph);
- fMetricsCount += 1;
}
return glyph;
diff --git a/core/SkGlyphCache.h b/core/SkGlyphCache.h
index 52a8132f..7b2ebb84 100644
--- a/core/SkGlyphCache.h
+++ b/core/SkGlyphCache.h
@@ -211,8 +211,6 @@ private:
SkTDArray<SkGlyph*> fGlyphArray;
SkChunkAlloc fGlyphAlloc;
- int fMetricsCount, fAdvanceCount;
-
struct CharGlyphRec {
uint32_t fID; // unichar + subpixel
SkGlyph* fGlyph;
diff --git a/core/SkImageFilter.cpp b/core/SkImageFilter.cpp
index cca22bba..cda635b4 100644
--- a/core/SkImageFilter.cpp
+++ b/core/SkImageFilter.cpp
@@ -17,8 +17,6 @@
#include "SkImageFilterUtils.h"
#endif
-SK_DEFINE_INST_COUNT(SkImageFilter)
-
SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect)
: fInputCount(inputCount),
fInputs(new SkImageFilter*[inputCount]),
@@ -53,9 +51,9 @@ SkImageFilter::~SkImageFilter() {
delete[] fInputs;
}
-SkImageFilter::SkImageFilter(int maxInputCount, SkFlattenableReadBuffer& buffer) {
+SkImageFilter::SkImageFilter(int inputCount, SkFlattenableReadBuffer& buffer) {
fInputCount = buffer.readInt();
- if (buffer.validate((fInputCount >= 0) && (fInputCount <= maxInputCount))) {
+ if (buffer.validate((fInputCount >= 0) && ((inputCount < 0) || (fInputCount == inputCount)))) {
fInputs = new SkImageFilter*[fInputCount];
for (int i = 0; i < fInputCount; i++) {
if (buffer.readBool()) {
@@ -63,10 +61,14 @@ SkImageFilter::SkImageFilter(int maxInputCount, SkFlattenableReadBuffer& buffer)
} else {
fInputs[i] = NULL;
}
+ if (!buffer.isValid()) {
+ fInputCount = i; // Do not use fInputs past that point in the destructor
+ break;
+ }
}
SkRect rect;
buffer.readRect(&rect);
- if (buffer.validate(SkIsValidRect(rect))) {
+ if (buffer.isValid() && buffer.validate(SkIsValidRect(rect))) {
uint32_t flags = buffer.readUInt();
fCropRect = CropRect(rect, flags);
}
diff --git a/core/SkImageInfo.cpp b/core/SkImageInfo.cpp
new file mode 100644
index 00000000..461bdc03
--- /dev/null
+++ b/core/SkImageInfo.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkImageInfo.h"
+#include "SkFlattenableBuffers.h"
+
+void SkImageInfo::unflatten(SkFlattenableReadBuffer& buffer) {
+ fWidth = buffer.read32();
+ fHeight = buffer.read32();
+
+ uint32_t packed = buffer.read32();
+ SkASSERT(0 == (packed >> 16));
+ fAlphaType = (SkAlphaType)((packed >> 8) & 0xFF);
+ fColorType = (SkColorType)((packed >> 0) & 0xFF);
+}
+
+void SkImageInfo::flatten(SkFlattenableWriteBuffer& buffer) const {
+ buffer.write32(fWidth);
+ buffer.write32(fHeight);
+
+ SkASSERT(0 == (fAlphaType & ~0xFF));
+ SkASSERT(0 == (fColorType & ~0xFF));
+ uint32_t packed = (fAlphaType << 8) | fColorType;
+ buffer.write32(packed);
+}
diff --git a/core/SkMaskFilter.cpp b/core/SkMaskFilter.cpp
index cd257163..f062f135 100644
--- a/core/SkMaskFilter.cpp
+++ b/core/SkMaskFilter.cpp
@@ -21,8 +21,6 @@
#include "SkGrPixelRef.h"
#endif
-SK_DEFINE_INST_COUNT(SkMaskFilter)
-
bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&,
SkIPoint*) const {
return false;
diff --git a/core/SkMaskGamma.h b/core/SkMaskGamma.h
index 9d3fd9a3..1f2b73ca 100644
--- a/core/SkMaskGamma.h
+++ b/core/SkMaskGamma.h
@@ -92,8 +92,8 @@ void SkTMaskGamma_build_correcting_lut(uint8_t table[256], U8CPU srcI, SkScalar
* @param B The number of luminance bits to use [1, 8] from the blue channel.
*/
template <int R_LUM_BITS, int G_LUM_BITS, int B_LUM_BITS> class SkTMaskGamma : public SkRefCnt {
+ SK_DECLARE_INST_COUNT(SkTMaskGamma)
public:
- SK_DECLARE_INST_COUNT_TEMPLATE(SkTMaskGamma)
/** Creates a linear SkTMaskGamma. */
SkTMaskGamma() : fIsLinear(true) { }
@@ -147,11 +147,6 @@ private:
};
-#define MacroComma ,
-SK_DEFINE_INST_COUNT_TEMPLATE(
- template <int R_LUM_BITS MacroComma int G_LUM_BITS MacroComma int B_LUM_BITS>,
- SkTMaskGamma<R_LUM_BITS MacroComma G_LUM_BITS MacroComma B_LUM_BITS>);
-
/**
* SkTMaskPreBlend is a tear-off of SkTMaskGamma. It provides the tables to
* convert a linear alpha value for a given channel to a gamma correcting alpha
diff --git a/core/SkMatrix.cpp b/core/SkMatrix.cpp
index 3caf51a0..474f2722 100644
--- a/core/SkMatrix.cpp
+++ b/core/SkMatrix.cpp
@@ -1857,45 +1857,71 @@ bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[],
///////////////////////////////////////////////////////////////////////////////
-SkScalar SkMatrix::getMaxStretch() const {
- TypeMask mask = this->getType();
+enum MinOrMax {
+ kMin_MinOrMax,
+ kMax_MinOrMax
+};
- if (this->hasPerspective()) {
+template <MinOrMax MIN_OR_MAX> SkScalar get_stretch_factor(SkMatrix::TypeMask typeMask,
+ const SkScalar m[9]) {
+ if (typeMask & SkMatrix::kPerspective_Mask) {
return -SK_Scalar1;
}
- if (this->isIdentity()) {
+ if (SkMatrix::kIdentity_Mask == typeMask) {
return SK_Scalar1;
}
- if (!(mask & kAffine_Mask)) {
- return SkMaxScalar(SkScalarAbs(fMat[kMScaleX]),
- SkScalarAbs(fMat[kMScaleY]));
+ if (!(typeMask & SkMatrix::kAffine_Mask)) {
+ if (kMin_MinOrMax == MIN_OR_MAX) {
+ return SkMinScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
+ SkScalarAbs(m[SkMatrix::kMScaleY]));
+ } else {
+ return SkMaxScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
+ SkScalarAbs(m[SkMatrix::kMScaleY]));
+ }
}
// ignore the translation part of the matrix, just look at 2x2 portion.
- // compute singular values, take largest abs value.
+ // compute singular values, take largest or smallest abs value.
// [a b; b c] = A^T*A
- SkScalar a = SkScalarMul(fMat[kMScaleX], fMat[kMScaleX]) +
- SkScalarMul(fMat[kMSkewY], fMat[kMSkewY]);
- SkScalar b = SkScalarMul(fMat[kMScaleX], fMat[kMSkewX]) +
- SkScalarMul(fMat[kMScaleY], fMat[kMSkewY]);
- SkScalar c = SkScalarMul(fMat[kMSkewX], fMat[kMSkewX]) +
- SkScalarMul(fMat[kMScaleY], fMat[kMScaleY]);
+ SkScalar a = SkScalarMul(m[SkMatrix::kMScaleX], m[SkMatrix::kMScaleX]) +
+ SkScalarMul(m[SkMatrix::kMSkewY], m[SkMatrix::kMSkewY]);
+ SkScalar b = SkScalarMul(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewX]) +
+ SkScalarMul(m[SkMatrix::kMScaleY], m[SkMatrix::kMSkewY]);
+ SkScalar c = SkScalarMul(m[SkMatrix::kMSkewX], m[SkMatrix::kMSkewX]) +
+ SkScalarMul(m[SkMatrix::kMScaleY], m[SkMatrix::kMScaleY]);
// eigenvalues of A^T*A are the squared singular values of A.
// characteristic equation is det((A^T*A) - l*I) = 0
// l^2 - (a + c)l + (ac-b^2)
// solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
- // and roots are guaraunteed to be pos and real).
- SkScalar largerRoot;
+ // and roots are guaranteed to be pos and real).
+ SkScalar chosenRoot;
SkScalar bSqd = SkScalarMul(b,b);
// if upper left 2x2 is orthogonal save some math
if (bSqd <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
- largerRoot = SkMaxScalar(a, c);
+ if (kMin_MinOrMax == MIN_OR_MAX) {
+ chosenRoot = SkMinScalar(a, c);
+ } else {
+ chosenRoot = SkMaxScalar(a, c);
+ }
} else {
SkScalar aminusc = a - c;
SkScalar apluscdiv2 = SkScalarHalf(a + c);
SkScalar x = SkScalarHalf(SkScalarSqrt(SkScalarMul(aminusc, aminusc) + 4 * bSqd));
- largerRoot = apluscdiv2 + x;
+ if (kMin_MinOrMax == MIN_OR_MAX) {
+ chosenRoot = apluscdiv2 - x;
+ } else {
+ chosenRoot = apluscdiv2 + x;
+ }
}
- return SkScalarSqrt(largerRoot);
+ SkASSERT(chosenRoot >= 0);
+ return SkScalarSqrt(chosenRoot);
+}
+
+SkScalar SkMatrix::getMinStretch() const {
+ return get_stretch_factor<kMin_MinOrMax>(this->getType(), fMat);
+}
+
+SkScalar SkMatrix::getMaxStretch() const {
+ return get_stretch_factor<kMax_MinOrMax>(this->getType(), fMat);
}
static void reset_identity_matrix(SkMatrix* identity) {
diff --git a/core/SkOnce.h b/core/SkOnce.h
index a469e22c..89de1124 100644
--- a/core/SkOnce.h
+++ b/core/SkOnce.h
@@ -13,15 +13,15 @@
// is particularly useful for lazy singleton initialization. E.g.
//
// static void set_up_my_singleton(Singleton** singleton) {
-// *singleton = new Singleton(...);
+// *singleton = new Singleton(...);
// }
// ...
// const Singleton& GetSingleton() {
-// static Singleton* singleton = NULL;
-// SK_DECLARE_STATIC_ONCE(once);
-// SkOnce(&once, set_up_my_singleton, &singleton);
-// SkASSERT(NULL != singleton);
-// return *singleton;
+// static Singleton* singleton = NULL;
+// SK_DECLARE_STATIC_ONCE(once);
+// SkOnce(&once, set_up_my_singleton, &singleton);
+// SkASSERT(NULL != singleton);
+// return *singleton;
// }
//
// OnceTest.cpp also should serve as a few other simple examples.
@@ -30,17 +30,17 @@
#include "SkTypes.h"
#ifdef SK_USE_POSIX_THREADS
-#define SK_DECLARE_STATIC_ONCE(name) \
- static SkOnceFlag name = { false, { PTHREAD_MUTEX_INITIALIZER } }
+# define SK_ONCE_INIT { false, { PTHREAD_MUTEX_INITIALIZER } }
#else
-#define SK_DECLARE_STATIC_ONCE(name) \
- static SkOnceFlag name = { false, SkBaseMutex() }
+# define SK_ONCE_INIT { false, SkBaseMutex() }
#endif
-struct SkOnceFlag;
+#define SK_DECLARE_STATIC_ONCE(name) static SkOnceFlag name = SK_ONCE_INIT
-template <typename Arg>
-inline void SkOnce(SkOnceFlag* once, void (*f)(Arg), Arg arg);
+struct SkOnceFlag; // If manually created, initialize with SkOnceFlag once = SK_ONCE_INIT
+
+template <typename Func, typename Arg>
+inline void SkOnce(SkOnceFlag* once, Func f, Arg arg);
// ---------------------- Implementation details below here. -----------------------------
@@ -96,19 +96,19 @@ inline static void acquire_barrier() {
// This is the guts of the code, called when we suspect the one-time code hasn't been run yet.
// This should be rarely called, so we separate it from SkOnce and don't mark it as inline.
// (We don't mind if this is an actual function call, but odds are it'll be inlined anyway.)
-template <typename Arg>
-static void sk_once_slow(SkOnceFlag* once, void (*f)(Arg), Arg arg) {
+template <typename Func, typename Arg>
+static void sk_once_slow(SkOnceFlag* once, Func f, Arg arg) {
const SkAutoMutexAcquire lock(once->mutex);
if (!once->done) {
f(arg);
// Also known as a store-store/load-store barrier, this makes sure that the writes
- // done before here---in particular, those done by calling once(arg)---are observable
+ // done before here---in particular, those done by calling f(arg)---are observable
// before the writes after the line, *done = true.
//
// In version control terms this is like saying, "check in the work up
- // to and including once(arg), then check in *done=true as a subsequent change".
+ // to and including f(arg), then check in *done=true as a subsequent change".
//
- // We'll use this in the fast path to make sure once(arg)'s effects are
+ // We'll use this in the fast path to make sure f(arg)'s effects are
// observable whenever we observe *done == true.
release_barrier();
once->done = true;
@@ -131,8 +131,8 @@ void AnnotateBenignRace(const char* file, int line, const volatile void* mem, co
#endif
// This is our fast path, called all the time. We do really want it to be inlined.
-template <typename Arg>
-inline void SkOnce(SkOnceFlag* once, void (*f)(Arg), Arg arg) {
+template <typename Func, typename Arg>
+inline void SkOnce(SkOnceFlag* once, Func f, Arg arg) {
ANNOTATE_BENIGN_RACE(&(once->done), "Don't worry TSAN, we're sure this is safe.");
if (!once->done) {
sk_once_slow(once, f, arg);
diff --git a/core/SkPaint.cpp b/core/SkPaint.cpp
index d6948dd8..91a76e15 100644
--- a/core/SkPaint.cpp
+++ b/core/SkPaint.cpp
@@ -2005,11 +2005,7 @@ enum FlatFlags {
};
// The size of a flat paint's POD fields
-// Include an SkScalar for hinting scale factor whether it is
-// supported or not so that an SKP is valid whether it was
-// created with support or not.
-
-static const uint32_t kPODPaintSize = 6 * sizeof(SkScalar) +
+static const uint32_t kPODPaintSize = 5 * sizeof(SkScalar) +
1 * sizeof(SkColor) +
1 * sizeof(uint16_t) +
6 * sizeof(uint8_t);
@@ -2046,8 +2042,6 @@ void SkPaint::flatten(SkFlattenableWriteBuffer& buffer) const {
ptr = write_scalar(ptr, this->getTextSize());
ptr = write_scalar(ptr, this->getTextScaleX());
ptr = write_scalar(ptr, this->getTextSkewX());
- // Dummy value for obsolete hinting scale factor. TODO: remove with next picture version
- ptr = write_scalar(ptr, SK_Scalar1);
ptr = write_scalar(ptr, this->getStrokeWidth());
ptr = write_scalar(ptr, this->getStrokeMiter());
*ptr++ = this->getColor();
@@ -2064,8 +2058,6 @@ void SkPaint::flatten(SkFlattenableWriteBuffer& buffer) const {
buffer.writeScalar(fTextSize);
buffer.writeScalar(fTextScaleX);
buffer.writeScalar(fTextSkewX);
- // Dummy value for obsolete hinting scale factor. TODO: remove with next picture version
- buffer.writeScalar(SK_Scalar1);
buffer.writeScalar(fWidth);
buffer.writeScalar(fMiterLimit);
buffer.writeColor(fColor);
@@ -2120,8 +2112,6 @@ void SkPaint::unflatten(SkFlattenableReadBuffer& buffer) {
this->setTextSize(read_scalar(pod));
this->setTextScaleX(read_scalar(pod));
this->setTextSkewX(read_scalar(pod));
- // Skip the hinting scalar factor, which is not supported.
- read_scalar(pod);
this->setStrokeWidth(read_scalar(pod));
this->setStrokeMiter(read_scalar(pod));
this->setColor(*pod++);
diff --git a/core/SkPath.cpp b/core/SkPath.cpp
index d25ec3c1..eaa6c93d 100644
--- a/core/SkPath.cpp
+++ b/core/SkPath.cpp
@@ -15,8 +15,6 @@
#include "SkRRect.h"
#include "SkThread.h"
-SK_DEFINE_INST_COUNT(SkPath);
-
// This value is just made-up for now. When count is 4, calling memset was much
// slower than just writing the loop. This seems odd, and hopefully in the
// future this we appear to have been a fluke...
@@ -42,22 +40,6 @@ static bool is_degenerate(const SkPath& path) {
return SkPath::kDone_Verb == iter.next(pts);
}
-class SkAutoDisableOvalCheck {
-public:
- SkAutoDisableOvalCheck(SkPath* path) : fPath(path) {
- fSaved = fPath->fIsOval;
- }
-
- ~SkAutoDisableOvalCheck() {
- fPath->fIsOval = fSaved;
- }
-
-private:
- SkPath* fPath;
- bool fSaved;
-};
-#define SkAutoDisableOvalCheck(...) SK_REQUIRE_LOCAL_VAR(SkAutoDisableOvalCheck)
-
class SkAutoDisableDirectionCheck {
public:
SkAutoDisableDirectionCheck(SkPath* path) : fPath(path) {
@@ -84,7 +66,7 @@ private:
It also notes if the path was originally degenerate, and if so, sets
isConvex to true. Thus it can only be used if the contour being added is
- convex (which is always true since we only allow the addition of rects).
+ convex.
*/
class SkAutoPathBoundsUpdate {
public:
@@ -164,7 +146,6 @@ void SkPath::resetFields() {
fSegmentMask = 0;
fConvexity = kUnknown_Convexity;
fDirection = kUnknown_Direction;
- fIsOval = false;
// We don't touch Android's fSourcePath. It's used to track texture garbage collection, so we
// don't want to muck with it if it's been set to something non-NULL.
@@ -204,7 +185,6 @@ void SkPath::copyFields(const SkPath& that) {
fSegmentMask = that.fSegmentMask;
fConvexity = that.fConvexity;
fDirection = that.fDirection;
- fIsOval = that.fIsOval;
}
bool operator==(const SkPath& a, const SkPath& b) {
@@ -230,7 +210,6 @@ void SkPath::swap(SkPath& that) {
SkTSwap<uint8_t>(fSegmentMask, that.fSegmentMask);
SkTSwap<uint8_t>(fConvexity, that.fConvexity);
SkTSwap<uint8_t>(fDirection, that.fDirection);
- SkTSwap<SkBool8>(fIsOval, that.fIsOval);
#ifdef SK_BUILD_FOR_ANDROID
SkTSwap<const SkPath*>(fSourcePath, that.fSourcePath);
#endif
@@ -631,7 +610,6 @@ void SkPath::setLastPt(SkScalar x, SkScalar y) {
if (count == 0) {
this->moveTo(x, y);
} else {
- fIsOval = false;
SkPathRef::Editor ed(&fPathRef);
ed.atPoint(count-1)->set(x, y);
}
@@ -650,7 +628,6 @@ void SkPath::setConvexity(Convexity c) {
do { \
fConvexity = kUnknown_Convexity; \
fDirection = kUnknown_Direction; \
- fIsOval = false; \
} while (0)
void SkPath::incReserve(U16CPU inc) {
@@ -1263,14 +1240,13 @@ void SkPath::addOval(const SkRect& oval, Direction dir) {
We can't simply check isEmpty() in this case, as additional
moveTo() would mark the path non empty.
*/
- fIsOval = hasOnlyMoveTos();
- if (fIsOval) {
+ bool isOval = hasOnlyMoveTos();
+ if (isOval) {
fDirection = dir;
} else {
fDirection = kUnknown_Direction;
}
- SkAutoDisableOvalCheck adoc(this);
SkAutoDisableDirectionCheck addc(this);
SkAutoPathBoundsUpdate apbu(this, oval);
@@ -1318,14 +1294,10 @@ void SkPath::addOval(const SkRect& oval, Direction dir) {
this->quadTo( R, cy - sy, R, cy );
}
this->close();
-}
-bool SkPath::isOval(SkRect* rect) const {
- if (fIsOval && rect) {
- *rect = getBounds();
- }
+ SkPathRef::Editor ed(&fPathRef);
- return fIsOval;
+ ed.setIsOval(isOval);
}
void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) {
@@ -1459,8 +1431,6 @@ void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy) {
void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) {
SkPathRef::Editor(&fPathRef, path.countVerbs(), path.countPoints());
- fIsOval = false;
-
RawIter iter(path);
SkPoint pts[4];
Verb verb;
@@ -1525,8 +1495,6 @@ void SkPath::reversePathTo(const SkPath& path) {
SkPathRef::Editor(&fPathRef, vcount, path.countPoints());
- fIsOval = false;
-
const uint8_t* verbs = path.fPathRef->verbs();
const SkPoint* pts = path.fPathRef->points();
const SkScalar* conicWeights = path.fPathRef->conicWeights();
@@ -1574,8 +1542,6 @@ void SkPath::reverseAddPath(const SkPath& src) {
const uint8_t* verbsEnd = src.fPathRef->verbs(); // points just past the first verb
const SkScalar* conicWeights = src.fPathRef->conicWeightsEnd();
- fIsOval = false;
-
bool needMove = true;
bool needClose = false;
while (verbs < verbsEnd) {
@@ -1725,9 +1691,6 @@ void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const {
}
}
- // It's an oval only if it stays a rect.
- dst->fIsOval = fIsOval && matrix.rectStaysRect();
-
SkDEBUGCODE(dst->validate();)
}
}
@@ -2080,12 +2043,11 @@ size_t SkPath::writeToMemory(void* storage) const {
SkWBuffer buffer(storage);
- int32_t packed = ((fIsOval & 1) << kIsOval_SerializationShift) |
- (fConvexity << kConvexity_SerializationShift) |
+ int32_t packed = (fConvexity << kConvexity_SerializationShift) |
(fFillType << kFillType_SerializationShift) |
(fSegmentMask << kSegmentMask_SerializationShift) |
(fDirection << kDirection_SerializationShift)
-#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TOO
+#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO
| (0x1 << kNewFormat_SerializationShift)
#endif
;
@@ -2106,17 +2068,16 @@ size_t SkPath::readFromMemory(const void* storage, size_t length) {
return 0;
}
- fIsOval = (packed >> kIsOval_SerializationShift) & 1;
fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF;
fFillType = (packed >> kFillType_SerializationShift) & 0xFF;
fSegmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF;
fDirection = (packed >> kDirection_SerializationShift) & 0x3;
-#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TOO
+#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO
bool newFormat = (packed >> kNewFormat_SerializationShift) & 1;
#endif
SkPathRef* pathRef = SkPathRef::CreateFromBuffer(&buffer
-#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TOO
+#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO
, newFormat, packed
#endif
);
diff --git a/core/SkPathEffect.cpp b/core/SkPathEffect.cpp
index e7f68225..59ba3ec3 100644
--- a/core/SkPathEffect.cpp
+++ b/core/SkPathEffect.cpp
@@ -12,8 +12,6 @@
///////////////////////////////////////////////////////////////////////////////
-SK_DEFINE_INST_COUNT(SkPathEffect)
-
void SkPathEffect::computeFastBounds(SkRect* dst, const SkRect& src) const {
*dst = src;
}
diff --git a/core/SkPathHeap.cpp b/core/SkPathHeap.cpp
index 12db3c48..c6e2129e 100644
--- a/core/SkPathHeap.cpp
+++ b/core/SkPathHeap.cpp
@@ -11,8 +11,6 @@
#include "SkFlattenableBuffers.h"
#include <new>
-SK_DEFINE_INST_COUNT(SkPathHeap)
-
#define kPathCount 64
SkPathHeap::SkPathHeap() : fHeap(kPathCount * sizeof(SkPath)) {
diff --git a/core/SkPathRef.cpp b/core/SkPathRef.cpp
index c66d75b3..a02df302 100644
--- a/core/SkPathRef.cpp
+++ b/core/SkPathRef.cpp
@@ -10,8 +10,6 @@
#include "SkPath.h"
#include "SkPathRef.h"
-SK_DEFINE_INST_COUNT(SkPathRef);
-
//////////////////////////////////////////////////////////////////////////////
SkPathRef::Editor::Editor(SkAutoTUnref<SkPathRef>* pathRef,
int incReserveVerbs,
@@ -26,6 +24,7 @@ SkPathRef::Editor::Editor(SkAutoTUnref<SkPathRef>* pathRef,
}
fPathRef = *pathRef;
fPathRef->fGenerationID = 0;
+ fPathRef->fIsOval = false;
SkDEBUGCODE(sk_atomic_inc(&fPathRef->fEditorsAttached);)
}
@@ -62,14 +61,20 @@ void SkPathRef::CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst,
return;
}
- bool dstUnique = (*dst)->unique();
- if (!dstUnique) {
+ if (!(*dst)->unique()) {
dst->reset(SkNEW(SkPathRef));
+ }
+
+ if (*dst != &src) {
(*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.count());
memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(), src.fVerbCnt * sizeof(uint8_t));
(*dst)->fConicWeights = src.fConicWeights;
}
+ SkASSERT((*dst)->countPoints() == src.countPoints());
+ SkASSERT((*dst)->countVerbs() == src.countVerbs());
+ SkASSERT((*dst)->fConicWeights.count() == src.fConicWeights.count());
+
// Need to check this here in case (&src == dst)
bool canXformBounds = !src.fBoundsIsDirty && matrix.rectStaysRect() && src.countPoints() > 1;
@@ -100,28 +105,35 @@ void SkPathRef::CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst,
(*dst)->fBoundsIsDirty = true;
}
+ // It's an oval only if it stays a rect.
+ (*dst)->fIsOval = src.fIsOval && matrix.rectStaysRect();
+
SkDEBUGCODE((*dst)->validate();)
}
SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer
-#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TOO
+#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO
, bool newFormat, int32_t oldPacked
#endif
) {
SkPathRef* ref = SkNEW(SkPathRef);
-#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TOO
+ bool isOval;
+
+ int32_t packed;
+ if (!buffer->readS32(&packed)) {
+ SkDELETE(ref);
+ return NULL;
+ }
+
+ ref->fIsFinite = (packed >> kIsFinite_SerializationShift) & 1;
+
+#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO
if (newFormat) {
#endif
- int32_t packed;
- if (!buffer->readS32(&packed)) {
- SkDELETE(ref);
- return NULL;
- }
-
- ref->fIsFinite = (packed >> kIsFinite_SerializationShift) & 1;
-#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TOO
+ isOval = (packed >> kIsOval_SerializationShift) & 1;
+#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO
} else {
- ref->fIsFinite = (oldPacked >> SkPath::kOldIsFinite_SerializationShift) & 1;
+ isOval = (oldPacked >> SkPath::kOldIsOval_SerializationShift) & 1;
}
#endif
@@ -147,6 +159,7 @@ SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer
return NULL;
}
ref->fBoundsIsDirty = false;
+ ref->fIsOval = isOval;
return ref;
}
@@ -159,6 +172,7 @@ void SkPathRef::Rewind(SkAutoTUnref<SkPathRef>* pathRef) {
(*pathRef)->fFreeSpace = (*pathRef)->currSize();
(*pathRef)->fGenerationID = 0;
(*pathRef)->fConicWeights.rewind();
+ (*pathRef)->fIsOval = false;
SkDEBUGCODE((*pathRef)->validate();)
} else {
int oldVCnt = (*pathRef)->countVerbs();
@@ -216,7 +230,8 @@ void SkPathRef::writeToBuffer(SkWBuffer* buffer) {
// and fIsFinite are computed.
const SkRect& bounds = this->getBounds();
- int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift);
+ int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift) |
+ ((fIsOval & 1) << kIsOval_SerializationShift);
buffer->write32(packed);
// TODO: write gen ID here. Problem: We don't know if we're cross process or not from
@@ -258,15 +273,18 @@ void SkPathRef::copy(const SkPathRef& ref,
fBounds = ref.fBounds;
fIsFinite = ref.fIsFinite;
}
+ fIsOval = ref.fIsOval;
SkDEBUGCODE(this->validate();)
}
SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb) {
SkDEBUGCODE(this->validate();)
int pCnt;
+ bool dirtyAfterEdit = true;
switch (verb) {
case SkPath::kMove_Verb:
pCnt = 1;
+ dirtyAfterEdit = false;
break;
case SkPath::kLine_Verb:
pCnt = 1;
@@ -281,12 +299,14 @@ SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb) {
break;
case SkPath::kClose_Verb:
pCnt = 0;
+ dirtyAfterEdit = false;
break;
case SkPath::kDone_Verb:
SkDEBUGFAIL("growForVerb called for kDone");
// fall through
default:
SkDEBUGFAIL("default is not reached");
+ dirtyAfterEdit = false;
pCnt = 0;
}
size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint);
@@ -297,6 +317,9 @@ SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb) {
fPointCnt += pCnt;
fFreeSpace -= space;
fBoundsIsDirty = true; // this also invalidates fIsFinite
+ if (dirtyAfterEdit) {
+ fIsOval = false;
+ }
SkDEBUGCODE(this->validate();)
return ret;
}
diff --git a/core/SkPicture.cpp b/core/SkPicture.cpp
index 4acc5493..2b9b9e93 100644
--- a/core/SkPicture.cpp
+++ b/core/SkPicture.cpp
@@ -26,8 +26,6 @@
#include "SkRTree.h"
#include "SkBBoxHierarchyRecord.h"
-SK_DEFINE_INST_COUNT(SkPicture)
-
#define DUMP_BUFFER_SIZE 65536
//#define ENABLE_TIME_DRAW // dumps milliseconds for each draw
@@ -266,23 +264,29 @@ void SkPicture::draw(SkCanvas* surface, SkDrawPictureCallback* callback) {
#include "SkStream.h"
+static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
+
bool SkPicture::StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
if (NULL == stream) {
return false;
}
+ // Check magic bytes.
+ char magic[sizeof(kMagic)];
+ stream->read(magic, sizeof(kMagic));
+ if (0 != memcmp(magic, kMagic, sizeof(kMagic))) {
+ return false;
+ }
+
SkPictInfo info;
if (!stream->read(&info, sizeof(SkPictInfo))) {
return false;
}
+
if (PICTURE_VERSION != info.fVersion
-#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V13_AND_ALL_OTHER_INSTANCES_TOO
- // V13 is backwards compatible with V12
- && PRIOR_PRIOR_PICTURE_VERSION != info.fVersion // TODO: remove when .skps regenerated
-#endif
-#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TOO
- // V14 is backwards compatible with V13
- && PRIOR_PICTURE_VERSION2 != info.fVersion // TODO: remove when .skps regenerated
+#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO
+ // V16 is backwards compatible with V15
+ && PRIOR_PICTURE_VERSION != info.fVersion // TODO: remove when .skps regenerated
#endif
) {
return false;
@@ -341,6 +345,10 @@ void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const {
info.fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
}
+ // Write 8 magic bytes to ID this file format.
+ SkASSERT(sizeof(kMagic) == 8);
+ stream->write(kMagic, sizeof(kMagic));
+
stream->write(&info, sizeof(info));
if (playback) {
stream->writeBool(true);
diff --git a/core/SkPictureFlat.cpp b/core/SkPictureFlat.cpp
index 2a7d15a7..149cf7cc 100644
--- a/core/SkPictureFlat.cpp
+++ b/core/SkPictureFlat.cpp
@@ -16,8 +16,6 @@
#include "SkTypeface.h"
#include "SkXfermode.h"
-SK_DEFINE_INST_COUNT(SkFlatController)
-
///////////////////////////////////////////////////////////////////////////////
SkTypefacePlayback::SkTypefacePlayback() : fCount(0), fArray(NULL) {}
diff --git a/core/SkPicturePlayback.cpp b/core/SkPicturePlayback.cpp
index 5a016d48..82c7a03b 100644
--- a/core/SkPicturePlayback.cpp
+++ b/core/SkPicturePlayback.cpp
@@ -882,18 +882,7 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
const SkRect* src = this->getRectPtr(reader); // may be null
const SkRect& dst = reader.skipT<SkRect>(); // required
SkCanvas::DrawBitmapRectFlags flags;
-#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V13_AND_ALL_OTHER_INSTANCES_TOO
- flags = SkCanvas::kNone_DrawBitmapRectFlag;
- // TODO: remove this backwards compatibility code once the .skps are
- // regenerated
- SkASSERT(32 == size || 48 == size || // old sizes
- 36 == size || 52 == size); // new sizes
- if (36 == size || 52 == size) {
-#endif
- flags = (SkCanvas::DrawBitmapRectFlags) reader.readInt();
-#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V13_AND_ALL_OTHER_INSTANCES_TOO
- }
-#endif
+ flags = (SkCanvas::DrawBitmapRectFlags) reader.readInt();
canvas.drawBitmapRectToRect(bitmap, src, dst, paint, flags);
} break;
case DRAW_BITMAP_MATRIX: {
diff --git a/core/SkPictureStateTree.cpp b/core/SkPictureStateTree.cpp
index 9f2db258..5f4ed934 100644
--- a/core/SkPictureStateTree.cpp
+++ b/core/SkPictureStateTree.cpp
@@ -9,8 +9,6 @@
#include "SkPictureStateTree.h"
#include "SkCanvas.h"
-SK_DEFINE_INST_COUNT(SkPictureStateTree)
-
SkPictureStateTree::SkPictureStateTree()
: fAlloc(2048)
, fRoot(NULL)
diff --git a/core/SkPixelRef.cpp b/core/SkPixelRef.cpp
index 972474cc..b5daf0b5 100644
--- a/core/SkPixelRef.cpp
+++ b/core/SkPixelRef.cpp
@@ -9,9 +9,6 @@
#include "SkFlattenableBuffers.h"
#include "SkThread.h"
-SK_DEFINE_INST_COUNT(SkPixelRef)
-
-
#ifdef SK_USE_POSIX_THREADS
static SkBaseMutex gPixelRefMutexRing[] = {
@@ -85,6 +82,28 @@ void SkPixelRef::setMutex(SkBaseMutex* mutex) {
// just need a > 0 value, so pick a funny one to aid in debugging
#define SKPIXELREF_PRELOCKED_LOCKCOUNT 123456789
+SkPixelRef::SkPixelRef(const SkImageInfo&, SkBaseMutex* mutex) {
+ this->setMutex(mutex);
+ fPixels = NULL;
+ fColorTable = NULL; // we do not track ownership of this
+ fLockCount = 0;
+ this->needsNewGenID();
+ fIsImmutable = false;
+ fPreLocked = false;
+}
+
+SkPixelRef::SkPixelRef(const SkImageInfo&) {
+ this->setMutex(NULL);
+ fPixels = NULL;
+ fColorTable = NULL; // we do not track ownership of this
+ fLockCount = 0;
+ this->needsNewGenID();
+ fIsImmutable = false;
+ fPreLocked = false;
+}
+
+#ifdef SK_SUPPORT_LEGACY_PIXELREF_CONSTRUCTOR
+// THIS GUY IS DEPRECATED -- don't use me!
SkPixelRef::SkPixelRef(SkBaseMutex* mutex) {
this->setMutex(mutex);
fPixels = NULL;
@@ -94,6 +113,7 @@ SkPixelRef::SkPixelRef(SkBaseMutex* mutex) {
fIsImmutable = false;
fPreLocked = false;
}
+#endif
SkPixelRef::SkPixelRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex)
: INHERITED(buffer) {
@@ -247,6 +267,10 @@ SkData* SkPixelRef::onRefEncodedData() {
return NULL;
}
+size_t SkPixelRef::getAllocatedSizeInBytes() const {
+ return 0;
+}
+
///////////////////////////////////////////////////////////////////////////////
#ifdef SK_BUILD_FOR_ANDROID
diff --git a/core/SkPtrRecorder.cpp b/core/SkPtrRecorder.cpp
index 2acb5af9..aae28d0e 100644
--- a/core/SkPtrRecorder.cpp
+++ b/core/SkPtrRecorder.cpp
@@ -8,9 +8,6 @@
#include "SkPtrRecorder.h"
#include "SkTSearch.h"
-SK_DEFINE_INST_COUNT(SkPtrSet)
-SK_DEFINE_INST_COUNT(SkNamedFactorySet)
-
void SkPtrSet::reset() {
Pair* p = fList.begin();
Pair* stop = fList.end();
diff --git a/core/SkRTree.cpp b/core/SkRTree.cpp
index e3d2eb69..253a7ee1 100644
--- a/core/SkRTree.cpp
+++ b/core/SkRTree.cpp
@@ -16,8 +16,6 @@ static inline void join_no_empty_check(const SkIRect& joinWith, SkIRect* out);
///////////////////////////////////////////////////////////////////////////////////////////////////
-SK_DEFINE_INST_COUNT(SkRTree)
-
SkRTree* SkRTree::Create(int minChildren, int maxChildren, SkScalar aspectRatio,
bool sortWhenBulkLoading) {
if (minChildren < maxChildren && (maxChildren + 1) / 2 >= minChildren &&
diff --git a/core/SkRasterizer.cpp b/core/SkRasterizer.cpp
index a65d541a..3a7af955 100644
--- a/core/SkRasterizer.cpp
+++ b/core/SkRasterizer.cpp
@@ -12,8 +12,6 @@
#include "SkMaskFilter.h"
#include "SkPath.h"
-SK_DEFINE_INST_COUNT(SkRasterizer)
-
bool SkRasterizer::rasterize(const SkPath& fillPath, const SkMatrix& matrix,
const SkIRect* clipBounds, SkMaskFilter* filter,
SkMask* mask, SkMask::CreateMode mode) const {
diff --git a/core/SkRefCnt.cpp b/core/SkRefCnt.cpp
deleted file mode 100644
index b922e03e..00000000
--- a/core/SkRefCnt.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#include "SkRefCnt.h"
-#include "SkWeakRefCnt.h"
-
-SK_DEFINE_INST_COUNT(SkRefCntBase)
-SK_DEFINE_INST_COUNT(SkWeakRefCnt)
diff --git a/core/SkScaledImageCache.cpp b/core/SkScaledImageCache.cpp
index ea29843c..5b166887 100644
--- a/core/SkScaledImageCache.cpp
+++ b/core/SkScaledImageCache.cpp
@@ -11,6 +11,13 @@
#include "SkPixelRef.h"
#include "SkRect.h"
+// This can be defined by the caller's build system
+//#define SK_USE_DISCARDABLE_SCALEDIMAGECACHE
+
+#ifndef SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT
+# define SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT 1024
+#endif
+
#ifndef SK_DEFAULT_IMAGE_CACHE_LIMIT
#define SK_DEFAULT_IMAGE_CACHE_LIMIT (2 * 1024 * 1024)
#endif
@@ -49,7 +56,7 @@ static uint32_t compute_hash(const uint32_t data[], int count) {
return hash;
}
-struct Key {
+struct SkScaledImageCache::Key {
Key(uint32_t genID,
SkScalar scaleX,
SkScalar scaleY,
@@ -129,22 +136,24 @@ struct SkScaledImageCache::Rec {
#include "SkTDynamicHash.h"
namespace { // can't use static functions w/ template parameters
-const Key& key_from_rec(const SkScaledImageCache::Rec& rec) {
+const SkScaledImageCache::Key& key_from_rec(const SkScaledImageCache::Rec& rec) {
return rec.fKey;
}
-uint32_t hash_from_key(const Key& key) {
+uint32_t hash_from_key(const SkScaledImageCache::Key& key) {
return key.fHash;
}
-bool eq_rec_key(const SkScaledImageCache::Rec& rec, const Key& key) {
+bool eq_rec_key(const SkScaledImageCache::Rec& rec, const SkScaledImageCache::Key& key) {
return rec.fKey == key;
}
}
class SkScaledImageCache::Hash : public SkTDynamicHash<SkScaledImageCache::Rec,
- Key, key_from_rec, hash_from_key,
- eq_rec_key> {};
+ SkScaledImageCache::Key,
+ key_from_rec,
+ hash_from_key,
+ eq_rec_key> {};
///////////////////////////////////////////////////////////////////////////////
@@ -162,7 +171,7 @@ static inline SkScaledImageCache::Rec* find_rec_in_list(
}
#endif
-SkScaledImageCache::SkScaledImageCache(size_t byteLimit) {
+void SkScaledImageCache::init() {
fHead = NULL;
fTail = NULL;
#ifdef USE_HASH
@@ -171,11 +180,133 @@ SkScaledImageCache::SkScaledImageCache(size_t byteLimit) {
fHash = NULL;
#endif
fBytesUsed = 0;
- fByteLimit = byteLimit;
fCount = 0;
+ fAllocator = NULL;
+
+ // One of these should be explicit set by the caller after we return.
+ fByteLimit = 0;
+ fDiscardableFactory = NULL;
+}
+
+#include "SkDiscardableMemory.h"
+
+class SkOneShotDiscardablePixelRef : public SkPixelRef {
+public:
+ // Ownership of the discardablememory is transfered to the pixelref
+ SkOneShotDiscardablePixelRef(const SkImageInfo&, SkDiscardableMemory*, size_t rowBytes);
+ ~SkOneShotDiscardablePixelRef();
+
+ SK_DECLARE_UNFLATTENABLE_OBJECT()
+
+protected:
+ virtual void* onLockPixels(SkColorTable**) SK_OVERRIDE;
+ virtual void onUnlockPixels() SK_OVERRIDE;
+ virtual size_t getAllocatedSizeInBytes() const SK_OVERRIDE;
+
+private:
+ SkImageInfo fInfo; // remove when SkPixelRef gets this in baseclass
+
+ SkDiscardableMemory* fDM;
+ size_t fRB;
+ bool fFirstTime;
+
+ typedef SkPixelRef INHERITED;
+};
+
+SkOneShotDiscardablePixelRef::SkOneShotDiscardablePixelRef(const SkImageInfo& info,
+ SkDiscardableMemory* dm,
+ size_t rowBytes)
+ : INHERITED(info)
+ , fDM(dm)
+ , fRB(rowBytes)
+{
+ fInfo = info; // remove this redundant field when SkPixelRef has info
+
+ SkASSERT(dm->data());
+ fFirstTime = true;
+}
+
+SkOneShotDiscardablePixelRef::~SkOneShotDiscardablePixelRef() {
+ SkDELETE(fDM);
+}
+
+void* SkOneShotDiscardablePixelRef::onLockPixels(SkColorTable** ctable) {
+ if (fFirstTime) {
+ // we're already locked
+ fFirstTime = false;
+ return fDM->data();
+ }
+ return fDM->lock() ? fDM->data() : NULL;
+}
+
+void SkOneShotDiscardablePixelRef::onUnlockPixels() {
+ SkASSERT(!fFirstTime);
+ fDM->unlock();
+}
+
+size_t SkOneShotDiscardablePixelRef::getAllocatedSizeInBytes() const {
+ return fInfo.fHeight * fRB;
+}
+
+class SkScaledImageCacheDiscardableAllocator : public SkBitmap::Allocator {
+public:
+ SkScaledImageCacheDiscardableAllocator(
+ SkScaledImageCache::DiscardableFactory factory) {
+ SkASSERT(factory);
+ fFactory = factory;
+ }
+
+ virtual bool allocPixelRef(SkBitmap*, SkColorTable*) SK_OVERRIDE;
+
+private:
+ SkScaledImageCache::DiscardableFactory fFactory;
+};
+
+bool SkScaledImageCacheDiscardableAllocator::allocPixelRef(SkBitmap* bitmap,
+ SkColorTable* ctable) {
+ size_t size = bitmap->getSize();
+ if (0 == size) {
+ return false;
+ }
+
+ SkDiscardableMemory* dm = fFactory(size);
+ if (NULL == dm) {
+ return false;
+ }
+
+ // can relax when we have bitmap::asImageInfo
+ if (SkBitmap::kARGB_8888_Config != bitmap->config()) {
+ return false;
+ }
+
+ SkImageInfo info = {
+ bitmap->width(),
+ bitmap->height(),
+ kPMColor_SkColorType,
+ bitmap->alphaType()
+ };
+
+ bitmap->setPixelRef(SkNEW_ARGS(SkOneShotDiscardablePixelRef,
+ (info, dm, bitmap->rowBytes())))->unref();
+ bitmap->lockPixels();
+ return bitmap->readyToDraw();
+}
+
+SkScaledImageCache::SkScaledImageCache(DiscardableFactory factory) {
+ this->init();
+ fDiscardableFactory = factory;
+
+ fAllocator = SkNEW_ARGS(SkScaledImageCacheDiscardableAllocator, (factory));
+}
+
+SkScaledImageCache::SkScaledImageCache(size_t byteLimit) {
+ this->init();
+ fByteLimit = byteLimit;
}
SkScaledImageCache::~SkScaledImageCache() {
+ SkSafeUnref(fAllocator);
+
Rec* rec = fHead;
while (rec) {
Rec* next = rec->fNext;
@@ -187,17 +318,22 @@ SkScaledImageCache::~SkScaledImageCache() {
////////////////////////////////////////////////////////////////////////////////
-/**
- This private method is the fully general record finder. All other
- record finders should call this funtion. */
+
SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(uint32_t genID,
SkScalar scaleX,
SkScalar scaleY,
const SkIRect& bounds) {
- if (bounds.isEmpty()) {
+ const Key key(genID, scaleX, scaleY, bounds);
+ return this->findAndLock(key);
+}
+
+/**
+ This private method is the fully general record finder. All other
+ record finders should call this function or the one above. */
+SkScaledImageCache::Rec* SkScaledImageCache::findAndLock(const SkScaledImageCache::Key& key) {
+ if (key.fBounds.isEmpty()) {
return NULL;
}
- Key key(genID, scaleX, scaleY, bounds);
#ifdef USE_HASH
Rec* rec = fHash->find(key);
#else
@@ -275,8 +411,14 @@ SkScaledImageCache::ID* SkScaledImageCache::findAndLockMip(const SkBitmap& orig,
/**
This private method is the fully general record adder. All other
record adders should call this funtion. */
-void SkScaledImageCache::addAndLock(SkScaledImageCache::Rec* rec) {
+SkScaledImageCache::ID* SkScaledImageCache::addAndLock(SkScaledImageCache::Rec* rec) {
SkASSERT(rec);
+ // See if we already have this key (racy inserts, etc.)
+ Rec* existing = this->findAndLock(rec->fKey);
+ if (existing != NULL) {
+ return rec_to_id(existing);
+ }
+
this->addToHead(rec);
SkASSERT(1 == rec->fLockCount);
#ifdef USE_HASH
@@ -285,6 +427,7 @@ void SkScaledImageCache::addAndLock(SkScaledImageCache::Rec* rec) {
#endif
// We may (now) be overbudget, so see if we need to purge something.
this->purgeAsNeeded();
+ return rec_to_id(rec);
}
SkScaledImageCache::ID* SkScaledImageCache::addAndLock(uint32_t genID,
@@ -293,8 +436,7 @@ SkScaledImageCache::ID* SkScaledImageCache::addAndLock(uint32_t genID,
const SkBitmap& bitmap) {
Key key(genID, SK_Scalar1, SK_Scalar1, SkIRect::MakeWH(width, height));
Rec* rec = SkNEW_ARGS(Rec, (key, bitmap));
- this->addAndLock(rec);
- return rec_to_id(rec);
+ return this->addAndLock(rec);
}
SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const SkBitmap& orig,
@@ -311,8 +453,7 @@ SkScaledImageCache::ID* SkScaledImageCache::addAndLock(const SkBitmap& orig,
}
Key key(orig.getGenerationID(), scaleX, scaleY, bounds);
Rec* rec = SkNEW_ARGS(Rec, (key, scaled));
- this->addAndLock(rec);
- return rec_to_id(rec);
+ return this->addAndLock(rec);
}
SkScaledImageCache::ID* SkScaledImageCache::addAndLockMip(const SkBitmap& orig,
@@ -323,8 +464,7 @@ SkScaledImageCache::ID* SkScaledImageCache::addAndLockMip(const SkBitmap& orig,
}
Key key(orig.getGenerationID(), 0, 0, bounds);
Rec* rec = SkNEW_ARGS(Rec, (key, mip));
- this->addAndLock(rec);
- return rec_to_id(rec);
+ return this->addAndLock(rec);
}
void SkScaledImageCache::unlock(SkScaledImageCache::ID* id) {
@@ -356,30 +496,45 @@ void SkScaledImageCache::unlock(SkScaledImageCache::ID* id) {
}
void SkScaledImageCache::purgeAsNeeded() {
- size_t byteLimit = fByteLimit;
+ size_t byteLimit;
+ int countLimit;
+
+ if (fDiscardableFactory) {
+ countLimit = SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT;
+ byteLimit = SK_MaxU32; // no limit based on bytes
+ } else {
+ countLimit = SK_MaxS32; // no limit based on count
+ byteLimit = fByteLimit;
+ }
+
size_t bytesUsed = fBytesUsed;
+ int countUsed = fCount;
Rec* rec = fTail;
while (rec) {
- if (bytesUsed < byteLimit) {
+ if (bytesUsed < byteLimit && countUsed < countLimit) {
break;
}
+
Rec* prev = rec->fPrev;
if (0 == rec->fLockCount) {
size_t used = rec->bytesUsed();
SkASSERT(used <= bytesUsed);
- bytesUsed -= used;
this->detach(rec);
#ifdef USE_HASH
fHash->remove(rec->fKey);
#endif
SkDELETE(rec);
- fCount -= 1;
+
+ bytesUsed -= used;
+ countUsed -= 1;
}
rec = prev;
}
+
fBytesUsed = bytesUsed;
+ fCount = countUsed;
}
size_t SkScaledImageCache::setByteLimit(size_t newLimit) {
@@ -502,13 +657,17 @@ void SkScaledImageCache::validate() const {
SK_DECLARE_STATIC_MUTEX(gMutex);
static void create_cache(SkScaledImageCache** cache) {
+#ifdef SK_USE_DISCARDABLE_SCALEDIMAGECACHE
+ *cache = SkNEW_ARGS(SkScaledImageCache, (SkDiscardableMemory::Create));
+#else
*cache = SkNEW_ARGS(SkScaledImageCache, (SK_DEFAULT_IMAGE_CACHE_LIMIT));
+#endif
}
static SkScaledImageCache* get_cache() {
static SkScaledImageCache* gCache(NULL);
SK_DECLARE_STATIC_ONCE(create_cache_once);
- SkOnce<SkScaledImageCache**>(&create_cache_once, create_cache, &gCache);
+ SkOnce(&create_cache_once, create_cache, &gCache);
SkASSERT(NULL != gCache);
return gCache;
}
@@ -581,6 +740,11 @@ size_t SkScaledImageCache::SetByteLimit(size_t newLimit) {
return get_cache()->setByteLimit(newLimit);
}
+SkBitmap::Allocator* SkScaledImageCache::GetAllocator() {
+ SkAutoMutexAcquire am(gMutex);
+ return get_cache()->allocator();
+}
+
///////////////////////////////////////////////////////////////////////////////
#include "SkGraphics.h"
diff --git a/core/SkScaledImageCache.h b/core/SkScaledImageCache.h
index fee69d2d..311db325 100644
--- a/core/SkScaledImageCache.h
+++ b/core/SkScaledImageCache.h
@@ -10,6 +10,7 @@
#include "SkBitmap.h"
+class SkDiscardableMemory;
class SkMipMap;
/**
@@ -26,6 +27,12 @@ class SkScaledImageCache {
public:
struct ID;
+ /**
+ * Returns a locked/pinned SkDiscardableMemory instance for the specified
+ * number of bytes, or NULL on failure.
+ */
+ typedef SkDiscardableMemory* (*DiscardableFactory)(size_t bytes);
+
/*
* The following static methods are thread-safe wrappers around a global
* instance of this cache.
@@ -57,9 +64,27 @@ public:
static size_t GetByteLimit();
static size_t SetByteLimit(size_t newLimit);
+ static SkBitmap::Allocator* GetAllocator();
+
///////////////////////////////////////////////////////////////////////////
+ /**
+ * Construct the cache to call DiscardableFactory when it
+ * allocates memory for the pixels. In this mode, the cache has
+ * not explicit budget, and so methods like getBytesUsed() and
+ * getByteLimit() will return 0, and setByteLimit will ignore its argument
+ * and return 0.
+ */
+ SkScaledImageCache(DiscardableFactory);
+
+ /**
+ * Construct the cache, allocating memory with malloc, and respect the
+ * byteLimit, purging automatically when a new image is added to the cache
+ * that pushes the total bytesUsed over the limit. Note: The limit can be
+ * changed at runtime with setByteLimit.
+ */
SkScaledImageCache(size_t byteLimit);
+
~SkScaledImageCache();
/**
@@ -124,8 +149,11 @@ public:
*/
size_t setByteLimit(size_t newLimit);
+ SkBitmap::Allocator* allocator() const { return fAllocator; };
+
public:
struct Rec;
+ struct Key;
private:
Rec* fHead;
Rec* fTail;
@@ -133,13 +161,18 @@ private:
class Hash;
Hash* fHash;
+ DiscardableFactory fDiscardableFactory;
+ // the allocator is NULL or one that matches discardables
+ SkBitmap::Allocator* fAllocator;
+
size_t fBytesUsed;
size_t fByteLimit;
int fCount;
Rec* findAndLock(uint32_t generationID, SkScalar sx, SkScalar sy,
const SkIRect& bounds);
- void addAndLock(Rec* rec);
+ Rec* findAndLock(const Key& key);
+ ID* addAndLock(Rec* rec);
void purgeAsNeeded();
@@ -147,6 +180,9 @@ private:
void moveToHead(Rec*);
void addToHead(Rec*);
void detach(Rec*);
+
+ void init(); // called by constructors
+
#ifdef SK_DEBUG
void validate() const;
#else
diff --git a/core/SkScalerContext.cpp b/core/SkScalerContext.cpp
index 1d6c2f79..04ef2a92 100644
--- a/core/SkScalerContext.cpp
+++ b/core/SkScalerContext.cpp
@@ -352,16 +352,16 @@ void SkScalerContext::getMetrics(SkGlyph* glyph) {
glyph->fHeight = SkToU16(ir.height());
if (glyph->fWidth > 0) {
- switch (fRec.fMaskFormat) {
- case SkMask::kLCD16_Format:
- case SkMask::kLCD32_Format:
- glyph->fWidth += 2;
- glyph->fLeft -= 1;
- break;
- default:
- break;
+ switch (fRec.fMaskFormat) {
+ case SkMask::kLCD16_Format:
+ case SkMask::kLCD32_Format:
+ glyph->fWidth += 2;
+ glyph->fLeft -= 1;
+ break;
+ default:
+ break;
+ }
}
- }
}
}
@@ -523,10 +523,54 @@ static void pack4xHToLCD32(const SkBitmap& src, const SkMask& dst,
}
}
+static inline int convert_8_to_1(unsigned byte) {
+ SkASSERT(byte <= 0xFF);
+ return byte >> 7;
+}
+
+static uint8_t pack_8_to_1(const uint8_t alpha[8]) {
+ unsigned bits = 0;
+ for (int i = 0; i < 8; ++i) {
+ bits <<= 1;
+ bits |= convert_8_to_1(alpha[i]);
+ }
+ return SkToU8(bits);
+}
+
+static void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
+ const int height = mask.fBounds.height();
+ const int width = mask.fBounds.width();
+ const int octs = width >> 3;
+ const int leftOverBits = width & 7;
+
+ uint8_t* dst = mask.fImage;
+ const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
+ SkASSERT(dstPad >= 0);
+
+ const int srcPad = srcRB - width;
+ SkASSERT(srcPad >= 0);
+
+ for (int y = 0; y < height; ++y) {
+ for (int i = 0; i < octs; ++i) {
+ *dst++ = pack_8_to_1(src);
+ src += 8;
+ }
+ if (leftOverBits > 0) {
+ unsigned bits = 0;
+ int shift = 7;
+ for (int i = 0; i < leftOverBits; ++i, --shift) {
+ bits |= convert_8_to_1(*src++) << shift;
+ }
+ *dst++ = bits;
+ }
+ src += srcPad;
+ dst += dstPad;
+ }
+}
+
static void generateMask(const SkMask& mask, const SkPath& path,
const SkMaskGamma::PreBlend& maskPreBlend) {
- SkBitmap::Config config;
- SkPaint paint;
+ SkPaint paint;
int srcW = mask.fBounds.width();
int srcH = mask.fBounds.height();
@@ -538,27 +582,25 @@ static void generateMask(const SkMask& mask, const SkPath& path,
matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
-SkIntToScalar(mask.fBounds.fTop));
- if (SkMask::kBW_Format == mask.fFormat) {
- config = SkBitmap::kA1_Config;
- paint.setAntiAlias(false);
- } else {
- config = SkBitmap::kA8_Config;
- paint.setAntiAlias(true);
- switch (mask.fFormat) {
- case SkMask::kA8_Format:
- break;
- case SkMask::kLCD16_Format:
- case SkMask::kLCD32_Format:
- // TODO: trigger off LCD orientation
- dstW = 4*dstW - 8;
- matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1),
- -SkIntToScalar(mask.fBounds.fTop));
- matrix.postScale(SkIntToScalar(4), SK_Scalar1);
- dstRB = 0; // signals we need a copy
- break;
- default:
- SkDEBUGFAIL("unexpected mask format");
- }
+ SkBitmap::Config config = SkBitmap::kA8_Config;
+ paint.setAntiAlias(SkMask::kBW_Format != mask.fFormat);
+ switch (mask.fFormat) {
+ case SkMask::kBW_Format:
+ dstRB = 0; // signals we need a copy
+ break;
+ case SkMask::kA8_Format:
+ break;
+ case SkMask::kLCD16_Format:
+ case SkMask::kLCD32_Format:
+ // TODO: trigger off LCD orientation
+ dstW = 4*dstW - 8;
+ matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1),
+ -SkIntToScalar(mask.fBounds.fTop));
+ matrix.postScale(SkIntToScalar(4), SK_Scalar1);
+ dstRB = 0; // signals we need a copy
+ break;
+ default:
+ SkDEBUGFAIL("unexpected mask format");
}
SkRasterClip clip;
@@ -587,6 +629,9 @@ static void generateMask(const SkMask& mask, const SkPath& path,
draw.drawPath(path, paint);
switch (mask.fFormat) {
+ case SkMask::kBW_Format:
+ packA8ToA1(mask, bm.getAddr8(0, 0), bm.rowBytes());
+ break;
case SkMask::kA8_Format:
if (maskPreBlend.isApplicable()) {
applyLUTToA8Mask(mask, maskPreBlend.fG);
diff --git a/core/SkScalerContext.h b/core/SkScalerContext.h
index 2820b5ac..e4950ede 100644
--- a/core/SkScalerContext.h
+++ b/core/SkScalerContext.h
@@ -202,16 +202,57 @@ protected:
Rec fRec;
unsigned fBaseGlyphCount;
- virtual unsigned generateGlyphCount() = 0;
- virtual uint16_t generateCharToGlyph(SkUnichar) = 0;
- virtual void generateAdvance(SkGlyph*) = 0;
- virtual void generateMetrics(SkGlyph*) = 0;
- virtual void generateImage(const SkGlyph&) = 0;
- virtual void generatePath(const SkGlyph&, SkPath*) = 0;
+ /** Generates the contents of glyph.fAdvanceX and glyph.fAdvanceY.
+ * May call getMetrics if that would be just as fast.
+ */
+ virtual void generateAdvance(SkGlyph* glyph) = 0;
+
+ /** Generates the contents of glyph.fWidth, fHeight, fTop, fLeft,
+ * as well as fAdvanceX and fAdvanceY if not already set.
+ *
+ * TODO: fMaskFormat is set by getMetrics later; cannot be set here.
+ */
+ virtual void generateMetrics(SkGlyph* glyph) = 0;
+
+ /** Generates the contents of glyph.fImage.
+ * When called, glyph.fImage will be pointing to a pre-allocated,
+ * uninitialized region of memory of size glyph.computeImageSize().
+ * This method may change glyph.fMaskFormat if the new image size is
+ * less than or equal to the old image size.
+ *
+ * Because glyph.computeImageSize() will determine the size of fImage,
+ * generateMetrics will be called before generateImage.
+ */
+ virtual void generateImage(const SkGlyph& glyph) = 0;
+
+ /** Sets the passed path to the glyph outline.
+ * If this cannot be done the path is set to empty;
+ * this is indistinguishable from a glyph with an empty path.
+ * This does not set glyph.fPath.
+ *
+ * TODO: path is always glyph.fPath, no reason to pass separately.
+ */
+ virtual void generatePath(const SkGlyph& glyph, SkPath* path) = 0;
+
+ /** Retrieves font metrics.
+ * TODO: there is now a vertical bit, no need for two parameters.
+ */
virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
SkPaint::FontMetrics* mY) = 0;
- // default impl returns 0, indicating failure.
- virtual SkUnichar generateGlyphToChar(uint16_t);
+
+ /** Returns the number of glyphs in the font. */
+ virtual unsigned generateGlyphCount() = 0;
+
+ /** Returns the glyph id for the given unichar.
+ * If there is no 1:1 mapping from the unichar to a glyph id, returns 0.
+ */
+ virtual uint16_t generateCharToGlyph(SkUnichar unichar) = 0;
+
+ /** Returns the unichar for the given glyph id.
+ * If there is no 1:1 mapping from the glyph id to a unichar, returns 0.
+ * The default implementation always returns 0, indicating failure.
+ */
+ virtual SkUnichar generateGlyphToChar(uint16_t glyphId);
void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
diff --git a/core/SkShader.cpp b/core/SkShader.cpp
index 8f6bfb5d..33fddb11 100644
--- a/core/SkShader.cpp
+++ b/core/SkShader.cpp
@@ -12,8 +12,6 @@
#include "SkPaint.h"
#include "SkMallocPixelRef.h"
-SK_DEFINE_INST_COUNT(SkShader)
-
SkShader::SkShader() {
fLocalMatrix.reset();
SkDEBUGCODE(fInSetContext = false;)
diff --git a/core/SkStream.cpp b/core/SkStream.cpp
index a7e92cf6..3350f82f 100644
--- a/core/SkStream.cpp
+++ b/core/SkStream.cpp
@@ -13,15 +13,6 @@
#include "SkString.h"
#include "SkOSFile.h"
-SK_DEFINE_INST_COUNT(SkStream)
-SK_DEFINE_INST_COUNT(SkWStream)
-SK_DEFINE_INST_COUNT(SkFILEStream)
-SK_DEFINE_INST_COUNT(SkMemoryStream)
-SK_DEFINE_INST_COUNT(SkFILEWStream)
-SK_DEFINE_INST_COUNT(SkMemoryWStream)
-SK_DEFINE_INST_COUNT(SkDynamicMemoryWStream)
-SK_DEFINE_INST_COUNT(SkDebugWStream)
-
///////////////////////////////////////////////////////////////////////////////
diff --git a/core/SkString.cpp b/core/SkString.cpp
index e30b89f1..643dfb13 100644
--- a/core/SkString.cpp
+++ b/core/SkString.cpp
@@ -634,5 +634,17 @@ SkString SkStringPrintf(const char* format, ...) {
return formattedOutput;
}
+void SkStrSplit(const char* str, const char* delimiters, SkTArray<SkString>* out) {
+ const char* end = str + strlen(str);
+ while (str != end) {
+ // Find a token.
+ const size_t len = strcspn(str, delimiters);
+ out->push_back().set(str, len);
+ str += len;
+ // Skip any delimiters.
+ str += strspn(str, delimiters);
+ }
+}
+
#undef VSNPRINTF
#undef SNPRINTF
diff --git a/core/SkTypeface.cpp b/core/SkTypeface.cpp
index 23627616..09a64324 100644
--- a/core/SkTypeface.cpp
+++ b/core/SkTypeface.cpp
@@ -11,8 +11,6 @@
#include "SkStream.h"
#include "SkTypeface.h"
-SK_DEFINE_INST_COUNT(SkTypeface)
-
//#define TRACE_LIFECYCLE
#ifdef TRACE_LIFECYCLE
diff --git a/core/SkValidatingReadBuffer.cpp b/core/SkValidatingReadBuffer.cpp
index a92c1b9b..692d0dd4 100644
--- a/core/SkValidatingReadBuffer.cpp
+++ b/core/SkValidatingReadBuffer.cpp
@@ -29,6 +29,10 @@ bool SkValidatingReadBuffer::validate(bool isValid) {
return !fError;
}
+bool SkValidatingReadBuffer::isValid() const {
+ return !fError;
+}
+
void SkValidatingReadBuffer::setMemory(const void* data, size_t size) {
this->validate(IsPtrAlign4(data) && (SkAlign4(size) == size));
if (!fError) {
@@ -203,7 +207,7 @@ bool SkValidatingReadBuffer::readScalarArray(SkScalar* values, size_t size) {
uint32_t SkValidatingReadBuffer::getArrayCount() {
const size_t inc = sizeof(uint32_t);
fError = fError || !IsPtrAlign4(fReader.peek()) || !fReader.isAvailable(inc);
- return *(uint32_t*)fReader.peek();
+ return fError ? 0 : *(uint32_t*)fReader.peek();
}
void SkValidatingReadBuffer::readBitmap(SkBitmap* bitmap) {
diff --git a/core/SkValidatingReadBuffer.h b/core/SkValidatingReadBuffer.h
index 2bcdc43e..febf0c0b 100644
--- a/core/SkValidatingReadBuffer.h
+++ b/core/SkValidatingReadBuffer.h
@@ -61,6 +61,7 @@ public:
virtual SkTypeface* readTypeface() SK_OVERRIDE;
virtual bool validate(bool isValid) SK_OVERRIDE;
+ virtual bool isValid() const SK_OVERRIDE;
private:
bool readArray(void* value, size_t size, size_t elementSize);
diff --git a/core/SkXfermode.cpp b/core/SkXfermode.cpp
index 20d88162..8cb79c2d 100644
--- a/core/SkXfermode.cpp
+++ b/core/SkXfermode.cpp
@@ -19,8 +19,6 @@
#include "SkXfermode_opts_arm_neon.h"
#endif
-SK_DEFINE_INST_COUNT(SkXfermode)
-
#define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b)
#if 0
@@ -1671,6 +1669,7 @@ void SkXfermode::Term() {
extern SkProcCoeffXfermode* SkPlatformXfermodeFactory(const ProcCoeff& rec,
SkXfermode::Mode mode);
+extern SkXfermodeProc SkPlatformXfermodeProcFactory(SkXfermode::Mode mode);
SkXfermode* SkXfermode::Create(Mode mode) {
SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
@@ -1692,7 +1691,13 @@ SkXfermode* SkXfermode::Create(Mode mode) {
SkXfermode* xfer = gCachedXfermodes[mode];
if (NULL == xfer) {
- const ProcCoeff& rec = gProcCoeffs[mode];
+ ProcCoeff rec = gProcCoeffs[mode];
+
+ SkXfermodeProc pp = SkPlatformXfermodeProcFactory(mode);
+
+ if (pp != NULL) {
+ rec.fProc = pp;
+ }
// check if we have a platform optim for that
SkProcCoeffXfermode* xfm = SkPlatformXfermodeFactory(rec, mode);
diff --git a/doc/SkDocument.cpp b/doc/SkDocument.cpp
index 85a2bad5..5b2237d1 100644
--- a/doc/SkDocument.cpp
+++ b/doc/SkDocument.cpp
@@ -8,8 +8,6 @@
#include "SkDocument.h"
#include "SkStream.h"
-SK_DEFINE_INST_COUNT(SkDocument)
-
SkDocument::SkDocument(SkWStream* stream, void (*doneProc)(SkWStream*, bool)) {
fStream = stream; // we do not own this object.
fDoneProc = doneProc;
diff --git a/effects/SkBitmapAlphaThresholdShader.cpp b/effects/SkBitmapAlphaThresholdShader.cpp
index 05d7ba30..44db167d 100644
--- a/effects/SkBitmapAlphaThresholdShader.cpp
+++ b/effects/SkBitmapAlphaThresholdShader.cpp
@@ -34,8 +34,6 @@ private:
typedef SkShader INHERITED;
};
-SK_DEFINE_INST_COUNT(BATShader)
-
SkShader* SkBitmapAlphaThresholdShader::Create(const SkBitmap& bitmap,
const SkRegion& region,
U8CPU threshold) {
diff --git a/effects/SkBitmapSource.cpp b/effects/SkBitmapSource.cpp
index 72f51f84..ef5ea869 100644
--- a/effects/SkBitmapSource.cpp
+++ b/effects/SkBitmapSource.cpp
@@ -6,24 +6,74 @@
*/
#include "SkBitmapSource.h"
+#include "SkDevice.h"
+#include "SkCanvas.h"
+#include "SkFlattenableBuffers.h"
+#include "SkValidationUtils.h"
SkBitmapSource::SkBitmapSource(const SkBitmap& bitmap)
: INHERITED(0, 0),
- fBitmap(bitmap) {
+ fBitmap(bitmap),
+ fSrcRect(SkRect::MakeWH(SkIntToScalar(bitmap.width()),
+ SkIntToScalar(bitmap.height()))),
+ fDstRect(fSrcRect) {
+}
+
+SkBitmapSource::SkBitmapSource(const SkBitmap& bitmap, const SkRect& srcRect, const SkRect& dstRect)
+ : INHERITED(0, 0),
+ fBitmap(bitmap),
+ fSrcRect(srcRect),
+ fDstRect(dstRect) {
}
SkBitmapSource::SkBitmapSource(SkFlattenableReadBuffer& buffer)
: INHERITED(0, buffer) {
fBitmap.unflatten(buffer);
+ buffer.readRect(&fSrcRect);
+ buffer.readRect(&fDstRect);
+ buffer.validate(SkIsValidRect(fSrcRect) && SkIsValidRect(fDstRect));
}
void SkBitmapSource::flatten(SkFlattenableWriteBuffer& buffer) const {
this->INHERITED::flatten(buffer);
fBitmap.flatten(buffer);
+ buffer.writeRect(fSrcRect);
+ buffer.writeRect(fDstRect);
}
-bool SkBitmapSource::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&,
+bool SkBitmapSource::onFilterImage(Proxy* proxy, const SkBitmap&, const SkMatrix& matrix,
SkBitmap* result, SkIPoint* offset) {
- *result = fBitmap;
+ SkRect bounds, dstRect;
+ fBitmap.getBounds(&bounds);
+ matrix.mapRect(&dstRect, fDstRect);
+ if (fSrcRect == bounds && dstRect == bounds) {
+ // No regions cropped out or resized; return entire bitmap.
+ *result = fBitmap;
+ return true;
+ }
+ SkIRect dstIRect;
+ dstRect.roundOut(&dstIRect);
+
+ SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(dstIRect.width(), dstIRect.height()));
+ if (NULL == device.get()) {
+ return false;
+ }
+
+ SkCanvas canvas(device.get());
+ SkPaint paint;
+
+ // Subtract off the integer component of the translation (will be applied in loc, below).
+ dstRect.offset(-SkIntToScalar(dstIRect.fLeft), -SkIntToScalar(dstIRect.fTop));
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ // FIXME: this probably shouldn't be necessary, but drawBitmapRectToRect asserts
+ // None filtering when it's translate-only
+ paint.setFilterLevel(
+ fSrcRect.width() == dstRect.width() && fSrcRect.height() == dstRect.height() ?
+ SkPaint::kNone_FilterLevel : SkPaint::kMedium_FilterLevel);
+ canvas.drawBitmapRectToRect(fBitmap, &fSrcRect, dstRect, &paint);
+
+ *result = device.get()->accessBitmap(false);
+ offset->fX += dstIRect.fLeft;
+ offset->fY += dstIRect.fTop;
return true;
}
diff --git a/effects/SkBlurImageFilter.cpp b/effects/SkBlurImageFilter.cpp
index 9bceda7d..2795f3a8 100644
--- a/effects/SkBlurImageFilter.cpp
+++ b/effects/SkBlurImageFilter.cpp
@@ -159,6 +159,10 @@ bool SkBlurImageFilter::onFilterImage(Proxy* proxy,
dst->setConfig(src.config(), srcBounds.width(), srcBounds.height());
dst->getBounds(&dstBounds);
dst->allocPixels();
+ if (!dst->getPixels()) {
+ return false;
+ }
+
int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX;
int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY;
getBox3Params(fSigma.width(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffsetX);
diff --git a/effects/SkBlurMaskFilter.cpp b/effects/SkBlurMaskFilter.cpp
index 9ed6d0c0..d2c43d71 100644
--- a/effects/SkBlurMaskFilter.cpp
+++ b/effects/SkBlurMaskFilter.cpp
@@ -483,18 +483,10 @@ void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src,
SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkFlattenableReadBuffer& buffer)
: SkMaskFilter(buffer) {
- fSigma = buffer.readScalar();
-#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V13_AND_ALL_OTHER_INSTANCES_TOO
- // Fixing this must be done in two stages. When the skps are recaptured in V13,
- // remove the ConvertRadiusToSigma but retain the absolute value.
- // At the same time, switch the code in flatten to write a positive value.
- // When the skps are captured in V14 the absolute value can be removed.
- if (fSigma > 0) {
- fSigma = SkBlurMask::ConvertRadiusToSigma(fSigma);
- } else {
- fSigma = -fSigma;
- }
+#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO
+ // TODO: when the skps are recaptured at > v15 the SkScalarAbs can be removed
#endif
+ fSigma = SkScalarAbs(buffer.readScalar());
fBlurStyle = (SkBlurMaskFilter::BlurStyle)buffer.readInt();
fBlurFlags = buffer.readUInt() & SkBlurMaskFilter::kAll_BlurFlag;
SkASSERT(fSigma >= 0);
@@ -503,7 +495,7 @@ SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkFlattenableReadBuffer& buffer)
void SkBlurMaskFilterImpl::flatten(SkFlattenableWriteBuffer& buffer) const {
this->INHERITED::flatten(buffer);
- buffer.writeScalar(-fSigma);
+ buffer.writeScalar(fSigma);
buffer.writeInt(fBlurStyle);
buffer.writeUInt(fBlurFlags);
}
diff --git a/effects/SkColorFilterImageFilter.cpp b/effects/SkColorFilterImageFilter.cpp
index 2042c126..8b7b390e 100755
--- a/effects/SkColorFilterImageFilter.cpp
+++ b/effects/SkColorFilterImageFilter.cpp
@@ -113,6 +113,9 @@ bool SkColorFilterImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& sourc
}
SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
+ if (NULL == device.get()) {
+ return false;
+ }
SkCanvas canvas(device.get());
SkPaint paint;
diff --git a/effects/SkColorFilters.cpp b/effects/SkColorFilters.cpp
index 8ef9edf2..d482a09d 100644
--- a/effects/SkColorFilters.cpp
+++ b/effects/SkColorFilters.cpp
@@ -101,8 +101,10 @@ protected:
SkModeColorFilter(SkFlattenableReadBuffer& buffer) {
fColor = buffer.readColor();
fMode = (SkXfermode::Mode)buffer.readUInt();
- this->updateCache();
- buffer.validate(SkIsValidMode(fMode));
+ if (buffer.isValid()) {
+ this->updateCache();
+ buffer.validate(SkIsValidMode(fMode));
+ }
}
private:
diff --git a/effects/SkColorMatrixFilter.cpp b/effects/SkColorMatrixFilter.cpp
index 5b36a8f7..fc1b77b7 100644
--- a/effects/SkColorMatrixFilter.cpp
+++ b/effects/SkColorMatrixFilter.cpp
@@ -308,10 +308,8 @@ void SkColorMatrixFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
SkColorMatrixFilter::SkColorMatrixFilter(SkFlattenableReadBuffer& buffer)
: INHERITED(buffer) {
SkASSERT(buffer.getArrayCount() == 20);
- buffer.readScalarArray(fMatrix.fMat, 20);
- this->initState(fMatrix.fMat);
- for (int i = 0; i < 20; ++i) {
- buffer.validate(SkScalarIsFinite(fMatrix.fMat[i]));
+ if (buffer.readScalarArray(fMatrix.fMat, 20)) {
+ this->initState(fMatrix.fMat);
}
}
diff --git a/effects/SkDropShadowImageFilter.cpp b/effects/SkDropShadowImageFilter.cpp
index b4d8689f..24a910d0 100644
--- a/effects/SkDropShadowImageFilter.cpp
+++ b/effects/SkDropShadowImageFilter.cpp
@@ -15,10 +15,21 @@
#include "SkFlattenableBuffers.h"
SkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy, SkScalar sigma, SkColor color, SkImageFilter* input)
- : SkImageFilter(input)
+ : INHERITED(input)
, fDx(dx)
, fDy(dy)
- , fSigma(sigma)
+ , fSigmaX(sigma)
+ , fSigmaY(sigma)
+ , fColor(color)
+{
+}
+
+SkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy, SkScalar sigmaX, SkScalar sigmaY, SkColor color, SkImageFilter* input, const CropRect* cropRect)
+ : INHERITED(input, cropRect)
+ , fDx(dx)
+ , fDy(dy)
+ , fSigmaX(sigmaX)
+ , fSigmaY(sigmaY)
, fColor(color)
{
}
@@ -27,11 +38,13 @@ SkDropShadowImageFilter::SkDropShadowImageFilter(SkFlattenableReadBuffer& buffer
: INHERITED(1, buffer) {
fDx = buffer.readScalar();
fDy = buffer.readScalar();
- fSigma = buffer.readScalar();
+ fSigmaX = buffer.readScalar();
+ fSigmaY = buffer.readScalar();
fColor = buffer.readColor();
buffer.validate(SkScalarIsFinite(fDx) &&
SkScalarIsFinite(fDy) &&
- SkScalarIsFinite(fSigma));
+ SkScalarIsFinite(fSigmaX) &&
+ SkScalarIsFinite(fSigmaY));
}
void SkDropShadowImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const
@@ -39,7 +52,8 @@ void SkDropShadowImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const
this->INHERITED::flatten(buffer);
buffer.writeScalar(fDx);
buffer.writeScalar(fDy);
- buffer.writeScalar(fSigma);
+ buffer.writeScalar(fSigmaX);
+ buffer.writeScalar(fSigmaY);
buffer.writeColor(fColor);
}
@@ -49,17 +63,29 @@ bool SkDropShadowImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source
if (getInput(0) && !getInput(0)->filterImage(proxy, source, matrix, &src, loc))
return false;
- SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(src.width(), src.height()));
+ SkIRect bounds;
+ src.getBounds(&bounds);
+ if (!this->applyCropRect(&bounds, matrix)) {
+ return false;
+ }
+
+ SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
+ if (NULL == device.get()) {
+ return false;
+ }
SkCanvas canvas(device.get());
- SkAutoTUnref<SkImageFilter> blurFilter(new SkBlurImageFilter(fSigma, fSigma));
+ SkAutoTUnref<SkImageFilter> blurFilter(new SkBlurImageFilter(fSigmaX, fSigmaY));
SkAutoTUnref<SkColorFilter> colorFilter(SkColorFilter::CreateModeFilter(fColor, SkXfermode::kSrcIn_Mode));
SkPaint paint;
paint.setImageFilter(blurFilter.get());
paint.setColorFilter(colorFilter.get());
paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
+ canvas.translate(-SkIntToScalar(bounds.fLeft), -SkIntToScalar(bounds.fTop));
canvas.drawBitmap(src, fDx, fDy, &paint);
canvas.drawBitmap(src, 0, 0);
*result = device->accessBitmap(false);
+ loc->fX += bounds.fLeft;
+ loc->fY += bounds.fTop;
return true;
}
diff --git a/effects/SkEmbossMaskFilter.cpp b/effects/SkEmbossMaskFilter.cpp
index 2d312500..905cfab9 100644
--- a/effects/SkEmbossMaskFilter.cpp
+++ b/effects/SkEmbossMaskFilter.cpp
@@ -134,18 +134,10 @@ SkEmbossMaskFilter::SkEmbossMaskFilter(SkFlattenableReadBuffer& buffer)
SkASSERT(buffer.getArrayCount() == sizeof(Light));
buffer.readByteArray(&fLight, sizeof(Light));
SkASSERT(fLight.fPad == 0); // for the font-cache lookup to be clean
- fBlurSigma = buffer.readScalar();
-#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V13_AND_ALL_OTHER_INSTANCES_TOO
- // Fixing this must be done in two stages. When the skps are recaptured in V13,
- // remove the ConvertRadiusToSigma but retain the absolute value.
- // At the same time, switch the code in flatten to write a positive value.
- // When the skps are captured in V14 the absolute value can be removed.
- if (fBlurSigma > 0) {
- fBlurSigma = SkBlurMask::ConvertRadiusToSigma(fBlurSigma);
- } else {
- fBlurSigma = -fBlurSigma;
- }
+#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO
+ // TODO: Once skps are recaptured in > v15 this SkScalarAbs can be removed
#endif
+ fBlurSigma = SkScalarAbs(buffer.readScalar());
}
void SkEmbossMaskFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
@@ -154,7 +146,7 @@ void SkEmbossMaskFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
Light tmpLight = fLight;
tmpLight.fPad = 0; // for the font-cache lookup to be clean
buffer.writeByteArray(&tmpLight, sizeof(tmpLight));
- buffer.writeScalar(-fBlurSigma);
+ buffer.writeScalar(fBlurSigma);
}
#ifdef SK_DEVELOPER
diff --git a/effects/SkGpuBlurUtils.cpp b/effects/SkGpuBlurUtils.cpp
index 02fdf485..6133db11 100644
--- a/effects/SkGpuBlurUtils.cpp
+++ b/effects/SkGpuBlurUtils.cpp
@@ -11,7 +11,7 @@
#if SK_SUPPORT_GPU
#include "effects/GrConvolutionEffect.h"
-#include "effects/GrTextureDomainEffect.h"
+#include "effects/GrTextureDomain.h"
#include "GrContext.h"
#endif
@@ -173,7 +173,7 @@ GrTexture* GaussianBlur(GrContext* context,
srcTexture,
matrix,
domain,
- GrTextureDomainEffect::kDecal_WrapMode,
+ GrTextureDomain::kDecal_Mode,
GrTextureParams::kBilerp_FilterMode));
paint.addColorEffect(effect);
} else {
diff --git a/effects/SkLayerDrawLooper.cpp b/effects/SkLayerDrawLooper.cpp
index 998c4bcd..65f058b9 100644
--- a/effects/SkLayerDrawLooper.cpp
+++ b/effects/SkLayerDrawLooper.cpp
@@ -13,8 +13,6 @@
#include "SkStringUtils.h"
#include "SkUnPreMultiply.h"
-SK_DEFINE_INST_COUNT(SkLayerDrawLooper)
-
SkLayerDrawLooper::LayerInfo::LayerInfo() {
fFlagsMask = 0; // ignore our paint flags
fPaintBits = 0; // ignore our paint fields
diff --git a/effects/SkLightingImageFilter.cpp b/effects/SkLightingImageFilter.cpp
index 8c8798f0..50cca07d 100644
--- a/effects/SkLightingImageFilter.cpp
+++ b/effects/SkLightingImageFilter.cpp
@@ -549,8 +549,6 @@ private:
SkPoint3 fColor;
};
-SK_DEFINE_INST_COUNT(SkLight)
-
///////////////////////////////////////////////////////////////////////////////
class SkDistantLight : public SkLight {
@@ -814,6 +812,7 @@ void SkLight::flattenLight(SkFlattenableWriteBuffer& buffer) const {
case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
default:
SkDEBUGFAIL("Unknown LightType.");
+ buffer.validate(false);
return NULL;
}
}
@@ -952,6 +951,9 @@ bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
dst->setConfig(src.config(), bounds.width(), bounds.height());
dst->allocPixels();
+ if (!dst->getPixels()) {
+ return false;
+ }
SkAutoTUnref<SkLight> transformedLight(light()->transform(ctm));
@@ -1040,6 +1042,9 @@ bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
dst->setConfig(src.config(), bounds.width(), bounds.height());
dst->allocPixels();
+ if (!dst->getPixels()) {
+ return false;
+ }
SpecularLightingType lightingType(fKS, fShininess);
SkAutoTUnref<SkLight> transformedLight(light()->transform(ctm));
diff --git a/effects/SkMagnifierImageFilter.cpp b/effects/SkMagnifierImageFilter.cpp
index d4120598..e6f3984b 100644
--- a/effects/SkMagnifierImageFilter.cpp
+++ b/effects/SkMagnifierImageFilter.cpp
@@ -240,7 +240,9 @@ SkMagnifierImageFilter::SkMagnifierImageFilter(SkFlattenableReadBuffer& buffer)
fSrcRect = SkRect::MakeXYWH(x, y, width, height);
fInset = buffer.readScalar();
- buffer.validate(SkIsValidRect(fSrcRect) && SkScalarIsFinite(fInset));
+ buffer.validate(SkScalarIsFinite(fInset) && SkIsValidRect(fSrcRect) &&
+ // Negative numbers in src rect are not supported
+ (fSrcRect.fLeft >= 0) && (fSrcRect.fTop >= 0));
}
// FIXME: implement single-input semantics
@@ -283,7 +285,9 @@ bool SkMagnifierImageFilter::onFilterImage(Proxy*, const SkBitmap& src,
SkASSERT(fSrcRect.width() < src.width());
SkASSERT(fSrcRect.height() < src.height());
- if (src.config() != SkBitmap::kARGB_8888_Config) {
+ if ((src.config() != SkBitmap::kARGB_8888_Config) ||
+ (fSrcRect.width() >= src.width()) ||
+ (fSrcRect.height() >= src.height())) {
return false;
}
@@ -293,13 +297,17 @@ bool SkMagnifierImageFilter::onFilterImage(Proxy*, const SkBitmap& src,
return false;
}
+ dst->setConfig(src.config(), src.width(), src.height());
+ dst->allocPixels();
+ if (!dst->getPixels()) {
+ return false;
+ }
+
SkScalar inv_inset = fInset > 0 ? SkScalarInvert(fInset) : SK_Scalar1;
SkScalar inv_x_zoom = fSrcRect.width() / src.width();
SkScalar inv_y_zoom = fSrcRect.height() / src.height();
- dst->setConfig(src.config(), src.width(), src.height());
- dst->allocPixels();
SkColor* sptr = src.getAddr32(0, 0);
SkColor* dptr = dst->getAddr32(0, 0);
int width = src.width(), height = src.height();
@@ -332,8 +340,8 @@ bool SkMagnifierImageFilter::onFilterImage(Proxy*, const SkBitmap& src,
SkScalar y_interp = SkScalarMul(weight, (fSrcRect.y() + y * inv_y_zoom)) +
(SK_Scalar1 - weight) * y;
- int x_val = SkMin32(SkScalarFloorToInt(x_interp), width - 1);
- int y_val = SkMin32(SkScalarFloorToInt(y_interp), height - 1);
+ int x_val = SkPin32(SkScalarFloorToInt(x_interp), 0, width - 1);
+ int y_val = SkPin32(SkScalarFloorToInt(y_interp), 0, height - 1);
*dptr = sptr[y_val * width + x_val];
dptr++;
diff --git a/effects/SkMatrixConvolutionImageFilter.cpp b/effects/SkMatrixConvolutionImageFilter.cpp
index cef0450f..3da27cef 100644
--- a/effects/SkMatrixConvolutionImageFilter.cpp
+++ b/effects/SkMatrixConvolutionImageFilter.cpp
@@ -279,6 +279,9 @@ bool SkMatrixConvolutionImageFilter::onFilterImage(Proxy* proxy,
result->setConfig(src.config(), bounds.width(), bounds.height());
result->allocPixels();
+ if (!result->getPixels()) {
+ return false;
+ }
SkIRect interior = SkIRect::MakeXYWH(bounds.left() + fTarget.fX,
bounds.top() + fTarget.fY,
diff --git a/effects/SkMergeImageFilter.cpp b/effects/SkMergeImageFilter.cpp
index a755fe68..33673b06 100755
--- a/effects/SkMergeImageFilter.cpp
+++ b/effects/SkMergeImageFilter.cpp
@@ -11,9 +11,6 @@
#include "SkFlattenableBuffers.h"
#include "SkValidationUtils.h"
-// Use 65535 as an arbitrary large number of inputs that this image filter should never overflow
-static const int kMaxInputs = 65535;
-
///////////////////////////////////////////////////////////////////////////////
void SkMergeImageFilter::initAllocModes() {
@@ -56,7 +53,7 @@ SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* first, SkImageFilter* seco
SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* filters[], int count,
const SkXfermode::Mode modes[],
const CropRect* cropRect) : INHERITED(count, filters, cropRect) {
- SkASSERT(count <= kMaxInputs);
+ SkASSERT(count >= 0);
this->initModes(modes);
}
@@ -161,16 +158,17 @@ void SkMergeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
}
SkMergeImageFilter::SkMergeImageFilter(SkFlattenableReadBuffer& buffer)
- : INHERITED(kMaxInputs, buffer) {
+ : INHERITED(-1, buffer) {
bool hasModes = buffer.readBool();
if (hasModes) {
this->initAllocModes();
int nbInputs = countInputs();
size_t size = nbInputs * sizeof(fModes[0]);
SkASSERT(buffer.getArrayCount() == size);
- buffer.readByteArray(fModes, size);
- for (int i = 0; i < nbInputs; ++i) {
- buffer.validate(SkIsValidMode((SkXfermode::Mode)fModes[i]));
+ if (buffer.readByteArray(fModes, size)) {
+ for (int i = 0; i < nbInputs; ++i) {
+ buffer.validate(SkIsValidMode((SkXfermode::Mode)fModes[i]));
+ }
}
} else {
fModes = 0;
diff --git a/effects/SkMorphologyImageFilter.cpp b/effects/SkMorphologyImageFilter.cpp
index 3f2f9855..0d00c359 100644
--- a/effects/SkMorphologyImageFilter.cpp
+++ b/effects/SkMorphologyImageFilter.cpp
@@ -188,6 +188,9 @@ bool SkErodeImageFilter::onFilterImage(Proxy* proxy,
dst->setConfig(src.config(), bounds.width(), bounds.height());
dst->allocPixels();
+ if (!dst->getPixels()) {
+ return false;
+ }
int width = radius().width();
int height = radius().height();
@@ -247,6 +250,9 @@ bool SkDilateImageFilter::onFilterImage(Proxy* proxy,
dst->setConfig(src.config(), bounds.width(), bounds.height());
dst->allocPixels();
+ if (!dst->getPixels()) {
+ return false;
+ }
int width = radius().width();
int height = radius().height();
diff --git a/effects/SkOffsetImageFilter.cpp b/effects/SkOffsetImageFilter.cpp
index aefbcba8..59318e39 100644
--- a/effects/SkOffsetImageFilter.cpp
+++ b/effects/SkOffsetImageFilter.cpp
@@ -48,6 +48,9 @@ bool SkOffsetImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source,
}
SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
+ if (NULL == device.get()) {
+ return false;
+ }
SkCanvas canvas(device);
SkPaint paint;
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
diff --git a/effects/SkRectShaderImageFilter.cpp b/effects/SkRectShaderImageFilter.cpp
index ab38fc48..5c34547c 100644
--- a/effects/SkRectShaderImageFilter.cpp
+++ b/effects/SkRectShaderImageFilter.cpp
@@ -62,6 +62,9 @@ bool SkRectShaderImageFilter::onFilterImage(Proxy* proxy,
SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(),
bounds.height()));
+ if (NULL == device.get()) {
+ return false;
+ }
SkCanvas canvas(device.get());
SkPaint paint;
paint.setShader(fShader);
diff --git a/effects/SkTileImageFilter.cpp b/effects/SkTileImageFilter.cpp
index ccca4ff7..73e5304a 100644
--- a/effects/SkTileImageFilter.cpp
+++ b/effects/SkTileImageFilter.cpp
@@ -24,22 +24,31 @@ bool SkTileImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, const S
return false;
}
- int w = SkScalarTruncToInt(fDstRect.width());
- int h = SkScalarTruncToInt(fDstRect.height());
+ SkRect dstRect;
+ ctm.mapRect(&dstRect, fDstRect);
+ int w = SkScalarCeilToInt(dstRect.width());
+ int h = SkScalarCeilToInt(dstRect.height());
if (!fSrcRect.width() || !fSrcRect.height() || !w || !h) {
return false;
}
- SkIRect srcRect;
- fSrcRect.roundOut(&srcRect);
+ SkRect srcRect;
+ ctm.mapRect(&srcRect, fSrcRect);
+ SkIRect srcIRect;
+ srcRect.roundOut(&srcIRect);
SkBitmap subset;
- if (!source.extractSubset(&subset, srcRect)) {
+ SkIRect bounds;
+ source.getBounds(&bounds);
+ if (!srcIRect.intersect(bounds)) {
+ return true;
+ } else if (!source.extractSubset(&subset, srcIRect)) {
return false;
}
SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(w, h));
- SkIRect bounds;
- source.getBounds(&bounds);
+ if (NULL == device.get()) {
+ return false;
+ }
SkCanvas canvas(device);
SkPaint paint;
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
@@ -47,7 +56,6 @@ bool SkTileImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, const S
SkAutoTUnref<SkShader> shader(SkShader::CreateBitmapShader(subset,
SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
paint.setShader(shader);
- SkRect dstRect = fDstRect;
dstRect.offset(SkIntToScalar(localOffset.fX), SkIntToScalar(localOffset.fY));
canvas.drawRect(dstRect, paint);
*dst = device->accessBitmap(false);
@@ -58,7 +66,7 @@ SkTileImageFilter::SkTileImageFilter(SkFlattenableReadBuffer& buffer)
: INHERITED(1, buffer) {
buffer.readRect(&fSrcRect);
buffer.readRect(&fDstRect);
- buffer.validate(SkIsValidRect(fSrcRect) && SkIsValidRect(fDstRect));
+ buffer.validate(buffer.isValid() && SkIsValidRect(fSrcRect) && SkIsValidRect(fDstRect));
}
void SkTileImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
diff --git a/effects/SkTransparentShader.cpp b/effects/SkTransparentShader.cpp
index 970e74fa..1d7e8087 100644
--- a/effects/SkTransparentShader.cpp
+++ b/effects/SkTransparentShader.cpp
@@ -94,9 +94,6 @@ void SkTransparentShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
}
break;
}
- case SkBitmap::kA1_Config:
- SkDEBUGFAIL("kA1_Config umimplemented at this time");
- break;
default: // to avoid warnings
break;
}
diff --git a/effects/SkXfermodeImageFilter.cpp b/effects/SkXfermodeImageFilter.cpp
index 620bde9f..3ab52950 100644
--- a/effects/SkXfermodeImageFilter.cpp
+++ b/effects/SkXfermodeImageFilter.cpp
@@ -72,6 +72,9 @@ bool SkXfermodeImageFilter::onFilterImage(Proxy* proxy,
foregroundOffset.fY -= bounds.top();
SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
+ if (NULL == device.get()) {
+ return false;
+ }
SkCanvas canvas(device);
SkPaint paint;
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
diff --git a/fonts/SkGScalerContext.cpp b/fonts/SkGScalerContext.cpp
index f0543c57..551b01c9 100644
--- a/fonts/SkGScalerContext.cpp
+++ b/fonts/SkGScalerContext.cpp
@@ -176,6 +176,8 @@ SkScalerContext* SkGTypeface::onCreateScalerContext(
void SkGTypeface::onFilterRec(SkScalerContextRec* rec) const {
fProxy->filterRec(rec);
+ rec->setHinting(SkPaint::kNo_Hinting);
+ rec->fMaskFormat = SkMask::kARGB32_Format;
}
SkAdvancedTypefaceMetrics* SkGTypeface::onGetAdvancedTypefaceMetrics(
diff --git a/gpu/GrAARectRenderer.cpp b/gpu/GrAARectRenderer.cpp
index aa599ca8..2c21f09f 100644
--- a/gpu/GrAARectRenderer.cpp
+++ b/gpu/GrAARectRenderer.cpp
@@ -13,8 +13,6 @@
#include "SkColorPriv.h"
#include "effects/GrVertexEffect.h"
-SK_DEFINE_INST_COUNT(GrAARectRenderer)
-
///////////////////////////////////////////////////////////////////////////////
class GrGLAlignedRectEffect;
diff --git a/gpu/GrAllocator.h b/gpu/GrAllocator.h
index 23bb6b76..f2afec8e 100755
--- a/gpu/GrAllocator.h
+++ b/gpu/GrAllocator.h
@@ -39,6 +39,22 @@ public:
SkDEBUGCODE(if (!fOwnFirstBlock) {*((char*)initialBlock+fBlockSize-1)='a';} );
}
+ /*
+ * Set first block of memory to write into. Must be called before any other methods.
+ * This requires that you have passed NULL in the constructor.
+ *
+ * @param initialBlock optional memory to use for the first block.
+ * Must be at least itemSize*itemsPerBlock sized.
+ * Caller is responsible for freeing this memory.
+ */
+ void setInitialBlock(void* initialBlock) {
+ SkASSERT(0 == fCount);
+ SkASSERT(1 == fBlocks.count());
+ SkASSERT(NULL == fBlocks.back());
+ fOwnFirstBlock = false;
+ fBlocks.back() = initialBlock;
+ }
+
/**
* Adds an item and returns pointer to it.
*
@@ -145,9 +161,6 @@ public:
* Create an allocator
*
* @param itemsPerBlock the number of items to allocate at once
- * @param initialBlock optional memory to use for the first block.
- * Must be at least size(T)*itemsPerBlock sized.
- * Caller is responsible for freeing this memory.
*/
explicit GrTAllocator(int itemsPerBlock)
: fAllocator(sizeof(T), itemsPerBlock, NULL) {}
@@ -223,8 +236,15 @@ public:
}
protected:
- GrTAllocator(int itemsPerBlock, void* initialBlock)
- : fAllocator(sizeof(T), itemsPerBlock, initialBlock) {
+ /*
+ * Set first block of memory to write into. Must be called before any other methods.
+ *
+ * @param initialBlock optional memory to use for the first block.
+ * Must be at least size(T)*itemsPerBlock sized.
+ * Caller is responsible for freeing this memory.
+ */
+ void setInitialBlock(void* initialBlock) {
+ fAllocator.setInitialBlock(initialBlock);
}
private:
@@ -237,7 +257,8 @@ private:
typedef GrTAllocator<T> INHERITED;
public:
- GrSTAllocator() : INHERITED(N, fStorage.get()) {
+ GrSTAllocator() : INHERITED(N) {
+ this->setInitialBlock(fStorage.get());
}
private:
diff --git a/gpu/GrBinHashKey.h b/gpu/GrBinHashKey.h
index 7d4aa0fb..585a1a1c 100644
--- a/gpu/GrBinHashKey.h
+++ b/gpu/GrBinHashKey.h
@@ -13,37 +13,19 @@
#include "GrTypes.h"
/**
- * Hash function class that can take a data chunk of any predetermined length. The hash function
- * used is the One-at-a-Time Hash (http://burtleburtle.net/bob/hash/doobs.html).
- *
- * Keys are computed from ENTRY objects. ENTRY must be fully ordered by a member:
- * int compare(const GrTBinHashKey<ENTRY, ..>& k);
- * which returns negative if the ENTRY < k, 0 if it equals k, and positive if k < the ENTRY.
- * Additionally, ENTRY must be flattenable into the key using setKeyData.
- *
- * This class satisfies the requirements to be a key for a GrTHashTable.
+ * GrBinHashKey is a hash key class that can take a data chunk of any predetermined
+ * length. The hash function used is the One-at-a-Time Hash
+ * (http://burtleburtle.net/bob/hash/doobs.html).
*/
-template<typename ENTRY, size_t KEY_SIZE>
-class GrTBinHashKey {
+template<size_t KEY_SIZE>
+class GrBinHashKey {
public:
enum { kKeySize = KEY_SIZE };
- GrTBinHashKey() {
+ GrBinHashKey() {
this->reset();
}
- GrTBinHashKey(const GrTBinHashKey<ENTRY, KEY_SIZE>& other) {
- *this = other;
- }
-
- GrTBinHashKey<ENTRY, KEY_SIZE>& operator=(const GrTBinHashKey<ENTRY, KEY_SIZE>& other) {
- memcpy(this, &other, sizeof(*this));
- return *this;
- }
-
- ~GrTBinHashKey() {
- }
-
void reset() {
fHash = 0;
#ifdef SK_DEBUG
@@ -52,39 +34,49 @@ public:
}
void setKeyData(const uint32_t* SK_RESTRICT data) {
- SkASSERT(GrIsALIGN4(KEY_SIZE));
+ SK_COMPILE_ASSERT(KEY_SIZE % 4 == 0, key_size_mismatch);
memcpy(&fData, data, KEY_SIZE);
uint32_t hash = 0;
size_t len = KEY_SIZE;
while (len >= 4) {
hash += *data++;
- hash += (fHash << 10);
+ hash += (hash << 10);
hash ^= (hash >> 6);
len -= 4;
}
- hash += (fHash << 3);
- hash ^= (fHash >> 11);
- hash += (fHash << 15);
+ hash += (hash << 3);
+ hash ^= (hash >> 11);
+ hash += (hash << 15);
#ifdef SK_DEBUG
fIsValid = true;
#endif
fHash = hash;
}
- int compare(const GrTBinHashKey<ENTRY, KEY_SIZE>& key) const {
+ bool operator==(const GrBinHashKey<KEY_SIZE>& key) const {
SkASSERT(fIsValid && key.fIsValid);
- return memcmp(fData, key.fData, KEY_SIZE);
- }
-
- static bool EQ(const ENTRY& entry, const GrTBinHashKey<ENTRY, KEY_SIZE>& key) {
- SkASSERT(key.fIsValid);
- return 0 == entry.compare(key);
+ if (fHash != key.fHash) {
+ return false;
+ }
+ for (size_t i = 0; i < SK_ARRAY_COUNT(fData); ++i) {
+ if (fData[i] != key.fData[i]) {
+ return false;
+ }
+ }
+ return true;
}
- static bool LT(const ENTRY& entry, const GrTBinHashKey<ENTRY, KEY_SIZE>& key) {
- SkASSERT(key.fIsValid);
- return entry.compare(key) < 0;
+ bool operator<(const GrBinHashKey<KEY_SIZE>& key) const {
+ SkASSERT(fIsValid && key.fIsValid);
+ for (size_t i = 0; i < SK_ARRAY_COUNT(fData); ++i) {
+ if (fData[i] < key.fData[i]) {
+ return true;
+ } else if (fData[i] > key.fData[i]) {
+ return false;
+ }
+ }
+ return false;
}
uint32_t getHash() const {
@@ -94,12 +86,12 @@ public:
const uint8_t* getData() const {
SkASSERT(fIsValid);
- return fData;
+ return reinterpret_cast<const uint8_t*>(fData);
}
private:
uint32_t fHash;
- uint8_t fData[KEY_SIZE]; // Buffer for key storage
+ uint32_t fData[KEY_SIZE / sizeof(uint32_t)]; // Buffer for key storage.
#ifdef SK_DEBUG
public:
diff --git a/gpu/GrBitmapTextContext.cpp b/gpu/GrBitmapTextContext.cpp
index 8d955bbb..a43c4a28 100755
--- a/gpu/GrBitmapTextContext.cpp
+++ b/gpu/GrBitmapTextContext.cpp
@@ -70,7 +70,10 @@ void GrBitmapTextContext::flushGlyphs() {
GrCustomCoordsTextureEffect::Create(fCurrTexture, params),
kGlyphCoordsAttributeIndex)->unref();
- if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) {
+ if (NULL != fStrike && kARGB_GrMaskFormat == fStrike->getMaskFormat()) {
+ drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
+ drawState->setColor(0xffffffff);
+ } else if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) {
if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
fPaint.numColorStages()) {
diff --git a/gpu/GrClipMaskManager.cpp b/gpu/GrClipMaskManager.cpp
index 3aef3dee..4fd746f3 100644
--- a/gpu/GrClipMaskManager.cpp
+++ b/gpu/GrClipMaskManager.cpp
@@ -17,7 +17,7 @@
#include "GrRenderTarget.h"
#include "GrStencilBuffer.h"
#include "GrSWMaskHelper.h"
-#include "effects/GrTextureDomainEffect.h"
+#include "effects/GrTextureDomain.h"
#include "SkRasterClip.h"
#include "SkStrokeRec.h"
#include "SkTLazy.h"
@@ -52,8 +52,8 @@ void setup_drawstate_aaclip(GrGpu* gpu,
drawState->addCoverageEffect(
GrTextureDomainEffect::Create(result,
mat,
- GrTextureDomainEffect::MakeTexelDomain(result, domainTexels),
- GrTextureDomainEffect::kDecal_WrapMode,
+ GrTextureDomain::MakeTexelDomain(result, domainTexels),
+ GrTextureDomain::kDecal_Mode,
GrTextureParams::kNone_FilterMode,
kPosition_GrCoordSet))->unref();
}
@@ -365,8 +365,8 @@ void GrClipMaskManager::mergeMask(GrTexture* dstMask,
drawState->addColorEffect(
GrTextureDomainEffect::Create(srcMask,
sampleM,
- GrTextureDomainEffect::MakeTexelDomain(srcMask, srcBound),
- GrTextureDomainEffect::kDecal_WrapMode,
+ GrTextureDomain::MakeTexelDomain(srcMask, srcBound),
+ GrTextureDomain::kDecal_Mode,
GrTextureParams::kNone_FilterMode))->unref();
fGpu->drawSimpleRect(SkRect::Make(dstBound), NULL);
}
diff --git a/gpu/GrContext.cpp b/gpu/GrContext.cpp
index cab4414a..0eb8c5b7 100644
--- a/gpu/GrContext.cpp
+++ b/gpu/GrContext.cpp
@@ -32,9 +32,6 @@
#include "SkTLS.h"
#include "SkTrace.h"
-SK_DEFINE_INST_COUNT(GrContext)
-SK_DEFINE_INST_COUNT(GrDrawState)
-
// It can be useful to set this to false to test whether a bug is caused by using the
// InOrderDrawBuffer, to compare performance of using/not using InOrderDrawBuffer, or to make
// debugging simpler.
@@ -88,19 +85,7 @@ GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext)
}
}
-namespace {
-void* CreateThreadInstanceCount() {
- return SkNEW_ARGS(int, (0));
-}
-void DeleteThreadInstanceCount(void* v) {
- delete reinterpret_cast<int*>(v);
-}
-#define THREAD_INSTANCE_COUNT \
- (*reinterpret_cast<int*>(SkTLS::Get(CreateThreadInstanceCount, DeleteThreadInstanceCount)))
-}
-
GrContext::GrContext() {
- ++THREAD_INSTANCE_COUNT;
fDrawState = NULL;
fGpu = NULL;
fClip = NULL;
@@ -148,10 +133,6 @@ bool GrContext::init(GrBackend backend, GrBackendContext backendContext) {
return true;
}
-int GrContext::GetThreadInstanceCount() {
- return THREAD_INSTANCE_COUNT;
-}
-
GrContext::~GrContext() {
if (NULL == fGpu) {
return;
@@ -181,8 +162,6 @@ GrContext::~GrContext() {
SkSafeUnref(fPathRendererChain);
SkSafeUnref(fSoftwarePathRenderer);
fDrawState->unref();
-
- --THREAD_INSTANCE_COUNT;
}
void GrContext::contextLost() {
diff --git a/gpu/GrDrawTarget.cpp b/gpu/GrDrawTarget.cpp
index 6a1c4544..0b4d96af 100644
--- a/gpu/GrDrawTarget.cpp
+++ b/gpu/GrDrawTarget.cpp
@@ -18,8 +18,6 @@
#include "SkStrokeRec.h"
-SK_DEFINE_INST_COUNT(GrDrawTarget)
-
////////////////////////////////////////////////////////////////////////////////
GrDrawTarget::DrawInfo& GrDrawTarget::DrawInfo::operator =(const DrawInfo& di) {
@@ -962,8 +960,6 @@ void GrDrawTarget::initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* d
///////////////////////////////////////////////////////////////////////////////
-SK_DEFINE_INST_COUNT(GrDrawTargetCaps)
-
void GrDrawTargetCaps::reset() {
f8BitPaletteSupport = false;
fNPOTTextureTileSupport = false;
diff --git a/gpu/GrEffect.cpp b/gpu/GrEffect.cpp
index a64fd7c4..986e80a5 100644
--- a/gpu/GrEffect.cpp
+++ b/gpu/GrEffect.cpp
@@ -12,8 +12,6 @@
#include "GrMemoryPool.h"
#include "SkTLS.h"
-SK_DEFINE_INST_COUNT(GrEffect)
-
#if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
SkTArray<GrEffectTestFactory*, true>* GrEffectTestFactory::GetFactories() {
static SkTArray<GrEffectTestFactory*, true> gFactories;
@@ -61,8 +59,6 @@ int32_t GrBackendEffectFactory::fCurrEffectClassID = GrBackendEffectFactory::kIl
///////////////////////////////////////////////////////////////////////////////
-SK_DEFINE_INST_COUNT(GrEffectRef)
-
GrEffectRef::~GrEffectRef() {
SkASSERT(this->unique());
fEffect->EffectRefDestroyed();
diff --git a/gpu/GrGeometryBuffer.cpp b/gpu/GrGeometryBuffer.cpp
deleted file mode 100644
index 202d0c33..00000000
--- a/gpu/GrGeometryBuffer.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrGeometryBuffer.h"
-
-SK_DEFINE_INST_COUNT(GrGeometryBuffer)
diff --git a/gpu/GrOvalRenderer.cpp b/gpu/GrOvalRenderer.cpp
index 8f078dbc..ac33a5cc 100644
--- a/gpu/GrOvalRenderer.cpp
+++ b/gpu/GrOvalRenderer.cpp
@@ -22,8 +22,6 @@
#include "effects/GrVertexEffect.h"
-SK_DEFINE_INST_COUNT(GrOvalRenderer)
-
namespace {
struct CircleVertex {
diff --git a/gpu/GrPath.cpp b/gpu/GrPath.cpp
index f928dffa..adb3fe63 100644
--- a/gpu/GrPath.cpp
+++ b/gpu/GrPath.cpp
@@ -7,8 +7,6 @@
#include "GrPath.h"
-SK_DEFINE_INST_COUNT(GrPath)
-
GrResourceKey GrPath::ComputeKey(const SkPath& path, const SkStrokeRec& stroke) {
static const GrResourceKey::ResourceType gPathResourceType = GrResourceKey::GenerateResourceType();
static const GrCacheID::Domain gPathDomain = GrCacheID::GenerateDomain();
diff --git a/gpu/GrPathRenderer.cpp b/gpu/GrPathRenderer.cpp
index e88db22b..3dcedf9f 100644
--- a/gpu/GrPathRenderer.cpp
+++ b/gpu/GrPathRenderer.cpp
@@ -8,8 +8,6 @@
#include "GrPathRenderer.h"
-SK_DEFINE_INST_COUNT(GrPathRenderer)
-
GrPathRenderer::GrPathRenderer() {
}
diff --git a/gpu/GrPathRendererChain.cpp b/gpu/GrPathRendererChain.cpp
index d6de12b3..cac0475b 100644
--- a/gpu/GrPathRendererChain.cpp
+++ b/gpu/GrPathRendererChain.cpp
@@ -14,8 +14,6 @@
#include "GrDrawTargetCaps.h"
#include "GrGpu.h"
-SK_DEFINE_INST_COUNT(GrPathRendererChain)
-
GrPathRendererChain::GrPathRendererChain(GrContext* context)
: fInit(false)
, fOwner(context) {
diff --git a/gpu/GrPathUtils.cpp b/gpu/GrPathUtils.cpp
index 81348ec2..e2b1ac76 100644
--- a/gpu/GrPathUtils.cpp
+++ b/gpu/GrPathUtils.cpp
@@ -187,8 +187,6 @@ int GrPathUtils::worstCasePointCount(const SkPath& path, int* subpaths,
}
void GrPathUtils::QuadUVMatrix::set(const GrPoint qPts[3]) {
- // can't make this static, no cons :(
- SkMatrix UVpts;
#ifndef SK_SCALAR_IS_FLOAT
GrCrash("Expected scalar is float.");
#endif
@@ -197,18 +195,23 @@ void GrPathUtils::QuadUVMatrix::set(const GrPoint qPts[3]) {
// We know M * control_pts = [0 1/2 1]
// [0 0 1]
// [1 1 1]
+ // And control_pts = [x0 x1 x2]
+ // [y0 y1 y2]
+ // [1 1 1 ]
// We invert the control pt matrix and post concat to both sides to get M.
- UVpts.setAll(0, SK_ScalarHalf, SK_Scalar1,
- 0, 0, SK_Scalar1,
- SkScalarToPersp(SK_Scalar1),
- SkScalarToPersp(SK_Scalar1),
- SkScalarToPersp(SK_Scalar1));
- m.setAll(qPts[0].fX, qPts[1].fX, qPts[2].fX,
- qPts[0].fY, qPts[1].fY, qPts[2].fY,
- SkScalarToPersp(SK_Scalar1),
- SkScalarToPersp(SK_Scalar1),
- SkScalarToPersp(SK_Scalar1));
- if (!m.invert(&m)) {
+ // Using the known form of the control point matrix and the result, we can
+ // optimize and improve precision.
+
+ double x0 = qPts[0].fX;
+ double y0 = qPts[0].fY;
+ double x1 = qPts[1].fX;
+ double y1 = qPts[1].fY;
+ double x2 = qPts[2].fX;
+ double y2 = qPts[2].fY;
+ double det = x0*y1 - y0*x1 + x2*y0 - y2*x0 + x1*y2 - y1*x2;
+
+ if (!sk_float_isfinite(det)
+ || SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero)) {
// The quad is degenerate. Hopefully this is rare. Find the pts that are
// farthest apart to compute a line (unless it is really a pt).
SkScalar maxD = qPts[0].distanceToSqd(qPts[1]);
@@ -247,7 +250,35 @@ void GrPathUtils::QuadUVMatrix::set(const GrPoint qPts[3]) {
fM[3] = 0; fM[4] = 0; fM[5] = 100.f;
}
} else {
- m.postConcat(UVpts);
+ double scale = 1.0/det;
+
+ // compute adjugate matrix
+ double a0, a1, a2, a3, a4, a5, a6, a7, a8;
+ a0 = y1-y2;
+ a1 = x2-x1;
+ a2 = x1*y2-x2*y1;
+
+ a3 = y2-y0;
+ a4 = x0-x2;
+ a5 = x2*y0-x0*y2;
+
+ a6 = y0-y1;
+ a7 = x1-x0;
+ a8 = x0*y1-x1*y0;
+
+ // this performs the uv_pts*adjugate(control_pts) multiply,
+ // then does the scale by 1/det afterwards to improve precision
+ m[SkMatrix::kMScaleX] = (float)((0.5*a3 + a6)*scale);
+ m[SkMatrix::kMSkewX] = (float)((0.5*a4 + a7)*scale);
+ m[SkMatrix::kMTransX] = (float)((0.5*a5 + a8)*scale);
+
+ m[SkMatrix::kMSkewY] = (float)(a6*scale);
+ m[SkMatrix::kMScaleY] = (float)(a7*scale);
+ m[SkMatrix::kMTransY] = (float)(a8*scale);
+
+ m[SkMatrix::kMPersp0] = (float)((a0 + a3 + a6)*scale);
+ m[SkMatrix::kMPersp1] = (float)((a1 + a4 + a7)*scale);
+ m[SkMatrix::kMPersp2] = (float)((a2 + a5 + a8)*scale);
// The matrix should not have perspective.
SkDEBUGCODE(static const SkScalar gTOL = 1.f / 100.f);
diff --git a/gpu/GrRenderTarget.cpp b/gpu/GrRenderTarget.cpp
index 49a76149..f18df2cf 100644
--- a/gpu/GrRenderTarget.cpp
+++ b/gpu/GrRenderTarget.cpp
@@ -13,8 +13,6 @@
#include "GrGpu.h"
#include "GrStencilBuffer.h"
-SK_DEFINE_INST_COUNT(GrRenderTarget)
-
bool GrRenderTarget::readPixels(int left, int top, int width, int height,
GrPixelConfig config,
void* buffer,
diff --git a/gpu/GrResource.cpp b/gpu/GrResource.cpp
index 8b439061..e20a30ff 100644
--- a/gpu/GrResource.cpp
+++ b/gpu/GrResource.cpp
@@ -10,8 +10,6 @@
#include "GrResource.h"
#include "GrGpu.h"
-SK_DEFINE_INST_COUNT(GrResource)
-
GrResource::GrResource(GrGpu* gpu, bool isWrapped) {
fGpu = gpu;
fCacheEntry = NULL;
diff --git a/gpu/GrResourceCache.h b/gpu/GrResourceCache.h
index 38378ac7..ca30732b 100644
--- a/gpu/GrResourceCache.h
+++ b/gpu/GrResourceCache.h
@@ -54,7 +54,7 @@ public:
}
GrResourceKey() {
- fKey.fHashedKey.reset();
+ fKey.reset();
}
void reset(const GrCacheID& id, ResourceType type, ResourceFlags flags) {
@@ -63,41 +63,34 @@ public:
//!< returns hash value [0..kHashMask] for the key
int getHash() const {
- return fKey.fHashedKey.getHash() & kHashMask;
+ return fKey.getHash() & kHashMask;
}
bool isScratch() const {
return ScratchDomain() ==
- *reinterpret_cast<const GrCacheID::Domain*>(fKey.fHashedKey.getData() +
+ *reinterpret_cast<const GrCacheID::Domain*>(fKey.getData() +
kCacheIDDomainOffset);
}
ResourceType getResourceType() const {
- return *reinterpret_cast<const ResourceType*>(fKey.fHashedKey.getData() +
+ return *reinterpret_cast<const ResourceType*>(fKey.getData() +
kResourceTypeOffset);
}
ResourceFlags getResourceFlags() const {
- return *reinterpret_cast<const ResourceFlags*>(fKey.fHashedKey.getData() +
+ return *reinterpret_cast<const ResourceFlags*>(fKey.getData() +
kResourceFlagsOffset);
}
- int compare(const GrResourceKey& other) const {
- return fKey.fHashedKey.compare(other.fKey.fHashedKey);
- }
-
- static bool LT(const GrResourceKey& a, const GrResourceKey& b) {
- return a.compare(b) < 0;
- }
-
- static bool EQ(const GrResourceKey& a, const GrResourceKey& b) {
- return 0 == a.compare(b);
- }
+ bool operator==(const GrResourceKey& other) const { return fKey == other.fKey; }
+ bool operator<(const GrResourceKey& other) const { return fKey < other.fKey; }
- inline static bool LT(const GrResourceEntry& entry, const GrResourceKey& key);
- inline static bool EQ(const GrResourceEntry& entry, const GrResourceKey& key);
- inline static bool LT(const GrResourceEntry& a, const GrResourceEntry& b);
- inline static bool EQ(const GrResourceEntry& a, const GrResourceEntry& b);
+ static bool LessThan(const GrResourceEntry& entry, const GrResourceKey& key);
+ static bool Equals(const GrResourceEntry& entry, const GrResourceKey& key);
+#ifdef SK_DEBUG
+ static bool LessThan(const GrResourceEntry& a, const GrResourceEntry& b);
+ static bool Equals(const GrResourceEntry& a, const GrResourceEntry& b);
+#endif
private:
enum {
@@ -125,21 +118,9 @@ private:
memcpy(k + kResourceTypeOffset, &type, sizeof(ResourceType));
memcpy(k + kResourceFlagsOffset, &flags, sizeof(ResourceFlags));
memset(k + kPadOffset, 0, kPadSize);
- fKey.fHashedKey.setKeyData(keyData.fKey32);
+ fKey.setKeyData(keyData.fKey32);
}
-
- struct Key;
- typedef GrTBinHashKey<Key, kKeySize> HashedKey;
-
- struct Key {
- int compare(const HashedKey& hashedKey) const {
- return fHashedKey.compare(hashedKey);
- }
-
- HashedKey fHashedKey;
- };
-
- Key fKey;
+ GrBinHashKey<kKeySize> fKey;
};
// The cache listens for these messages to purge junk resources proactively.
@@ -174,21 +155,23 @@ private:
friend class GrDLinkedList;
};
-bool GrResourceKey::LT(const GrResourceEntry& entry, const GrResourceKey& key) {
- return LT(entry.key(), key);
+inline bool GrResourceKey::LessThan(const GrResourceEntry& entry, const GrResourceKey& key) {
+ return entry.key() < key;
}
-bool GrResourceKey::EQ(const GrResourceEntry& entry, const GrResourceKey& key) {
- return EQ(entry.key(), key);
+inline bool GrResourceKey::Equals(const GrResourceEntry& entry, const GrResourceKey& key) {
+ return entry.key() == key;
}
-bool GrResourceKey::LT(const GrResourceEntry& a, const GrResourceEntry& b) {
- return LT(a.key(), b.key());
+#ifdef SK_DEBUG
+inline bool GrResourceKey::LessThan(const GrResourceEntry& a, const GrResourceEntry& b) {
+ return a.key() < b.key();
}
-bool GrResourceKey::EQ(const GrResourceEntry& a, const GrResourceEntry& b) {
- return EQ(a.key(), b.key());
+inline bool GrResourceKey::Equals(const GrResourceEntry& a, const GrResourceEntry& b) {
+ return a.key() == b.key();
}
+#endif
///////////////////////////////////////////////////////////////////////////////
diff --git a/gpu/GrStencilBuffer.cpp b/gpu/GrStencilBuffer.cpp
index c12de523..ea7b4fa1 100644
--- a/gpu/GrStencilBuffer.cpp
+++ b/gpu/GrStencilBuffer.cpp
@@ -12,8 +12,6 @@
#include "GrGpu.h"
#include "GrResourceCache.h"
-SK_DEFINE_INST_COUNT(GrStencilBuffer)
-
void GrStencilBuffer::transferToCache() {
SkASSERT(NULL == this->getCacheEntry());
diff --git a/gpu/GrSurface.cpp b/gpu/GrSurface.cpp
index 3ac8bc22..fed95f23 100644
--- a/gpu/GrSurface.cpp
+++ b/gpu/GrSurface.cpp
@@ -11,8 +11,6 @@
#include "SkImageEncoder.h"
#include <stdio.h>
-SK_DEFINE_INST_COUNT(GrSurface)
-
bool GrSurface::savePixels(const char* filename) {
SkBitmap bm;
bm.setConfig(SkBitmap::kARGB_8888_Config, this->width(), this->height());
diff --git a/gpu/GrTHashTable.h b/gpu/GrTHashTable.h
index 3b329778..83462c70 100644
--- a/gpu/GrTHashTable.h
+++ b/gpu/GrTHashTable.h
@@ -16,8 +16,10 @@
/**
* Key needs
- * static bool EQ(const Entry&, const HashKey&);
- * static bool LT(const Entry&, const HashKey&);
+ * static bool Equals(const Entry&, const Key&);
+ * static bool LessThan(const Entry&, const Key&);
+ * static bool Equals(const Entry&, const Entry&); for SK_DEBUG if GrTHashTable::validate() is called
+ * static bool LessThan(const Entry&, const Entry&); for SK_DEBUG if GrTHashTable::validate() is called
* uint32_t getHash() const;
*
* Allows duplicate key entries but on find you may get
@@ -90,7 +92,7 @@ int GrTHashTable<T, Key, kHashBits>::searchArray(const Key& key) const {
int low = 0;
while (high > low) {
int index = (low + high) >> 1;
- if (Key::LT(*array[index], key)) {
+ if (Key::LessThan(*array[index], key)) {
low = index + 1;
} else {
high = index;
@@ -98,15 +100,15 @@ int GrTHashTable<T, Key, kHashBits>::searchArray(const Key& key) const {
}
// check if we found it
- if (Key::EQ(*array[high], key)) {
+ if (Key::Equals(*array[high], key)) {
// above search should have found the first occurrence if there
// are multiple.
- SkASSERT(0 == high || Key::LT(*array[high - 1], key));
+ SkASSERT(0 == high || Key::LessThan(*array[high - 1], key));
return high;
}
// now return the ~ of where we should insert it
- if (Key::LT(*array[high], key)) {
+ if (Key::LessThan(*array[high], key)) {
high += 1;
}
return ~high;
@@ -119,7 +121,7 @@ T* GrTHashTable<T, Key, kHashBits>::find(const Key& key, Filter filter) const {
int hashIndex = hash2Index(key.getHash());
T* elem = fHash[hashIndex];
- if (NULL != elem && Key::EQ(*elem, key) && filter(elem)) {
+ if (NULL != elem && Key::Equals(*elem, key) && filter(elem)) {
return elem;
}
@@ -133,9 +135,9 @@ T* GrTHashTable<T, Key, kHashBits>::find(const Key& key, Filter filter) const {
// above search should have found the first occurrence if there
// are multiple.
- SkASSERT(0 == index || Key::LT(*array[index - 1], key));
+ SkASSERT(0 == index || Key::LessThan(*array[index - 1], key));
- for ( ; index < count() && Key::EQ(*array[index], key); ++index) {
+ for ( ; index < count() && Key::Equals(*array[index], key); ++index) {
if (filter(fSorted[index])) {
// update the hash
fHash[hashIndex] = fSorted[index];
@@ -192,8 +194,8 @@ template <typename T, typename Key, size_t kHashBits>
void GrTHashTable<T, Key, kHashBits>::validate() const {
int count = fSorted.count();
for (int i = 1; i < count; i++) {
- SkASSERT(Key::LT(*fSorted[i - 1], *fSorted[i]) ||
- Key::EQ(*fSorted[i - 1], *fSorted[i]));
+ SkASSERT(Key::LessThan(*fSorted[i - 1], *fSorted[i]) ||
+ Key::Equals(*fSorted[i - 1], *fSorted[i]));
}
}
diff --git a/gpu/GrTextStrike.cpp b/gpu/GrTextStrike.cpp
index ddab1e95..c70e822c 100644
--- a/gpu/GrTextStrike.cpp
+++ b/gpu/GrTextStrike.cpp
@@ -16,9 +16,6 @@
#include "edtaa3.h"
#endif
-SK_DEFINE_INST_COUNT(GrFontScaler)
-SK_DEFINE_INST_COUNT(GrKey)
-
///////////////////////////////////////////////////////////////////////////////
#define FONT_CACHE_STATS 0
@@ -28,7 +25,7 @@ static int g_PurgeCount = 0;
GrFontCache::GrFontCache(GrGpu* gpu) : fGpu(gpu) {
gpu->ref();
- for (int i = 0; i < kMaskFormatCount; ++i) {
+ for (int i = 0; i < kAtlasCount; ++i) {
fAtlasMgr[i] = NULL;
}
@@ -37,7 +34,7 @@ GrFontCache::GrFontCache(GrGpu* gpu) : fGpu(gpu) {
GrFontCache::~GrFontCache() {
fCache.deleteAll();
- for (int i = 0; i < kMaskFormatCount; ++i) {
+ for (int i = 0; i < kAtlasCount; ++i) {
delete fAtlasMgr[i];
}
fGpu->unref();
@@ -47,28 +44,40 @@ GrFontCache::~GrFontCache() {
}
static GrPixelConfig mask_format_to_pixel_config(GrMaskFormat format) {
- switch (format) {
- case kA8_GrMaskFormat:
- return kAlpha_8_GrPixelConfig;
- case kA565_GrMaskFormat:
- return kRGB_565_GrPixelConfig;
- case kA888_GrMaskFormat:
- return kSkia8888_GrPixelConfig;
- default:
- SkDEBUGFAIL("unknown maskformat");
- }
- return kUnknown_GrPixelConfig;
+ static const GrPixelConfig sPixelConfigs[] = {
+ kAlpha_8_GrPixelConfig,
+ kRGB_565_GrPixelConfig,
+ kSkia8888_GrPixelConfig,
+ kSkia8888_GrPixelConfig
+ };
+ SK_COMPILE_ASSERT(SK_ARRAY_COUNT(sPixelConfigs) == kMaskFormatCount, array_size_mismatch);
+
+ return sPixelConfigs[format];
+}
+
+static int mask_format_to_atlas_index(GrMaskFormat format) {
+ static const int sAtlasIndices[] = {
+ GrFontCache::kA8_AtlasType,
+ GrFontCache::k565_AtlasType,
+ GrFontCache::k8888_AtlasType,
+ GrFontCache::k8888_AtlasType
+ };
+ SK_COMPILE_ASSERT(SK_ARRAY_COUNT(sAtlasIndices) == kMaskFormatCount, array_size_mismatch);
+
+ SkASSERT(sAtlasIndices[format] < GrFontCache::kAtlasCount);
+ return sAtlasIndices[format];
}
GrTextStrike* GrFontCache::generateStrike(GrFontScaler* scaler,
const Key& key) {
GrMaskFormat format = scaler->getMaskFormat();
GrPixelConfig config = mask_format_to_pixel_config(format);
- if (NULL == fAtlasMgr[format]) {
- fAtlasMgr[format] = SkNEW_ARGS(GrAtlasMgr, (fGpu, config));
+ int atlasIndex = mask_format_to_atlas_index(format);
+ if (NULL == fAtlasMgr[atlasIndex]) {
+ fAtlasMgr[atlasIndex] = SkNEW_ARGS(GrAtlasMgr, (fGpu, config));
}
GrTextStrike* strike = SkNEW_ARGS(GrTextStrike,
- (this, scaler->getKey(), format, fAtlasMgr[format]));
+ (this, scaler->getKey(), format, fAtlasMgr[atlasIndex]));
fCache.insert(key, strike);
if (fHead) {
@@ -86,7 +95,7 @@ GrTextStrike* GrFontCache::generateStrike(GrFontScaler* scaler,
void GrFontCache::freeAll() {
fCache.deleteAll();
- for (int i = 0; i < kMaskFormatCount; ++i) {
+ for (int i = 0; i < kAtlasCount; ++i) {
delete fAtlasMgr[i];
fAtlasMgr[i] = NULL;
}
@@ -177,7 +186,7 @@ void GrFontCache::validate() const {
#ifdef SK_DEVELOPER
void GrFontCache::dump() const {
static int gDumpCount = 0;
- for (int i = 0; i < kMaskFormatCount; ++i) {
+ for (int i = 0; i < kAtlasCount; ++i) {
if (NULL != fAtlasMgr[i]) {
GrTexture* texture = fAtlasMgr[i]->getTexture();
if (NULL != texture) {
diff --git a/gpu/GrTextStrike.h b/gpu/GrTextStrike.h
index 422ae0c3..c5a3f656 100644
--- a/gpu/GrTextStrike.h
+++ b/gpu/GrTextStrike.h
@@ -108,6 +108,15 @@ public:
void dump() const;
#endif
+ enum AtlasType {
+ kA8_AtlasType, //!< 1-byte per pixel
+ k565_AtlasType, //!< 2-bytes per pixel
+ k8888_AtlasType, //!< 4-bytes per pixel
+
+ kLast_AtlasType = k8888_AtlasType
+ };
+ static const int kAtlasCount = kLast_AtlasType + 1;
+
private:
friend class GrFontPurgeListener;
@@ -118,7 +127,7 @@ private:
GrTextStrike* fTail;
GrGpu* fGpu;
- GrAtlasMgr* fAtlasMgr[kMaskFormatCount];
+ GrAtlasMgr* fAtlasMgr[kAtlasCount];
GrTextStrike* generateStrike(GrFontScaler*, const Key&);
inline void detachStrikeFromList(GrTextStrike*);
diff --git a/gpu/GrTextStrike_impl.h b/gpu/GrTextStrike_impl.h
index 42971855..0691eaa6 100644
--- a/gpu/GrTextStrike_impl.h
+++ b/gpu/GrTextStrike_impl.h
@@ -19,10 +19,10 @@ public:
intptr_t getHash() const { return fFontScalerKey->getHash(); }
- static bool LT(const GrTextStrike& strike, const Key& key) {
+ static bool LessThan(const GrTextStrike& strike, const Key& key) {
return *strike.getFontScalerKey() < *key.fFontScalerKey;
}
- static bool EQ(const GrTextStrike& strike, const Key& key) {
+ static bool Equals(const GrTextStrike& strike, const Key& key) {
return *strike.getFontScalerKey() == *key.fFontScalerKey;
}
@@ -88,10 +88,10 @@ public:
uint32_t getHash() const { return fPackedID; }
- static bool LT(const GrGlyph& glyph, const Key& key) {
+ static bool LessThan(const GrGlyph& glyph, const Key& key) {
return glyph.fPackedID < key.fPackedID;
}
- static bool EQ(const GrGlyph& glyph, const Key& key) {
+ static bool Equals(const GrGlyph& glyph, const Key& key) {
return glyph.fPackedID == key.fPackedID;
}
diff --git a/gpu/GrTexture.cpp b/gpu/GrTexture.cpp
index b5a0195d..f8515153 100644
--- a/gpu/GrTexture.cpp
+++ b/gpu/GrTexture.cpp
@@ -15,8 +15,6 @@
#include "GrRenderTarget.h"
#include "GrResourceCache.h"
-SK_DEFINE_INST_COUNT(GrTexture)
-
GrTexture::~GrTexture() {
if (NULL != fRenderTarget.get()) {
fRenderTarget.get()->owningTextureDestroyed();
diff --git a/gpu/SkGpuDevice.cpp b/gpu/SkGpuDevice.cpp
index 6fb1403c..ce02f2c5 100644
--- a/gpu/SkGpuDevice.cpp
+++ b/gpu/SkGpuDevice.cpp
@@ -7,7 +7,8 @@
#include "SkGpuDevice.h"
-#include "effects/GrTextureDomainEffect.h"
+#include "effects/GrBicubicEffect.h"
+#include "effects/GrTextureDomain.h"
#include "effects/GrSimpleTextureEffect.h"
#include "GrContext.h"
@@ -154,6 +155,20 @@ static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
return bitmap;
}
+/*
+ * Calling SkBitmapDevice with individual params asks it to allocate pixel memory.
+ * We never want that, so we always need to call it with a bitmap argument
+ * (which says take my allocate (or lack thereof)).
+ *
+ * This is a REALLY good reason to finish the clean-up of SkBaseDevice, and have
+ * SkGpuDevice inherit from that instead of SkBitmapDevice.
+ */
+static SkBitmap make_bitmap(SkBitmap::Config config, int width, int height, bool isOpaque) {
+ SkBitmap bm;
+ bm.setConfig(config, width, height, isOpaque);
+ return bm;
+}
+
SkGpuDevice* SkGpuDevice::Create(GrSurface* surface) {
SkASSERT(NULL != surface);
if (NULL == surface->asRenderTarget() || NULL == surface->getContext()) {
@@ -209,7 +224,7 @@ SkGpuDevice::SkGpuDevice(GrContext* context,
int width,
int height,
int sampleCount)
- : SkBitmapDevice(config, width, height, false /*isOpaque*/) {
+ : SkBitmapDevice(make_bitmap(config, width, height, false /*isOpaque*/)) {
fDrawProcs = NULL;
@@ -1057,22 +1072,29 @@ void SkGpuDevice::drawBitmap(const SkDraw& draw,
SkCanvas::kNone_DrawBitmapRectFlag);
}
-// This method outsets 'iRect' by 1 all around and then clamps its extents to
+// This method outsets 'iRect' by 'outset' all around and then clamps its extents to
// 'clamp'. 'offset' is adjusted to remain positioned over the top-left corner
// of 'iRect' for all possible outsets/clamps.
-static inline void clamped_unit_outset_with_offset(SkIRect* iRect, SkPoint* offset,
- const SkIRect& clamp) {
- iRect->outset(1, 1);
-
- if (iRect->fLeft < clamp.fLeft) {
+static inline void clamped_outset_with_offset(SkIRect* iRect,
+ int outset,
+ SkPoint* offset,
+ const SkIRect& clamp) {
+ iRect->outset(outset, outset);
+
+ int leftClampDelta = clamp.fLeft - iRect->fLeft;
+ if (leftClampDelta > 0) {
+ offset->fX -= outset - leftClampDelta;
iRect->fLeft = clamp.fLeft;
} else {
- offset->fX -= SK_Scalar1;
+ offset->fX -= outset;
}
- if (iRect->fTop < clamp.fTop) {
+
+ int topClampDelta = clamp.fTop - iRect->fTop;
+ if (topClampDelta > 0) {
+ offset->fY -= outset - topClampDelta;
iRect->fTop = clamp.fTop;
} else {
- offset->fY -= SK_Scalar1;
+ offset->fY -= outset;
}
if (iRect->fRight > clamp.fRight) {
@@ -1092,10 +1114,17 @@ void SkGpuDevice::drawBitmapCommon(const SkDraw& draw,
CHECK_SHOULD_DRAW(draw, false);
SkRect srcRect;
+ // If there is no src rect, or the src rect contains the entire bitmap then we're effectively
+ // in the (easier) bleed case, so update flags.
if (NULL == srcRectPtr) {
srcRect.set(0, 0, SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
+ flags = (SkCanvas::DrawBitmapRectFlags) (flags | SkCanvas::kBleed_DrawBitmapRectFlag);
} else {
srcRect = *srcRectPtr;
+ if (srcRect.fLeft <= 0 && srcRect.fTop <= 0 &&
+ srcRect.fRight >= bitmap.width() && srcRect.fBottom >= bitmap.height()) {
+ flags = (SkCanvas::DrawBitmapRectFlags) (flags | SkCanvas::kBleed_DrawBitmapRectFlag);
+ }
}
if (paint.getMaskFilter()){
@@ -1148,47 +1177,62 @@ void SkGpuDevice::drawBitmapCommon(const SkDraw& draw,
GrTextureParams params;
SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel();
GrTextureParams::FilterMode textureFilterMode;
+
+ int tileFilterPad;
+ bool doBicubic = false;
+
switch(paintFilterLevel) {
case SkPaint::kNone_FilterLevel:
+ tileFilterPad = 0;
textureFilterMode = GrTextureParams::kNone_FilterMode;
break;
case SkPaint::kLow_FilterLevel:
+ tileFilterPad = 1;
textureFilterMode = GrTextureParams::kBilerp_FilterMode;
break;
case SkPaint::kMedium_FilterLevel:
+ tileFilterPad = 1;
textureFilterMode = GrTextureParams::kMipMap_FilterMode;
break;
- case SkPaint::kHigh_FilterLevel:
- // Fall back to mips for now
- textureFilterMode = GrTextureParams::kMipMap_FilterMode;
+ case SkPaint::kHigh_FilterLevel: {
+ // Minification can look bad with the bicubic effect.
+ if (fContext->getMatrix().getMinStretch() >= SK_Scalar1 &&
+ (flags & SkCanvas::kBleed_DrawBitmapRectFlag)) {
+ // We will install an effect that does the filtering in the shader.
+ textureFilterMode = GrTextureParams::kNone_FilterMode;
+ tileFilterPad = GrBicubicEffect::kFilterTexelPad;
+ doBicubic = true;
+ } else {
+ // We don't yet support doing bicubic filtering with an interior clamp. Fall back
+ // to MIPs
+ textureFilterMode = GrTextureParams::kMipMap_FilterMode;
+ tileFilterPad = 1;
+ }
break;
+ }
default:
SkErrorInternals::SetError( kInvalidPaint_SkError,
"Sorry, I don't understand the filtering "
"mode you asked for. Falling back to "
"MIPMaps.");
+ tileFilterPad = 1;
textureFilterMode = GrTextureParams::kMipMap_FilterMode;
break;
-
}
params.setFilterMode(textureFilterMode);
- int maxTileSize = fContext->getMaxTextureSize();
- if (SkPaint::kNone_FilterLevel != paint.getFilterLevel()) {
- // We may need a skosh more room if we have to bump out the tile
- // by 1 pixel all around
- maxTileSize -= 2;
- }
+ int maxTileSize = fContext->getMaxTextureSize() - 2 * tileFilterPad;
int tileSize;
SkIRect clippedSrcRect;
if (this->shouldTileBitmap(bitmap, params, srcRectPtr, maxTileSize, &tileSize,
&clippedSrcRect)) {
- this->drawTiledBitmap(bitmap, srcRect, clippedSrcRect, params, paint, flags, tileSize);
+ this->drawTiledBitmap(bitmap, srcRect, clippedSrcRect, params, paint, flags, tileSize,
+ doBicubic);
} else {
// take the simple case
- this->internalDrawBitmap(bitmap, srcRect, params, paint, flags);
+ this->internalDrawBitmap(bitmap, srcRect, params, paint, flags, doBicubic);
}
}
@@ -1200,7 +1244,8 @@ void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
const GrTextureParams& params,
const SkPaint& paint,
SkCanvas::DrawBitmapRectFlags flags,
- int tileSize) {
+ int tileSize,
+ bool bicubic) {
SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect);
int nx = bitmap.width() / tileSize;
@@ -1227,7 +1272,7 @@ void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
SkPoint offset = SkPoint::Make(SkIntToScalar(iTileR.fLeft),
SkIntToScalar(iTileR.fTop));
- if (SkPaint::kNone_FilterLevel != paint.getFilterLevel()) {
+ if (SkPaint::kNone_FilterLevel != paint.getFilterLevel() || bicubic) {
SkIRect iClampRect;
if (SkCanvas::kBleed_DrawBitmapRectFlag & flags) {
@@ -1235,13 +1280,15 @@ void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
// but stay within the bitmap bounds
iClampRect = SkIRect::MakeWH(bitmap.width(), bitmap.height());
} else {
+ SkASSERT(!bicubic); // Bicubic is not supported with non-bleed yet.
+
// In texture-domain/clamp mode we only want to expand the
// tile on edges interior to "srcRect" (i.e., we want to
// not bleed across the original clamped edges)
srcRect.roundOut(&iClampRect);
}
-
- clamped_unit_outset_with_offset(&iTileR, &offset, iClampRect);
+ int outset = bicubic ? GrBicubicEffect::kFilterTexelPad : 1;
+ clamped_outset_with_offset(&iTileR, outset, &offset, iClampRect);
}
if (bitmap.extractSubset(&tmpB, iTileR)) {
@@ -1251,7 +1298,7 @@ void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
tmpM.setTranslate(offset.fX, offset.fY);
GrContext::AutoMatrix am;
am.setPreConcat(fContext, tmpM);
- this->internalDrawBitmap(tmpB, tileR, params, paint, flags);
+ this->internalDrawBitmap(tmpB, tileR, params, paint, flags, bicubic);
}
}
}
@@ -1310,7 +1357,8 @@ void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap,
const SkRect& srcRect,
const GrTextureParams& params,
const SkPaint& paint,
- SkCanvas::DrawBitmapRectFlags flags) {
+ SkCanvas::DrawBitmapRectFlags flags,
+ bool bicubic) {
SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
bitmap.height() <= fContext->getMaxTextureSize());
@@ -1332,6 +1380,7 @@ void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap,
bool needsTextureDomain = false;
if (!(flags & SkCanvas::kBleed_DrawBitmapRectFlag) &&
params.filterMode() != GrTextureParams::kNone_FilterMode) {
+ SkASSERT(!bicubic);
// Need texture domain if drawing a sub rect.
needsTextureDomain = srcRect.width() < bitmap.width() ||
srcRect.height() < bitmap.height();
@@ -1374,8 +1423,12 @@ void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap,
effect.reset(GrTextureDomainEffect::Create(texture,
SkMatrix::I(),
textureDomain,
- GrTextureDomainEffect::kClamp_WrapMode,
+ GrTextureDomain::kClamp_Mode,
params.filterMode()));
+ } else if (bicubic) {
+ SkASSERT(GrTextureParams::kNone_FilterMode == params.filterMode());
+ SkShader::TileMode tileModes[2] = { params.getTileModeX(), params.getTileModeY() };
+ effect.reset(GrBicubicEffect::Create(texture, SkMatrix::I(), tileModes));
} else {
effect.reset(GrSimpleTextureEffect::Create(texture, SkMatrix::I(), params));
}
diff --git a/gpu/SkGrFontScaler.cpp b/gpu/SkGrFontScaler.cpp
index 65148666..8fdae48a 100644
--- a/gpu/SkGrFontScaler.cpp
+++ b/gpu/SkGrFontScaler.cpp
@@ -87,6 +87,8 @@ GrMaskFormat SkGrFontScaler::getMaskFormat() {
return kA565_GrMaskFormat;
case SkMask::kLCD32_Format:
return kA888_GrMaskFormat;
+ case SkMask::kARGB32_Format:
+ return kARGB_GrMaskFormat;
default:
SkDEBUGFAIL("unsupported SkMask::Format");
return kA8_GrMaskFormat;
@@ -172,8 +174,8 @@ bool SkGrFontScaler::getPackedGlyphImage(GrGlyph::PackedID packed,
expand_bits(rgba8888, bits, width, height, dstRB, srcRB);
break;
}
- default:
- GrCrash("Unknown GrMaskFormat");
+ default:
+ GrCrash("Invalid GrMaskFormat");
}
} else if (srcRB == dstRB) {
memcpy(dst, src, dstRB * height);
diff --git a/gpu/SkGrPixelRef.cpp b/gpu/SkGrPixelRef.cpp
index dc5d7558..01294266 100644
--- a/gpu/SkGrPixelRef.cpp
+++ b/gpu/SkGrPixelRef.cpp
@@ -117,6 +117,23 @@ SkGrPixelRef::SkGrPixelRef(GrSurface* surface, bool transferCacheLock) {
SkSafeRef(surface);
}
+SkGrPixelRef::SkGrPixelRef(const SkImageInfo&, GrSurface* surface, bool transferCacheLock) {
+ // TODO: figure out if this is responsible for Chrome canvas errors
+#if 0
+ // The GrTexture has a ref to the GrRenderTarget but not vice versa.
+ // If the GrTexture exists take a ref to that (rather than the render
+ // target)
+ fSurface = surface->asTexture();
+#else
+ fSurface = NULL;
+#endif
+ if (NULL == fSurface) {
+ fSurface = surface;
+ }
+ fUnlock = transferCacheLock;
+ SkSafeRef(surface);
+}
+
SkGrPixelRef::~SkGrPixelRef() {
if (fUnlock) {
GrContext* context = fSurface->getContext();
diff --git a/gpu/effects/GrBicubicEffect.cpp b/gpu/effects/GrBicubicEffect.cpp
index f6cc37dc..a6e08f20 100644
--- a/gpu/effects/GrBicubicEffect.cpp
+++ b/gpu/effects/GrBicubicEffect.cpp
@@ -73,8 +73,14 @@ void GrGLBicubicEffect::emitCode(GrGLShaderBuilder* builder,
"\tvec4 c = coefficients * ts;\n"
"\treturn c.x * c0 + c.y * c1 + c.z * c2 + c.w * c3;\n",
&cubicBlendName);
- builder->fsCodeAppendf("\tvec2 coord = %s - %s * vec2(0.5, 0.5);\n", coords2D.c_str(), imgInc);
- builder->fsCodeAppendf("\tvec2 f = fract(coord / %s);\n", imgInc);
+ builder->fsCodeAppendf("\tvec2 coord = %s - %s * vec2(0.5);\n", coords2D.c_str(), imgInc);
+ // We unnormalize the coord in order to determine our fractional offset (f) within the texel
+ // We then snap coord to a texel center and renormalize. The snap prevents cases where the
+ // starting coords are near a texel boundary and accumulations of imgInc would cause us to skip/
+ // double hit a texel.
+ builder->fsCodeAppendf("\tcoord /= %s;\n", imgInc);
+ builder->fsCodeAppend("\tvec2 f = fract(coord);\n");
+ builder->fsCodeAppendf("\tcoord = (coord - f + vec2(0.5)) * %s;\n", imgInc);
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
SkString coord;
@@ -100,23 +106,10 @@ void GrGLBicubicEffect::setData(const GrGLUniformManager& uman,
}
GrBicubicEffect::GrBicubicEffect(GrTexture* texture,
- const SkScalar coefficients[16])
- : INHERITED(texture, MakeDivByTextureWHMatrix(texture)) {
- for (int y = 0; y < 4; y++) {
- for (int x = 0; x < 4; x++) {
- // Convert from row-major scalars to column-major floats.
- fCoefficients[x * 4 + y] = SkScalarToFloat(coefficients[y * 4 + x]);
- }
- }
- this->setWillNotUseInputColor();
-}
-
-GrBicubicEffect::GrBicubicEffect(GrTexture* texture,
const SkScalar coefficients[16],
const SkMatrix &matrix,
- const GrTextureParams &params,
- GrCoordSet coordSet)
- : INHERITED(texture, matrix, params, coordSet) {
+ const SkShader::TileMode tileModes[2])
+ : INHERITED(texture, matrix, GrTextureParams(tileModes, GrTextureParams::kNone_FilterMode)) {
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
// Convert from row-major scalars to column-major floats.
diff --git a/gpu/effects/GrBicubicEffect.h b/gpu/effects/GrBicubicEffect.h
index eabc79fe..85bec771 100644
--- a/gpu/effects/GrBicubicEffect.h
+++ b/gpu/effects/GrBicubicEffect.h
@@ -17,6 +17,10 @@ class GrGLBicubicEffect;
class GrBicubicEffect : public GrSingleTextureEffect {
public:
+ enum {
+ kFilterTexelPad = 2, // Given a src rect in texels to be filtered, this number of
+ // surrounding texels are needed by the kernel in x and y.
+ };
virtual ~GrBicubicEffect();
static const char* Name() { return "Bicubic"; }
@@ -27,34 +31,44 @@ public:
virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
- static GrEffectRef* Create(GrTexture* tex, const SkScalar coefficients[16]) {
- AutoEffectUnref effect(SkNEW_ARGS(GrBicubicEffect, (tex, coefficients)));
- return CreateEffectRef(effect);
+ /**
+ * Create a simple Mitchell filter effect.
+ */
+ static GrEffectRef* Create(GrTexture* tex) {
+ return Create(tex, gMitchellCoefficients);
}
- static GrEffectRef* Create(GrTexture* tex, const SkScalar coefficients[16],
- const SkMatrix& matrix,
- const GrTextureParams& p,
- GrCoordSet coordSet = kLocal_GrCoordSet) {
- AutoEffectUnref effect(SkNEW_ARGS(GrBicubicEffect, (tex, coefficients, matrix, p, coordSet)));
- return CreateEffectRef(effect);
+ /**
+ * Create a simple filter effect with custom bicubic coefficients.
+ */
+ static GrEffectRef* Create(GrTexture* tex, const SkScalar coefficients[16]) {
+ const SkShader::TileMode tm[] = { SkShader::kClamp_TileMode, SkShader::kClamp_TileMode };
+ return Create(tex, coefficients, MakeDivByTextureWHMatrix(tex), tm);
}
- static GrEffectRef* Create(GrTexture* tex) {
- return Create(tex, gMitchellCoefficients);
+ /**
+ * Create a Mitchell filter effect with specified texture matrix and x/y tile modes.
+ */
+ static GrEffectRef* Create(GrTexture* tex,
+ const SkMatrix& matrix,
+ SkShader::TileMode tileModes[2]) {
+ return Create(tex, gMitchellCoefficients, matrix, tileModes);
}
- static GrEffectRef* Create(GrTexture* tex,
+ /**
+ * The most general Create method. This allows specification of the bicubic coefficients, the
+ * texture matrix, and the x/y tilemodes.
+ */
+ static GrEffectRef* Create(GrTexture* tex, const SkScalar coefficients[16],
const SkMatrix& matrix,
- const GrTextureParams& p,
- GrCoordSet coordSet = kLocal_GrCoordSet) {
- return Create(tex, gMitchellCoefficients, matrix, p, coordSet);
+ const SkShader::TileMode tileModes[2]) {
+ AutoEffectUnref effect(SkNEW_ARGS(GrBicubicEffect, (tex, coefficients, matrix, tileModes)));
+ return CreateEffectRef(effect);
}
private:
- GrBicubicEffect(GrTexture*, const SkScalar coefficients[16]);
GrBicubicEffect(GrTexture*, const SkScalar coefficients[16],
- const SkMatrix &matrix, const GrTextureParams &p, GrCoordSet coordSet);
+ const SkMatrix &matrix, const SkShader::TileMode tileModes[2]);
virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
float fCoefficients[16];
diff --git a/gpu/effects/GrTextureDomainEffect.cpp b/gpu/effects/GrTextureDomain.cpp
index 699aa729..70d61592 100644
--- a/gpu/effects/GrTextureDomainEffect.cpp
+++ b/gpu/effects/GrTextureDomain.cpp
@@ -5,12 +5,141 @@
* found in the LICENSE file.
*/
-#include "GrTextureDomainEffect.h"
+#include "GrTextureDomain.h"
#include "GrSimpleTextureEffect.h"
#include "GrTBackendEffectFactory.h"
#include "gl/GrGLEffect.h"
#include "SkFloatingPoint.h"
+
+GrTextureDomain::GrTextureDomain(const SkRect& domain, Mode mode, int index)
+ : fIndex(index) {
+
+ static const SkRect kFullRect = {0, 0, SK_Scalar1, SK_Scalar1};
+ if (domain.contains(kFullRect)) {
+ fMode = kIgnore_Mode;
+ } else {
+ fMode = mode;
+ }
+
+ if (fMode != kIgnore_Mode) {
+ // We don't currently handle domains that are empty or don't intersect the texture.
+ // It is OK if the domain rect is a line or point, but it should not be inverted. We do not
+ // handle rects that do not intersect the [0..1]x[0..1] rect.
+ SkASSERT(domain.fLeft <= domain.fRight);
+ SkASSERT(domain.fTop <= domain.fBottom);
+ fDomain.fLeft = SkMaxScalar(domain.fLeft, kFullRect.fLeft);
+ fDomain.fRight = SkMinScalar(domain.fRight, kFullRect.fRight);
+ fDomain.fTop = SkMaxScalar(domain.fTop, kFullRect.fTop);
+ fDomain.fBottom = SkMinScalar(domain.fBottom, kFullRect.fBottom);
+ SkASSERT(fDomain.fLeft <= fDomain.fRight);
+ SkASSERT(fDomain.fTop <= fDomain.fBottom);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void GrTextureDomain::GLDomain::sampleTexture(GrGLShaderBuilder* builder,
+ const GrTextureDomain& textureDomain,
+ const char* outColor,
+ const SkString& inCoords,
+ const GrGLEffect::TextureSampler sampler,
+ const char* inModulateColor) {
+ SkASSERT((Mode)-1 == fMode || textureDomain.mode() == fMode);
+ SkDEBUGCODE(fMode = textureDomain.mode();)
+
+ if (kIgnore_Mode == textureDomain.mode()) {
+ builder->fsCodeAppendf("\t%s = ", outColor);
+ builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler,
+ inCoords.c_str());
+ builder->fsCodeAppend(";\n");
+ return;
+ }
+
+ if (!fDomainUni.isValid()) {
+ const char* name;
+ SkString uniName("TexDom");
+ if (textureDomain.fIndex >= 0) {
+ uniName.appendS32(textureDomain.fIndex);
+ }
+ fDomainUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+ kVec4f_GrSLType, uniName.c_str(), &name);
+ fDomainName = name;
+ }
+ if (kClamp_Mode == textureDomain.mode()) {
+ SkString clampedCoords;
+ clampedCoords.appendf("\tclamp(%s, %s.xy, %s.zw)",
+ inCoords.c_str(), fDomainName.c_str(), fDomainName.c_str());
+
+ builder->fsCodeAppendf("\t%s = ", outColor);
+ builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler, clampedCoords.c_str());
+ builder->fsCodeAppend(";\n");
+ } else {
+ SkASSERT(GrTextureDomain::kDecal_Mode == textureDomain.mode());
+ // Add a block since we're going to declare variables.
+ GrGLShaderBuilder::FSBlock block(builder);
+
+ const char* domain = fDomainName.c_str();
+ if (kImagination_GrGLVendor == builder->ctxInfo().vendor()) {
+ // On the NexusS and GalaxyNexus, the other path (with the 'any'
+ // call) causes the compilation error "Calls to any function that
+ // may require a gradient calculation inside a conditional block
+ // may return undefined results". This appears to be an issue with
+ // the 'any' call since even the simple "result=black; if (any())
+ // result=white;" code fails to compile.
+ builder->fsCodeAppend("\tvec4 outside = vec4(0.0, 0.0, 0.0, 0.0);\n");
+ builder->fsCodeAppend("\tvec4 inside = ");
+ builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler, inCoords.c_str());
+ builder->fsCodeAppend(";\n");
+
+ builder->fsCodeAppendf("\tfloat x = abs(2.0*(%s.x - %s.x)/(%s.z - %s.x) - 1.0);\n",
+ inCoords.c_str(), domain, domain, domain);
+ builder->fsCodeAppendf("\tfloat y = abs(2.0*(%s.y - %s.y)/(%s.w - %s.y) - 1.0);\n",
+ inCoords.c_str(), domain, domain, domain);
+ builder->fsCodeAppend("\tfloat blend = step(1.0, max(x, y));\n");
+ builder->fsCodeAppendf("\t%s = mix(inside, outside, blend);\n", outColor);
+ } else {
+ builder->fsCodeAppend("\tbvec4 outside;\n");
+ builder->fsCodeAppendf("\toutside.xy = lessThan(%s, %s.xy);\n", inCoords.c_str(),
+ domain);
+ builder->fsCodeAppendf("\toutside.zw = greaterThan(%s, %s.zw);\n", inCoords.c_str(),
+ domain);
+ builder->fsCodeAppendf("\t%s = any(outside) ? vec4(0.0, 0.0, 0.0, 0.0) : ", outColor);
+ builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler, inCoords.c_str());
+ builder->fsCodeAppend(";\n");
+ }
+ }
+}
+
+void GrTextureDomain::GLDomain::setData(const GrGLUniformManager& uman,
+ const GrTextureDomain& textureDomain,
+ GrSurfaceOrigin textureOrigin) {
+ SkASSERT(textureDomain.mode() == fMode);
+ if (kIgnore_Mode != textureDomain.mode()) {
+ GrGLfloat values[4] = {
+ SkScalarToFloat(textureDomain.domain().left()),
+ SkScalarToFloat(textureDomain.domain().top()),
+ SkScalarToFloat(textureDomain.domain().right()),
+ SkScalarToFloat(textureDomain.domain().bottom())
+ };
+ // vertical flip if necessary
+ if (kBottomLeft_GrSurfaceOrigin == textureOrigin) {
+ values[1] = 1.0f - values[1];
+ values[3] = 1.0f - values[3];
+ // The top and bottom were just flipped, so correct the ordering
+ // of elements so that values = (l, t, r, b).
+ SkTSwap(values[1], values[3]);
+ }
+ if (0 != memcmp(values, fPrevDomain, 4 * sizeof(GrGLfloat))) {
+ uman.set4fv(fDomainUni, 1, values);
+ memcpy(fPrevDomain, values, 4 * sizeof(GrGLfloat));
+ }
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
class GrGLTextureDomainEffect : public GrGLEffect {
public:
GrGLTextureDomainEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
@@ -28,16 +157,13 @@ public:
static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
private:
- GrGLUniformManager::UniformHandle fNameUni;
- GrGLfloat fPrevDomain[4];
-
+ GrTextureDomain::GLDomain fGLDomain;
typedef GrGLEffect INHERITED;
};
GrGLTextureDomainEffect::GrGLTextureDomainEffect(const GrBackendEffectFactory& factory,
const GrDrawEffect&)
: INHERITED(factory) {
- fPrevDomain[0] = SK_FloatNaN;
}
void GrGLTextureDomainEffect::emitCode(GrGLShaderBuilder* builder,
@@ -47,80 +173,24 @@ void GrGLTextureDomainEffect::emitCode(GrGLShaderBuilder* builder,
const char* inputColor,
const TransformedCoordsArray& coords,
const TextureSamplerArray& samplers) {
- const GrTextureDomainEffect& texDom = drawEffect.castEffect<GrTextureDomainEffect>();
+ const GrTextureDomainEffect& effect = drawEffect.castEffect<GrTextureDomainEffect>();
+ const GrTextureDomain& domain = effect.textureDomain();
SkString coords2D = builder->ensureFSCoords2D(coords, 0);
- const char* domain;
- fNameUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
- kVec4f_GrSLType, "TexDom", &domain);
- if (GrTextureDomainEffect::kClamp_WrapMode == texDom.wrapMode()) {
-
- builder->fsCodeAppendf("\tvec2 clampCoord = clamp(%s, %s.xy, %s.zw);\n",
- coords2D.c_str(), domain, domain);
-
- builder->fsCodeAppendf("\t%s = ", outputColor);
- builder->fsAppendTextureLookupAndModulate(inputColor, samplers[0], "clampCoord");
- builder->fsCodeAppend(";\n");
- } else {
- SkASSERT(GrTextureDomainEffect::kDecal_WrapMode == texDom.wrapMode());
-
- if (kImagination_GrGLVendor == builder->ctxInfo().vendor()) {
- // On the NexusS and GalaxyNexus, the other path (with the 'any'
- // call) causes the compilation error "Calls to any function that
- // may require a gradient calculation inside a conditional block
- // may return undefined results". This appears to be an issue with
- // the 'any' call since even the simple "result=black; if (any())
- // result=white;" code fails to compile.
- builder->fsCodeAppend("\tvec4 outside = vec4(0.0, 0.0, 0.0, 0.0);\n");
- builder->fsCodeAppend("\tvec4 inside = ");
- builder->fsAppendTextureLookupAndModulate(inputColor, samplers[0], coords2D.c_str());
- builder->fsCodeAppend(";\n");
-
- builder->fsCodeAppendf("\tfloat x = abs(2.0*(%s.x - %s.x)/(%s.z - %s.x) - 1.0);\n",
- coords2D.c_str(), domain, domain, domain);
- builder->fsCodeAppendf("\tfloat y = abs(2.0*(%s.y - %s.y)/(%s.w - %s.y) - 1.0);\n",
- coords2D.c_str(), domain, domain, domain);
- builder->fsCodeAppend("\tfloat blend = step(1.0, max(x, y));\n");
- builder->fsCodeAppendf("\t%s = mix(inside, outside, blend);\n", outputColor);
- } else {
- builder->fsCodeAppend("\tbvec4 outside;\n");
- builder->fsCodeAppendf("\toutside.xy = lessThan(%s, %s.xy);\n", coords2D.c_str(), domain);
- builder->fsCodeAppendf("\toutside.zw = greaterThan(%s, %s.zw);\n", coords2D.c_str(), domain);
- builder->fsCodeAppendf("\t%s = any(outside) ? vec4(0.0, 0.0, 0.0, 0.0) : ", outputColor);
- builder->fsAppendTextureLookupAndModulate(inputColor, samplers[0], coords2D.c_str());
- builder->fsCodeAppend(";\n");
- }
- }
+ fGLDomain.sampleTexture(builder, domain, outputColor, coords2D, samplers[0], inputColor);
}
void GrGLTextureDomainEffect::setData(const GrGLUniformManager& uman,
const GrDrawEffect& drawEffect) {
- const GrTextureDomainEffect& texDom = drawEffect.castEffect<GrTextureDomainEffect>();
- const SkRect& domain = texDom.domain();
-
- float values[4] = {
- SkScalarToFloat(domain.left()),
- SkScalarToFloat(domain.top()),
- SkScalarToFloat(domain.right()),
- SkScalarToFloat(domain.bottom())
- };
- // vertical flip if necessary
- if (kBottomLeft_GrSurfaceOrigin == texDom.texture(0)->origin()) {
- values[1] = 1.0f - values[1];
- values[3] = 1.0f - values[3];
- // The top and bottom were just flipped, so correct the ordering
- // of elements so that values = (l, t, r, b).
- SkTSwap(values[1], values[3]);
- }
- if (0 != memcmp(values, fPrevDomain, 4 * sizeof(GrGLfloat))) {
- uman.set4fv(fNameUni, 1, values);
- memcpy(fPrevDomain, values, 4 * sizeof(GrGLfloat));
- }
+ const GrTextureDomainEffect& effect = drawEffect.castEffect<GrTextureDomainEffect>();
+ const GrTextureDomain& domain = effect.textureDomain();
+ fGLDomain.setData(uman, domain, effect.texture(0)->origin());
}
GrGLEffect::EffectKey GrGLTextureDomainEffect::GenKey(const GrDrawEffect& drawEffect,
const GrGLCaps&) {
- return drawEffect.castEffect<GrTextureDomainEffect>().wrapMode();
+ const GrTextureDomain& domain = drawEffect.castEffect<GrTextureDomainEffect>().textureDomain();
+ return GrTextureDomain::GLDomain::DomainKey(domain);
}
@@ -129,30 +199,19 @@ GrGLEffect::EffectKey GrGLTextureDomainEffect::GenKey(const GrDrawEffect& drawEf
GrEffectRef* GrTextureDomainEffect::Create(GrTexture* texture,
const SkMatrix& matrix,
const SkRect& domain,
- WrapMode wrapMode,
+ GrTextureDomain::Mode mode,
GrTextureParams::FilterMode filterMode,
GrCoordSet coordSet) {
static const SkRect kFullRect = {0, 0, SK_Scalar1, SK_Scalar1};
- if (kClamp_WrapMode == wrapMode && domain.contains(kFullRect)) {
+ if (GrTextureDomain::kIgnore_Mode == mode ||
+ (GrTextureDomain::kClamp_Mode == mode && domain.contains(kFullRect))) {
return GrSimpleTextureEffect::Create(texture, matrix, filterMode);
} else {
- SkRect clippedDomain;
- // We don't currently handle domains that are empty or don't intersect the texture.
- // It is OK if the domain rect is a line or point, but it should not be inverted. We do not
- // handle rects that do not intersect the [0..1]x[0..1] rect.
- SkASSERT(domain.fLeft <= domain.fRight);
- SkASSERT(domain.fTop <= domain.fBottom);
- clippedDomain.fLeft = SkMaxScalar(domain.fLeft, kFullRect.fLeft);
- clippedDomain.fRight = SkMinScalar(domain.fRight, kFullRect.fRight);
- clippedDomain.fTop = SkMaxScalar(domain.fTop, kFullRect.fTop);
- clippedDomain.fBottom = SkMinScalar(domain.fBottom, kFullRect.fBottom);
- SkASSERT(clippedDomain.fLeft <= clippedDomain.fRight);
- SkASSERT(clippedDomain.fTop <= clippedDomain.fBottom);
AutoEffectUnref effect(SkNEW_ARGS(GrTextureDomainEffect, (texture,
matrix,
- clippedDomain,
- wrapMode,
+ domain,
+ mode,
filterMode,
coordSet)));
return CreateEffectRef(effect);
@@ -163,12 +222,11 @@ GrEffectRef* GrTextureDomainEffect::Create(GrTexture* texture,
GrTextureDomainEffect::GrTextureDomainEffect(GrTexture* texture,
const SkMatrix& matrix,
const SkRect& domain,
- WrapMode wrapMode,
+ GrTextureDomain::Mode mode,
GrTextureParams::FilterMode filterMode,
GrCoordSet coordSet)
: GrSingleTextureEffect(texture, matrix, filterMode, coordSet)
- , fWrapMode(wrapMode)
- , fTextureDomain(domain) {
+ , fTextureDomain(domain, mode) {
}
GrTextureDomainEffect::~GrTextureDomainEffect() {
@@ -186,7 +244,7 @@ bool GrTextureDomainEffect::onIsEqual(const GrEffect& sBase) const {
}
void GrTextureDomainEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
- if (kDecal_WrapMode == fWrapMode) {
+ if (GrTextureDomain::kDecal_Mode == fTextureDomain.mode()) { // TODO: helper
*validFlags = 0;
} else {
this->updateConstantColorComponentsForModulation(color, validFlags);
@@ -208,14 +266,15 @@ GrEffectRef* GrTextureDomainEffect::TestCreate(SkRandom* random,
domain.fRight = random->nextRangeScalar(domain.fLeft, SK_Scalar1);
domain.fTop = random->nextUScalar1();
domain.fBottom = random->nextRangeScalar(domain.fTop, SK_Scalar1);
- WrapMode wrapMode = random->nextBool() ? kClamp_WrapMode : kDecal_WrapMode;
+ GrTextureDomain::Mode mode =
+ (GrTextureDomain::Mode) random->nextULessThan(GrTextureDomain::kModeCount);
const SkMatrix& matrix = GrEffectUnitTest::TestMatrix(random);
bool bilerp = random->nextBool();
GrCoordSet coords = random->nextBool() ? kLocal_GrCoordSet : kPosition_GrCoordSet;
return GrTextureDomainEffect::Create(textures[texIdx],
matrix,
domain,
- wrapMode,
+ mode,
bilerp ? GrTextureParams::kBilerp_FilterMode : GrTextureParams::kNone_FilterMode,
coords);
}
diff --git a/gpu/effects/GrTextureDomain.h b/gpu/effects/GrTextureDomain.h
new file mode 100644
index 00000000..f64d5c3c
--- /dev/null
+++ b/gpu/effects/GrTextureDomain.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrTextureDomainEffect_DEFINED
+#define GrTextureDomainEffect_DEFINED
+
+#include "GrSingleTextureEffect.h"
+#include "gl/GrGLEffect.h"
+
+class GrGLShaderBuilder;
+struct SkRect;
+
+/**
+ * Limits a texture's lookup coordinates to a domain. Samples outside the domain are either clamped
+ * the edge of the domain or result in a vec4 of zeros (decal mode). The domain is clipped to
+ * normalized texture coords ([0,1]x[0,1] square). Bilinear filtering can cause texels outside the
+ * domain to affect the read value unless the caller considers this when calculating the domain.
+ */
+class GrTextureDomain {
+public:
+ enum Mode {
+ kIgnore_Mode, // Ignore the texture domain rectangle.
+ kClamp_Mode, // Clamp texture coords to the domain rectangle.
+ kDecal_Mode, // Treat the area outside the domain rectangle as fully transparent.
+
+ kLastMode = kDecal_Mode
+ };
+ static const int kModeCount = kLastMode + 1;
+
+ /**
+ * @param index Pass a value >= 0 if using multiple texture domains in the same effect.
+ * It is used to keep inserted variables from causing name collisions.
+ */
+ GrTextureDomain(const SkRect& domain, Mode, int index = -1);
+
+ const SkRect& domain() const { return fDomain; }
+ Mode mode() const { return fMode; }
+
+ /* Computes a domain that bounds all the texels in texelRect. Note that with bilerp enabled
+ texels neighboring the domain may be read. */
+ static const SkRect MakeTexelDomain(const GrTexture* texture, const SkIRect& texelRect) {
+ SkScalar wInv = SK_Scalar1 / texture->width();
+ SkScalar hInv = SK_Scalar1 / texture->height();
+ SkRect result = {
+ texelRect.fLeft * wInv,
+ texelRect.fTop * hInv,
+ texelRect.fRight * wInv,
+ texelRect.fBottom * hInv
+ };
+ return result;
+ }
+
+ bool operator== (const GrTextureDomain& that) const {
+ return fMode == that.fMode && fDomain == that.fDomain;
+ }
+
+ /**
+ * A GrGLEffect subclass that corresponds to a GrEffect subclass that uses GrTextureDomain
+ * should include this helper. It generates the texture domain GLSL, produces the part of the
+ * effect key that reflects the texture domain code, and performs the uniform uploads necessary
+ * for texture domains.
+ */
+ class GLDomain {
+ public:
+ GLDomain() {
+ fPrevDomain[0] = SK_FloatNaN;
+ SkDEBUGCODE(fMode = (Mode) -1;)
+ }
+
+ /**
+ * Call this from GrGLEffect::emitCode() to sample the texture W.R.T. the domain and mode.
+ *
+ * @param outcolor name of vec4 variable to hold the sampled color.
+ * @param inCoords name of vec2 variable containing the coords to be used with the domain.
+ * It is assumed that this is a variable and not an expression.
+ * @param inModulateColor if non-NULL the sampled color will be modulated with this
+ * expression before being written to outColor.
+ */
+ void sampleTexture(GrGLShaderBuilder* builder,
+ const GrTextureDomain& textureDomain,
+ const char* outColor,
+ const SkString& inCoords,
+ const GrGLEffect::TextureSampler sampler,
+ const char* inModulateColor = NULL);
+
+ /**
+ * Call this from GrGLEffect::setData() to upload uniforms necessary for the texture domain.
+ * The rectangle is automatically adjusted to account for the texture's origin.
+ */
+ void setData(const GrGLUniformManager& uman, const GrTextureDomain& textureDomain,
+ GrSurfaceOrigin textureOrigin);
+
+ enum {
+ kDomainKeyBits = 2, // See DomainKey().
+ };
+
+ /**
+ * GrGLEffect::GenKey() must call this and include the returned value in it's computed key.
+ * The returned will be limited to the lower kDomainKeyBits bits.
+ */
+ static GrGLEffect::EffectKey DomainKey(const GrTextureDomain& domain) {
+ GR_STATIC_ASSERT(kModeCount <= 4);
+ return domain.mode();
+ }
+
+ private:
+ SkDEBUGCODE(Mode fMode;)
+ GrGLUniformManager::UniformHandle fDomainUni;
+ SkString fDomainName;
+ GrGLfloat fPrevDomain[4];
+ };
+
+protected:
+ Mode fMode;
+ SkRect fDomain;
+ int fIndex;
+
+ typedef GrSingleTextureEffect INHERITED;
+};
+
+class GrGLTextureDomainEffect;
+
+/**
+ * A basic texture effect that uses GrTextureDomain.
+ */
+class GrTextureDomainEffect : public GrSingleTextureEffect {
+
+public:
+ static GrEffectRef* Create(GrTexture*,
+ const SkMatrix&,
+ const SkRect& domain,
+ GrTextureDomain::Mode,
+ GrTextureParams::FilterMode filterMode,
+ GrCoordSet = kLocal_GrCoordSet);
+
+ virtual ~GrTextureDomainEffect();
+
+ static const char* Name() { return "TextureDomain"; }
+
+ typedef GrGLTextureDomainEffect GLEffect;
+
+ virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
+ virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
+
+ const GrTextureDomain& textureDomain() const { return fTextureDomain; }
+
+protected:
+ GrTextureDomain fTextureDomain;
+
+private:
+ GrTextureDomainEffect(GrTexture*,
+ const SkMatrix&,
+ const SkRect& domain,
+ GrTextureDomain::Mode,
+ GrTextureParams::FilterMode,
+ GrCoordSet);
+
+ virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
+
+ GR_DECLARE_EFFECT_TEST;
+
+ typedef GrSingleTextureEffect INHERITED;
+};
+
+#endif
diff --git a/gpu/effects/GrTextureDomainEffect.h b/gpu/effects/GrTextureDomainEffect.h
deleted file mode 100644
index 46ee2a65..00000000
--- a/gpu/effects/GrTextureDomainEffect.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrTextureDomainEffect_DEFINED
-#define GrTextureDomainEffect_DEFINED
-
-#include "GrSingleTextureEffect.h"
-
-class GrGLTextureDomainEffect;
-struct SkRect;
-
-/**
- * Limits a texture's lookup coordinates to a domain. Samples outside the domain are either clamped
- * the edge of the domain or result in a vec4 of zeros. The domain is clipped to normalized texture
- * coords ([0,1]x[0,1] square). Bilinear filtering can cause texels outside the domain to affect the
- * read value unless the caller considers this when calculating the domain. TODO: This should be a
- * helper that can assist an effect rather than effect unto itself.
- */
-class GrTextureDomainEffect : public GrSingleTextureEffect {
-
-public:
- /**
- * If SkShader::kDecal_TileMode sticks then this enum could be replaced by SkShader::TileMode.
- * We could also consider replacing/augmenting Decal mode with Border mode where the color
- * outside of the domain is user-specifiable. Decal mode currently has a hard (non-lerped)
- * transition between the border and the interior.
- */
- enum WrapMode {
- kClamp_WrapMode,
- kDecal_WrapMode,
- };
-
- static GrEffectRef* Create(GrTexture*,
- const SkMatrix&,
- const SkRect& domain,
- WrapMode,
- GrTextureParams::FilterMode filterMode,
- GrCoordSet = kLocal_GrCoordSet);
-
- virtual ~GrTextureDomainEffect();
-
- static const char* Name() { return "TextureDomain"; }
-
- typedef GrGLTextureDomainEffect GLEffect;
-
- virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
- virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
-
- const SkRect& domain() const { return fTextureDomain; }
- WrapMode wrapMode() const { return fWrapMode; }
-
- /* Computes a domain that bounds all the texels in texelRect. Note that with bilerp enabled
- texels neighboring the domain may be read. */
- static const SkRect MakeTexelDomain(const GrTexture* texture, const SkIRect& texelRect) {
- SkScalar wInv = SK_Scalar1 / texture->width();
- SkScalar hInv = SK_Scalar1 / texture->height();
- SkRect result = {
- texelRect.fLeft * wInv,
- texelRect.fTop * hInv,
- texelRect.fRight * wInv,
- texelRect.fBottom * hInv
- };
- return result;
- }
-
-protected:
- WrapMode fWrapMode;
- SkRect fTextureDomain;
-
-private:
- GrTextureDomainEffect(GrTexture*,
- const SkMatrix&,
- const SkRect& domain,
- WrapMode,
- GrTextureParams::FilterMode filterMode,
- GrCoordSet);
-
- virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
-
- GR_DECLARE_EFFECT_TEST;
-
- typedef GrSingleTextureEffect INHERITED;
-};
-
-#endif
diff --git a/gpu/effects/GrTextureStripAtlas.h b/gpu/effects/GrTextureStripAtlas.h
index e56e736d..e06e273e 100644
--- a/gpu/effects/GrTextureStripAtlas.h
+++ b/gpu/effects/GrTextureStripAtlas.h
@@ -136,12 +136,15 @@ private:
// Hash table entry for atlases
class AtlasEntry;
- typedef GrTBinHashKey<AtlasEntry, sizeof(GrTextureStripAtlas::Desc)> AtlasHashKey;
+ class AtlasHashKey : public GrBinHashKey<sizeof(GrTextureStripAtlas::Desc)> {
+ public:
+ static bool Equals(const AtlasEntry& entry, const AtlasHashKey& key);
+ static bool LessThan(const AtlasEntry& entry, const AtlasHashKey& key);
+ };
class AtlasEntry : public ::SkNoncopyable {
public:
AtlasEntry() : fAtlas(NULL) {}
~AtlasEntry() { SkDELETE(fAtlas); }
- int compare(const AtlasHashKey& key) const { return fKey.compare(key); }
AtlasHashKey fKey;
GrTextureStripAtlas* fAtlas;
};
@@ -178,4 +181,14 @@ private:
SkTDArray<AtlasRow*> fKeyTable;
};
+inline bool GrTextureStripAtlas::AtlasHashKey::Equals(const AtlasEntry& entry,
+ const AtlasHashKey& key) {
+ return entry.fKey == key;
+}
+
+inline bool GrTextureStripAtlas::AtlasHashKey::LessThan(const AtlasEntry& entry,
+ const AtlasHashKey& key) {
+ return entry.fKey < key;
+}
+
#endif
diff --git a/gpu/gl/GrGLCaps.cpp b/gpu/gl/GrGLCaps.cpp
index 1a39ba59..8d8c0225 100644
--- a/gpu/gl/GrGLCaps.cpp
+++ b/gpu/gl/GrGLCaps.cpp
@@ -11,8 +11,6 @@
#include "SkTSearch.h"
#include "SkTSort.h"
-SK_DEFINE_INST_COUNT(GrGLCaps)
-
GrGLCaps::GrGLCaps() {
this->reset();
}
diff --git a/gpu/gl/GrGLEffect.h b/gpu/gl/GrGLEffect.h
index b6807383..1cc3df24 100644
--- a/gpu/gl/GrGLEffect.h
+++ b/gpu/gl/GrGLEffect.h
@@ -40,6 +40,7 @@ class GrGLEffect {
public:
typedef GrBackendEffectFactory::EffectKey EffectKey;
typedef GrGLProgramEffects::TransformedCoordsArray TransformedCoordsArray;
+ typedef GrGLProgramEffects::TextureSampler TextureSampler;
typedef GrGLProgramEffects::TextureSamplerArray TextureSamplerArray;
enum {
diff --git a/gpu/gl/GrGLInterface.cpp b/gpu/gl/GrGLInterface.cpp
index 09f6a65e..e1c69e18 100644
--- a/gpu/gl/GrGLInterface.cpp
+++ b/gpu/gl/GrGLInterface.cpp
@@ -12,8 +12,6 @@
#include <stdio.h>
-SK_DEFINE_INST_COUNT(GrGLInterface)
-
#if GR_GL_PER_GL_FUNC_CALLBACK
namespace {
void GrGLDefaultInterfaceCallback(const GrGLInterface*) {}
diff --git a/gpu/gl/GrGLProgram.cpp b/gpu/gl/GrGLProgram.cpp
index 5b030fa3..cac38b4b 100644
--- a/gpu/gl/GrGLProgram.cpp
+++ b/gpu/gl/GrGLProgram.cpp
@@ -17,8 +17,6 @@
#include "GrGLSL.h"
#include "SkXfermode.h"
-SK_DEFINE_INST_COUNT(GrGLProgram)
-
#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fGpu->glInterface(), R, X)
diff --git a/gpu/gl/GrGLShaderBuilder.h b/gpu/gl/GrGLShaderBuilder.h
index 52c24ae3..103efa5a 100644
--- a/gpu/gl/GrGLShaderBuilder.h
+++ b/gpu/gl/GrGLShaderBuilder.h
@@ -208,6 +208,25 @@ public:
const GrGLContextInfo& ctxInfo() const;
+ /**
+ * Helper for begining and ending a block in the fragment code. TODO: Make GrGLShaderBuilder
+ * aware of all blocks and turn single \t's into the correct number of tabs (or spaces) so that
+ * our shaders print pretty without effect writers tracking indentation.
+ */
+ class FSBlock {
+ public:
+ FSBlock(GrGLShaderBuilder* builder) : fBuilder(builder) {
+ SkASSERT(NULL != builder);
+ fBuilder->fsCodeAppend("\t{\n");
+ }
+
+ ~FSBlock() {
+ fBuilder->fsCodeAppend("\t}\n");
+ }
+ private:
+ GrGLShaderBuilder* fBuilder;
+ };
+
protected:
GrGpuGL* gpu() const { return fGpu; }
diff --git a/gpu/gl/GrGLTexture.cpp b/gpu/gl/GrGLTexture.cpp
index 97721225..856cfb12 100644
--- a/gpu/gl/GrGLTexture.cpp
+++ b/gpu/gl/GrGLTexture.cpp
@@ -8,8 +8,6 @@
#include "GrGLTexture.h"
#include "GrGpuGL.h"
-SK_DEFINE_INST_COUNT(GrGLTexID)
-
#define GPUGL static_cast<GrGpuGL*>(getGpu())
#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
diff --git a/gpu/gl/GrGpuGL.cpp b/gpu/gl/GrGpuGL.cpp
index 9cf39b65..4b5221c3 100644
--- a/gpu/gl/GrGpuGL.cpp
+++ b/gpu/gl/GrGpuGL.cpp
@@ -552,7 +552,12 @@ bool GrGpuGL::uploadTexData(const GrGLTexture::Desc& desc,
SkAutoSMalloc<128 * 128> tempStorage;
// paletted textures cannot be partially updated
- bool useTexStorage = isNewTexture &&
+ // We currently lazily create MIPMAPs when the we see a draw with
+ // GrTextureParams::kMipMap_FilterMode. Using texture storage requires that the
+ // MIP levels are all created when the texture is created. So for now we don't use
+ // texture storage.
+ bool useTexStorage = false &&
+ isNewTexture &&
desc.fConfig != kIndex_8_GrPixelConfig &&
this->glCaps().texStorageSupport();
@@ -638,8 +643,7 @@ bool GrGpuGL::uploadTexData(const GrGLTexture::Desc& desc,
desc.fWidth == width && desc.fHeight == height) {
CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
if (useTexStorage) {
- // We never resize or change formats of textures. We don't use
- // mipmaps currently.
+ // We never resize or change formats of textures.
GL_ALLOC_CALL(this->glInterface(),
TexStorage2D(GR_GL_TEXTURE_2D,
1, // levels
@@ -1276,6 +1280,7 @@ void GrGpuGL::onClear(const SkIRect* rect, GrColor color, bool canIgnoreRect) {
return;
}
}
+
this->flushRenderTarget(rect);
GrAutoTRestore<ScissorState> asr(&fScissorState);
fScissorState.fEnabled = (NULL != rect);
@@ -1522,10 +1527,16 @@ void GrGpuGL::flushRenderTarget(const SkIRect* bound) {
if (fHWBoundRenderTarget != rt) {
GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, rt->renderFBOID()));
#ifdef SK_DEBUG
- GrGLenum status;
- GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
- if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
- GrPrintf("GrGpuGL::flushRenderTarget glCheckFramebufferStatus %x\n", status);
+ // don't do this check in Chromium -- this is causing
+ // lots of repeated command buffer flushes when the compositor is
+ // rendering with Ganesh, which is really slow; even too slow for
+ // Debug mode.
+ if (!this->glContext().info().isChromium()) {
+ GrGLenum status;
+ GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
+ if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
+ GrPrintf("GrGpuGL::flushRenderTarget glCheckFramebufferStatus %x\n", status);
+ }
}
#endif
fHWBoundRenderTarget = rt;
diff --git a/gpu/gl/GrGpuGL_program.cpp b/gpu/gl/GrGpuGL_program.cpp
index a777e8f3..a3beab1a 100644
--- a/gpu/gl/GrGpuGL_program.cpp
+++ b/gpu/gl/GrGpuGL_program.cpp
@@ -27,8 +27,6 @@ struct GrGpuGL::ProgramCache::Entry {
unsigned int fLRUStamp;
};
-SK_DEFINE_INST_COUNT(GrGpuGL::ProgramCache::Entry);
-
struct GrGpuGL::ProgramCache::ProgDescLess {
bool operator() (const GrGLProgramDesc& desc, const Entry* entry) {
SkASSERT(NULL != entry->fProgram.get());
diff --git a/gpu/gl/SkGLContextHelper.cpp b/gpu/gl/SkGLContextHelper.cpp
index 6f0372dd..da446be0 100644
--- a/gpu/gl/SkGLContextHelper.cpp
+++ b/gpu/gl/SkGLContextHelper.cpp
@@ -8,8 +8,6 @@
#include "gl/SkGLContextHelper.h"
#include "GrGLUtil.h"
-SK_DEFINE_INST_COUNT(SkGLContextHelper)
-
SkGLContextHelper::SkGLContextHelper()
: fFBO(0)
, fColorBufferID(0)
diff --git a/gpu/gl/debug/GrGLCreateDebugInterface.cpp b/gpu/gl/debug/GrGLCreateDebugInterface.cpp
index 2ccd1584..1a0e7acc 100644
--- a/gpu/gl/debug/GrGLCreateDebugInterface.cpp
+++ b/gpu/gl/debug/GrGLCreateDebugInterface.cpp
@@ -786,8 +786,6 @@ private:
typedef GrGLInterface INHERITED;
};
-SK_DEFINE_INST_COUNT(GrDebugGLInterface)
-
////////////////////////////////////////////////////////////////////////////////
const GrGLInterface* GrGLCreateDebugInterface() {
GrGLInterface* interface = SkNEW(GrDebugGLInterface);
diff --git a/gpu/gl/win/GrGLCreateNativeInterface_win.cpp b/gpu/gl/win/GrGLCreateNativeInterface_win.cpp
index e9207b16..06e406f8 100644
--- a/gpu/gl/win/GrGLCreateNativeInterface_win.cpp
+++ b/gpu/gl/win/GrGLCreateNativeInterface_win.cpp
@@ -11,7 +11,7 @@
#include "gl/GrGLInterface.h"
#include "gl/GrGLUtil.h"
#define WIN32_LEAN_AND_MEAN
-#include <Windows.h>
+#include <windows.h>
/*
* Windows makes the GL funcs all be __stdcall instead of __cdecl :(
diff --git a/gpu/gl/win/SkNativeGLContext_win.cpp b/gpu/gl/win/SkNativeGLContext_win.cpp
index d8777274..392c2bc9 100644
--- a/gpu/gl/win/SkNativeGLContext_win.cpp
+++ b/gpu/gl/win/SkNativeGLContext_win.cpp
@@ -10,7 +10,7 @@
#include "SkWGL.h"
#define WIN32_LEAN_AND_MEAN
-#include <Windows.h>
+#include <windows.h>
SkNativeGLContext::AutoContextRestore::AutoContextRestore() {
fOldHGLRC = wglGetCurrentContext();
diff --git a/gpu/gr_unittests.cpp b/gpu/gr_unittests.cpp
deleted file mode 100644
index ae9f67f2..00000000
--- a/gpu/gr_unittests.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-
-/*
- * Copyright 2010 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrBinHashKey.h"
-#include "GrDrawTarget.h"
-#include "SkMatrix.h"
-#include "GrRedBlackTree.h"
-
-// FIXME: needs to be in a header
-void gr_run_unittests();
-
-// If we aren't inheriting these as #defines from elsewhere,
-// clang demands they be declared before we #include the template
-// that relies on them.
-#ifdef SK_DEBUG
-static bool LT(const int& elem, int value) {
- return elem < value;
-}
-static bool EQ(const int& elem, int value) {
- return elem == value;
-}
-#include "GrTBSearch.h"
-
-static void test_bsearch() {
- const int array[] = {
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99
- };
-
- for (int n = 0; n < static_cast<int>(GR_ARRAY_COUNT(array)); ++n) {
- for (int i = 0; i < n; i++) {
- int index = GrTBSearch<int, int>(array, n, array[i]);
- SkASSERT(index == (int) i);
- index = GrTBSearch<int, int>(array, n, -array[i]);
- SkASSERT(index < 0);
- }
- }
-}
-#endif
-
-// bogus empty class for GrBinHashKey
-class BogusEntry {};
-
-static void test_binHashKey()
-{
- const char* testStringA_ = "abcdABCD";
- const char* testStringB_ = "abcdBBCD";
- const uint32_t* testStringA = reinterpret_cast<const uint32_t*>(testStringA_);
- const uint32_t* testStringB = reinterpret_cast<const uint32_t*>(testStringB_);
- enum {
- kDataLenUsedForKey = 8
- };
-
- GrTBinHashKey<BogusEntry, kDataLenUsedForKey> keyA;
- keyA.setKeyData(testStringA);
- // test copy constructor and comparison
- GrTBinHashKey<BogusEntry, kDataLenUsedForKey> keyA2(keyA);
- SkASSERT(keyA.compare(keyA2) == 0);
- SkASSERT(keyA.getHash() == keyA2.getHash());
- // test re-init
- keyA2.setKeyData(testStringA);
- SkASSERT(keyA.compare(keyA2) == 0);
- SkASSERT(keyA.getHash() == keyA2.getHash());
- // test sorting
- GrTBinHashKey<BogusEntry, kDataLenUsedForKey> keyB;
- keyB.setKeyData(testStringB);
- SkASSERT(keyA.compare(keyB) < 0);
- SkASSERT(keyA.getHash() != keyB.getHash());
-}
-
-
-void gr_run_unittests() {
- SkDEBUGCODE(test_bsearch();)
- test_binHashKey();
- GrRedBlackTree<int>::UnitTest();
-}
diff --git a/image/SkDataPixelRef.cpp b/image/SkDataPixelRef.cpp
index 05242433..7897bf93 100644
--- a/image/SkDataPixelRef.cpp
+++ b/image/SkDataPixelRef.cpp
@@ -27,6 +27,10 @@ void SkDataPixelRef::onUnlockPixels() {
// nothing to do
}
+size_t SkDataPixelRef::getAllocatedSizeInBytes() const {
+ return fData ? fData->size() : 0;
+}
+
void SkDataPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const {
this->INHERITED::flatten(buffer);
buffer.writeDataAsByteArray(fData);
diff --git a/image/SkDataPixelRef.h b/image/SkDataPixelRef.h
index 6b15802b..50c88571 100644
--- a/image/SkDataPixelRef.h
+++ b/image/SkDataPixelRef.h
@@ -22,6 +22,7 @@ public:
protected:
virtual void* onLockPixels(SkColorTable**) SK_OVERRIDE;
virtual void onUnlockPixels() SK_OVERRIDE;
+ virtual size_t getAllocatedSizeInBytes() const SK_OVERRIDE;
SkDataPixelRef(SkFlattenableReadBuffer& buffer);
virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
diff --git a/image/SkImage.cpp b/image/SkImage.cpp
index 39fd93ac..620922f6 100644
--- a/image/SkImage.cpp
+++ b/image/SkImage.cpp
@@ -10,8 +10,6 @@
#include "SkImagePriv.h"
#include "SkImage_Base.h"
-SK_DEFINE_INST_COUNT(SkImage)
-
static SkImage_Base* as_IB(SkImage* image) {
return static_cast<SkImage_Base*>(image);
}
diff --git a/image/SkImagePriv.cpp b/image/SkImagePriv.cpp
index f1916c6c..976a5b33 100644
--- a/image/SkImagePriv.cpp
+++ b/image/SkImagePriv.cpp
@@ -14,13 +14,16 @@ SkBitmap::Config SkImageInfoToBitmapConfig(const SkImageInfo& info) {
case kAlpha_8_SkColorType:
return SkBitmap::kA8_Config;
+ case kARGB_4444_SkColorType:
+ return SkBitmap::kARGB_4444_Config;
+
case kRGB_565_SkColorType:
return SkBitmap::kRGB_565_Config;
case kPMColor_SkColorType:
return SkBitmap::kARGB_8888_Config;
- case kIndex8_SkColorType:
+ case kIndex_8_SkColorType:
return SkBitmap::kIndex8_Config;
default:
@@ -30,52 +33,9 @@ SkBitmap::Config SkImageInfoToBitmapConfig(const SkImageInfo& info) {
return SkBitmap::kNo_Config;
}
-int SkImageBytesPerPixel(SkColorType ct) {
- static const uint8_t gColorTypeBytesPerPixel[] = {
- 1, // kAlpha_8_SkColorType
- 2, // kRGB_565_SkColorType
- 4, // kRGBA_8888_SkColorType
- 4, // kBGRA_8888_SkColorType
- 4, // kPMColor_SkColorType
- 1, // kIndex8_SkColorType
- };
-
- SkASSERT((size_t)ct < SK_ARRAY_COUNT(gColorTypeBytesPerPixel));
- return gColorTypeBytesPerPixel[ct];
-}
-
-bool SkBitmapToImageInfo(const SkBitmap& bm, SkImageInfo* info) {
- switch (bm.config()) {
- case SkBitmap::kA8_Config:
- info->fColorType = kAlpha_8_SkColorType;
- break;
-
- case SkBitmap::kIndex8_Config:
- info->fColorType = kIndex8_SkColorType;
- break;
-
- case SkBitmap::kRGB_565_Config:
- info->fColorType = kRGB_565_SkColorType;
- break;
-
- case SkBitmap::kARGB_8888_Config:
- info->fColorType = kPMColor_SkColorType;
- break;
-
- default:
- return false;
- }
-
- info->fWidth = bm.width();
- info->fHeight = bm.height();
- info->fAlphaType = bm.isOpaque() ? kOpaque_SkAlphaType :
- kPremul_SkAlphaType;
- return true;
-}
-
SkImage* SkNewImageFromBitmap(const SkBitmap& bm, bool canSharePixelRef) {
SkImageInfo info;
- if (!SkBitmapToImageInfo(bm, &info)) {
+ if (!bm.asImageInfo(&info)) {
return NULL;
}
diff --git a/image/SkImagePriv.h b/image/SkImagePriv.h
index 188b16d5..bf28f598 100644
--- a/image/SkImagePriv.h
+++ b/image/SkImagePriv.h
@@ -15,10 +15,6 @@ class SkPicture;
extern SkBitmap::Config SkImageInfoToBitmapConfig(const SkImageInfo&);
-extern int SkImageBytesPerPixel(SkColorType);
-
-extern bool SkBitmapToImageInfo(const SkBitmap&, SkImageInfo*);
-
// Call this if you explicitly want to use/share this pixelRef in the image
extern SkImage* SkNewImageFromPixelRef(const SkImageInfo&, SkPixelRef*,
size_t rowBytes);
@@ -48,8 +44,7 @@ extern void SkImagePrivDrawPicture(SkCanvas*, SkPicture*,
extern SkImage* SkNewImageFromPicture(const SkPicture*);
static inline size_t SkImageMinRowBytes(const SkImageInfo& info) {
- size_t rb = info.fWidth * SkImageBytesPerPixel(info.fColorType);
- return SkAlign4(rb);
+ return SkAlign4(info.minRowBytes());
}
// Given an image created from SkNewImageFromBitmap, return its pixelref. This
diff --git a/image/SkImage_Gpu.cpp b/image/SkImage_Gpu.cpp
index 036e45bb..ab0a5237 100644
--- a/image/SkImage_Gpu.cpp
+++ b/image/SkImage_Gpu.cpp
@@ -36,8 +36,6 @@ private:
typedef SkImage_Base INHERITED;
};
-SK_DEFINE_INST_COUNT(SkImage_Gpu)
-
///////////////////////////////////////////////////////////////////////////////
SkImage_Gpu::SkImage_Gpu(const SkBitmap& bitmap)
diff --git a/image/SkSurface.cpp b/image/SkSurface.cpp
index 2fd4e104..2dde36b9 100644
--- a/image/SkSurface.cpp
+++ b/image/SkSurface.cpp
@@ -9,8 +9,6 @@
#include "SkImagePriv.h"
#include "SkCanvas.h"
-SK_DEFINE_INST_COUNT(SkSurface)
-
///////////////////////////////////////////////////////////////////////////////
SkSurface_Base::SkSurface_Base(int width, int height) : INHERITED(width, height) {
diff --git a/image/SkSurface_Gpu.cpp b/image/SkSurface_Gpu.cpp
index e9049aef..e673cef6 100644
--- a/image/SkSurface_Gpu.cpp
+++ b/image/SkSurface_Gpu.cpp
@@ -31,8 +31,6 @@ private:
typedef SkSurface_Base INHERITED;
};
-SK_DEFINE_INST_COUNT(SkSurface_Gpu)
-
///////////////////////////////////////////////////////////////////////////////
SkSurface_Gpu::SkSurface_Gpu(GrContext* ctx, const SkImageInfo& info,
diff --git a/images/SkDecodingImageGenerator.cpp b/images/SkDecodingImageGenerator.cpp
index 65fa6fd5..a833c636 100644
--- a/images/SkDecodingImageGenerator.cpp
+++ b/images/SkDecodingImageGenerator.cpp
@@ -6,47 +6,203 @@
*/
#include "SkDecodingImageGenerator.h"
-
-#include "SkBitmapFactory.h"
#include "SkData.h"
-#include "SkDiscardablePixelRef.h"
#include "SkImageDecoder.h"
+#include "SkImageGenerator.h"
+#include "SkImagePriv.h"
+#include "SkStream.h"
+
+
+namespace {
+/**
+ * Special allocator used by getPixels(). Uses preallocated memory
+ * provided.
+ */
+class TargetAllocator : public SkBitmap::Allocator {
+public:
+ TargetAllocator(void* target, size_t rowBytes, const SkImageInfo& info)
+ : fTarget(target)
+ , fRowBytes(rowBytes)
+ , fInfo(info) { }
+
+ virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) SK_OVERRIDE {
+ if ((SkImageInfoToBitmapConfig(fInfo) != bm->config())
+ || (bm->width() != fInfo.fWidth)
+ || (bm->height() != fInfo.fHeight)) {
+ return false;
+ }
+ bm->setConfig(bm->config(), bm->width(), bm->height(),
+ fRowBytes, bm->alphaType());
+ bm->setPixels(fTarget, ct);
+ return true;
+ }
+
+private:
+ void* fTarget;
+ size_t fRowBytes;
+ SkImageInfo fInfo;
+ typedef SkBitmap::Allocator INHERITED;
+};
+} // namespace
+////////////////////////////////////////////////////////////////////////////////
SkDecodingImageGenerator::SkDecodingImageGenerator(SkData* data)
- : fData(data) {
+ : fData(data)
+ , fHasInfo(false)
+ , fDoCopyTo(false) {
SkASSERT(fData != NULL);
+ fStream = SkNEW_ARGS(SkMemoryStream, (fData));
+ SkASSERT(fStream != NULL);
+ SkASSERT(fStream->unique());
fData->ref();
}
+SkDecodingImageGenerator::SkDecodingImageGenerator(SkStreamRewindable* stream)
+ : fData(NULL)
+ , fStream(stream)
+ , fHasInfo(false)
+ , fDoCopyTo(false) {
+ SkASSERT(fStream != NULL);
+ SkASSERT(fStream->unique());
+}
+
SkDecodingImageGenerator::~SkDecodingImageGenerator() {
- fData->unref();
+ SkSafeUnref(fData);
+ fStream->unref();
}
+// TODO(halcanary): Give this macro a better name and move it into SkTypes.h
+#ifdef SK_DEBUG
+ #define SkCheckResult(expr, value) SkASSERT((value) == (expr))
+#else
+ #define SkCheckResult(expr, value) (void)(expr)
+#endif
+
SkData* SkDecodingImageGenerator::refEncodedData() {
- fData->ref();
- return fData;
+ // This functionality is used in `gm --serialize`
+ if (fData != NULL) {
+ return SkSafeRef(fData);
+ }
+ // TODO(halcanary): SkStreamRewindable needs a refData() function
+ // which returns a cheap copy of the underlying data.
+ if (!fStream->rewind()) {
+ return NULL;
+ }
+ size_t length = fStream->getLength();
+ if (0 == length) {
+ return NULL;
+ }
+ void* buffer = sk_malloc_flags(length, 0);
+ SkCheckResult(fStream->read(buffer, length), length);
+ fData = SkData::NewFromMalloc(buffer, length);
+ return SkSafeRef(fData);
}
bool SkDecodingImageGenerator::getInfo(SkImageInfo* info) {
- SkASSERT(info != NULL);
- return SkImageDecoder::DecodeMemoryToTarget(fData->data(),
- fData->size(),
- info, NULL);
+ // info can be NULL. If so, will update fInfo, fDoCopyTo, and fHasInfo.
+ if (fHasInfo) {
+ if (info != NULL) {
+ *info = fInfo;
+ }
+ return true;
+ }
+ SkAssertResult(fStream->rewind());
+ SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
+ if (NULL == decoder.get()) {
+ return false;
+ }
+ SkBitmap bitmap;
+ if (!decoder->decode(fStream, &bitmap,
+ SkImageDecoder::kDecodeBounds_Mode)) {
+ return false;
+ }
+ if (bitmap.config() == SkBitmap::kNo_Config) {
+ return false;
+ }
+ if (!bitmap.asImageInfo(&fInfo)) {
+ // We can't use bitmap.config() as is.
+ if (!bitmap.canCopyTo(SkBitmap::kARGB_8888_Config)) {
+ SkDEBUGFAIL("!bitmap->canCopyTo(SkBitmap::kARGB_8888_Config)");
+ return false;
+ }
+ fDoCopyTo = true;
+ fInfo.fWidth = bitmap.width();
+ fInfo.fHeight = bitmap.height();
+ fInfo.fColorType = kPMColor_SkColorType;
+ fInfo.fAlphaType = bitmap.alphaType();
+ }
+ if (info != NULL) {
+ *info = fInfo;
+ }
+ fHasInfo = true;
+ return true;
}
bool SkDecodingImageGenerator::getPixels(const SkImageInfo& info,
void* pixels,
size_t rowBytes) {
- SkASSERT(pixels != NULL);
- SkBitmapFactory::Target target = {pixels, rowBytes};
- SkImageInfo tmpInfo = info;
- return SkImageDecoder::DecodeMemoryToTarget(fData->data(),
- fData->size(),
- &tmpInfo, &target);
-}
-bool SkDecodingImageGenerator::Install(SkData* data, SkBitmap* dst) {
+ if (NULL == pixels) {
+ return false;
+ }
+ if (!this->getInfo(NULL)) {
+ return false;
+ }
+ if (SkImageInfoToBitmapConfig(info) == SkBitmap::kNo_Config) {
+ return false; // Unsupported SkColorType.
+ }
+ SkAssertResult(fStream->rewind());
+ SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
+ if (NULL == decoder.get()) {
+ return false;
+ }
+ if (fInfo != info) {
+ // The caller has specified a different info. For now, this
+ // is an error. In the future, we will check to see if we can
+ // convert.
+ return false;
+ }
+ int bpp = SkBitmap::ComputeBytesPerPixel(SkImageInfoToBitmapConfig(info));
+ if (static_cast<size_t>(bpp * info.fWidth) > rowBytes) {
+ return false;
+ }
+ SkBitmap bitmap;
+ if (!bitmap.setConfig(info, rowBytes)) {
+ return false;
+ }
+
+ TargetAllocator allocator(pixels, rowBytes, info);
+ if (!fDoCopyTo) {
+ decoder->setAllocator(&allocator);
+ }
+ bool success = decoder->decode(fStream, &bitmap,
+ SkImageDecoder::kDecodePixels_Mode);
+ decoder->setAllocator(NULL);
+ if (!success) {
+ return false;
+ }
+ if (fDoCopyTo) {
+ SkBitmap bm8888;
+ bitmap.copyTo(&bm8888, SkBitmap::kARGB_8888_Config, &allocator);
+ }
+ return true;
+}
+bool SkDecodingImageGenerator::Install(SkData* data, SkBitmap* dst,
+ SkDiscardableMemory::Factory* factory) {
SkASSERT(data != NULL);
SkASSERT(dst != NULL);
SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (data)));
- return SkDiscardablePixelRef::Install(gen, dst);
+ return SkInstallDiscardablePixelRef(gen, dst, factory);
+}
+
+bool SkDecodingImageGenerator::Install(SkStreamRewindable* stream,
+ SkBitmap* dst,
+ SkDiscardableMemory::Factory* factory) {
+ SkASSERT(stream != NULL);
+ SkASSERT(dst != NULL);
+ if ((stream == NULL) || !stream->unique()) {
+ SkSafeUnref(stream);
+ return false;
+ }
+ SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (stream)));
+ return SkInstallDiscardablePixelRef(gen, dst, factory);
}
diff --git a/images/SkDecodingImageGenerator.h b/images/SkDecodingImageGenerator.h
index 682aeb61..dba234bc 100644
--- a/images/SkDecodingImageGenerator.h
+++ b/images/SkDecodingImageGenerator.h
@@ -8,9 +8,12 @@
#ifndef SkDecodingImageGenerator_DEFINED
#define SkDecodingImageGenerator_DEFINED
+#include "SkDiscardableMemory.h"
#include "SkImageGenerator.h"
+#include "SkImageInfo.h"
class SkBitmap;
+class SkStreamRewindable;
/**
* Calls into SkImageDecoder::DecodeMemoryToTarget to implement a
@@ -22,7 +25,32 @@ public:
* The constructor will take a reference to the SkData. The
* destructor will unref() it.
*/
- SkDecodingImageGenerator(SkData* data);
+ explicit SkDecodingImageGenerator(SkData* data);
+
+ /*
+ * The SkData version of this constructor is preferred. If the
+ * stream has an underlying SkData (such as a SkMemoryStream)
+ * pass that in.
+ *
+ * This object will unref the stream when done. Since streams
+ * have internal state (position), the caller should not pass a
+ * shared stream in. Pass either a new duplicated stream in or
+ * transfer ownership of the stream. In the latter case, be sure
+ * that there are no other consumers of the stream who will
+ * modify the stream's position. This constructor asserts
+ * stream->unique().
+ *
+ * For example:
+ * SkStreamRewindable* stream;
+ * ...
+ * SkImageGenerator* gen
+ * = SkNEW_ARGS(SkDecodingImageGenerator,
+ * (stream->duplicate()));
+ * ...
+ * SkDELETE(gen);
+ */
+ explicit SkDecodingImageGenerator(SkStreamRewindable* stream);
+
virtual ~SkDecodingImageGenerator();
virtual SkData* refEncodedData() SK_OVERRIDE;
@@ -36,10 +64,57 @@ public:
/**
* Install the SkData into the destination bitmap, using a new
* SkDiscardablePixelRef and a new SkDecodingImageGenerator.
+ *
+ * @param data Contains the encoded image data that will be used
+ * by the SkDecodingImageGenerator. Will be ref()ed.
+ *
+ * @param destination Upon success, this bitmap will be
+ * configured and have a pixelref installed.
+ *
+ * @param factory If not NULL, this object will be used as a
+ * source of discardable memory when decoding. If NULL, then
+ * SkDiscardableMemory::Create() will be called.
+ *
+ * @return true iff successful.
+ */
+ static bool Install(SkData* data, SkBitmap* destination,
+ SkDiscardableMemory::Factory* factory = NULL);
+ /**
+ * Install the stream into the destination bitmap, using a new
+ * SkDiscardablePixelRef and a new SkDecodingImageGenerator.
+ *
+ * The SkData version of this function is preferred. If the
+ * stream has an underlying SkData (such as a SkMemoryStream)
+ * pass that in.
+ *
+ * @param stream The source of encoded data that will be passed
+ * to the decoder. The installed SkDecodingImageGenerator will
+ * unref the stream when done. If false is returned, this
+ * function will perform the unref. Since streams have internal
+ * state (position), the caller should not pass a shared stream
+ * in. Pass either a new duplicated stream in or transfer
+ * ownership of the stream. In the latter case, be sure that
+ * there are no other consumers of the stream who will modify the
+ * stream's position. This function will fail if
+ * (!stream->unique()).
+ *
+ * @param destination Upon success, this bitmap will be
+ * configured and have a pixelref installed.
+ *
+ * @param factory If not NULL, this object will be used as a
+ * source of discardable memory when decoding. If NULL, then
+ * SkDiscardableMemory::Create() will be called.
+ *
+ * @return true iff successful.
*/
- static bool Install(SkData* data, SkBitmap* destination);
+ static bool Install(SkStreamRewindable* stream, SkBitmap* destination,
+ SkDiscardableMemory::Factory* factory = NULL);
private:
- SkData* fData;
+ SkData* fData;
+ SkStreamRewindable* fStream;
+ SkImageInfo fInfo;
+ bool fHasInfo;
+ bool fDoCopyTo;
};
#endif // SkDecodingImageGenerator_DEFINED
diff --git a/images/SkImageDecoder.cpp b/images/SkImageDecoder.cpp
index 1ba93652..32cf087e 100644
--- a/images/SkImageDecoder.cpp
+++ b/images/SkImageDecoder.cpp
@@ -14,10 +14,6 @@
#include "SkTemplates.h"
#include "SkCanvas.h"
-SK_DEFINE_INST_COUNT(SkImageDecoder::Peeker)
-SK_DEFINE_INST_COUNT(SkImageDecoder::Chooser)
-SK_DEFINE_INST_COUNT(SkImageDecoderFactory)
-
static SkBitmap::Config gDeviceConfig = SkBitmap::kNo_Config;
SkBitmap::Config SkImageDecoder::GetDeviceConfig()
@@ -143,19 +139,6 @@ bool SkImageDecoder::allocPixelRef(SkBitmap* bitmap,
///////////////////////////////////////////////////////////////////////////////
-void SkImageDecoder::setPrefConfigTable(const SkBitmap::Config pref[6]) {
- if (NULL == pref) {
- fUsePrefTable = false;
- } else {
- fUsePrefTable = true;
- fPrefTable.fPrefFor_8Index_NoAlpha_src = pref[0];
- fPrefTable.fPrefFor_8Index_YesAlpha_src = pref[1];
- fPrefTable.fPrefFor_8Gray_src = SkBitmap::kNo_Config;
- fPrefTable.fPrefFor_8bpc_NoAlpha_src = pref[4];
- fPrefTable.fPrefFor_8bpc_YesAlpha_src = pref[5];
- }
-}
-
void SkImageDecoder::setPrefConfigTable(const PrefConfigTable& prefTable) {
fUsePrefTable = true;
fPrefTable = prefTable;
@@ -299,153 +282,6 @@ bool SkImageDecoder::DecodeMemory(const void* buffer, size_t size, SkBitmap* bm,
return SkImageDecoder::DecodeStream(&stream, bm, pref, mode, format);
}
-/**
- * Special allocator used by DecodeMemoryToTarget. Uses preallocated memory
- * provided if the bm is 8888. Otherwise, uses a heap allocator. The same
- * allocator will be used again for a copy to 8888, when the preallocated
- * memory will be used.
- */
-class TargetAllocator : public SkBitmap::HeapAllocator {
-
-public:
- TargetAllocator(void* target)
- : fTarget(target) {}
-
- virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) SK_OVERRIDE {
- // If the config is not 8888, allocate a pixelref using the heap.
- // fTarget will be used to store the final pixels when copied to
- // 8888.
- if (bm->config() != SkBitmap::kARGB_8888_Config) {
- return INHERITED::allocPixelRef(bm, ct);
- }
- // In kARGB_8888_Config, there is no colortable.
- SkASSERT(NULL == ct);
- bm->setPixels(fTarget);
- return true;
- }
-
-private:
- void* fTarget;
- typedef SkBitmap::HeapAllocator INHERITED;
-};
-
-/**
- * Helper function for DecodeMemoryToTarget. DecodeMemoryToTarget wants
- * 8888, so set the config to it. All parameters must not be null.
- * @param decoder Decoder appropriate for this stream.
- * @param stream Rewound stream to the encoded data.
- * @param bitmap On success, will have its bounds set to the bounds of the
- * encoded data, and its config set to 8888.
- * @return True if the bounds were decoded and the bitmap is 8888 or can be
- * copied to 8888.
- */
-static bool decode_bounds_to_8888(SkImageDecoder* decoder, SkStream* stream,
- SkBitmap* bitmap) {
- SkASSERT(decoder != NULL);
- SkASSERT(stream != NULL);
- SkASSERT(bitmap != NULL);
-
- if (!decoder->decode(stream, bitmap, SkImageDecoder::kDecodeBounds_Mode)) {
- return false;
- }
-
- if (bitmap->config() == SkBitmap::kARGB_8888_Config) {
- return true;
- }
-
- if (!bitmap->canCopyTo(SkBitmap::kARGB_8888_Config)) {
- return false;
- }
-
- bitmap->setConfig(SkBitmap::kARGB_8888_Config, bitmap->width(), bitmap->height());
- return true;
-}
-
-/**
- * Helper function for DecodeMemoryToTarget. Decodes the stream into bitmap, and if
- * the bitmap is not 8888, then it is copied to 8888. Either way, the end result has
- * its pixels stored in target. All parameters must not be null.
- * @param decoder Decoder appropriate for this stream.
- * @param stream Rewound stream to the encoded data.
- * @param bitmap On success, will contain the decoded image, with its pixels stored
- * at target.
- * @param target Preallocated memory for storing pixels.
- * @return bool Whether the decode (and copy, if necessary) succeeded.
- */
-static bool decode_pixels_to_8888(SkImageDecoder* decoder, SkStream* stream,
- SkBitmap* bitmap, void* target) {
- SkASSERT(decoder != NULL);
- SkASSERT(stream != NULL);
- SkASSERT(bitmap != NULL);
- SkASSERT(target != NULL);
-
- TargetAllocator allocator(target);
- decoder->setAllocator(&allocator);
-
- bool success = decoder->decode(stream, bitmap, SkImageDecoder::kDecodePixels_Mode);
- decoder->setAllocator(NULL);
-
- if (!success) {
- return false;
- }
-
- if (bitmap->config() == SkBitmap::kARGB_8888_Config) {
- return true;
- }
-
- SkBitmap bm8888;
- if (!bitmap->copyTo(&bm8888, SkBitmap::kARGB_8888_Config, &allocator)) {
- return false;
- }
-
- bitmap->swap(bm8888);
- return true;
-}
-
-bool SkImageDecoder::DecodeMemoryToTarget(const void* buffer, size_t size,
- SkImageInfo* info,
- const SkBitmapFactory::Target* target) {
- // FIXME: Just to get this working, implement in terms of existing
- // ImageDecoder calls.
- SkBitmap bm;
- SkMemoryStream stream(buffer, size);
- SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
- if (NULL == decoder.get()) {
- return false;
- }
-
- if (!decode_bounds_to_8888(decoder.get(), &stream, &bm)) {
- return false;
- }
-
- SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
-
- // Now set info properly.
- // Since Config is SkBitmap::kARGB_8888_Config, SkBitmapToImageInfo
- // will always succeed.
- if (info) {
- SkAssertResult(SkBitmapToImageInfo(bm, info));
- }
-
- if (NULL == target) {
- return true;
- }
-
- if (target->fRowBytes != SkToU32(bm.rowBytes())) {
- size_t minRB = SkBitmap::ComputeRowBytes(bm.config(), bm.width());
- if (target->fRowBytes < minRB) {
- SkDEBUGFAIL("Desired row bytes is too small");
- return false;
- }
- bm.setConfig(bm.config(), bm.width(), bm.height(), target->fRowBytes);
- }
-
- // SkMemoryStream.rewind() will always return true.
- SkAssertResult(stream.rewind());
- return decode_pixels_to_8888(decoder.get(), &stream, &bm, target->fAddr);
-}
-
-
bool SkImageDecoder::DecodeStream(SkStreamRewindable* stream, SkBitmap* bm,
SkBitmap::Config pref, Mode mode,
Format* format) {
diff --git a/images/SkMovie.cpp b/images/SkMovie.cpp
index d2439eb6..9a2a71cd 100644
--- a/images/SkMovie.cpp
+++ b/images/SkMovie.cpp
@@ -9,8 +9,6 @@
#include "SkCanvas.h"
#include "SkPaint.h"
-SK_DEFINE_INST_COUNT(SkMovie)
-
// We should never see this in normal operation since our time values are
// 0-based. So we use it as a sentinal.
#define UNINITIALIZED_MSEC ((SkMSec)-1)
diff --git a/lazy/SkBitmapFactory.cpp b/lazy/SkBitmapFactory.cpp
deleted file mode 100644
index 1bbb6f0d..00000000
--- a/lazy/SkBitmapFactory.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkBitmapFactory.h"
-
-#include "SkBitmap.h"
-#include "SkData.h"
-#include "SkImageCache.h"
-#include "SkImagePriv.h"
-#include "SkLazyPixelRef.h"
-
-SK_DEFINE_INST_COUNT(SkBitmapFactory::CacheSelector)
-
-SkBitmapFactory::SkBitmapFactory(SkBitmapFactory::DecodeProc proc)
- : fDecodeProc(proc)
- , fImageCache(NULL)
- , fCacheSelector(NULL) {
- SkASSERT(fDecodeProc != NULL);
-}
-
-SkBitmapFactory::~SkBitmapFactory() {
- SkSafeUnref(fImageCache);
- SkSafeUnref(fCacheSelector);
-}
-
-void SkBitmapFactory::setImageCache(SkImageCache *cache) {
- SkRefCnt_SafeAssign(fImageCache, cache);
- if (cache != NULL) {
- SkSafeUnref(fCacheSelector);
- fCacheSelector = NULL;
- }
-}
-
-void SkBitmapFactory::setCacheSelector(CacheSelector* selector) {
- SkRefCnt_SafeAssign(fCacheSelector, selector);
- if (selector != NULL) {
- SkSafeUnref(fImageCache);
- fImageCache = NULL;
- }
-}
-
-bool SkBitmapFactory::installPixelRef(SkData* data, SkBitmap* dst) {
- if (NULL == data || 0 == data->size() || dst == NULL) {
- return false;
- }
-
- SkImageInfo info;
- if (!fDecodeProc(data->data(), data->size(), &info, NULL)) {
- return false;
- }
-
- SkBitmap::Config config = SkImageInfoToBitmapConfig(info);
-
- Target target;
- // FIMXE: There will be a problem if this rowbytes is calculated differently from
- // in SkLazyPixelRef.
- target.fRowBytes = SkImageMinRowBytes(info);
- dst->setConfig(config, info.fWidth, info.fHeight, target.fRowBytes, info.fAlphaType);
-
- // fImageCache and fCacheSelector are mutually exclusive.
- SkASSERT(NULL == fImageCache || NULL == fCacheSelector);
-
- SkImageCache* cache = NULL == fCacheSelector ? fImageCache : fCacheSelector->selectCache(info);
-
- if (cache != NULL) {
- // Now set a new LazyPixelRef on dst.
- SkAutoTUnref<SkLazyPixelRef> lazyRef(SkNEW_ARGS(SkLazyPixelRef,
- (data, fDecodeProc, cache)));
- dst->setPixelRef(lazyRef);
- return true;
- } else {
- dst->allocPixels();
- target.fAddr = dst->getPixels();
- return fDecodeProc(data->data(), data->size(), &info, &target);
- }
-}
diff --git a/lazy/SkCachingPixelRef.cpp b/lazy/SkCachingPixelRef.cpp
index d12b7cf8..667a9493 100644
--- a/lazy/SkCachingPixelRef.cpp
+++ b/lazy/SkCachingPixelRef.cpp
@@ -8,66 +8,71 @@
#include "SkCachingPixelRef.h"
#include "SkScaledImageCache.h"
-SkCachingPixelRef::SkCachingPixelRef()
- : fErrorInDecoding(false)
- , fScaledCacheId(NULL) {
- memset(&fInfo, 0xFF, sizeof(fInfo));
-}
-SkCachingPixelRef::~SkCachingPixelRef() {
- SkASSERT(NULL == fScaledCacheId);
- // Assert always unlock before unref.
-}
-bool SkCachingPixelRef::getInfo(SkImageInfo* info) {
- SkASSERT(info != NULL);
- if (fErrorInDecoding) {
- return false; // Don't try again.
- }
- if (fInfo.fWidth < 0) {
- SkImageInfo tmp;
- if (!this->onDecodeInfo(&tmp)) {
- fErrorInDecoding = true;
- return false;
- }
- SkASSERT(tmp.fWidth >= 0);
- fInfo = tmp;
+bool SkCachingPixelRef::Install(SkImageGenerator* generator,
+ SkBitmap* dst) {
+ SkImageInfo info;
+ SkASSERT(generator != NULL);
+ SkASSERT(dst != NULL);
+ if ((NULL == generator)
+ || !(generator->getInfo(&info))
+ || !dst->setConfig(info, 0)) {
+ SkDELETE(generator);
+ return false;
}
- *info = fInfo;
+ SkAutoTUnref<SkCachingPixelRef> ref(SkNEW_ARGS(SkCachingPixelRef,
+ (generator,
+ info,
+ dst->rowBytes())));
+ dst->setPixelRef(ref);
return true;
}
-bool SkCachingPixelRef::configure(SkBitmap* bitmap) {
- SkASSERT(bitmap != NULL);
- SkImageInfo info;
- if (!this->getInfo(&info)) {
- return false;
- }
- return bitmap->setConfig(info, 0);
+SkCachingPixelRef::SkCachingPixelRef(SkImageGenerator* generator,
+ const SkImageInfo& info,
+ size_t rowBytes)
+ : fImageGenerator(generator)
+ , fErrorInDecoding(false)
+ , fScaledCacheId(NULL)
+ , fInfo(info)
+ , fRowBytes(rowBytes) {
+ SkASSERT(fImageGenerator != NULL);
+}
+SkCachingPixelRef::~SkCachingPixelRef() {
+ SkDELETE(fImageGenerator);
+ SkASSERT(NULL == fScaledCacheId);
+ // Assert always unlock before unref.
}
void* SkCachingPixelRef::onLockPixels(SkColorTable** colorTable) {
(void)colorTable;
- SkImageInfo info;
- if (!this->getInfo(&info)) {
- return NULL;
+ if (fErrorInDecoding) {
+ return NULL; // don't try again.
}
SkBitmap bitmap;
-
+ SkASSERT(NULL == fScaledCacheId);
fScaledCacheId = SkScaledImageCache::FindAndLock(this->getGenerationID(),
- info.fWidth,
- info.fHeight,
+ fInfo.fWidth,
+ fInfo.fHeight,
&bitmap);
if (NULL == fScaledCacheId) {
// Cache has been purged, must re-decode.
- if (!this->onDecodeInto(0, &bitmap)) {
+ if ((!bitmap.setConfig(fInfo, fRowBytes)) || !bitmap.allocPixels()) {
+ fErrorInDecoding = true;
+ return NULL;
+ }
+ SkAutoLockPixels autoLockPixels(bitmap);
+ if (!fImageGenerator->getPixels(fInfo, bitmap.getPixels(), fRowBytes)) {
+ fErrorInDecoding = true;
return NULL;
}
fScaledCacheId = SkScaledImageCache::AddAndLock(this->getGenerationID(),
- info.fWidth,
- info.fHeight,
+ fInfo.fWidth,
+ fInfo.fHeight,
bitmap);
SkASSERT(fScaledCacheId != NULL);
}
+
// Now bitmap should contain a concrete PixelRef of the decoded
// image.
SkAutoLockPixels autoLockPixels(bitmap);
@@ -91,21 +96,3 @@ void SkCachingPixelRef::onUnlockPixels() {
fScaledCacheId = NULL;
}
}
-
-bool SkCachingPixelRef::onDecodeInto(int pow2, SkBitmap* bitmap) {
- SkASSERT(bitmap != NULL);
- SkBitmap tmp;
- SkImageInfo info;
- // TODO(halcanary) - Enable SkCachingPixelRef to use a custom
- // allocator. `tmp.allocPixels(fAllocator, NULL)`
- if (!(this->configure(&tmp) && tmp.allocPixels())) {
- return false;
- }
- SkAssertResult(this->getInfo(&info)); // since configure() succeeded.
- if (!this->onDecodePixels(info, tmp.getPixels(), tmp.rowBytes())) {
- fErrorInDecoding = true;
- return false;
- }
- *bitmap = tmp;
- return true;
-}
diff --git a/lazy/SkCachingPixelRef.h b/lazy/SkCachingPixelRef.h
index db968dfc..4a0387dd 100644
--- a/lazy/SkCachingPixelRef.h
+++ b/lazy/SkCachingPixelRef.h
@@ -8,7 +8,8 @@
#ifndef SkCachingPixelRef_DEFINED
#define SkCachingPixelRef_DEFINED
-#include "SkImage.h"
+#include "SkImageInfo.h"
+#include "SkImageGenerator.h"
#include "SkPixelRef.h"
class SkColorTable;
@@ -20,60 +21,49 @@ class SkColorTable;
* or be destroyed before the next lock. If so, onLockPixels will
* attempt to re-decode.
*
- * Decoding is handled by the pure-virtual functions onDecodeInfo()
- * and onDecodePixels(). Subclasses of this class need only provide
- * those two functions.
+ * Decoding is handled by the SkImageGenerator
*/
class SkCachingPixelRef : public SkPixelRef {
public:
- SkCachingPixelRef();
- virtual ~SkCachingPixelRef();
+ /**
+ * Takes ownership of SkImageGenerator. If this method fails for
+ * whatever reason, it will return false and immediatetely delete
+ * the generator. If it succeeds, it will modify destination
+ * bitmap.
+ *
+ * If Install fails or when the SkCachingPixelRef that is
+ * installed into destination is destroyed, it will call
+ * SkDELETE() on the generator. Therefore, generator should be
+ * allocated with SkNEW() or SkNEW_ARGS().
+ */
+ static bool Install(SkImageGenerator* gen, SkBitmap* dst);
protected:
+ virtual ~SkCachingPixelRef();
virtual void* onLockPixels(SkColorTable** colorTable) SK_OVERRIDE;
virtual void onUnlockPixels() SK_OVERRIDE;
virtual bool onLockPixelsAreWritable() const SK_OVERRIDE { return false; }
- virtual bool onImplementsDecodeInto() SK_OVERRIDE { return true; }
- virtual bool onDecodeInto(int pow2, SkBitmap*) SK_OVERRIDE;
-
- /**
- * Configure the supplied bitmap for this pixelRef, based on
- * information provided by onDecodeInfo(). Does not set the
- * bitmap's pixelRef. */
- bool configure(SkBitmap* bitmap);
-
- /**
- * Cache info from onDecodeInfo(). Returns false on failure.
- */
- bool getInfo(SkImageInfo* info);
- /**
- * Return some information about the pixels, allowing this class
- * to allocate pixels. @return false if anything goes wrong.
- */
- virtual bool onDecodeInfo(SkImageInfo* info) = 0;
- /**
- * Decode into the given pixels, a block of memory of size
- * (info.fHeight - 1) * rowBytes + (info.fWidth * bytesPerPixel)
- *
- * @param info Should be identical to the info returned by
- * onDecodeInfo so that the implementation can confirm
- * that the caller knows what it is asking for (config,
- * size). Thiscontract also allows the caller to specify
- * different output-configs, which the implementation can
- * decide to support or not.
- *
- * @return false if anything goes wrong.
- */
- virtual bool onDecodePixels(const SkImageInfo& info,
- void* pixels,
- size_t rowBytes) = 0;
+ virtual SkData* onRefEncodedData() SK_OVERRIDE {
+ return fImageGenerator->refEncodedData();
+ }
+ // No need to flatten this object. When flattening an SkBitmap,
+ // SkOrderedWriteBuffer will check the encoded data and write that
+ // instead.
+ // Future implementations of SkFlattenableWriteBuffer will need to
+ // special case for onRefEncodedData as well.
+ SK_DECLARE_UNFLATTENABLE_OBJECT()
private:
- bool fErrorInDecoding;
- void* fScaledCacheId;
- SkImageInfo fInfo;
+ SkImageGenerator* const fImageGenerator;
+ bool fErrorInDecoding;
+ void* fScaledCacheId;
+ const SkImageInfo fInfo;
+ const size_t fRowBytes;
+ SkCachingPixelRef(SkImageGenerator* imageGenerator,
+ const SkImageInfo& info,
+ size_t rowBytes);
typedef SkPixelRef INHERITED;
};
diff --git a/lazy/SkDiscardableMemoryPool.cpp b/lazy/SkDiscardableMemoryPool.cpp
new file mode 100644
index 00000000..a1b2438a
--- /dev/null
+++ b/lazy/SkDiscardableMemoryPool.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkDiscardableMemoryPool.h"
+#include "SkOnce.h"
+
+// Note:
+// A PoolDiscardableMemory is memory that is counted in a pool.
+// A DiscardableMemoryPool is a pool of PoolDiscardableMemorys.
+
+/**
+ * A SkPoolDiscardableMemory is a SkDiscardableMemory that relies on
+ * a SkDiscardableMemoryPool object to manage the memory.
+ */
+class SkPoolDiscardableMemory : public SkDiscardableMemory {
+public:
+ SkPoolDiscardableMemory(SkDiscardableMemoryPool* pool,
+ void* pointer, size_t bytes);
+ virtual ~SkPoolDiscardableMemory();
+ virtual bool lock() SK_OVERRIDE;
+ virtual void* data() SK_OVERRIDE;
+ virtual void unlock() SK_OVERRIDE;
+ friend class SkDiscardableMemoryPool;
+private:
+ SK_DECLARE_INTERNAL_LLIST_INTERFACE(SkPoolDiscardableMemory);
+ SkDiscardableMemoryPool* const fPool;
+ bool fLocked;
+ void* fPointer;
+ const size_t fBytes;
+};
+
+SkPoolDiscardableMemory::SkPoolDiscardableMemory(SkDiscardableMemoryPool* pool,
+ void* pointer,
+ size_t bytes)
+ : fPool(pool)
+ , fLocked(true)
+ , fPointer(pointer)
+ , fBytes(bytes) {
+ SkASSERT(fPool != NULL);
+ SkASSERT(fPointer != NULL);
+ SkASSERT(fBytes > 0);
+ fPool->ref();
+}
+
+SkPoolDiscardableMemory::~SkPoolDiscardableMemory() {
+ fPool->free(this);
+ fPool->unref();
+}
+
+bool SkPoolDiscardableMemory::lock() {
+ return fPool->lock(this);
+}
+
+void* SkPoolDiscardableMemory::data() {
+ return fLocked ? fPointer : NULL;
+}
+
+void SkPoolDiscardableMemory::unlock() {
+ fPool->unlock(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+SkDiscardableMemoryPool::SkDiscardableMemoryPool(size_t budget,
+ SkBaseMutex* mutex)
+ : fMutex(mutex)
+ , fBudget(budget)
+ , fUsed(0) {
+ #if LAZY_CACHE_STATS
+ fCacheHits = 0;
+ fCacheMisses = 0;
+ #endif // LAZY_CACHE_STATS
+}
+SkDiscardableMemoryPool::~SkDiscardableMemoryPool() {
+ // SkPoolDiscardableMemory objects that belong to this pool are
+ // always deleted before deleting this pool since each one has a
+ // ref to the pool.
+ SkASSERT(fList.isEmpty());
+}
+
+void SkDiscardableMemoryPool::dumpDownTo(size_t budget) {
+ // assert((NULL = fMutex) || fMutex->isLocked());
+ // TODO(halcanary) implement bool fMutex::isLocked().
+ // WARNING: only call this function after aquiring lock.
+ if (fUsed <= budget) {
+ return;
+ }
+ typedef SkTInternalLList<SkPoolDiscardableMemory>::Iter Iter;
+ Iter iter;
+ SkPoolDiscardableMemory* cur = iter.init(fList, Iter::kTail_IterStart);
+ while ((fUsed > budget) && (NULL != cur)) {
+ if (!cur->fLocked) {
+ SkPoolDiscardableMemory* dm = cur;
+ SkASSERT(dm->fPointer != NULL);
+ sk_free(dm->fPointer);
+ dm->fPointer = NULL;
+ SkASSERT(fUsed >= dm->fBytes);
+ fUsed -= dm->fBytes;
+ cur = iter.prev();
+ // Purged DMs are taken out of the list. This saves times
+ // looking them up. Purged DMs are NOT deleted.
+ fList.remove(dm);
+ } else {
+ cur = iter.prev();
+ }
+ }
+}
+
+SkDiscardableMemory* SkDiscardableMemoryPool::create(size_t bytes) {
+ void* addr = sk_malloc_flags(bytes, 0);
+ if (NULL == addr) {
+ return NULL;
+ }
+ SkPoolDiscardableMemory* dm = SkNEW_ARGS(SkPoolDiscardableMemory,
+ (this, addr, bytes));
+ SkAutoMutexAcquire autoMutexAcquire(fMutex);
+ fList.addToHead(dm);
+ fUsed += bytes;
+ this->dumpDownTo(fBudget);
+ return dm;
+}
+
+void SkDiscardableMemoryPool::free(SkPoolDiscardableMemory* dm) {
+ // This is called by dm's destructor.
+ if (dm->fPointer != NULL) {
+ SkAutoMutexAcquire autoMutexAcquire(fMutex);
+ sk_free(dm->fPointer);
+ dm->fPointer = NULL;
+ SkASSERT(fUsed >= dm->fBytes);
+ fUsed -= dm->fBytes;
+ fList.remove(dm);
+ } else {
+ SkASSERT(!fList.isInList(dm));
+ }
+}
+
+bool SkDiscardableMemoryPool::lock(SkPoolDiscardableMemory* dm) {
+ SkASSERT(dm != NULL);
+ if (NULL == dm->fPointer) {
+ #if LAZY_CACHE_STATS
+ SkAutoMutexAcquire autoMutexAcquire(fMutex);
+ ++fCacheMisses;
+ #endif // LAZY_CACHE_STATS
+ return false;
+ }
+ SkAutoMutexAcquire autoMutexAcquire(fMutex);
+ if (NULL == dm->fPointer) {
+ // May have been purged while waiting for lock.
+ #if LAZY_CACHE_STATS
+ ++fCacheMisses;
+ #endif // LAZY_CACHE_STATS
+ return false;
+ }
+ dm->fLocked = true;
+ fList.remove(dm);
+ fList.addToHead(dm);
+ #if LAZY_CACHE_STATS
+ ++fCacheHits;
+ #endif // LAZY_CACHE_STATS
+ return true;
+}
+
+void SkDiscardableMemoryPool::unlock(SkPoolDiscardableMemory* dm) {
+ SkASSERT(dm != NULL);
+ SkAutoMutexAcquire autoMutexAcquire(fMutex);
+ dm->fLocked = false;
+ this->dumpDownTo(fBudget);
+}
+
+size_t SkDiscardableMemoryPool::getRAMUsed() {
+ return fUsed;
+}
+void SkDiscardableMemoryPool::setRAMBudget(size_t budget) {
+ SkAutoMutexAcquire autoMutexAcquire(fMutex);
+ fBudget = budget;
+ this->dumpDownTo(fBudget);
+}
+void SkDiscardableMemoryPool::dumpPool() {
+ SkAutoMutexAcquire autoMutexAcquire(fMutex);
+ this->dumpDownTo(0);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+SK_DECLARE_STATIC_MUTEX(gMutex);
+static void create_pool(SkDiscardableMemoryPool** pool) {
+ SkASSERT(NULL == *pool);
+ *pool = SkNEW_ARGS(SkDiscardableMemoryPool,
+ (SK_DEFAULT_GLOBAL_DISCARDABLE_MEMORY_POOL_SIZE,
+ &gMutex));
+}
+SkDiscardableMemoryPool* SkGetGlobalDiscardableMemoryPool() {
+ static SkDiscardableMemoryPool* gPool(NULL);
+ SK_DECLARE_STATIC_ONCE(create_pool_once);
+ SkOnce(&create_pool_once, create_pool, &gPool);
+ SkASSERT(NULL != gPool);
+ return gPool;
+}
+
+////////////////////////////////////////////////////////////////////////////////
diff --git a/lazy/SkDiscardableMemoryPool.h b/lazy/SkDiscardableMemoryPool.h
new file mode 100644
index 00000000..e9f3b04f
--- /dev/null
+++ b/lazy/SkDiscardableMemoryPool.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkDiscardableMemoryPool_DEFINED
+#define SkDiscardableMemoryPool_DEFINED
+
+#include "SkDiscardableMemory.h"
+#include "SkTInternalLList.h"
+#include "SkThread.h"
+
+#ifdef SK_DEBUG
+ #define LAZY_CACHE_STATS 1
+#elif !defined(LAZY_CACHE_STATS)
+ #define LAZY_CACHE_STATS 0
+#endif
+
+/**
+ * This non-global pool can be used for unit tests to verify that the
+ * pool works.
+ */
+class SkPoolDiscardableMemory;
+class SkDiscardableMemoryPool : public SkDiscardableMemory::Factory {
+public:
+ /**
+ * Without mutex, will be not be thread safe.
+ */
+ SkDiscardableMemoryPool(size_t budget, SkBaseMutex* mutex = NULL);
+ ~SkDiscardableMemoryPool();
+ SkDiscardableMemory* create(size_t bytes) SK_OVERRIDE;
+ size_t getRAMUsed();
+ void setRAMBudget(size_t budget);
+ /** purges all unlocked DMs */
+ void dumpPool();
+ friend class SkPoolDiscardableMemory;
+ #if LAZY_CACHE_STATS
+ int fCacheHits;
+ int fCacheMisses;
+ #endif // LAZY_CACHE_STATS
+
+private:
+ SkBaseMutex* fMutex;
+ size_t fBudget;
+ size_t fUsed;
+ SkTInternalLList<SkPoolDiscardableMemory> fList;
+ /** Function called to free memory if needed */
+ void dumpDownTo(size_t budget);
+ /** called by SkDiscardableMemoryPool upon destruction */
+ void free(SkPoolDiscardableMemory* dm);
+ /** called by SkDiscardableMemoryPool::lock() */
+ bool lock(SkPoolDiscardableMemory* dm);
+ /** called by SkDiscardableMemoryPool::unlock() */
+ void unlock(SkPoolDiscardableMemory* dm);
+ typedef SkDiscardableMemory::Factory INHERITED;
+};
+
+/**
+ * Returns (and creates if needed) a threadsafe global
+ * SkDiscardableMemoryPool.
+ */
+SkDiscardableMemoryPool* SkGetGlobalDiscardableMemoryPool();
+
+#if !defined(SK_DEFAULT_GLOBAL_DISCARDABLE_MEMORY_POOL_SIZE)
+#define SK_DEFAULT_GLOBAL_DISCARDABLE_MEMORY_POOL_SIZE (128 * 1024 * 1024)
+#endif
+
+#endif // SkDiscardableMemoryPool_DEFINED
diff --git a/lazy/SkDiscardablePixelRef.cpp b/lazy/SkDiscardablePixelRef.cpp
index b6e1b100..6a9507c8 100644
--- a/lazy/SkDiscardablePixelRef.cpp
+++ b/lazy/SkDiscardablePixelRef.cpp
@@ -7,12 +7,15 @@
#include "SkDiscardablePixelRef.h"
#include "SkDiscardableMemory.h"
+#include "SkImageGenerator.h"
SkDiscardablePixelRef::SkDiscardablePixelRef(SkImageGenerator* generator,
const SkImageInfo& info,
size_t size,
- size_t rowBytes)
+ size_t rowBytes,
+ SkDiscardableMemory::Factory* fact)
: fGenerator(generator)
+ , fDMFactory(fact)
, fInfo(info)
, fSize(size)
, fRowBytes(rowBytes)
@@ -20,9 +23,15 @@ SkDiscardablePixelRef::SkDiscardablePixelRef(SkImageGenerator* generator,
SkASSERT(fGenerator != NULL);
SkASSERT(fSize > 0);
SkASSERT(fRowBytes > 0);
+ // The SkImageGenerator contract requires fGenerator to always
+ // decode the same image on each call to getPixels().
+ this->setImmutable();
+ SkSafeRef(fDMFactory);
}
SkDiscardablePixelRef::~SkDiscardablePixelRef() {
+ SkDELETE(fDiscardableMemory);
+ SkSafeUnref(fDMFactory);
SkDELETE(fGenerator);
}
@@ -31,9 +40,14 @@ void* SkDiscardablePixelRef::onLockPixels(SkColorTable**) {
if (fDiscardableMemory->lock()) {
return fDiscardableMemory->data();
}
+ SkDELETE(fDiscardableMemory);
fDiscardableMemory = NULL;
}
- fDiscardableMemory = SkDiscardableMemory::Create(fSize);
+ if (fDMFactory != NULL) {
+ fDiscardableMemory = fDMFactory->create(fSize);
+ } else {
+ fDiscardableMemory = SkDiscardableMemory::Create(fSize);
+ }
if (NULL == fDiscardableMemory) {
return NULL; // Memory allocation failed.
}
@@ -49,8 +63,9 @@ void SkDiscardablePixelRef::onUnlockPixels() {
}
}
-bool SkDiscardablePixelRef::Install(SkImageGenerator* generator,
- SkBitmap* dst) {
+bool SkInstallDiscardablePixelRef(SkImageGenerator* generator,
+ SkBitmap* dst,
+ SkDiscardableMemory::Factory* factory) {
SkImageInfo info;
SkASSERT(generator != NULL);
if ((NULL == generator)
@@ -59,10 +74,16 @@ bool SkDiscardablePixelRef::Install(SkImageGenerator* generator,
SkDELETE(generator);
return false;
}
+ SkASSERT(dst->config() != SkBitmap::kNo_Config);
+ if (dst->empty()) { // Use a normal pixelref.
+ SkDELETE(generator); // Do not need this anymore.
+ return dst->allocPixels(NULL, NULL);
+ }
SkAutoTUnref<SkDiscardablePixelRef> ref(SkNEW_ARGS(SkDiscardablePixelRef,
(generator, info,
dst->getSize(),
- dst->rowBytes())));
+ dst->rowBytes(),
+ factory)));
dst->setPixelRef(ref);
return true;
}
diff --git a/lazy/SkDiscardablePixelRef.h b/lazy/SkDiscardablePixelRef.h
index bbe19b8b..44c6df96 100644
--- a/lazy/SkDiscardablePixelRef.h
+++ b/lazy/SkDiscardablePixelRef.h
@@ -8,31 +8,13 @@
#ifndef SkDiscardablePixelRef_DEFINED
#define SkDiscardablePixelRef_DEFINED
-#include "SkPixelRef.h"
+#include "SkDiscardableMemory.h"
#include "SkImageGenerator.h"
#include "SkImageInfo.h"
-
-class SkDiscardableMemory;
-
-/**
- * An interface that allows a purgable PixelRef to re-decode an image.
- */
+#include "SkPixelRef.h"
class SkDiscardablePixelRef : public SkPixelRef {
public:
- /**
- * Takes ownership of SkImageGenerator. If this method fails for
- * whatever reason, it will return false and immediatetely delete
- * the generator. If it succeeds, it will modify destination
- * bitmap.
- *
- * If Install fails or when the SkDiscardablePixelRef that is
- * installed into destination is destroyed, it will call
- * SkDELETE() on the generator. Therefore, generator should be
- * allocated with SkNEW() or SkNEW_ARGS().
- */
- static bool Install(SkImageGenerator* generator, SkBitmap* destination);
-
SK_DECLARE_UNFLATTENABLE_OBJECT()
protected:
@@ -47,6 +29,7 @@ protected:
private:
SkImageGenerator* const fGenerator;
+ SkDiscardableMemory::Factory* const fDMFactory;
const SkImageInfo fInfo;
const size_t fSize; // size of memory to be allocated
const size_t fRowBytes;
@@ -59,6 +42,11 @@ private:
SkDiscardablePixelRef(SkImageGenerator* generator,
const SkImageInfo& info,
size_t size,
- size_t rowBytes);
+ size_t rowBytes,
+ SkDiscardableMemory::Factory* factory);
+ friend bool SkInstallDiscardablePixelRef(SkImageGenerator*,
+ SkBitmap*,
+ SkDiscardableMemory::Factory*);
+ typedef SkPixelRef INHERITED;
};
#endif // SkDiscardablePixelRef_DEFINED
diff --git a/lazy/SkLazyCachingPixelRef.cpp b/lazy/SkLazyCachingPixelRef.cpp
deleted file mode 100644
index 730b5f7d..00000000
--- a/lazy/SkLazyCachingPixelRef.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "Sk64.h"
-#include "SkColorTable.h"
-#include "SkData.h"
-#include "SkImageDecoder.h"
-#include "SkImagePriv.h"
-#include "SkLazyCachingPixelRef.h"
-#include "SkPostConfig.h"
-
-SkLazyCachingPixelRef::SkLazyCachingPixelRef(SkData* data,
- SkBitmapFactory::DecodeProc proc)
- : fDecodeProc(proc) {
- if (NULL == data) {
- fData = SkData::NewEmpty();
- } else {
- fData = data;
- fData->ref();
- }
- if (NULL == fDecodeProc) { // use a reasonable default.
- fDecodeProc = SkImageDecoder::DecodeMemoryToTarget;
- }
- this->setImmutable();
-}
-
-SkLazyCachingPixelRef::~SkLazyCachingPixelRef() {
- SkASSERT(fData != NULL);
- fData->unref();
-}
-
-bool SkLazyCachingPixelRef::onDecodeInfo(SkImageInfo* info) {
- SkASSERT(info);
- return fDecodeProc(fData->data(), fData->size(), info, NULL);
-}
-
-bool SkLazyCachingPixelRef::onDecodePixels(const SkImageInfo& passedInfo,
- void* pixels, size_t rowBytes) {
- SkASSERT(pixels);
- SkImageInfo info;
- if (!this->getInfo(&info)) {
- return false;
- }
- if (passedInfo != info) {
- return false; // This implementation can not handle this case.
- }
- SkBitmapFactory::Target target = {pixels, rowBytes};
- return fDecodeProc(fData->data(), fData->size(), &info, &target);
-}
-
-bool SkLazyCachingPixelRef::Install(SkBitmapFactory::DecodeProc proc,
- SkData* data,
- SkBitmap* destination) {
- SkAutoTUnref<SkLazyCachingPixelRef> ref(
- SkNEW_ARGS(SkLazyCachingPixelRef, (data, proc)));
- return ref->configure(destination) && destination->setPixelRef(ref);
-}
diff --git a/lazy/SkLazyCachingPixelRef.h b/lazy/SkLazyCachingPixelRef.h
deleted file mode 100644
index a9d2dad9..00000000
--- a/lazy/SkLazyCachingPixelRef.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkLazyCachingPixelRef_DEFINED
-#define SkLazyCachingPixelRef_DEFINED
-
-#include "SkBitmapFactory.h"
-#include "SkCachingPixelRef.h"
-
-class SkData;
-
-/**
- * PixelRef which defers decoding until SkBitmap::lockPixels() is
- * called. Makes use of a supplied decode procedure. Will decode at
- * the procedure's preferred size.
- */
-class SkLazyCachingPixelRef : public SkCachingPixelRef {
-public:
- /**
- * @param data Encoded data representing the pixels. NULL is
- * equivalent to an empty data, and will be passed to
- * DecodeProc with length zero.
- *
- * @param procedure Called to decode the pixels when
- * needed. If NULL, use SkImageDecoder::DecodeMemoryToTarget.
- */
- SkLazyCachingPixelRef(SkData* data,
- SkBitmapFactory::DecodeProc procedure);
-
- virtual ~SkLazyCachingPixelRef();
-
- virtual SkData* onRefEncodedData() SK_OVERRIDE { return SkSafeRef(fData); }
-
- /**
- * A simplified version of SkBitmapFactory. Installs a new
- * SkLazyCachingPixelRef into the provided bitmap. Will
- * immediately call onDecodeInfo() to configure the bitmap, but
- * will defer decoding until the first time the bitmap's pixels
- * are locked.
- *
- * @param data Encoded data representing the pixels. NULL is
- * equivalent to an empty data, and will be passed to
- * DecodeProc with length zero.
- *
- * @param procedure Called to decode the pixels when
- * needed. If NULL, use SkImageDecoder::DecodeMemoryToTarget.
- *
- * @param destination Bitmap that will be modified on success.
- *
- * @returns true on success.
- */
- static bool Install(SkBitmapFactory::DecodeProc procedure,
- SkData* data,
- SkBitmap* destination);
-
- // No need to flatten this object. When flattening an SkBitmap,
- // SkOrderedWriteBuffer will check the encoded data and write that
- // instead.
- // Future implementations of SkFlattenableWriteBuffer will need to
- // special case for onRefEncodedData as well.
- SK_DECLARE_UNFLATTENABLE_OBJECT()
-
-protected:
- /**
- * Return some information about the pixels, allowing this class
- * to allocate pixels. @return false if anything goes wrong.
- *
- * This implementation calls SkBitmapFactory::DecodeProc with a
- * NULL target.
- */
- virtual bool onDecodeInfo(SkImageInfo* info) SK_OVERRIDE;
- /**
- * Decode into the given pixels, a block of memory of size
- * (info.fHeight * rowBytes) bytes.
- *
- * @param info Should be identical to the info returned by
- * onDecodeInfo so that the implementation can confirm
- * that the caller knows what its asking for (config,
- * size).
- *
- * @return false if anything goes wrong.
- */
- virtual bool onDecodePixels(const SkImageInfo& info,
- void* pixels,
- size_t rowBytes) SK_OVERRIDE;
-
-private:
- SkData* fData;
- SkBitmapFactory::DecodeProc fDecodeProc;
-
- typedef SkCachingPixelRef INHERITED;
-};
-
-#endif // SkLazyCachingPixelRef_DEFINED
diff --git a/lazy/SkLazyPixelRef.cpp b/lazy/SkLazyPixelRef.cpp
deleted file mode 100644
index c2ca041b..00000000
--- a/lazy/SkLazyPixelRef.cpp
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "Sk64.h"
-#include "SkLazyPixelRef.h"
-#include "SkColorTable.h"
-#include "SkData.h"
-#include "SkImageCache.h"
-#include "SkImagePriv.h"
-#include "SkScaledImageCache.h"
-
-#if LAZY_CACHE_STATS
-#include "SkThread.h"
-
-int32_t SkLazyPixelRef::gCacheHits;
-int32_t SkLazyPixelRef::gCacheMisses;
-#endif
-
-SkLazyPixelRef::SkLazyPixelRef(SkData* data, SkBitmapFactory::DecodeProc proc, SkImageCache* cache)
- // Pass NULL for the Mutex so that the default (ring buffer) will be used.
- : INHERITED(NULL)
- , fErrorInDecoding(false)
- , fDecodeProc(proc)
- , fImageCache(cache)
- , fRowBytes(0) {
- SkASSERT(fDecodeProc != NULL);
- if (NULL == data) {
- fData = SkData::NewEmpty();
- fErrorInDecoding = true;
- } else {
- fData = data;
- fData->ref();
- fErrorInDecoding = data->size() == 0;
- }
- if (fImageCache != NULL) {
- fImageCache->ref();
- fCacheId = SkImageCache::UNINITIALIZED_ID;
- } else {
- fScaledCacheId = NULL;
- }
-
- // mark as uninitialized -- all fields are -1
- memset(&fLazilyCachedInfo, 0xFF, sizeof(fLazilyCachedInfo));
-
- // Since this pixel ref bases its data on encoded data, it should never change.
- this->setImmutable();
-}
-
-SkLazyPixelRef::~SkLazyPixelRef() {
- SkASSERT(fData != NULL);
- fData->unref();
- if (NULL == fImageCache) {
- if (fScaledCacheId != NULL) {
- SkScaledImageCache::Unlock(fScaledCacheId);
- // TODO(halcanary): SkScaledImageCache needs a
- // throwAwayCache(id) method.
- }
- return;
- }
- SkASSERT(fImageCache);
- if (fCacheId != SkImageCache::UNINITIALIZED_ID) {
- fImageCache->throwAwayCache(fCacheId);
- }
- fImageCache->unref();
-}
-
-static size_t ComputeMinRowBytesAndSize(const SkImageInfo& info, size_t* rowBytes) {
- *rowBytes = SkImageMinRowBytes(info);
-
- Sk64 safeSize;
- safeSize.setZero();
- if (info.fHeight > 0) {
- safeSize.setMul(info.fHeight, SkToS32(*rowBytes));
- }
- SkASSERT(!safeSize.isNeg());
- return safeSize.is32() ? safeSize.get32() : 0;
-}
-
-const SkImageInfo* SkLazyPixelRef::getCachedInfo() {
- if (fLazilyCachedInfo.fWidth < 0) {
- SkImageInfo info;
- fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, NULL);
- if (fErrorInDecoding) {
- return NULL;
- }
- fLazilyCachedInfo = info;
- }
- return &fLazilyCachedInfo;
-}
-
-/**
- Returns bitmap->getPixels() on success; NULL on failure */
-static void* decode_into_bitmap(SkImageInfo* info,
- SkBitmapFactory::DecodeProc decodeProc,
- size_t* rowBytes,
- SkData* data,
- SkBitmap* bm) {
- SkASSERT(info && decodeProc && rowBytes && data && bm);
- if (!(bm->setConfig(SkImageInfoToBitmapConfig(*info), info->fWidth,
- info->fHeight, *rowBytes, info->fAlphaType)
- && bm->allocPixels(NULL, NULL))) {
- // Use the default allocator. It may be necessary for the
- // SkLazyPixelRef to have a allocator field which is passed
- // into allocPixels().
- return NULL;
- }
- SkBitmapFactory::Target target;
- target.fAddr = bm->getPixels();
- target.fRowBytes = bm->rowBytes();
- *rowBytes = target.fRowBytes;
- if (!decodeProc(data->data(), data->size(), info, &target)) {
- return NULL;
- }
- return target.fAddr;
-}
-
-void* SkLazyPixelRef::lockScaledImageCachePixels() {
- SkASSERT(!fErrorInDecoding);
- SkASSERT(NULL == fImageCache);
- SkBitmap bitmap;
- const SkImageInfo* info = this->getCachedInfo();
- if (info == NULL) {
- return NULL;
- }
- // If this is the first time though, this is guaranteed to fail.
- // Maybe we should have a flag that says "don't even bother looking"
- fScaledCacheId = SkScaledImageCache::FindAndLock(this->getGenerationID(),
- info->fWidth,
- info->fHeight,
- &bitmap);
- if (fScaledCacheId != NULL) {
- SkAutoLockPixels autoLockPixels(bitmap);
- void* pixels = bitmap.getPixels();
- SkASSERT(NULL != pixels);
- // At this point, the autoLockPixels will unlockPixels()
- // to remove bitmap's lock on the pixels. We will then
- // destroy bitmap. The *only* guarantee that this pointer
- // remains valid is the guarantee made by
- // SkScaledImageCache that it will not destroy the *other*
- // bitmap (SkScaledImageCache::Rec.fBitmap) that holds a
- // reference to the concrete PixelRef while this record is
- // locked.
- return pixels;
- } else {
- // Cache has been purged, must re-decode.
- void* pixels = decode_into_bitmap(const_cast<SkImageInfo*>(info),
- fDecodeProc, &fRowBytes, fData,
- &bitmap);
- if (NULL == pixels) {
- fErrorInDecoding = true;
- return NULL;
- }
- fScaledCacheId = SkScaledImageCache::AddAndLock(this->getGenerationID(),
- info->fWidth,
- info->fHeight,
- bitmap);
- SkASSERT(fScaledCacheId != NULL);
- return pixels;
- }
-}
-
-void* SkLazyPixelRef::onLockPixels(SkColorTable**) {
- if (fErrorInDecoding) {
- return NULL;
- }
- if (NULL == fImageCache) {
- return this->lockScaledImageCachePixels();
- } else {
- return this->lockImageCachePixels();
- }
-}
-
-void* SkLazyPixelRef::lockImageCachePixels() {
- SkASSERT(fImageCache != NULL);
- SkASSERT(!fErrorInDecoding);
- SkBitmapFactory::Target target;
- // Check to see if the pixels still exist in the cache.
- if (SkImageCache::UNINITIALIZED_ID == fCacheId) {
- target.fAddr = NULL;
- } else {
- SkImageCache::DataStatus status;
- target.fAddr = fImageCache->pinCache(fCacheId, &status);
- if (target.fAddr == NULL) {
- fCacheId = SkImageCache::UNINITIALIZED_ID;
- } else {
- if (SkImageCache::kRetained_DataStatus == status) {
-#if LAZY_CACHE_STATS
- sk_atomic_inc(&gCacheHits);
-#endif
- return target.fAddr;
- }
- SkASSERT(SkImageCache::kUninitialized_DataStatus == status);
- }
- // Cache miss. Either pinCache returned NULL or it returned a memory address without the old
- // data
-#if LAZY_CACHE_STATS
- sk_atomic_inc(&gCacheMisses);
-#endif
- }
-
- SkASSERT(fData != NULL && fData->size() > 0);
- if (NULL == target.fAddr) {
- const SkImageInfo* info = this->getCachedInfo();
- if (NULL == info) {
- SkASSERT(SkImageCache::UNINITIALIZED_ID == fCacheId);
- return NULL;
- }
- size_t bytes = ComputeMinRowBytesAndSize(*info, &target.fRowBytes);
- target.fAddr = fImageCache->allocAndPinCache(bytes, &fCacheId);
- if (NULL == target.fAddr) {
- // Space could not be allocated.
- // Just like the last assert, fCacheId must be UNINITIALIZED_ID.
- SkASSERT(SkImageCache::UNINITIALIZED_ID == fCacheId);
- return NULL;
- }
- } else {
- // pinCache returned purged memory to which target.fAddr already points. Set
- // target.fRowBytes properly.
- target.fRowBytes = fRowBytes;
- // Assume that the size is correct, since it was determined by this same function
- // previously.
- }
- SkASSERT(target.fAddr != NULL);
- SkASSERT(SkImageCache::UNINITIALIZED_ID != fCacheId);
- fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), NULL, &target);
- if (fErrorInDecoding) {
- fImageCache->throwAwayCache(fCacheId);
- fCacheId = SkImageCache::UNINITIALIZED_ID;
- return NULL;
- }
- // Upon success, store fRowBytes so it can be used in case pinCache later returns purged memory.
- fRowBytes = target.fRowBytes;
- return target.fAddr;
-}
-
-void SkLazyPixelRef::onUnlockPixels() {
- if (fErrorInDecoding) {
- return;
- }
- if (NULL == fImageCache) {
- // onUnlockPixels() should never be called a second time from
- // PixelRef::Unlock() without calling onLockPixels() first.
- SkASSERT(NULL != fScaledCacheId);
- if (NULL != fScaledCacheId) {
- SkScaledImageCache::Unlock(fScaledCacheId);
- fScaledCacheId = NULL;
- }
- } else { // use fImageCache
- SkASSERT(SkImageCache::UNINITIALIZED_ID != fCacheId);
- if (SkImageCache::UNINITIALIZED_ID != fCacheId) {
- fImageCache->releaseCache(fCacheId);
- }
- }
-}
-
-SkData* SkLazyPixelRef::onRefEncodedData() {
- fData->ref();
- return fData;
-}
-
-static bool init_from_info(SkBitmap* bm, const SkImageInfo& info,
- size_t rowBytes) {
- SkBitmap::Config config = SkImageInfoToBitmapConfig(info);
- if (SkBitmap::kNo_Config == config) {
- return false;
- }
-
- return bm->setConfig(config, info.fWidth, info.fHeight, rowBytes, info.fAlphaType)
- &&
- bm->allocPixels();
-}
-
-bool SkLazyPixelRef::onImplementsDecodeInto() {
- return true;
-}
-
-bool SkLazyPixelRef::onDecodeInto(int pow2, SkBitmap* bitmap) {
- SkASSERT(fData != NULL && fData->size() > 0);
- if (fErrorInDecoding) {
- return false;
- }
-
- SkImageInfo info;
- // Determine the size of the image in order to determine how much memory to allocate.
- // FIXME: As an optimization, only do this part once.
- fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, NULL);
- if (fErrorInDecoding) {
- return false;
- }
-
- SkBitmapFactory::Target target;
- (void)ComputeMinRowBytesAndSize(info, &target.fRowBytes);
-
- SkBitmap tmp;
- if (!init_from_info(&tmp, info, target.fRowBytes)) {
- return false;
- }
-
- target.fAddr = tmp.getPixels();
- fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, &target);
- if (fErrorInDecoding) {
- return false;
- }
-
- *bitmap = tmp;
- return true;
-}
diff --git a/lazy/SkLazyPixelRef.h b/lazy/SkLazyPixelRef.h
deleted file mode 100644
index f8a16d16..00000000
--- a/lazy/SkLazyPixelRef.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkLazyPixelRef_DEFINED
-#define SkLazyPixelRef_DEFINED
-
-#include "SkBitmapFactory.h"
-#include "SkImage.h"
-#include "SkImageCache.h"
-#include "SkPixelRef.h"
-#include "SkFlattenable.h"
-#include "SkScaledImageCache.h"
-
-class SkColorTable;
-class SkData;
-class SkImageCache;
-
-#ifdef SK_DEBUG
- #define LAZY_CACHE_STATS 1
-#elif !defined(LAZY_CACHE_STATS)
- #define LAZY_CACHE_STATS 0
-#endif
-
-/**
- * PixelRef which defers decoding until SkBitmap::lockPixels() is called.
- */
-class SkLazyPixelRef : public SkPixelRef {
-
-public:
- /**
- * Create a new SkLazyPixelRef.
- * @param SkData Encoded data representing the pixels.
- * @param DecodeProc Called to decode the pixels when needed. Must be non-NULL.
- * @param SkImageCache Object that handles allocating and freeing
- * the pixel memory, as needed. If NULL, use the global
- * SkScaledImageCache.
- */
- SkLazyPixelRef(SkData*, SkBitmapFactory::DecodeProc, SkImageCache*);
-
- virtual ~SkLazyPixelRef();
-
-#ifdef SK_DEBUG
- intptr_t getCacheId() const { return fCacheId; }
-#endif
-
-#if LAZY_CACHE_STATS
- static int32_t GetCacheHits() { return gCacheHits; }
- static int32_t GetCacheMisses() { return gCacheMisses; }
- static void ResetCacheStats() { gCacheHits = gCacheMisses = 0; }
-#endif
-
- // No need to flatten this object. When flattening an SkBitmap, SkOrderedWriteBuffer will check
- // the encoded data and write that instead.
- // Future implementations of SkFlattenableWriteBuffer will need to special case for
- // onRefEncodedData as well.
- SK_DECLARE_UNFLATTENABLE_OBJECT()
-
-protected:
- virtual void* onLockPixels(SkColorTable**) SK_OVERRIDE;
- virtual void onUnlockPixels() SK_OVERRIDE;
- virtual bool onLockPixelsAreWritable() const SK_OVERRIDE { return false; }
- virtual SkData* onRefEncodedData() SK_OVERRIDE;
- virtual bool onImplementsDecodeInto() SK_OVERRIDE;
- virtual bool onDecodeInto(int pow2, SkBitmap*) SK_OVERRIDE;
-
-private:
- bool fErrorInDecoding;
- SkData* fData;
- SkBitmapFactory::DecodeProc fDecodeProc;
- SkImageCache* fImageCache;
- union {
- SkImageCache::ID fCacheId;
- SkScaledImageCache::ID* fScaledCacheId;
- };
- size_t fRowBytes;
- SkImageInfo fLazilyCachedInfo;
-
-#if LAZY_CACHE_STATS
- static int32_t gCacheHits;
- static int32_t gCacheMisses;
-#endif
-
- // lazily initialized our cached info. Returns NULL on failure.
- const SkImage::Info* getCachedInfo();
- void* lockScaledImageCachePixels();
- void* lockImageCachePixels();
-
-
- typedef SkPixelRef INHERITED;
-};
-
-#endif // SkLazyPixelRef_DEFINED
diff --git a/lazy/SkLruImageCache.cpp b/lazy/SkLruImageCache.cpp
deleted file mode 100644
index 40cfefa2..00000000
--- a/lazy/SkLruImageCache.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkLruImageCache.h"
-
-SK_DEFINE_INST_COUNT(SkImageCache)
-SK_DEFINE_INST_COUNT(SkLruImageCache)
-
-static intptr_t NextGenerationID() {
- static intptr_t gNextID;
- do {
- gNextID++;
- } while (SkImageCache::UNINITIALIZED_ID == gNextID);
- return gNextID;
-}
-
-class CachedPixels : public SkNoncopyable {
-
-public:
- CachedPixels(size_t length)
- : fLength(length)
- , fID(NextGenerationID())
- , fLocked(false) {
- fAddr = sk_malloc_throw(length);
- }
-
- ~CachedPixels() {
- sk_free(fAddr);
- }
-
- void* getData() { return fAddr; }
-
- intptr_t getID() const { return fID; }
-
- size_t getLength() const { return fLength; }
-
- void lock() { SkASSERT(!fLocked); fLocked = true; }
-
- void unlock() { SkASSERT(fLocked); fLocked = false; }
-
- bool isLocked() const { return fLocked; }
-
-private:
- void* fAddr;
- size_t fLength;
- const intptr_t fID;
- bool fLocked;
- SK_DECLARE_INTERNAL_LLIST_INTERFACE(CachedPixels);
-};
-
-////////////////////////////////////////////////////////////////////////////////////
-
-SkLruImageCache::SkLruImageCache(size_t budget)
- : fRamBudget(budget)
- , fRamUsed(0) {}
-
-SkLruImageCache::~SkLruImageCache() {
- // Don't worry about updating pointers. All will be deleted.
- Iter iter;
- CachedPixels* pixels = iter.init(fLRU, Iter::kTail_IterStart);
- while (pixels != NULL) {
- CachedPixels* prev = iter.prev();
- SkASSERT(!pixels->isLocked());
-#ifdef SK_DEBUG
- fRamUsed -= pixels->getLength();
-#endif
- SkDELETE(pixels);
- pixels = prev;
- }
-#ifdef SK_DEBUG
- SkASSERT(fRamUsed == 0);
-#endif
-}
-
-#ifdef SK_DEBUG
-SkImageCache::MemoryStatus SkLruImageCache::getMemoryStatus(intptr_t ID) const {
- if (SkImageCache::UNINITIALIZED_ID == ID) {
- return SkImageCache::kFreed_MemoryStatus;
- }
- SkAutoMutexAcquire ac(&fMutex);
- CachedPixels* pixels = this->findByID(ID);
- if (NULL == pixels) {
- return SkImageCache::kFreed_MemoryStatus;
- }
- if (pixels->isLocked()) {
- return SkImageCache::kPinned_MemoryStatus;
- }
- return SkImageCache::kUnpinned_MemoryStatus;
-}
-
-void SkLruImageCache::purgeAllUnpinnedCaches() {
- SkAutoMutexAcquire ac(&fMutex);
- this->purgeTilAtOrBelow(0);
-}
-#endif
-
-size_t SkLruImageCache::setImageCacheLimit(size_t newLimit) {
- size_t oldLimit = fRamBudget;
- SkAutoMutexAcquire ac(&fMutex);
- fRamBudget = newLimit;
- this->purgeIfNeeded();
- return oldLimit;
-}
-
-void* SkLruImageCache::allocAndPinCache(size_t bytes, intptr_t* ID) {
- SkAutoMutexAcquire ac(&fMutex);
- CachedPixels* pixels = SkNEW_ARGS(CachedPixels, (bytes));
- if (ID != NULL) {
- *ID = pixels->getID();
- }
- pixels->lock();
- fRamUsed += bytes;
- fLRU.addToHead(pixels);
- this->purgeIfNeeded();
- return pixels->getData();
-}
-
-void* SkLruImageCache::pinCache(intptr_t ID, SkImageCache::DataStatus* status) {
- SkASSERT(ID != SkImageCache::UNINITIALIZED_ID);
- SkAutoMutexAcquire ac(&fMutex);
- CachedPixels* pixels = this->findByID(ID);
- if (NULL == pixels) {
- return NULL;
- }
- if (pixels != fLRU.head()) {
- fLRU.remove(pixels);
- fLRU.addToHead(pixels);
- }
- SkASSERT(status != NULL);
- // This cache will never return pinned memory whose data has been overwritten.
- *status = SkImageCache::kRetained_DataStatus;
- pixels->lock();
- return pixels->getData();
-}
-
-void SkLruImageCache::releaseCache(intptr_t ID) {
- SkASSERT(ID != SkImageCache::UNINITIALIZED_ID);
- SkAutoMutexAcquire ac(&fMutex);
- CachedPixels* pixels = this->findByID(ID);
- SkASSERT(pixels != NULL);
- pixels->unlock();
- this->purgeIfNeeded();
-}
-
-void SkLruImageCache::throwAwayCache(intptr_t ID) {
- SkASSERT(ID != SkImageCache::UNINITIALIZED_ID);
- SkAutoMutexAcquire ac(&fMutex);
- CachedPixels* pixels = this->findByID(ID);
- if (pixels != NULL) {
- if (pixels->isLocked()) {
- pixels->unlock();
- }
- this->removePixels(pixels);
- }
-}
-
-void SkLruImageCache::removePixels(CachedPixels* pixels) {
- // Mutex is already locked.
- SkASSERT(!pixels->isLocked());
- const size_t size = pixels->getLength();
- SkASSERT(size <= fRamUsed);
- fLRU.remove(pixels);
- SkDELETE(pixels);
- fRamUsed -= size;
-}
-
-CachedPixels* SkLruImageCache::findByID(intptr_t ID) const {
- // Mutex is already locked.
- Iter iter;
- // Start from the head, most recently used.
- CachedPixels* pixels = iter.init(fLRU, Iter::kHead_IterStart);
- while (pixels != NULL) {
- if (pixels->getID() == ID) {
- return pixels;
- }
- pixels = iter.next();
- }
- return NULL;
-}
-
-void SkLruImageCache::purgeIfNeeded() {
- // Mutex is already locked.
- if (fRamBudget > 0) {
- this->purgeTilAtOrBelow(fRamBudget);
- }
-}
-
-void SkLruImageCache::purgeTilAtOrBelow(size_t limit) {
- // Mutex is already locked.
- if (fRamUsed > limit) {
- Iter iter;
- // Start from the tail, least recently used.
- CachedPixels* pixels = iter.init(fLRU, Iter::kTail_IterStart);
- while (pixels != NULL && fRamUsed > limit) {
- CachedPixels* prev = iter.prev();
- if (!pixels->isLocked()) {
- this->removePixels(pixels);
- }
- pixels = prev;
- }
- }
-}
diff --git a/lazy/SkPurgeableImageCache.cpp b/lazy/SkPurgeableImageCache.cpp
deleted file mode 100644
index 0d36e4a9..00000000
--- a/lazy/SkPurgeableImageCache.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkThread.h"
-#include "SkPurgeableImageCache.h"
-#include "SkPurgeableMemoryBlock.h"
-
-#ifdef SK_DEBUG
- #include "SkTSearch.h"
-#endif
-
-SK_DEFINE_INST_COUNT(SkPurgeableImageCache)
-SK_DECLARE_STATIC_MUTEX(gPurgeableImageMutex);
-
-SkImageCache* SkPurgeableImageCache::Create() {
- if (!SkPurgeableMemoryBlock::IsSupported()) {
- return NULL;
- }
- SkAutoMutexAcquire ac(&gPurgeableImageMutex);
- static SkPurgeableImageCache gCache;
- gCache.ref();
- return &gCache;
-}
-
-SkPurgeableImageCache::SkPurgeableImageCache() {}
-
-#ifdef SK_DEBUG
-SkPurgeableImageCache::~SkPurgeableImageCache() {
- SkASSERT(fRecs.count() == 0);
-}
-#endif
-
-
-void* SkPurgeableImageCache::allocAndPinCache(size_t bytes, intptr_t* ID) {
- SkAutoMutexAcquire ac(&gPurgeableImageMutex);
-
- SkPurgeableMemoryBlock* block = SkPurgeableMemoryBlock::Create(bytes);
- if (NULL == block) {
- return NULL;
- }
-
- SkPurgeableMemoryBlock::PinResult pinResult;
- void* data = block->pin(&pinResult);
- if (NULL == data) {
- SkDELETE(block);
- return NULL;
- }
-
- SkASSERT(ID != NULL);
- *ID = reinterpret_cast<intptr_t>(block);
-#ifdef SK_DEBUG
- // Insert into the array of all recs:
- int index = this->findRec(*ID);
- SkASSERT(index < 0);
- fRecs.insert(~index, 1, ID);
-#endif
- return data;
-}
-
-void* SkPurgeableImageCache::pinCache(intptr_t ID, SkImageCache::DataStatus* status) {
- SkASSERT(ID != SkImageCache::UNINITIALIZED_ID);
- SkAutoMutexAcquire ac(&gPurgeableImageMutex);
-
- SkASSERT(this->findRec(ID) >= 0);
- SkPurgeableMemoryBlock* block = reinterpret_cast<SkPurgeableMemoryBlock*>(ID);
- SkPurgeableMemoryBlock::PinResult pinResult;
- void* data = block->pin(&pinResult);
- if (NULL == data) {
- this->removeRec(ID);
- return NULL;
- }
-
- switch (pinResult) {
- case SkPurgeableMemoryBlock::kRetained_PinResult:
- *status = SkImageCache::kRetained_DataStatus;
- break;
-
- case SkPurgeableMemoryBlock::kUninitialized_PinResult:
- *status = SkImageCache::kUninitialized_DataStatus;
- break;
-
- default:
- // Invalid value. Treat as a failure to pin.
- SkASSERT(false);
- this->removeRec(ID);
- return NULL;
- }
-
- return data;
-}
-
-void SkPurgeableImageCache::releaseCache(intptr_t ID) {
- SkASSERT(ID != SkImageCache::UNINITIALIZED_ID);
- SkAutoMutexAcquire ac(&gPurgeableImageMutex);
-
- SkASSERT(this->findRec(ID) >= 0);
- SkPurgeableMemoryBlock* block = reinterpret_cast<SkPurgeableMemoryBlock*>(ID);
- block->unpin();
-}
-
-void SkPurgeableImageCache::throwAwayCache(intptr_t ID) {
- SkASSERT(ID != SkImageCache::UNINITIALIZED_ID);
- SkAutoMutexAcquire ac(&gPurgeableImageMutex);
-
- this->removeRec(ID);
-}
-
-#ifdef SK_DEBUG
-SkImageCache::MemoryStatus SkPurgeableImageCache::getMemoryStatus(intptr_t ID) const {
- SkAutoMutexAcquire ac(&gPurgeableImageMutex);
- if (SkImageCache::UNINITIALIZED_ID == ID || this->findRec(ID) < 0) {
- return SkImageCache::kFreed_MemoryStatus;
- }
-
- SkPurgeableMemoryBlock* block = reinterpret_cast<SkPurgeableMemoryBlock*>(ID);
- if (block->isPinned()) {
- return SkImageCache::kPinned_MemoryStatus;
- }
- return SkImageCache::kUnpinned_MemoryStatus;
-}
-
-void SkPurgeableImageCache::purgeAllUnpinnedCaches() {
- SkAutoMutexAcquire ac(&gPurgeableImageMutex);
- if (SkPurgeableMemoryBlock::PlatformSupportsPurgingAllUnpinnedBlocks()) {
- SkPurgeableMemoryBlock::PurgeAllUnpinnedBlocks();
- } else {
- // Go through the blocks, and purge them individually.
- // Rather than deleting the blocks, which would interfere with further calls, purge them
- // and keep them around.
- for (int i = 0; i < fRecs.count(); i++) {
- SkPurgeableMemoryBlock* block = reinterpret_cast<SkPurgeableMemoryBlock*>(fRecs[i]);
- if (!block->isPinned()) {
- if (!block->purge()) {
- // FIXME: This should be more meaningful (which one, etc...)
- SkDebugf("Failed to purge\n");
- }
- }
- }
- }
-}
-
-int SkPurgeableImageCache::findRec(intptr_t rec) const {
- return SkTSearch(fRecs.begin(), fRecs.count(), rec, sizeof(intptr_t));
-}
-#endif
-
-void SkPurgeableImageCache::removeRec(intptr_t ID) {
-#ifdef SK_DEBUG
- int index = this->findRec(ID);
- SkASSERT(index >= 0);
- fRecs.remove(index);
-#endif
- SkPurgeableMemoryBlock* block = reinterpret_cast<SkPurgeableMemoryBlock*>(ID);
- SkASSERT(!block->isPinned());
- SkDELETE(block);
-}
diff --git a/opts/SkBlitMask_opts_arm.cpp b/opts/SkBlitMask_opts_arm.cpp
index 0ad09193..2bf76031 100644
--- a/opts/SkBlitMask_opts_arm.cpp
+++ b/opts/SkBlitMask_opts_arm.cpp
@@ -1,14 +1,39 @@
+#include "SkColor.h"
+#include "SkColorPriv.h"
#include "SkBlitMask.h"
+#include "SkUtilsArm.h"
+#include "SkBlitMask_opts_arm_neon.h"
SkBlitMask::ColorProc SkBlitMask::PlatformColorProcs(SkBitmap::Config dstConfig,
SkMask::Format maskFormat,
SkColor color) {
+#if SK_ARM_NEON_IS_NONE
+ return NULL;
+#else
+#if SK_ARM_NEON_IS_DYNAMIC
+ if (!sk_cpu_arm_has_neon()) {
+ return NULL;
+ }
+#endif
+ if ((SkBitmap::kARGB_8888_Config == dstConfig) &&
+ (SkMask::kA8_Format == maskFormat)) {
+ return D32_A8_Factory_neon(color);
+ }
+#endif
+
+ // We don't need to handle the SkMask::kLCD16_Format case as the default
+ // LCD16 will call us through SkBlitMask::PlatformBlitRowProcs16()
+
return NULL;
}
SkBlitMask::BlitLCD16RowProc SkBlitMask::PlatformBlitRowProcs16(bool isOpaque) {
- return NULL;
+ if (isOpaque) {
+ return SK_ARM_NEON_WRAP(SkBlitLCD16OpaqueRow);
+ } else {
+ return SK_ARM_NEON_WRAP(SkBlitLCD16Row);
+ }
}
SkBlitMask::RowProc SkBlitMask::PlatformRowProcs(SkBitmap::Config dstConfig,
diff --git a/opts/SkBlitMask_opts_arm_neon.cpp b/opts/SkBlitMask_opts_arm_neon.cpp
new file mode 100644
index 00000000..84b5c3da
--- /dev/null
+++ b/opts/SkBlitMask_opts_arm_neon.cpp
@@ -0,0 +1,254 @@
+
+#include "SkBlitMask.h"
+#include "SkColor_opts_neon.h"
+
+static void D32_A8_Black_neon(void* SK_RESTRICT dst, size_t dstRB,
+ const void* SK_RESTRICT maskPtr, size_t maskRB,
+ SkColor, int width, int height) {
+ SkPMColor* SK_RESTRICT device = (SkPMColor*)dst;
+ const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr;
+
+ maskRB -= width;
+ dstRB -= (width << 2);
+ do {
+ int w = width;
+ while (w >= 8) {
+ uint8x8_t vmask = vld1_u8(mask);
+ uint16x8_t vscale = vsubw_u8(vdupq_n_u16(256), vmask);
+ uint8x8x4_t vdevice = vld4_u8((uint8_t*)device);
+
+ vdevice = SkAlphaMulQ_neon8(vdevice, vscale);
+ vdevice.val[NEON_A] += vmask;
+
+ vst4_u8((uint8_t*)device, vdevice);
+
+ mask += 8;
+ device += 8;
+ w -= 8;
+ }
+ while (w-- > 0) {
+ unsigned aa = *mask++;
+ *device = (aa << SK_A32_SHIFT)
+ + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
+ device += 1;
+ };
+ device = (uint32_t*)((char*)device + dstRB);
+ mask += maskRB;
+ } while (--height != 0);
+}
+
+template <bool isColor>
+static void D32_A8_Opaque_Color_neon(void* SK_RESTRICT dst, size_t dstRB,
+ const void* SK_RESTRICT maskPtr, size_t maskRB,
+ SkColor color, int width, int height) {
+ SkPMColor pmc = SkPreMultiplyColor(color);
+ SkPMColor* SK_RESTRICT device = (SkPMColor*)dst;
+ const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr;
+ uint8x8x4_t vpmc;
+
+ maskRB -= width;
+ dstRB -= (width << 2);
+
+ if (width >= 8) {
+ vpmc.val[NEON_A] = vdup_n_u8(SkGetPackedA32(pmc));
+ vpmc.val[NEON_R] = vdup_n_u8(SkGetPackedR32(pmc));
+ vpmc.val[NEON_G] = vdup_n_u8(SkGetPackedG32(pmc));
+ vpmc.val[NEON_B] = vdup_n_u8(SkGetPackedB32(pmc));
+ }
+ do {
+ int w = width;
+ while (w >= 8) {
+ uint8x8_t vmask = vld1_u8(mask);
+ uint16x8_t vscale, vmask256 = SkAlpha255To256_neon8(vmask);
+ if (isColor) {
+ vscale = vsubw_u8(vdupq_n_u16(256),
+ SkAlphaMul_neon8(vpmc.val[NEON_A], vmask256));
+ } else {
+ vscale = vsubw_u8(vdupq_n_u16(256), vmask);
+ }
+ uint8x8x4_t vdev = vld4_u8((uint8_t*)device);
+
+ vdev.val[NEON_A] = SkAlphaMul_neon8(vpmc.val[NEON_A], vmask256)
+ + SkAlphaMul_neon8(vdev.val[NEON_A], vscale);
+ vdev.val[NEON_R] = SkAlphaMul_neon8(vpmc.val[NEON_R], vmask256)
+ + SkAlphaMul_neon8(vdev.val[NEON_R], vscale);
+ vdev.val[NEON_G] = SkAlphaMul_neon8(vpmc.val[NEON_G], vmask256)
+ + SkAlphaMul_neon8(vdev.val[NEON_G], vscale);
+ vdev.val[NEON_B] = SkAlphaMul_neon8(vpmc.val[NEON_B], vmask256)
+ + SkAlphaMul_neon8(vdev.val[NEON_B], vscale);
+
+ vst4_u8((uint8_t*)device, vdev);
+
+ mask += 8;
+ device += 8;
+ w -= 8;
+ }
+
+ while (w--) {
+ unsigned aa = *mask++;
+ if (isColor) {
+ *device = SkBlendARGB32(pmc, *device, aa);
+ } else {
+ *device = SkAlphaMulQ(pmc, SkAlpha255To256(aa))
+ + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
+ }
+ device += 1;
+ };
+
+ device = (uint32_t*)((char*)device + dstRB);
+ mask += maskRB;
+
+ } while (--height != 0);
+}
+
+static void D32_A8_Opaque_neon(void* SK_RESTRICT dst, size_t dstRB,
+ const void* SK_RESTRICT maskPtr, size_t maskRB,
+ SkColor color, int width, int height) {
+ D32_A8_Opaque_Color_neon<false>(dst, dstRB, maskPtr, maskRB, color, width, height);
+}
+
+static void D32_A8_Color_neon(void* SK_RESTRICT dst, size_t dstRB,
+ const void* SK_RESTRICT maskPtr, size_t maskRB,
+ SkColor color, int width, int height) {
+ D32_A8_Opaque_Color_neon<true>(dst, dstRB, maskPtr, maskRB, color, width, height);
+}
+
+SkBlitMask::ColorProc D32_A8_Factory_neon(SkColor color) {
+ if (SK_ColorBLACK == color) {
+ return D32_A8_Black_neon;
+ } else if (0xFF == SkColorGetA(color)) {
+ return D32_A8_Opaque_neon;
+ } else {
+ return D32_A8_Color_neon;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void SkBlitLCD16OpaqueRow_neon(SkPMColor dst[], const uint16_t src[],
+ SkColor color, int width,
+ SkPMColor opaqueDst) {
+ int colR = SkColorGetR(color);
+ int colG = SkColorGetG(color);
+ int colB = SkColorGetB(color);
+
+ uint8x8_t vcolR, vcolG, vcolB;
+ uint8x8_t vopqDstA, vopqDstR, vopqDstG, vopqDstB;
+
+ if (width >= 8) {
+ vcolR = vdup_n_u8(colR);
+ vcolG = vdup_n_u8(colG);
+ vcolB = vdup_n_u8(colB);
+ vopqDstA = vdup_n_u8(SkGetPackedA32(opaqueDst));
+ vopqDstR = vdup_n_u8(SkGetPackedR32(opaqueDst));
+ vopqDstG = vdup_n_u8(SkGetPackedG32(opaqueDst));
+ vopqDstB = vdup_n_u8(SkGetPackedB32(opaqueDst));
+ }
+
+ while (width >= 8) {
+ uint8x8x4_t vdst;
+ uint16x8_t vmask;
+ uint16x8_t vmaskR, vmaskG, vmaskB;
+ uint8x8_t vsel_trans, vsel_opq;
+
+ vdst = vld4_u8((uint8_t*)dst);
+ vmask = vld1q_u16(src);
+
+ // Prepare compare masks
+ vsel_trans = vmovn_u16(vceqq_u16(vmask, vdupq_n_u16(0)));
+ vsel_opq = vmovn_u16(vceqq_u16(vmask, vdupq_n_u16(0xFFFF)));
+
+ // Get all the color masks on 5 bits
+ vmaskR = vshrq_n_u16(vmask, SK_R16_SHIFT);
+ vmaskG = vshrq_n_u16(vshlq_n_u16(vmask, SK_R16_BITS),
+ SK_B16_BITS + SK_R16_BITS + 1);
+ vmaskB = vmask & vdupq_n_u16(SK_B16_MASK);
+
+ // Upscale to 0..32
+ vmaskR = vmaskR + vshrq_n_u16(vmaskR, 4);
+ vmaskG = vmaskG + vshrq_n_u16(vmaskG, 4);
+ vmaskB = vmaskB + vshrq_n_u16(vmaskB, 4);
+
+ vdst.val[NEON_A] = vbsl_u8(vsel_trans, vdst.val[NEON_A], vdup_n_u8(0xFF));
+ vdst.val[NEON_A] = vbsl_u8(vsel_opq, vopqDstA, vdst.val[NEON_A]);
+
+ vdst.val[NEON_R] = SkBlend32_neon8(vcolR, vdst.val[NEON_R], vmaskR);
+ vdst.val[NEON_G] = SkBlend32_neon8(vcolG, vdst.val[NEON_G], vmaskG);
+ vdst.val[NEON_B] = SkBlend32_neon8(vcolB, vdst.val[NEON_B], vmaskB);
+
+ vdst.val[NEON_R] = vbsl_u8(vsel_opq, vopqDstR, vdst.val[NEON_R]);
+ vdst.val[NEON_G] = vbsl_u8(vsel_opq, vopqDstG, vdst.val[NEON_G]);
+ vdst.val[NEON_B] = vbsl_u8(vsel_opq, vopqDstB, vdst.val[NEON_B]);
+
+ vst4_u8((uint8_t*)dst, vdst);
+
+ dst += 8;
+ src += 8;
+ width -= 8;
+ }
+
+ // Leftovers
+ for (int i = 0; i < width; i++) {
+ dst[i] = SkBlendLCD16Opaque(colR, colG, colB, dst[i], src[i],
+ opaqueDst);
+ }
+}
+
+void SkBlitLCD16Row_neon(SkPMColor dst[], const uint16_t src[],
+ SkColor color, int width, SkPMColor) {
+ int colA = SkColorGetA(color);
+ int colR = SkColorGetR(color);
+ int colG = SkColorGetG(color);
+ int colB = SkColorGetB(color);
+
+ colA = SkAlpha255To256(colA);
+
+ uint8x8_t vcolR, vcolG, vcolB;
+ uint16x8_t vcolA;
+
+ if (width >= 8) {
+ vcolA = vdupq_n_u16(colA);
+ vcolR = vdup_n_u8(colR);
+ vcolG = vdup_n_u8(colG);
+ vcolB = vdup_n_u8(colB);
+ }
+
+ while (width >= 8) {
+ uint8x8x4_t vdst;
+ uint16x8_t vmask;
+ uint16x8_t vmaskR, vmaskG, vmaskB;
+
+ vdst = vld4_u8((uint8_t*)dst);
+ vmask = vld1q_u16(src);
+
+ // Get all the color masks on 5 bits
+ vmaskR = vshrq_n_u16(vmask, SK_R16_SHIFT);
+ vmaskG = vshrq_n_u16(vshlq_n_u16(vmask, SK_R16_BITS),
+ SK_B16_BITS + SK_R16_BITS + 1);
+ vmaskB = vmask & vdupq_n_u16(SK_B16_MASK);
+
+ // Upscale to 0..32
+ vmaskR = vmaskR + vshrq_n_u16(vmaskR, 4);
+ vmaskG = vmaskG + vshrq_n_u16(vmaskG, 4);
+ vmaskB = vmaskB + vshrq_n_u16(vmaskB, 4);
+
+ vmaskR = vshrq_n_u16(vmaskR * vcolA, 8);
+ vmaskG = vshrq_n_u16(vmaskG * vcolA, 8);
+ vmaskB = vshrq_n_u16(vmaskB * vcolA, 8);
+
+ vdst.val[NEON_A] = vdup_n_u8(0xFF);
+ vdst.val[NEON_R] = SkBlend32_neon8(vcolR, vdst.val[NEON_R], vmaskR);
+ vdst.val[NEON_G] = SkBlend32_neon8(vcolG, vdst.val[NEON_G], vmaskG);
+ vdst.val[NEON_B] = SkBlend32_neon8(vcolB, vdst.val[NEON_B], vmaskB);
+
+ vst4_u8((uint8_t*)dst, vdst);
+
+ dst += 8;
+ src += 8;
+ width -= 8;
+ }
+
+ for (int i = 0; i < width; i++) {
+ dst[i] = SkBlendLCD16(colA, colR, colG, colB, dst[i], src[i]);
+ }
+}
diff --git a/opts/SkBlitMask_opts_arm_neon.h b/opts/SkBlitMask_opts_arm_neon.h
new file mode 100644
index 00000000..fdbce14f
--- /dev/null
+++ b/opts/SkBlitMask_opts_arm_neon.h
@@ -0,0 +1,16 @@
+#ifndef SkBlitMask_opts_arm_neon_DEFINED
+#define SkBlitMask_opts_arm_neon_DEFINED
+
+#include "SkColor.h"
+#include "SkBlitMask.h"
+
+extern SkBlitMask::ColorProc D32_A8_Factory_neon(SkColor color);
+
+extern void SkBlitLCD16OpaqueRow_neon(SkPMColor dst[], const uint16_t src[],
+ SkColor color, int width,
+ SkPMColor opaqueDst);
+
+extern void SkBlitLCD16Row_neon(SkPMColor dst[], const uint16_t src[],
+ SkColor color, int width, SkPMColor);
+
+#endif // #ifndef SkBlitMask_opts_arm_neon_DEFINED
diff --git a/opts/SkBlurImage_opts_neon.cpp b/opts/SkBlurImage_opts_neon.cpp
new file mode 100644
index 00000000..4e33d72d
--- /dev/null
+++ b/opts/SkBlurImage_opts_neon.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "SkBitmap.h"
+#include "SkColorPriv.h"
+#include "SkBlurImage_opts.h"
+#include "SkRect.h"
+
+#include <arm_neon.h>
+
+namespace {
+
+enum BlurDirection {
+ kX, kY
+};
+
+/**
+ * Helper function to spread the components of a 32-bit integer into the
+ * lower 8 bits of each 16-bit element of a NEON register.
+ */
+
+static inline uint16x4_t expand(uint32_t a) {
+ // ( ARGB ) -> ( ARGB ARGB ) -> ( A R G B A R G B )
+ uint8x8_t v8 = vreinterpret_u8_u32(vdup_n_u32(a));
+ // ( A R G B A R G B ) -> ( 0A 0R 0G 0B 0A 0R 0G 0B ) -> ( 0A 0R 0G 0B )
+ return vget_low_u16(vmovl_u8(v8));
+}
+
+template<BlurDirection srcDirection, BlurDirection dstDirection>
+void SkBoxBlur_NEON(const SkPMColor* src, int srcStride, SkPMColor* dst, int kernelSize,
+ int leftOffset, int rightOffset, int width, int height)
+{
+ const int rightBorder = SkMin32(rightOffset + 1, width);
+ const int srcStrideX = srcDirection == kX ? 1 : srcStride;
+ const int dstStrideX = dstDirection == kX ? 1 : height;
+ const int srcStrideY = srcDirection == kX ? srcStride : 1;
+ const int dstStrideY = dstDirection == kX ? width : 1;
+ const uint32x4_t scale = vdupq_n_u32((1 << 24) / kernelSize);
+ const uint32x4_t half = vdupq_n_u32(1 << 23);
+ for (int y = 0; y < height; ++y) {
+ uint32x4_t sum = vdupq_n_u32(0);
+ const SkPMColor* p = src;
+ for (int i = 0; i < rightBorder; ++i) {
+ sum = vaddw_u16(sum, expand(*p));
+ p += srcStrideX;
+ }
+
+ const SkPMColor* sptr = src;
+ SkPMColor* dptr = dst;
+ for (int x = 0; x < width; ++x) {
+ // ( half+sumA*scale half+sumR*scale half+sumG*scale half+sumB*scale )
+ uint32x4_t result = vmlaq_u32(half, sum, scale);
+
+ // Saturated conversion to 16-bit.
+ // ( AAAA RRRR GGGG BBBB ) -> ( 0A 0R 0G 0B )
+ uint16x4_t result16 = vqshrn_n_u32(result, 16);
+
+ // Saturated conversion to 8-bit.
+ // ( 0A 0R 0G 0B ) -> ( 0A 0R 0G 0B 0A 0R 0G 0B ) -> ( A R G B A R G B )
+ uint8x8_t result8 = vqshrn_n_u16(vcombine_u16(result16, result16), 8);
+
+ // ( A R G B A R G B ) -> ( ARGB ARGB ) -> ( ARGB )
+ // Store low 32 bits to destination.
+ vst1_lane_u32(dptr, vreinterpret_u32_u8(result8), 0);
+
+ if (x >= leftOffset) {
+ const SkPMColor* l = sptr - leftOffset * srcStrideX;
+ sum = vsubw_u16(sum, expand(*l));
+ }
+ if (x + rightOffset + 1 < width) {
+ const SkPMColor* r = sptr + (rightOffset + 1) * srcStrideX;
+ sum = vaddw_u16(sum, expand(*r));
+ }
+ sptr += srcStrideX;
+ if (srcDirection == kY) {
+ SK_PREFETCH(sptr + (rightOffset + 1) * srcStrideX);
+ }
+ dptr += dstStrideX;
+ }
+ src += srcStrideY;
+ dst += dstStrideY;
+ }
+}
+
+} // namespace
+
+bool SkBoxBlurGetPlatformProcs_NEON(SkBoxBlurProc* boxBlurX,
+ SkBoxBlurProc* boxBlurY,
+ SkBoxBlurProc* boxBlurXY,
+ SkBoxBlurProc* boxBlurYX) {
+ *boxBlurX = SkBoxBlur_NEON<kX, kX>;
+ *boxBlurY = SkBoxBlur_NEON<kY, kY>;
+ *boxBlurXY = SkBoxBlur_NEON<kX, kY>;
+ *boxBlurYX = SkBoxBlur_NEON<kY, kX>;
+ return true;
+}
diff --git a/opts/SkBlurImage_opts_neon.h b/opts/SkBlurImage_opts_neon.h
new file mode 100644
index 00000000..7fbe9633
--- /dev/null
+++ b/opts/SkBlurImage_opts_neon.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBlurImage_opts.h"
+
+bool SkBoxBlurGetPlatformProcs_NEON(SkBoxBlurProc* boxBlurX,
+ SkBoxBlurProc* boxBlurY,
+ SkBoxBlurProc* boxBlurXY,
+ SkBoxBlurProc* boxBlurYX);
diff --git a/opts/SkColor_opts_neon.h b/opts/SkColor_opts_neon.h
index f8123971..a3430b5c 100644
--- a/opts/SkColor_opts_neon.h
+++ b/opts/SkColor_opts_neon.h
@@ -2,6 +2,7 @@
#define SkColor_opts_neon_DEFINED
#include "SkTypes.h"
+#include "SkColorPriv.h"
#include <arm_neon.h>
@@ -65,4 +66,49 @@ static inline uint16x8_t SkPixel32ToPixel16_neon8(uint8x8x4_t vsrc) {
return ret;
}
+/* This function blends 8 pixels of the same channel in the exact same way as
+ * SkBlend32.
+ */
+static inline uint8x8_t SkBlend32_neon8(uint8x8_t src, uint8x8_t dst, uint16x8_t scale) {
+ int16x8_t src_wide, dst_wide;
+
+ src_wide = vreinterpretq_s16_u16(vmovl_u8(src));
+ dst_wide = vreinterpretq_s16_u16(vmovl_u8(dst));
+
+ src_wide = (src_wide - dst_wide) * vreinterpretq_s16_u16(scale);
+
+ dst_wide += vshrq_n_s16(src_wide, 5);
+
+ return vmovn_u16(vreinterpretq_u16_s16(dst_wide));
+}
+
+static inline SkPMColor SkFourByteInterp256_neon(SkPMColor src, SkPMColor dst,
+ unsigned srcScale) {
+ SkASSERT(srcScale <= 256);
+ int16x8_t vscale = vdupq_n_s16(srcScale);
+ int16x8_t vsrc_wide, vdst_wide, vdiff;
+ uint8x8_t res;
+
+ vsrc_wide = vreinterpretq_s16_u16(vmovl_u8(vreinterpret_u8_u32(vdup_n_u32(src))));
+ vdst_wide = vreinterpretq_s16_u16(vmovl_u8(vreinterpret_u8_u32(vdup_n_u32(dst))));
+
+ vdiff = vsrc_wide - vdst_wide;
+ vdiff *= vscale;
+
+ vdiff = vshrq_n_s16(vdiff, 8);
+
+ vdst_wide += vdiff;
+
+ res = vmovn_u16(vreinterpretq_u16_s16(vdst_wide));
+
+ return vget_lane_u32(vreinterpret_u32_u8(res), 0);
+}
+
+static inline SkPMColor SkFourByteInterp_neon(SkPMColor src, SkPMColor dst,
+ U8CPU srcWeight) {
+ SkASSERT(srcWeight <= 255);
+ unsigned scale = SkAlpha255To256(srcWeight);
+ return SkFourByteInterp256_neon(src, dst, scale);
+}
+
#endif /* #ifndef SkColor_opts_neon_DEFINED */
diff --git a/opts/SkXfermode_opts_arm.cpp b/opts/SkXfermode_opts_arm.cpp
index eb3b3016..2a796d6f 100644
--- a/opts/SkXfermode_opts_arm.cpp
+++ b/opts/SkXfermode_opts_arm.cpp
@@ -5,12 +5,22 @@
extern SkProcCoeffXfermode* SkPlatformXfermodeFactory_impl_neon(const ProcCoeff& rec,
SkXfermode::Mode mode);
+extern SkXfermodeProc SkPlatformXfermodeProcFactory_impl_neon(SkXfermode::Mode mode);
+
SkProcCoeffXfermode* SkPlatformXfermodeFactory_impl(const ProcCoeff& rec,
SkXfermode::Mode mode) {
return NULL;
}
+SkXfermodeProc SkPlatformXfermodeProcFactory_impl(SkXfermode::Mode mode) {
+ return NULL;
+}
+
SkProcCoeffXfermode* SkPlatformXfermodeFactory(const ProcCoeff& rec,
SkXfermode::Mode mode) {
return SK_ARM_NEON_WRAP(SkPlatformXfermodeFactory_impl)(rec, mode);
}
+
+SkXfermodeProc SkPlatformXfermodeProcFactory(SkXfermode::Mode mode) {
+ return SK_ARM_NEON_WRAP(SkPlatformXfermodeProcFactory_impl)(mode);
+}
diff --git a/opts/SkXfermode_opts_arm_neon.cpp b/opts/SkXfermode_opts_arm_neon.cpp
index b8d8ef52..6a79b737 100644
--- a/opts/SkXfermode_opts_arm_neon.cpp
+++ b/opts/SkXfermode_opts_arm_neon.cpp
@@ -93,6 +93,133 @@ static inline uint8x8_t clamp_div255round_simd8_32(int32x4_t val1, int32x4_t val
}
////////////////////////////////////////////////////////////////////////////////
+// 1 pixel modeprocs
+////////////////////////////////////////////////////////////////////////////////
+
+// kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]
+SkPMColor srcatop_modeproc_neon(SkPMColor src, SkPMColor dst) {
+ unsigned sa = SkGetPackedA32(src);
+ unsigned da = SkGetPackedA32(dst);
+ unsigned isa = 255 - sa;
+
+ uint8x8_t vda, visa, vsrc, vdst;
+
+ vda = vdup_n_u8(da);
+ visa = vdup_n_u8(isa);
+
+ uint16x8_t vsrc_wide, vdst_wide;
+ vsrc_wide = vmull_u8(vda, vreinterpret_u8_u32(vdup_n_u32(src)));
+ vdst_wide = vmull_u8(visa, vreinterpret_u8_u32(vdup_n_u32(dst)));
+
+ vsrc_wide += vdupq_n_u16(128);
+ vsrc_wide += vshrq_n_u16(vsrc_wide, 8);
+
+ vdst_wide += vdupq_n_u16(128);
+ vdst_wide += vshrq_n_u16(vdst_wide, 8);
+
+ vsrc = vshrn_n_u16(vsrc_wide, 8);
+ vdst = vshrn_n_u16(vdst_wide, 8);
+
+ vsrc += vdst;
+ vsrc = vset_lane_u8(da, vsrc, 3);
+
+ return vget_lane_u32(vreinterpret_u32_u8(vsrc), 0);
+}
+
+// kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
+SkPMColor dstatop_modeproc_neon(SkPMColor src, SkPMColor dst) {
+ unsigned sa = SkGetPackedA32(src);
+ unsigned da = SkGetPackedA32(dst);
+ unsigned ida = 255 - da;
+
+ uint8x8_t vsa, vida, vsrc, vdst;
+
+ vsa = vdup_n_u8(sa);
+ vida = vdup_n_u8(ida);
+
+ uint16x8_t vsrc_wide, vdst_wide;
+ vsrc_wide = vmull_u8(vida, vreinterpret_u8_u32(vdup_n_u32(src)));
+ vdst_wide = vmull_u8(vsa, vreinterpret_u8_u32(vdup_n_u32(dst)));
+
+ vsrc_wide += vdupq_n_u16(128);
+ vsrc_wide += vshrq_n_u16(vsrc_wide, 8);
+
+ vdst_wide += vdupq_n_u16(128);
+ vdst_wide += vshrq_n_u16(vdst_wide, 8);
+
+ vsrc = vshrn_n_u16(vsrc_wide, 8);
+ vdst = vshrn_n_u16(vdst_wide, 8);
+
+ vsrc += vdst;
+ vsrc = vset_lane_u8(sa, vsrc, 3);
+
+ return vget_lane_u32(vreinterpret_u32_u8(vsrc), 0);
+}
+
+// kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
+SkPMColor xor_modeproc_neon(SkPMColor src, SkPMColor dst) {
+ unsigned sa = SkGetPackedA32(src);
+ unsigned da = SkGetPackedA32(dst);
+ unsigned ret_alpha = sa + da - (SkAlphaMulAlpha(sa, da) << 1);
+ unsigned isa = 255 - sa;
+ unsigned ida = 255 - da;
+
+ uint8x8_t vsrc, vdst, visa, vida;
+ uint16x8_t vsrc_wide, vdst_wide;
+
+ visa = vdup_n_u8(isa);
+ vida = vdup_n_u8(ida);
+ vsrc = vreinterpret_u8_u32(vdup_n_u32(src));
+ vdst = vreinterpret_u8_u32(vdup_n_u32(dst));
+
+ vsrc_wide = vmull_u8(vsrc, vida);
+ vdst_wide = vmull_u8(vdst, visa);
+
+ vsrc_wide += vdupq_n_u16(128);
+ vsrc_wide += vshrq_n_u16(vsrc_wide, 8);
+
+ vdst_wide += vdupq_n_u16(128);
+ vdst_wide += vshrq_n_u16(vdst_wide, 8);
+
+ vsrc = vshrn_n_u16(vsrc_wide, 8);
+ vdst = vshrn_n_u16(vdst_wide, 8);
+
+ vsrc += vdst;
+
+ vsrc = vset_lane_u8(ret_alpha, vsrc, 3);
+
+ return vget_lane_u32(vreinterpret_u32_u8(vsrc), 0);
+}
+
+// kPlus_Mode
+SkPMColor plus_modeproc_neon(SkPMColor src, SkPMColor dst) {
+ uint8x8_t vsrc, vdst;
+ vsrc = vreinterpret_u8_u32(vdup_n_u32(src));
+ vdst = vreinterpret_u8_u32(vdup_n_u32(dst));
+ vsrc = vqadd_u8(vsrc, vdst);
+
+ return vget_lane_u32(vreinterpret_u32_u8(vsrc), 0);
+}
+
+// kModulate_Mode
+SkPMColor modulate_modeproc_neon(SkPMColor src, SkPMColor dst) {
+ uint8x8_t vsrc, vdst, vres;
+ uint16x8_t vres_wide;
+
+ vsrc = vreinterpret_u8_u32(vdup_n_u32(src));
+ vdst = vreinterpret_u8_u32(vdup_n_u32(dst));
+
+ vres_wide = vmull_u8(vsrc, vdst);
+
+ vres_wide += vdupq_n_u16(128);
+ vres_wide += vshrq_n_u16(vres_wide, 8);
+
+ vres = vshrn_n_u16(vres_wide, 8);
+
+ return vget_lane_u32(vreinterpret_u32_u8(vres), 0);
+}
+
+////////////////////////////////////////////////////////////////////////////////
// 8 pixels modeprocs
////////////////////////////////////////////////////////////////////////////////
@@ -632,7 +759,7 @@ void SkNEONProcCoeffXfermode::xfer32(SkPMColor dst[], const SkPMColor src[],
SkPMColor dstC = dst[i];
SkPMColor C = proc(src[i], dstC);
if (a != 0xFF) {
- C = SkFourByteInterp(C, dstC, a);
+ C = SkFourByteInterp_neon(C, dstC, a);
}
dst[i] = C;
}
@@ -700,7 +827,7 @@ void SkNEONProcCoeffXfermode::xfer16(uint16_t* SK_RESTRICT dst,
SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
SkPMColor C = proc(src[i], dstC);
if (0xFF != a) {
- C = SkFourByteInterp(C, dstC, a);
+ C = SkFourByteInterp_neon(C, dstC, a);
}
dst[i] = SkPixel32ToPixel16_ToU16(C);
}
@@ -755,6 +882,45 @@ SK_COMPILE_ASSERT(
mode_count_arm
);
+SkXfermodeProc gNEONXfermodeProcs1[] = {
+ NULL, // kClear_Mode
+ NULL, // kSrc_Mode
+ NULL, // kDst_Mode
+ NULL, // kSrcOver_Mode
+ NULL, // kDstOver_Mode
+ NULL, // kSrcIn_Mode
+ NULL, // kDstIn_Mode
+ NULL, // kSrcOut_Mode
+ NULL, // kDstOut_Mode
+ srcatop_modeproc_neon,
+ dstatop_modeproc_neon,
+ xor_modeproc_neon,
+ plus_modeproc_neon,
+ modulate_modeproc_neon,
+ NULL, // kScreen_Mode
+
+ NULL, // kOverlay_Mode
+ NULL, // kDarken_Mode
+ NULL, // kLighten_Mode
+ NULL, // kColorDodge_Mode
+ NULL, // kColorBurn_Mode
+ NULL, // kHardLight_Mode
+ NULL, // kSoftLight_Mode
+ NULL, // kDifference_Mode
+ NULL, // kExclusion_Mode
+ NULL, // kMultiply_Mode
+
+ NULL, // kHue_Mode
+ NULL, // kSaturation_Mode
+ NULL, // kColor_Mode
+ NULL, // kLuminosity_Mode
+};
+
+SK_COMPILE_ASSERT(
+ SK_ARRAY_COUNT(gNEONXfermodeProcs1) == SkXfermode::kLastMode + 1,
+ mode1_count_arm
+);
+
SkProcCoeffXfermode* SkPlatformXfermodeFactory_impl_neon(const ProcCoeff& rec,
SkXfermode::Mode mode) {
@@ -765,3 +931,7 @@ SkProcCoeffXfermode* SkPlatformXfermodeFactory_impl_neon(const ProcCoeff& rec,
}
return NULL;
}
+
+SkXfermodeProc SkPlatformXfermodeProcFactory_impl_neon(SkXfermode::Mode mode) {
+ return gNEONXfermodeProcs1[mode];
+}
diff --git a/opts/SkXfermode_opts_arm_neon.h b/opts/SkXfermode_opts_arm_neon.h
index 4c88fc7a..a8d43819 100644
--- a/opts/SkXfermode_opts_arm_neon.h
+++ b/opts/SkXfermode_opts_arm_neon.h
@@ -26,4 +26,10 @@ private:
typedef SkProcCoeffXfermode INHERITED;
};
+extern SkPMColor srcatop_modeproc_neon(SkPMColor src, SkPMColor dst);
+extern SkPMColor dstatop_modeproc_neon(SkPMColor src, SkPMColor dst);
+extern SkPMColor xor_modeproc_neon(SkPMColor src, SkPMColor dst);
+extern SkPMColor plus_modeproc_neon(SkPMColor src, SkPMColor dst);
+extern SkPMColor modulate_modeproc_neon(SkPMColor src, SkPMColor dst);
+
#endif //#ifdef SkXfermode_opts_arm_neon_DEFINED
diff --git a/opts/SkXfermode_opts_none.cpp b/opts/SkXfermode_opts_none.cpp
index ca53fa0d..7c46fdd9 100644
--- a/opts/SkXfermode_opts_none.cpp
+++ b/opts/SkXfermode_opts_none.cpp
@@ -1,11 +1,17 @@
#include "SkXfermode.h"
#include "SkXfermode_proccoeff.h"
-// The prototype below is for Clang
+// The prototypes below are for Clang
extern SkProcCoeffXfermode* SkPlatformXfermodeFactory(const ProcCoeff& rec,
SkXfermode::Mode mode);
+extern SkXfermodeProc SkPlatformXfermodeProcFactory(SkXfermode::Mode mode);
+
SkProcCoeffXfermode* SkPlatformXfermodeFactory(const ProcCoeff& rec,
SkXfermode::Mode mode) {
return NULL;
}
+
+SkXfermodeProc SkPlatformXfermodeProcFactory(SkXfermode::Mode mode) {
+ return NULL;
+}
diff --git a/opts/opts_check_arm.cpp b/opts/opts_check_arm.cpp
index a9afa75b..3a322aa0 100644
--- a/opts/opts_check_arm.cpp
+++ b/opts/opts_check_arm.cpp
@@ -19,6 +19,7 @@
#include "SkUtilsArm.h"
#include "SkMorphology_opts.h"
#include "SkMorphology_opts_neon.h"
+#include "SkBlurImage_opts_neon.h"
#if defined(SK_CPU_LENDIAN) && !SK_ARM_NEON_IS_NONE
extern "C" void memset16_neon(uint16_t dst[], uint16_t value, int count);
@@ -91,3 +92,19 @@ SkMorphologyProc SkMorphologyGetPlatformProc(SkMorphologyProcType type) {
}
#endif
}
+
+bool SkBoxBlurGetPlatformProcs(SkBoxBlurProc* boxBlurX,
+ SkBoxBlurProc* boxBlurY,
+ SkBoxBlurProc* boxBlurXY,
+ SkBoxBlurProc* boxBlurYX) {
+#if SK_ARM_NEON_IS_NONE
+ return false;
+#else
+#if SK_ARM_NEON_IS_DYNAMIC
+ if (!sk_cpu_arm_has_neon()) {
+ return false;
+ }
+#endif
+ return SkBoxBlurGetPlatformProcs_NEON(boxBlurX, boxBlurY, boxBlurXY, boxBlurYX);
+#endif
+}
diff --git a/pdf/SkPDFDevice.cpp b/pdf/SkPDFDevice.cpp
index bdabc53f..cdfec330 100644
--- a/pdf/SkPDFDevice.cpp
+++ b/pdf/SkPDFDevice.cpp
@@ -1875,11 +1875,12 @@ ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
return entry;
}
-void SkPDFDevice::finishContentEntry(const SkXfermode::Mode xfermode,
+void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode,
SkPDFFormXObject* dst,
SkPath* shape) {
if (xfermode != SkXfermode::kClear_Mode &&
xfermode != SkXfermode::kSrc_Mode &&
+ xfermode != SkXfermode::kDstOver_Mode &&
xfermode != SkXfermode::kSrcIn_Mode &&
xfermode != SkXfermode::kDstIn_Mode &&
xfermode != SkXfermode::kSrcOut_Mode &&
@@ -1890,6 +1891,18 @@ void SkPDFDevice::finishContentEntry(const SkXfermode::Mode xfermode,
SkASSERT(!dst);
return;
}
+ if (xfermode == SkXfermode::kDstOver_Mode) {
+ SkASSERT(!dst);
+ ContentEntry* firstContentEntry = getContentEntries()->get();
+ if (firstContentEntry->fContent.getOffset() == 0) {
+ // For DstOver, an empty content entry was inserted before the rest
+ // of the content entries. If nothing was drawn, it needs to be
+ // removed.
+ SkAutoTDelete<ContentEntry>* contentEntries = getContentEntries();
+ contentEntries->reset(firstContentEntry->fNext.detach());
+ }
+ return;
+ }
if (!dst) {
SkASSERT(xfermode == SkXfermode::kSrc_Mode ||
xfermode == SkXfermode::kSrcOut_Mode);
@@ -1904,17 +1917,32 @@ void SkPDFDevice::finishContentEntry(const SkXfermode::Mode xfermode,
SkClipStack clipStack = contentEntries->fState.fClipStack;
SkRegion clipRegion = contentEntries->fState.fClipRegion;
+ SkMatrix identity;
+ identity.reset();
+ SkPaint stockPaint;
+
SkAutoTUnref<SkPDFFormXObject> srcFormXObject;
if (isContentEmpty()) {
- SkASSERT(xfermode == SkXfermode::kClear_Mode);
+ // If nothing was drawn and there's no shape, then the draw was a
+ // no-op, but dst needs to be restored for that to be true.
+ // If there is shape, then an empty source with Src, SrcIn, SrcOut,
+ // DstIn, DstAtop or Modulate reduces to Clear and DstOut or SrcAtop
+ // reduces to Dst.
+ if (shape == NULL || xfermode == SkXfermode::kDstOut_Mode ||
+ xfermode == SkXfermode::kSrcATop_Mode) {
+ ScopedContentEntry content(this, &clipStack, clipRegion, identity,
+ stockPaint);
+ SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst),
+ &content.entry()->fContent);
+ return;
+ } else {
+ xfermode = SkXfermode::kClear_Mode;
+ }
} else {
SkASSERT(!fContentEntries->fNext.get());
srcFormXObject.reset(createFormXObjectFromDevice());
}
- SkMatrix identity;
- identity.reset();
-
// TODO(vandebo) srcFormXObject may contain alpha, but here we want it
// without alpha.
if (xfermode == SkXfermode::kSrcATop_Mode) {
@@ -1946,16 +1974,7 @@ void SkPDFDevice::finishContentEntry(const SkXfermode::Mode xfermode,
clipRegion, SkXfermode::kSrcOver_Mode, true);
}
- SkPaint stockPaint;
-
- if (xfermode == SkXfermode::kSrcATop_Mode) {
- ScopedContentEntry content(this, &clipStack, clipRegion, identity,
- stockPaint);
- if (content.entry()) {
- SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst),
- &content.entry()->fContent);
- }
- } else if (xfermode == SkXfermode::kClear_Mode || !srcFormXObject.get()) {
+ if (xfermode == SkXfermode::kClear_Mode) {
return;
} else if (xfermode == SkXfermode::kSrc_Mode ||
xfermode == SkXfermode::kDstATop_Mode) {
@@ -1969,6 +1988,13 @@ void SkPDFDevice::finishContentEntry(const SkXfermode::Mode xfermode,
if (xfermode == SkXfermode::kSrc_Mode) {
return;
}
+ } else if (xfermode == SkXfermode::kSrcATop_Mode) {
+ ScopedContentEntry content(this, &clipStack, clipRegion, identity,
+ stockPaint);
+ if (content.entry()) {
+ SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst),
+ &content.entry()->fContent);
+ }
}
SkASSERT(xfermode == SkXfermode::kSrcIn_Mode ||
diff --git a/pdf/SkPDFFont.cpp b/pdf/SkPDFFont.cpp
index b824506b..1641a891 100644
--- a/pdf/SkPDFFont.cpp
+++ b/pdf/SkPDFFont.cpp
@@ -875,9 +875,8 @@ SkPDFFont::SkPDFFont(SkAdvancedTypefaceMetrics* info, SkTypeface* typeface,
fTypeface(ref_or_default(typeface)),
fFirstGlyphID(1),
fLastGlyphID(info ? info->fLastGlyphID : 0),
- fFontInfo(info),
- fDescriptor(relatedFontDescriptor) {
- SkSafeRef(info);
+ fFontInfo(SkSafeRef(info)),
+ fDescriptor(SkSafeRef(relatedFontDescriptor)) {
if (info == NULL) {
fFontType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
} else if (info->fMultiMaster) {
diff --git a/pdf/SkPDFFont.h b/pdf/SkPDFFont.h
index f5d358f3..694c69ac 100644
--- a/pdf/SkPDFFont.h
+++ b/pdf/SkPDFFont.h
@@ -78,6 +78,7 @@ private:
reference to each instantiated class.
*/
class SkPDFFont : public SkPDFDict {
+ SK_DECLARE_INST_COUNT(SkPDFFont)
public:
virtual ~SkPDFFont();
@@ -198,6 +199,7 @@ private:
// This should be made a hash table if performance is a problem.
static SkTDArray<FontRec>& CanonicalFonts();
static SkBaseMutex& CanonicalFontsMutex();
+ typedef SkPDFDict INHERITED;
};
#endif
diff --git a/pdf/SkPDFGraphicState.h b/pdf/SkPDFGraphicState.h
index 84c42910..9182efef 100644
--- a/pdf/SkPDFGraphicState.h
+++ b/pdf/SkPDFGraphicState.h
@@ -27,6 +27,7 @@ class SkPDFFormXObject;
*/
class SkPDFGraphicState : public SkPDFDict {
+ SK_DECLARE_INST_COUNT(SkPDFGraphicState)
public:
enum SkPDFSMaskMode {
kAlpha_SMaskMode,
@@ -104,6 +105,7 @@ private:
static SkPDFObject* GetInvertFunction();
static int Find(const SkPaint& paint);
+ typedef SkPDFDict INHERITED;
};
#endif
diff --git a/pdf/SkPDFImage.cpp b/pdf/SkPDFImage.cpp
index a99c9fe3..81adcc20 100644
--- a/pdf/SkPDFImage.cpp
+++ b/pdf/SkPDFImage.cpp
@@ -36,7 +36,6 @@ static size_t get_uncompressed_size(const SkBitmap& bitmap,
return srcRect.width() * 3 * srcRect.height();
case SkBitmap::kARGB_8888_Config:
return srcRect.width() * 3 * srcRect.height();
- case SkBitmap::kA1_Config:
case SkBitmap::kA8_Config:
return 1;
default:
@@ -166,48 +165,6 @@ static SkStream* extract_argb8888_data(const SkBitmap& bitmap,
return stream;
}
-static SkStream* extract_a1_alpha(const SkBitmap& bitmap,
- const SkIRect& srcRect,
- bool* isOpaque,
- bool* isTransparent) {
- const int alphaRowBytes = (srcRect.width() + 7) / 8;
- SkStream* stream = SkNEW_ARGS(SkMemoryStream,
- (alphaRowBytes * srcRect.height()));
- uint8_t* alphaDst = (uint8_t*)stream->getMemoryBase();
-
- int offset1 = srcRect.fLeft % 8;
- int offset2 = 8 - offset1;
-
- for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
- uint8_t* src = bitmap.getAddr1(0, y);
- // This may read up to one byte after src, but the
- // potentially invalid bits are never used for computation.
- for (int x = srcRect.fLeft; x < srcRect.fRight; x += 8) {
- if (offset1) {
- alphaDst[0] = src[x / 8] << offset1 |
- src[x / 8 + 1] >> offset2;
- } else {
- alphaDst[0] = src[x / 8];
- }
- if (x + 7 < srcRect.fRight) {
- *isOpaque &= alphaDst[0] == SK_AlphaOPAQUE;
- *isTransparent &= alphaDst[0] == SK_AlphaTRANSPARENT;
- }
- alphaDst++;
- }
- // Calculate the mask of bits we're interested in within the
- // last byte of alphaDst.
- // width mod 8 == 1 -> 0x80 ... width mod 8 == 7 -> 0xFE
- uint8_t mask = ~((1 << (8 - (srcRect.width() % 8))) - 1);
- if (srcRect.width() % 8) {
- *isOpaque &= (alphaDst[-1] & mask) == (SK_AlphaOPAQUE & mask);
- *isTransparent &=
- (alphaDst[-1] & mask) == (SK_AlphaTRANSPARENT & mask);
- }
- }
- return stream;
-}
-
static SkStream* extract_a8_alpha(const SkBitmap& bitmap,
const SkIRect& srcRect,
bool* isOpaque,
@@ -283,14 +240,6 @@ static SkStream* extract_image_data(const SkBitmap& bitmap,
stream = extract_argb8888_data(bitmap, srcRect, extractAlpha,
&isOpaque, &transparent);
break;
- case SkBitmap::kA1_Config:
- if (!extractAlpha) {
- stream = create_black_image();
- } else {
- stream = extract_a1_alpha(bitmap, srcRect,
- &isOpaque, &transparent);
- }
- break;
case SkBitmap::kA8_Config:
if (!extractAlpha) {
stream = create_black_image();
@@ -574,8 +523,7 @@ SkPDFImage::SkPDFImage(SkStream* stream,
insertName("Type", "XObject");
insertName("Subtype", "Image");
- bool alphaOnly = (config == SkBitmap::kA1_Config ||
- config == SkBitmap::kA8_Config);
+ bool alphaOnly = (config == SkBitmap::kA8_Config);
if (!isAlpha && alphaOnly) {
// For alpha only images, we stretch a single pixel of black for
@@ -601,8 +549,6 @@ SkPDFImage::SkPDFImage(SkStream* stream,
int bitsPerComp = 8;
if (config == SkBitmap::kARGB_4444_Config) {
bitsPerComp = 4;
- } else if (isAlpha && config == SkBitmap::kA1_Config) {
- bitsPerComp = 1;
}
insertInt("BitsPerComponent", bitsPerComp);
diff --git a/pdf/SkPDFPage.h b/pdf/SkPDFPage.h
index 2ce773c0..47573c74 100644
--- a/pdf/SkPDFPage.h
+++ b/pdf/SkPDFPage.h
@@ -25,6 +25,7 @@ class SkWStream;
tree and points to the content of the page.
*/
class SkPDFPage : public SkPDFDict {
+ SK_DECLARE_INST_COUNT(SkPDFPage)
public:
/** Create a PDF page with the passed PDF device. The device need not
* have content on it yet.
@@ -102,6 +103,7 @@ private:
// Once the content is finalized, put it into a stream for output.
SkAutoTUnref<SkPDFStream> fContentStream;
+ typedef SkPDFDict INHERITED;
};
#endif
diff --git a/pdf/SkPDFResourceDict.cpp b/pdf/SkPDFResourceDict.cpp
index 6f5d1679..8a0208d6 100644
--- a/pdf/SkPDFResourceDict.cpp
+++ b/pdf/SkPDFResourceDict.cpp
@@ -8,8 +8,6 @@
#include "SkPDFResourceDict.h"
#include "SkPostConfig.h"
-SK_DEFINE_INST_COUNT(SkPDFResourceDict)
-
// Sanity check that the values of enum SkPDFResourceType correspond to the
// expected values as defined in the arrays below.
// If these are failing, you may need to update the resource_type_prefixes
diff --git a/pdf/SkPDFResourceDict.h b/pdf/SkPDFResourceDict.h
index ab25b4a4..17ea338f 100644
--- a/pdf/SkPDFResourceDict.h
+++ b/pdf/SkPDFResourceDict.h
@@ -95,6 +95,7 @@ private:
SkTSet<SkPDFObject*> fResources;
SkTDArray<SkPDFDict*> fTypes;
+ typedef SkPDFDict INHERITED;
};
#endif
diff --git a/pdf/SkPDFShader.cpp b/pdf/SkPDFShader.cpp
index 60992c3b..94bdf2d7 100644
--- a/pdf/SkPDFShader.cpp
+++ b/pdf/SkPDFShader.cpp
@@ -499,6 +499,7 @@ private:
};
class SkPDFFunctionShader : public SkPDFDict, public SkPDFShader {
+ SK_DECLARE_INST_COUNT(SkPDFFunctionShader)
public:
explicit SkPDFFunctionShader(SkPDFShader::State* state);
virtual ~SkPDFFunctionShader() {
@@ -524,6 +525,7 @@ private:
SkAutoTDelete<const SkPDFShader::State> fState;
SkPDFStream* makePSFunction(const SkString& psCode, SkPDFArray* domain);
+ typedef SkPDFDict INHERITED;
};
/**
diff --git a/pdf/SkPDFStream.h b/pdf/SkPDFStream.h
index d7ff115b..6371bc18 100644
--- a/pdf/SkPDFStream.h
+++ b/pdf/SkPDFStream.h
@@ -25,6 +25,7 @@ class SkPDFCatalog;
is feasible.
*/
class SkPDFStream : public SkPDFDict {
+ SK_DECLARE_INST_COUNT(SkPDFStream)
public:
/** Create a PDF stream. A Length entry is automatically added to the
* stream dictionary. The stream may be retained (stream->ref() may be
diff --git a/pdf/SkPDFTypes.cpp b/pdf/SkPDFTypes.cpp
index ed02d2bd..55871c50 100644
--- a/pdf/SkPDFTypes.cpp
+++ b/pdf/SkPDFTypes.cpp
@@ -17,16 +17,6 @@
#define SNPRINTF snprintf
#endif
-SK_DEFINE_INST_COUNT(SkPDFArray)
-SK_DEFINE_INST_COUNT(SkPDFBool)
-SK_DEFINE_INST_COUNT(SkPDFDict)
-SK_DEFINE_INST_COUNT(SkPDFInt)
-SK_DEFINE_INST_COUNT(SkPDFName)
-SK_DEFINE_INST_COUNT(SkPDFObject)
-SK_DEFINE_INST_COUNT(SkPDFObjRef)
-SK_DEFINE_INST_COUNT(SkPDFScalar)
-SK_DEFINE_INST_COUNT(SkPDFString)
-
///////////////////////////////////////////////////////////////////////////////
void SkPDFObject::emit(SkWStream* stream, SkPDFCatalog* catalog,
diff --git a/ports/SkDebug_win.cpp b/ports/SkDebug_win.cpp
index 599b133e..fe28ee27 100644
--- a/ports/SkDebug_win.cpp
+++ b/ports/SkDebug_win.cpp
@@ -14,7 +14,7 @@ static const size_t kBufferSize = 2048;
#include <stdarg.h>
#include <stdio.h>
-#include <Windows.h>
+#include <windows.h>
void SkDebugf(const char format[], ...) {
char buffer[kBufferSize + 1];
diff --git a/ports/SkDiscardableMemory_ashmem.cpp b/ports/SkDiscardableMemory_ashmem.cpp
new file mode 100644
index 00000000..6f8684e3
--- /dev/null
+++ b/ports/SkDiscardableMemory_ashmem.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <unistd.h>
+#include <sys/mman.h>
+#include "SkDiscardableMemory.h"
+#include "SkTypes.h"
+#include "android/ashmem.h"
+
+////////////////////////////////////////////////////////////////////////////////
+namespace {
+/**
+ * DiscardableMemory implementation that uses the Android kernel's
+ * ashmem (Android shared memory).
+ */
+class SkAshmemDiscardableMemory : public SkDiscardableMemory {
+public:
+ SkAshmemDiscardableMemory(int fd, void* address, size_t size);
+ virtual ~SkAshmemDiscardableMemory();
+ virtual bool lock() SK_OVERRIDE;
+ virtual void* data() SK_OVERRIDE;
+ virtual void unlock() SK_OVERRIDE;
+private:
+ bool fLocked;
+ int fFd;
+ void* fMemory;
+ const size_t fSize;
+};
+
+SkAshmemDiscardableMemory::SkAshmemDiscardableMemory(int fd,
+ void* address,
+ size_t size)
+ : fLocked(true) // Ashmem pages are pinned by default.
+ , fFd(fd)
+ , fMemory(address)
+ , fSize(size) {
+ SkASSERT(fFd >= 0);
+ SkASSERT(fMemory != NULL);
+ SkASSERT(fSize > 0);
+}
+
+SkAshmemDiscardableMemory::~SkAshmemDiscardableMemory() {
+ SkASSERT(!fLocked);
+ if (NULL != fMemory) {
+ munmap(fMemory, fSize);
+ }
+ if (fFd != -1) {
+ close(fFd);
+ }
+}
+
+bool SkAshmemDiscardableMemory::lock() {
+ SkASSERT(!fLocked);
+ if (-1 == fFd) {
+ fLocked = false;
+ return false;
+ }
+ SkASSERT(fMemory != NULL);
+ if (fLocked || (ASHMEM_NOT_PURGED == ashmem_pin_region(fFd, 0, 0))) {
+ fLocked = true;
+ return true;
+ } else {
+ munmap(fMemory, fSize);
+ fMemory = NULL;
+
+ close(fFd);
+ fFd = -1;
+ fLocked = false;
+ return false;
+ }
+}
+
+void* SkAshmemDiscardableMemory::data() {
+ SkASSERT(fLocked);
+ return fLocked ? fMemory : NULL;
+}
+
+void SkAshmemDiscardableMemory::unlock() {
+ SkASSERT(fLocked);
+ if (fLocked && (fFd != -1)) {
+ ashmem_unpin_region(fFd, 0, 0);
+ }
+ fLocked = false;
+}
+} // namespace
+////////////////////////////////////////////////////////////////////////////////
+
+SkDiscardableMemory* SkDiscardableMemory::Create(size_t bytes) {
+ // ashmem likes lengths on page boundaries.
+ const size_t mask = getpagesize() - 1;
+ size_t size = (bytes + mask) & ~mask;
+
+ static const char name[] = "Skia_Ashmem_Discardable_Memory";
+ int fd = ashmem_create_region(name, size);
+ if (fd < 0) {
+ return NULL;
+ }
+ if (0 != ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE)) {
+ close(fd);
+ return NULL;
+ }
+ void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+ if ((MAP_FAILED == addr) || (NULL == addr)) {
+ close(fd);
+ return NULL;
+ }
+
+ return SkNEW_ARGS(SkAshmemDiscardableMemory, (fd, addr, size));
+}
+
diff --git a/ports/SkDiscardableMemory_none.cpp b/ports/SkDiscardableMemory_none.cpp
index 700713ba..51c3164d 100644
--- a/ports/SkDiscardableMemory_none.cpp
+++ b/ports/SkDiscardableMemory_none.cpp
@@ -5,57 +5,9 @@
* found in the LICENSE file.
*/
-#include "SkDiscardableMemory.h"
+#include "SkDiscardableMemoryPool.h"
#include "SkTypes.h"
-namespace {
-////////////////////////////////////////////////////////////////////////////////
-/**
- * Always successful, never purges. Useful for testing.
- */
-class SkMockDiscardableMemory : public SkDiscardableMemory {
-public:
- SkMockDiscardableMemory(void*);
- virtual ~SkMockDiscardableMemory();
- virtual bool lock() SK_OVERRIDE;
- virtual void* data() SK_OVERRIDE;
- virtual void unlock() SK_OVERRIDE;
-private:
- bool fLocked;
- void* fPointer;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-SkMockDiscardableMemory::SkMockDiscardableMemory(void* ptr)
- : fLocked(true)
- , fPointer(ptr) { // Takes ownership of ptr.
- SkASSERT(fPointer != NULL);
-}
-
-SkMockDiscardableMemory::~SkMockDiscardableMemory() {
- SkASSERT(!fLocked);
- sk_free(fPointer);
-}
-
-bool SkMockDiscardableMemory::lock() {
- SkASSERT(!fLocked);
- return fLocked = true;
-}
-
-void* SkMockDiscardableMemory::data() {
- SkASSERT(fLocked);
- return fLocked ? fPointer : NULL;
-}
-
-void SkMockDiscardableMemory::unlock() {
- SkASSERT(fLocked);
- fLocked = false;
-}
-////////////////////////////////////////////////////////////////////////////////
-} // namespace
-
SkDiscardableMemory* SkDiscardableMemory::Create(size_t bytes) {
- void* ptr = sk_malloc_throw(bytes);
- return (ptr != NULL) ? SkNEW_ARGS(SkMockDiscardableMemory, (ptr)) : NULL;
+ return SkGetGlobalDiscardableMemoryPool()->create(bytes);
}
diff --git a/ports/SkFontConfigInterface_direct.cpp b/ports/SkFontConfigInterface_direct.cpp
index f1ac7342..13993f10 100644
--- a/ports/SkFontConfigInterface_direct.cpp
+++ b/ports/SkFontConfigInterface_direct.cpp
@@ -330,11 +330,13 @@ bool IsFallbackFontAllowed(const std::string& family) {
}
static bool valid_pattern(FcPattern* pattern) {
+#ifdef SK_FONT_CONFIG_ONLY_ALLOW_SCALABLE_FONTS
FcBool is_scalable;
if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &is_scalable) != FcResultMatch
|| !is_scalable) {
return false;
}
+#endif
// fontconfig can also return fonts which are unreadable
const char* c_filename = get_name(pattern, FC_FILE);
diff --git a/ports/SkFontHost_FreeType.cpp b/ports/SkFontHost_FreeType.cpp
index f4ec4205..745a58a9 100644
--- a/ports/SkFontHost_FreeType.cpp
+++ b/ports/SkFontHost_FreeType.cpp
@@ -58,6 +58,21 @@
#include <freetype/ftsynth.h>
#endif
+// FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA
+// were introduced in FreeType 2.5.0.
+// The following may be removed once FreeType 2.5.0 is required to build.
+#ifndef FT_LOAD_COLOR
+# define FT_LOAD_COLOR ( 1L << 20 )
+# define FT_PIXEL_MODE_BGRA 7
+#endif
+
+// FT_HAS_COLOR and the corresponding FT_FACE_FLAG_COLOR
+// were introduced in FreeType 2.5.1
+// The following may be removed once FreeType 2.5.1 is required to build.
+#ifndef FT_HAS_COLOR
+# define FT_HAS_COLOR(face) false
+#endif
+
//#define ENABLE_GLYPH_SPEW // for tracing calls
//#define DUMP_STRIKE_CREATION
@@ -184,6 +199,7 @@ private:
SkFaceRec* fFaceRec;
FT_Face fFace; // reference to shared face in gFaceRecHead
FT_Size fFTSize; // our own copy
+ FT_Int fStrikeIndex;
SkFixed fScaleX, fScaleY;
FT_Matrix fMatrix22;
uint32_t fLoadGlyphFlags;
@@ -516,6 +532,8 @@ SkAdvancedTypefaceMetrics* SkTypeface_FreeType::onGetAdvancedTypefaceMetrics(
ft_sfnt_head)) != NULL) {
info->fEmSize = ttHeader->Units_Per_EM;
}
+ } else {
+ info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
}
info->fStyle = 0;
@@ -749,6 +767,50 @@ bool SkTypeface_FreeType::onGetKerningPairAdjustments(const uint16_t glyphs[],
return true;
}
+static FT_Int chooseBitmapStrike(FT_Face face, SkFixed scaleY) {
+ // early out if face is bad
+ if (face == NULL) {
+ SkDEBUGF(("chooseBitmapStrike aborted due to NULL face\n"));
+ return -1;
+ }
+ // determine target ppem
+ FT_Pos targetPPEM = SkFixedToFDot6(scaleY);
+ // find a bitmap strike equal to or just larger than the requested size
+ FT_Int chosenStrikeIndex = -1;
+ FT_Pos chosenPPEM = 0;
+ for (FT_Int strikeIndex = 0; strikeIndex < face->num_fixed_sizes; ++strikeIndex) {
+ FT_Pos thisPPEM = face->available_sizes[strikeIndex].y_ppem;
+ if (thisPPEM == targetPPEM) {
+ // exact match - our search stops here
+ chosenPPEM = thisPPEM;
+ chosenStrikeIndex = strikeIndex;
+ break;
+ } else if (chosenPPEM < targetPPEM) {
+ // attempt to increase chosenPPEM
+ if (thisPPEM > chosenPPEM) {
+ chosenPPEM = thisPPEM;
+ chosenStrikeIndex = strikeIndex;
+ }
+ } else {
+ // attempt to decrease chosenPPEM, but not below targetPPEM
+ if (thisPPEM < chosenPPEM && thisPPEM > targetPPEM) {
+ chosenPPEM = thisPPEM;
+ chosenStrikeIndex = strikeIndex;
+ }
+ }
+ }
+ if (chosenStrikeIndex != -1) {
+ // use the chosen strike
+ FT_Error err = FT_Select_Size(face, chosenStrikeIndex);
+ if (err != 0) {
+ SkDEBUGF(("FT_Select_Size(%s, %d) returned 0x%x\n", face->family_name,
+ chosenStrikeIndex, err));
+ chosenStrikeIndex = -1;
+ }
+ }
+ return chosenStrikeIndex;
+}
+
SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface,
const SkDescriptor* desc)
: SkScalerContext_FreeType_Base(typeface, desc) {
@@ -762,6 +824,7 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface,
++gFTCount;
// load the font file
+ fStrikeIndex = -1;
fFTSize = NULL;
fFace = NULL;
fFaceRec = ref_ft_face(typeface);
@@ -821,9 +884,9 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface,
fLCDIsVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
// compute the flags we send to Load_Glyph
+ bool linearMetrics = SkToBool(fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag);
{
FT_Int32 loadFlags = FT_LOAD_DEFAULT;
- bool linearMetrics = SkToBool(fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag);
if (SkMask::kBW_Format == fRec.fMaskFormat) {
// See http://code.google.com/p/chromium/issues/detail?id=43252#c24
@@ -881,42 +944,57 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface,
loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
}
+ loadFlags |= FT_LOAD_COLOR;
+
fLoadGlyphFlags = loadFlags;
- fDoLinearMetrics = linearMetrics;
}
- // now create the FT_Size
-
- {
- FT_Error err;
+ FT_Error err = FT_New_Size(fFace, &fFTSize);
+ if (err != 0) {
+ SkDEBUGF(("FT_New_Size returned %x for face %s\n", err, fFace->family_name));
+ fFace = NULL;
+ return;
+ }
+ err = FT_Activate_Size(fFTSize);
+ if (err != 0) {
+ SkDEBUGF(("FT_Activate_Size(%08x, 0x%x, 0x%x) returned 0x%x\n", fFace, fScaleX, fScaleY,
+ err));
+ fFTSize = NULL;
+ return;
+ }
- err = FT_New_Size(fFace, &fFTSize);
+ if (FT_IS_SCALABLE(fFace)) {
+ err = FT_Set_Char_Size(fFace, SkFixedToFDot6(fScaleX), SkFixedToFDot6(fScaleY), 72, 72);
if (err != 0) {
- SkDEBUGF(("SkScalerContext_FreeType::FT_New_Size(%x): FT_Set_Char_Size(0x%x, 0x%x) returned 0x%x\n",
- fFaceRec->fFontID, fScaleX, fScaleY, err));
+ SkDEBUGF(("FT_Set_CharSize(%08x, 0x%x, 0x%x) returned 0x%x\n",
+ fFace, fScaleX, fScaleY, err));
fFace = NULL;
return;
}
-
- err = FT_Activate_Size(fFTSize);
- if (err != 0) {
- SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%x, 0x%x, 0x%x) returned 0x%x\n",
- fFaceRec->fFontID, fScaleX, fScaleY, err));
- fFTSize = NULL;
- }
-
- err = FT_Set_Char_Size( fFace,
- SkFixedToFDot6(fScaleX), SkFixedToFDot6(fScaleY),
- 72, 72);
- if (err != 0) {
- SkDEBUGF(("SkScalerContext_FreeType::FT_Set_Char_Size(%x, 0x%x, 0x%x) returned 0x%x\n",
- fFaceRec->fFontID, fScaleX, fScaleY, err));
- fFace = NULL;
- return;
+ FT_Set_Transform(fFace, &fMatrix22, NULL);
+ } else if (FT_HAS_FIXED_SIZES(fFace)) {
+ fStrikeIndex = chooseBitmapStrike(fFace, fScaleY);
+ if (fStrikeIndex == -1) {
+ SkDEBUGF(("no glyphs for font \"%s\" size %f?\n",
+ fFace->family_name, SkFixedToScalar(fScaleY)));
+ } else {
+ // FreeType does no provide linear metrics for bitmap fonts.
+ linearMetrics = false;
+
+ // FreeType documentation says:
+ // FT_LOAD_NO_BITMAP -- Ignore bitmap strikes when loading.
+ // Bitmap-only fonts ignore this flag.
+ //
+ // However, in FreeType 2.5.1 color bitmap only fonts do not ignore this flag.
+ // Force this flag off for bitmap only fonts.
+ fLoadGlyphFlags &= ~FT_LOAD_NO_BITMAP;
}
-
- FT_Set_Transform( fFace, &fMatrix22, NULL);
+ } else {
+ SkDEBUGF(("unknown kind of font \"%s\" size %f?\n",
+ fFace->family_name, SkFixedToScalar(fScaleY)));
}
+
+ fDoLinearMetrics = linearMetrics;
}
SkScalerContext_FreeType::~SkScalerContext_FreeType() {
@@ -930,7 +1008,6 @@ SkScalerContext_FreeType::~SkScalerContext_FreeType() {
unref_ft_face(fFace);
}
if (--gFTCount == 0) {
-// SkDEBUGF(("FT_Done_FreeType\n"));
FT_Done_FreeType(gFTLibrary);
SkDEBUGCODE(gFTLibrary = NULL;)
}
@@ -940,18 +1017,18 @@ SkScalerContext_FreeType::~SkScalerContext_FreeType() {
this face with other context (at different sizes).
*/
FT_Error SkScalerContext_FreeType::setupSize() {
- FT_Error err = FT_Activate_Size(fFTSize);
-
+ FT_Error err = FT_Activate_Size(fFTSize);
if (err != 0) {
SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%x, 0x%x, 0x%x) returned 0x%x\n",
- fFaceRec->fFontID, fScaleX, fScaleY, err));
+ fFaceRec->fFontID, fScaleX, fScaleY, err));
fFTSize = NULL;
- } else {
- // seems we need to reset this every time (not sure why, but without it
- // I get random italics from some other fFTSize)
- FT_Set_Transform( fFace, &fMatrix22, NULL);
+ return err;
}
- return err;
+
+ // seems we need to reset this every time (not sure why, but without it
+ // I get random italics from some other fFTSize)
+ FT_Set_Transform(fFace, &fMatrix22, NULL);
+ return 0;
}
unsigned SkScalerContext_FreeType::generateGlyphCount() {
@@ -1061,6 +1138,17 @@ void SkScalerContext_FreeType::updateGlyphIfLCD(SkGlyph* glyph) {
}
}
+inline void scaleGlyphMetrics(SkGlyph& glyph, SkScalar scale) {
+ glyph.fWidth *= scale;
+ glyph.fHeight *= scale;
+ glyph.fTop *= scale;
+ glyph.fLeft *= scale;
+
+ SkFixed fixedScale = SkScalarToFixed(scale);
+ glyph.fAdvanceX = SkFixedMul(glyph.fAdvanceX, fixedScale);
+ glyph.fAdvanceY = SkFixedMul(glyph.fAdvanceY, fixedScale);
+}
+
void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
SkAutoMutexAcquire ac(gFTMutex);
@@ -1085,32 +1173,28 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
}
switch ( fFace->glyph->format ) {
- case FT_GLYPH_FORMAT_OUTLINE: {
- FT_BBox bbox;
-
+ case FT_GLYPH_FORMAT_OUTLINE:
if (0 == fFace->glyph->outline.n_contours) {
glyph->fWidth = 0;
glyph->fHeight = 0;
glyph->fTop = 0;
glyph->fLeft = 0;
- break;
- }
-
- if (fRec.fFlags & kEmbolden_Flag) {
- emboldenOutline(fFace, &fFace->glyph->outline);
- }
-
- getBBoxForCurrentGlyph(glyph, &bbox, true);
+ } else {
+ if (fRec.fFlags & kEmbolden_Flag && !(fFace->style_flags & FT_STYLE_FLAG_BOLD)) {
+ emboldenOutline(fFace, &fFace->glyph->outline);
+ }
- glyph->fWidth = SkToU16(SkFDot6Floor(bbox.xMax - bbox.xMin));
- glyph->fHeight = SkToU16(SkFDot6Floor(bbox.yMax - bbox.yMin));
- glyph->fTop = -SkToS16(SkFDot6Floor(bbox.yMax));
- glyph->fLeft = SkToS16(SkFDot6Floor(bbox.xMin));
+ FT_BBox bbox;
+ getBBoxForCurrentGlyph(glyph, &bbox, true);
- updateGlyphIfLCD(glyph);
+ glyph->fWidth = SkToU16(SkFDot6Floor(bbox.xMax - bbox.xMin));
+ glyph->fHeight = SkToU16(SkFDot6Floor(bbox.yMax - bbox.yMin));
+ glyph->fTop = -SkToS16(SkFDot6Floor(bbox.yMax));
+ glyph->fLeft = SkToS16(SkFDot6Floor(bbox.xMin));
+ updateGlyphIfLCD(glyph);
+ }
break;
- }
case FT_GLYPH_FORMAT_BITMAP:
if (fRec.fFlags & kEmbolden_Flag) {
@@ -1127,6 +1211,10 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
fFace->glyph->bitmap_top += SkFDot6Floor(vector.y);
}
+ if (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
+ glyph->fMaskFormat = SkMask::kARGB32_Format;
+ }
+
glyph->fWidth = SkToU16(fFace->glyph->bitmap.width);
glyph->fHeight = SkToU16(fFace->glyph->bitmap.rows);
glyph->fTop = -SkToS16(fFace->glyph->bitmap_top);
@@ -1161,6 +1249,11 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
}
}
+ if (fFace->glyph->format == FT_GLYPH_FORMAT_BITMAP && fScaleY && fFace->size->metrics.y_ppem) {
+ // NOTE: both dimensions are scaled by y_ppem. this is WAI.
+ scaleGlyphMetrics(*glyph, SkScalarDiv(SkFixedToScalar(fScaleY),
+ SkIntToScalar(fFace->size->metrics.y_ppem)));
+ }
#ifdef ENABLE_GLYPH_SPEW
SkDEBUGF(("FT_Set_Char_Size(this:%p sx:%x sy:%x ", this, fScaleX, fScaleY));
@@ -1248,77 +1341,104 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx,
}
FT_Face face = fFace;
- int upem = face->units_per_EM;
- if (upem <= 0) {
- goto ERROR;
- }
-
- SkPoint pts[6];
- SkFixed ys[6];
+ SkScalar scaleX = fScale.x();
SkScalar scaleY = fScale.y();
- SkScalar mxy = fMatrix22Scalar.getSkewX();
- SkScalar myy = fMatrix22Scalar.getScaleY();
- SkScalar xmin = SkIntToScalar(face->bbox.xMin) / upem;
- SkScalar xmax = SkIntToScalar(face->bbox.xMax) / upem;
-
- int leading = face->height - (face->ascender + -face->descender);
- if (leading < 0) {
- leading = 0;
+ SkScalar mxy = fMatrix22Scalar.getSkewX() * scaleY;
+ SkScalar myy = fMatrix22Scalar.getScaleY() * scaleY;
+
+ // fetch units/EM from "head" table if needed (ie for bitmap fonts)
+ SkScalar upem = SkIntToScalar(face->units_per_EM);
+ if (!upem) {
+ TT_Header* ttHeader = (TT_Header*)FT_Get_Sfnt_Table(face, ft_sfnt_head);
+ if (ttHeader) {
+ upem = SkIntToScalar(ttHeader->Units_Per_EM);
+ }
}
- // Try to get the OS/2 table from the font. This contains the specific
- // average font width metrics which Windows uses.
+ // use the os/2 table as a source of reasonable defaults.
+ SkScalar x_height = 0.0f;
+ SkScalar avgCharWidth = 0.0f;
TT_OS2* os2 = (TT_OS2*) FT_Get_Sfnt_Table(face, ft_sfnt_os2);
-
- ys[0] = -face->bbox.yMax;
- ys[1] = -face->ascender;
- ys[2] = -face->descender;
- ys[3] = -face->bbox.yMin;
- ys[4] = leading;
- ys[5] = os2 ? os2->xAvgCharWidth : 0;
-
- SkScalar x_height;
- if (os2 && os2->sxHeight) {
- x_height = fScale.x() * os2->sxHeight / upem;
- } else {
- const FT_UInt x_glyph = FT_Get_Char_Index(fFace, 'x');
- if (x_glyph) {
- FT_BBox bbox;
- FT_Load_Glyph(fFace, x_glyph, fLoadGlyphFlags);
- if (fRec.fFlags & kEmbolden_Flag) {
- emboldenOutline(fFace, &fFace->glyph->outline);
+ if (os2) {
+ x_height = scaleX * SkIntToScalar(os2->sxHeight) / upem;
+ avgCharWidth = SkIntToScalar(os2->xAvgCharWidth) / upem;
+ }
+
+ // pull from format-specific metrics as needed
+ SkScalar ascent, descent, leading, xmin, xmax, ymin, ymax;
+ if (face->face_flags & FT_FACE_FLAG_SCALABLE) { // scalable outline font
+ ascent = -SkIntToScalar(face->ascender) / upem;
+ descent = -SkIntToScalar(face->descender) / upem;
+ leading = SkIntToScalar(face->height + (face->descender - face->ascender)) / upem;
+ xmin = SkIntToScalar(face->bbox.xMin) / upem;
+ xmax = SkIntToScalar(face->bbox.xMax) / upem;
+ ymin = -SkIntToScalar(face->bbox.yMin) / upem;
+ ymax = -SkIntToScalar(face->bbox.yMax) / upem;
+ // we may be able to synthesize x_height from outline
+ if (!x_height) {
+ const FT_UInt x_glyph = FT_Get_Char_Index(fFace, 'x');
+ if (x_glyph) {
+ FT_BBox bbox;
+ FT_Load_Glyph(fFace, x_glyph, fLoadGlyphFlags);
+ if ((fRec.fFlags & kEmbolden_Flag) && !(fFace->style_flags & FT_STYLE_FLAG_BOLD)) {
+ emboldenOutline(fFace, &fFace->glyph->outline);
+ }
+ FT_Outline_Get_CBox(&fFace->glyph->outline, &bbox);
+ x_height = SkIntToScalar(bbox.yMax) / 64.0f;
}
- FT_Outline_Get_CBox(&fFace->glyph->outline, &bbox);
- x_height = bbox.yMax / 64.0f;
- } else {
- x_height = 0;
}
+ } else if (fStrikeIndex != -1) { // bitmap strike metrics
+ SkScalar xppem = SkIntToScalar(face->size->metrics.x_ppem);
+ SkScalar yppem = SkIntToScalar(face->size->metrics.y_ppem);
+ ascent = -SkIntToScalar(face->size->metrics.ascender) / (yppem * 64.0f);
+ descent = -SkIntToScalar(face->size->metrics.descender) / (yppem * 64.0f);
+ leading = (SkIntToScalar(face->size->metrics.height) / (yppem * 64.0f))
+ + ascent - descent;
+ xmin = 0.0f;
+ xmax = SkIntToScalar(face->available_sizes[fStrikeIndex].width) / xppem;
+ ymin = descent + leading;
+ ymax = ascent - descent;
+ if (!x_height) {
+ x_height = -ascent;
+ }
+ if (!avgCharWidth) {
+ avgCharWidth = xmax - xmin;
+ }
+ } else {
+ goto ERROR;
+ }
+
+ // synthesize elements that were not provided by the os/2 table or format-specific metrics
+ if (!x_height) {
+ x_height = -ascent;
+ }
+ if (!avgCharWidth) {
+ avgCharWidth = xmax - xmin;
}
- // convert upem-y values into scalar points
- for (int i = 0; i < 6; i++) {
- SkScalar y = scaleY * ys[i] / upem;
- pts[i].set(y * mxy, y * myy);
+ // disallow negative linespacing
+ if (leading < 0.0f) {
+ leading = 0.0f;
}
if (mx) {
- mx->fTop = pts[0].fX;
- mx->fAscent = pts[1].fX;
- mx->fDescent = pts[2].fX;
- mx->fBottom = pts[3].fX;
- mx->fLeading = pts[4].fX;
- mx->fAvgCharWidth = pts[5].fX;
+ mx->fTop = ymax * mxy;
+ mx->fAscent = ascent * mxy;
+ mx->fDescent = descent * mxy;
+ mx->fBottom = ymin * mxy;
+ mx->fLeading = leading * mxy;
+ mx->fAvgCharWidth = avgCharWidth * mxy;
mx->fXMin = xmin;
mx->fXMax = xmax;
mx->fXHeight = x_height;
}
if (my) {
- my->fTop = pts[0].fY;
- my->fAscent = pts[1].fY;
- my->fDescent = pts[2].fY;
- my->fBottom = pts[3].fY;
- my->fLeading = pts[4].fY;
- my->fAvgCharWidth = pts[5].fY;
+ my->fTop = ymax * myy;
+ my->fAscent = ascent * myy;
+ my->fDescent = descent * myy;
+ my->fBottom = ymin * myy;
+ my->fLeading = leading * myy;
+ my->fAvgCharWidth = avgCharWidth * myy;
my->fXMin = xmin;
my->fXMax = xmax;
my->fXHeight = x_height;
diff --git a/ports/SkFontHost_FreeType_common.cpp b/ports/SkFontHost_FreeType_common.cpp
index 2c486847..065a83a4 100644
--- a/ports/SkFontHost_FreeType_common.cpp
+++ b/ports/SkFontHost_FreeType_common.cpp
@@ -6,17 +6,32 @@
* found in the LICENSE file.
*/
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkFDot6.h"
#include "SkFontHost_FreeType_common.h"
#include "SkPath.h"
#include <ft2build.h>
-#include FT_OUTLINE_H
+#include FT_FREETYPE_H
#include FT_BITMAP_H
+#include FT_IMAGE_H
+#include FT_OUTLINE_H
// In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file.
#include FT_SYNTHESIS_H
+// FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA
+// were introduced in FreeType 2.5.0.
+// The following may be removed once FreeType 2.5.0 is required to build.
+#ifndef FT_LOAD_COLOR
+# define FT_LOAD_COLOR ( 1L << 20 )
+# define FT_PIXEL_MODE_BGRA 7
+#endif
+
+//#define SK_SHOW_TEXT_BLIT_COVERAGE
+
static FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) {
switch (format) {
case SkMask::kBW_Format:
@@ -29,13 +44,20 @@ static FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) {
///////////////////////////////////////////////////////////////////////////////
-static uint16_t packTriple(unsigned r, unsigned g, unsigned b) {
- return SkPackRGB16(r >> 3, g >> 2, b >> 3);
+static uint16_t packTriple(U8CPU r, U8CPU g, U8CPU b) {
+#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
+ r = SkTMax(r, (U8CPU)0x40);
+ g = SkTMax(g, (U8CPU)0x40);
+ b = SkTMax(b, (U8CPU)0x40);
+#endif
+ return SkPack888ToRGB16(r, g, b);
}
static uint16_t grayToRGB16(U8CPU gray) {
- SkASSERT(gray <= 255);
- return SkPackRGB16(gray >> 3, gray >> 2, gray >> 3);
+#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
+ gray = SkTMax(gray, (U8CPU)0x40);
+#endif
+ return SkPack888ToRGB16(gray, gray, gray);
}
static int bittst(const uint8_t data[], int bitOffset) {
@@ -44,78 +66,271 @@ static int bittst(const uint8_t data[], int bitOffset) {
return lowBit & 1;
}
+/**
+ * Copies a FT_Bitmap into an SkMask with the same dimensions.
+ *
+ * FT_PIXEL_MODE_MONO
+ * FT_PIXEL_MODE_GRAY
+ * FT_PIXEL_MODE_LCD
+ * FT_PIXEL_MODE_LCD_V
+ */
template<bool APPLY_PREBLEND>
-static void copyFT2LCD16(const SkGlyph& glyph, const FT_Bitmap& bitmap,
- int lcdIsBGR, bool lcdIsVert, const uint8_t* tableR,
- const uint8_t* tableG, const uint8_t* tableB) {
- if (lcdIsVert) {
- SkASSERT(3 * glyph.fHeight == bitmap.rows);
- } else {
- SkASSERT(glyph.fHeight == bitmap.rows);
+static void copyFT2LCD16(const FT_Bitmap& bitmap, const SkMask& mask, int lcdIsBGR,
+ const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB)
+{
+ SkASSERT(SkMask::kLCD16_Format == mask.fFormat);
+ if (FT_PIXEL_MODE_LCD != bitmap.pixel_mode) {
+ SkASSERT(mask.fBounds.width() == bitmap.width);
+ }
+ if (FT_PIXEL_MODE_LCD_V != bitmap.pixel_mode) {
+ SkASSERT(mask.fBounds.height() == bitmap.rows);
}
- uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage);
- const size_t dstRB = glyph.rowBytes();
- const int width = glyph.fWidth;
const uint8_t* src = bitmap.buffer;
+ uint16_t* dst = reinterpret_cast<uint16_t*>(mask.fImage);
+ const size_t dstRB = mask.fRowBytes;
+
+ const int width = mask.fBounds.width();
+ const int height = mask.fBounds.height();
switch (bitmap.pixel_mode) {
- case FT_PIXEL_MODE_MONO: {
- for (int y = 0; y < glyph.fHeight; ++y) {
+ case FT_PIXEL_MODE_MONO:
+ for (int y = height; y --> 0;) {
for (int x = 0; x < width; ++x) {
dst[x] = -bittst(src, x);
}
dst = (uint16_t*)((char*)dst + dstRB);
src += bitmap.pitch;
}
- } break;
- case FT_PIXEL_MODE_GRAY: {
- for (int y = 0; y < glyph.fHeight; ++y) {
+ break;
+ case FT_PIXEL_MODE_GRAY:
+ for (int y = height; y --> 0;) {
for (int x = 0; x < width; ++x) {
dst[x] = grayToRGB16(src[x]);
}
dst = (uint16_t*)((char*)dst + dstRB);
src += bitmap.pitch;
}
- } break;
- default: {
- SkASSERT(lcdIsVert || (glyph.fWidth * 3 == bitmap.width));
- for (int y = 0; y < glyph.fHeight; y++) {
- if (lcdIsVert) { // vertical stripes
- const uint8_t* srcR = src;
- const uint8_t* srcG = srcR + bitmap.pitch;
- const uint8_t* srcB = srcG + bitmap.pitch;
- if (lcdIsBGR) {
- SkTSwap(srcR, srcB);
- }
+ break;
+ case FT_PIXEL_MODE_LCD:
+ SkASSERT(3 * mask.fBounds.width() == bitmap.width);
+ for (int y = height; y --> 0;) {
+ const uint8_t* triple = src;
+ if (lcdIsBGR) {
for (int x = 0; x < width; x++) {
- dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(*srcR++, tableR),
- sk_apply_lut_if<APPLY_PREBLEND>(*srcG++, tableG),
- sk_apply_lut_if<APPLY_PREBLEND>(*srcB++, tableB));
+ dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableR),
+ sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
+ sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableB));
+ triple += 3;
}
- src += 3 * bitmap.pitch;
- } else { // horizontal stripes
- const uint8_t* triple = src;
- if (lcdIsBGR) {
- for (int x = 0; x < width; x++) {
- dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableR),
- sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
- sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableB));
- triple += 3;
- }
- } else {
- for (int x = 0; x < width; x++) {
- dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableR),
- sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
- sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableB));
- triple += 3;
- }
+ } else {
+ for (int x = 0; x < width; x++) {
+ dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableR),
+ sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
+ sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableB));
+ triple += 3;
}
- src += bitmap.pitch;
}
+ src += bitmap.pitch;
dst = (uint16_t*)((char*)dst + dstRB);
}
- } break;
+ break;
+ case FT_PIXEL_MODE_LCD_V:
+ SkASSERT(3 * mask.fBounds.height() == bitmap.rows);
+ for (int y = height; y --> 0;) {
+ const uint8_t* srcR = src;
+ const uint8_t* srcG = srcR + bitmap.pitch;
+ const uint8_t* srcB = srcG + bitmap.pitch;
+ if (lcdIsBGR) {
+ SkTSwap(srcR, srcB);
+ }
+ for (int x = 0; x < width; x++) {
+ dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(*srcR++, tableR),
+ sk_apply_lut_if<APPLY_PREBLEND>(*srcG++, tableG),
+ sk_apply_lut_if<APPLY_PREBLEND>(*srcB++, tableB));
+ }
+ src += 3 * bitmap.pitch;
+ dst = (uint16_t*)((char*)dst + dstRB);
+ }
+ break;
+ default:
+ SkDEBUGF(("FT_Pixel_Mode %d", bitmap.pixel_mode));
+ SkDEBUGFAIL("unsupported FT_Pixel_Mode for LCD16");
+ break;
+ }
+}
+
+/**
+ * Copies a FT_Bitmap into an SkMask with the same dimensions.
+ *
+ * Yes, No, Never Requested, Never Produced
+ *
+ * kBW kA8 k3D kARGB32 kLCD16 kLCD32
+ * FT_PIXEL_MODE_MONO Y Y NR N Y NR
+ * FT_PIXEL_MODE_GRAY N Y NR N Y NR
+ * FT_PIXEL_MODE_GRAY2 NP NP NR NP NP NR
+ * FT_PIXEL_MODE_GRAY4 NP NP NR NP NP NR
+ * FT_PIXEL_MODE_LCD NP NP NR NP NP NR
+ * FT_PIXEL_MODE_LCD_V NP NP NR NP NP NR
+ * FT_PIXEL_MODE_BGRA N N NR Y N NR
+ *
+ * TODO: All of these N need to be Y or otherwise ruled out.
+ */
+static void copyFTBitmap(const FT_Bitmap& srcFTBitmap, SkMask& dstMask) {
+ SkASSERT(dstMask.fBounds.width() == srcFTBitmap.width);
+ SkASSERT(dstMask.fBounds.height() == srcFTBitmap.rows);
+
+ const uint8_t* src = reinterpret_cast<const uint8_t*>(srcFTBitmap.buffer);
+ const FT_Pixel_Mode srcFormat = static_cast<FT_Pixel_Mode>(srcFTBitmap.pixel_mode);
+ // FT_Bitmap::pitch is an int and allowed to be negative.
+ const int srcPitch = srcFTBitmap.pitch;
+ const size_t srcRowBytes = SkTAbs(srcPitch);
+
+ uint8_t* dst = dstMask.fImage;
+ const SkMask::Format dstFormat = static_cast<SkMask::Format>(dstMask.fFormat);
+ const size_t dstRowBytes = dstMask.fRowBytes;
+
+ const size_t width = srcFTBitmap.width;
+ const size_t height = srcFTBitmap.rows;
+
+ if (SkMask::kLCD16_Format == dstFormat) {
+ copyFT2LCD16<false>(srcFTBitmap, dstMask, false, NULL, NULL, NULL);
+ return;
+ }
+
+ if ((FT_PIXEL_MODE_MONO == srcFormat && SkMask::kBW_Format == dstFormat) ||
+ (FT_PIXEL_MODE_GRAY == srcFormat && SkMask::kA8_Format == dstFormat))
+ {
+ size_t commonRowBytes = SkTMin(srcRowBytes, dstRowBytes);
+ for (size_t y = height; y --> 0;) {
+ memcpy(dst, src, commonRowBytes);
+ src += srcPitch;
+ dst += dstRowBytes;
+ }
+ } else if (FT_PIXEL_MODE_MONO == srcFormat && SkMask::kA8_Format == dstFormat) {
+ for (size_t y = height; y --> 0;) {
+ uint8_t byte = 0;
+ int bits = 0;
+ const uint8_t* src_row = src;
+ uint8_t* dst_row = dst;
+ for (size_t x = width; x --> 0;) {
+ if (0 == bits) {
+ byte = *src_row++;
+ bits = 8;
+ }
+ *dst_row++ = byte & 0x80 ? 0xff : 0x00;
+ bits--;
+ byte <<= 1;
+ }
+ src += srcPitch;
+ dst += dstRowBytes;
+ }
+ } else if (FT_PIXEL_MODE_BGRA == srcFormat && SkMask::kARGB32_Format == dstFormat) {
+ // FT_PIXEL_MODE_BGRA is pre-multiplied.
+ for (size_t y = height; y --> 0;) {
+ const uint8_t* src_row = src;
+ SkPMColor* dst_row = reinterpret_cast<SkPMColor*>(dst);
+ for (size_t x = 0; x < width; ++x) {
+ uint8_t b = *src_row++;
+ uint8_t g = *src_row++;
+ uint8_t r = *src_row++;
+ uint8_t a = *src_row++;
+ *dst_row++ = SkPackARGB32(a, r, g, b);
+#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
+ *(dst_row-1) = SkFourByteInterp256(*(dst_row-1), SK_ColorWHITE, 0x40);
+#endif
+ }
+ src += srcPitch;
+ dst += dstRowBytes;
+ }
+ } else {
+ SkDEBUGF(("FT_Pixel_Mode %d, SkMask::Format %d\n", srcFormat, dstFormat));
+ SkDEBUGFAIL("unsupported combination of FT_Pixel_Mode and SkMask::Format");
+ }
+}
+
+static inline int convert_8_to_1(unsigned byte) {
+ SkASSERT(byte <= 0xFF);
+ // Arbitrary decision that making the cutoff at 1/4 instead of 1/2 in general looks better.
+ return (byte >> 6) != 0;
+}
+
+static uint8_t pack_8_to_1(const uint8_t alpha[8]) {
+ unsigned bits = 0;
+ for (int i = 0; i < 8; ++i) {
+ bits <<= 1;
+ bits |= convert_8_to_1(alpha[i]);
+ }
+ return SkToU8(bits);
+}
+
+static void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
+ const int height = mask.fBounds.height();
+ const int width = mask.fBounds.width();
+ const int octs = width >> 3;
+ const int leftOverBits = width & 7;
+
+ uint8_t* dst = mask.fImage;
+ const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
+ SkASSERT(dstPad >= 0);
+
+ const int srcPad = srcRB - width;
+ SkASSERT(srcPad >= 0);
+
+ for (int y = 0; y < height; ++y) {
+ for (int i = 0; i < octs; ++i) {
+ *dst++ = pack_8_to_1(src);
+ src += 8;
+ }
+ if (leftOverBits > 0) {
+ unsigned bits = 0;
+ int shift = 7;
+ for (int i = 0; i < leftOverBits; ++i, --shift) {
+ bits |= convert_8_to_1(*src++) << shift;
+ }
+ *dst++ = bits;
+ }
+ src += srcPad;
+ dst += dstPad;
+ }
+}
+
+inline SkMask::Format SkMaskFormat_for_SkBitmapConfig(SkBitmap::Config config) {
+ switch (config) {
+ case SkBitmap::kA8_Config:
+ return SkMask::kA8_Format;
+ case SkBitmap::kARGB_8888_Config:
+ return SkMask::kARGB32_Format;
+ default:
+ SkDEBUGFAIL("unsupported SkBitmap::Config");
+ return SkMask::kA8_Format;
+ }
+}
+
+inline SkBitmap::Config SkBitmapConfig_for_FTPixelMode(FT_Pixel_Mode pixel_mode) {
+ switch (pixel_mode) {
+ case FT_PIXEL_MODE_MONO:
+ case FT_PIXEL_MODE_GRAY:
+ return SkBitmap::kA8_Config;
+ case FT_PIXEL_MODE_BGRA:
+ return SkBitmap::kARGB_8888_Config;
+ default:
+ SkDEBUGFAIL("unsupported FT_PIXEL_MODE");
+ return SkBitmap::kA8_Config;
+ }
+}
+
+inline SkBitmap::Config SkBitmapConfig_for_SkMaskFormat(SkMask::Format format) {
+ switch (format) {
+ case SkMask::kBW_Format:
+ case SkMask::kA8_Format:
+ case SkMask::kLCD16_Format:
+ return SkBitmap::kA8_Config;
+ case SkMask::kARGB32_Format:
+ return SkBitmap::kARGB_8888_Config;
+ default:
+ SkDEBUGFAIL("unsupported destination SkBitmap::Config");
+ return SkBitmap::kA8_Config;
}
}
@@ -129,7 +344,8 @@ void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGly
FT_BBox bbox;
FT_Bitmap target;
- if (fRec.fFlags & SkScalerContext::kEmbolden_Flag) {
+ if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
+ !(face->style_flags & FT_STYLE_FLAG_BOLD)) {
emboldenOutline(face, outline);
}
@@ -154,11 +370,13 @@ void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGly
if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V : FT_RENDER_MODE_LCD);
+ SkMask mask;
+ glyph.toMask(&mask);
if (fPreBlend.isApplicable()) {
- copyFT2LCD16<true>(glyph, face->glyph->bitmap, doBGR, doVert,
+ copyFT2LCD16<true>(face->glyph->bitmap, mask, doBGR,
fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
} else {
- copyFT2LCD16<false>(glyph, face->glyph->bitmap, doBGR, doVert,
+ copyFT2LCD16<false>(face->glyph->bitmap, mask, doBGR,
fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
}
} else {
@@ -166,8 +384,7 @@ void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGly
target.rows = glyph.fHeight;
target.pitch = glyph.rowBytes();
target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage);
- target.pixel_mode = compute_pixel_mode(
- (SkMask::Format)fRec.fMaskFormat);
+ target.pixel_mode = compute_pixel_mode( (SkMask::Format)fRec.fMaskFormat);
target.num_grays = 256;
memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
@@ -176,71 +393,106 @@ void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGly
} break;
case FT_GLYPH_FORMAT_BITMAP: {
- if (fRec.fFlags & SkScalerContext::kEmbolden_Flag) {
+ FT_Pixel_Mode pixel_mode = static_cast<FT_Pixel_Mode>(face->glyph->bitmap.pixel_mode);
+ SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
+
+ // Assume that the other formats do not exist.
+ SkASSERT(FT_PIXEL_MODE_MONO == pixel_mode ||
+ FT_PIXEL_MODE_GRAY == pixel_mode ||
+ FT_PIXEL_MODE_BGRA == pixel_mode);
+
+ // These are the only formats this ScalerContext should request.
+ SkASSERT(SkMask::kBW_Format == maskFormat ||
+ SkMask::kA8_Format == maskFormat ||
+ SkMask::kARGB32_Format == maskFormat ||
+ SkMask::kLCD16_Format == maskFormat);
+
+ if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
+ !(face->style_flags & FT_STYLE_FLAG_BOLD))
+ {
FT_GlyphSlot_Own_Bitmap(face->glyph);
- FT_Bitmap_Embolden(face->glyph->library, &face->glyph->bitmap, kBitmapEmboldenStrength, 0);
+ FT_Bitmap_Embolden(face->glyph->library, &face->glyph->bitmap,
+ kBitmapEmboldenStrength, 0);
}
- SkASSERT_CONTINUE(glyph.fWidth == face->glyph->bitmap.width);
- SkASSERT_CONTINUE(glyph.fHeight == face->glyph->bitmap.rows);
- SkASSERT_CONTINUE(glyph.fTop == -face->glyph->bitmap_top);
- SkASSERT_CONTINUE(glyph.fLeft == face->glyph->bitmap_left);
-
- const uint8_t* src = (const uint8_t*)face->glyph->bitmap.buffer;
- uint8_t* dst = (uint8_t*)glyph.fImage;
-
- if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ||
- (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO &&
- glyph.fMaskFormat == SkMask::kBW_Format)) {
- unsigned srcRowBytes = face->glyph->bitmap.pitch;
- unsigned dstRowBytes = glyph.rowBytes();
- unsigned minRowBytes = SkMin32(srcRowBytes, dstRowBytes);
- unsigned extraRowBytes = dstRowBytes - minRowBytes;
-
- for (int y = face->glyph->bitmap.rows - 1; y >= 0; --y) {
- memcpy(dst, src, minRowBytes);
- memset(dst + minRowBytes, 0, extraRowBytes);
- src += srcRowBytes;
- dst += dstRowBytes;
- }
- } else if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO &&
- glyph.fMaskFormat == SkMask::kA8_Format) {
- for (int y = 0; y < face->glyph->bitmap.rows; ++y) {
- uint8_t byte = 0;
- int bits = 0;
- const uint8_t* src_row = src;
- uint8_t* dst_row = dst;
-
- for (int x = 0; x < face->glyph->bitmap.width; ++x) {
- if (!bits) {
- byte = *src_row++;
- bits = 8;
- }
-
- *dst_row++ = byte & 0x80 ? 0xff : 0;
- bits--;
- byte <<= 1;
- }
- src += face->glyph->bitmap.pitch;
- dst += glyph.rowBytes();
- }
- } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
- if (fPreBlend.isApplicable()) {
- copyFT2LCD16<true>(glyph, face->glyph->bitmap, doBGR, doVert,
- fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
- } else {
- copyFT2LCD16<false>(glyph, face->glyph->bitmap, doBGR, doVert,
- fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
- }
+ // If no scaling needed, directly copy glyph bitmap.
+ if (glyph.fWidth == face->glyph->bitmap.width &&
+ glyph.fHeight == face->glyph->bitmap.rows &&
+ glyph.fTop == -face->glyph->bitmap_top &&
+ glyph.fLeft == face->glyph->bitmap_left)
+ {
+ SkMask dstMask;
+ glyph.toMask(&dstMask);
+ copyFTBitmap(face->glyph->bitmap, dstMask);
+ break;
+ }
+
+ // Otherwise, scale the bitmap.
+
+ // Copy the FT_Bitmap into an SkBitmap (either A8 or ARGB)
+ SkBitmap unscaledBitmap;
+ unscaledBitmap.setConfig(SkBitmapConfig_for_FTPixelMode(pixel_mode),
+ face->glyph->bitmap.width, face->glyph->bitmap.rows);
+ unscaledBitmap.allocPixels();
+
+ SkMask unscaledBitmapAlias;
+ unscaledBitmapAlias.fImage = reinterpret_cast<uint8_t*>(unscaledBitmap.getPixels());
+ unscaledBitmapAlias.fBounds.set(0, 0, unscaledBitmap.width(), unscaledBitmap.height());
+ unscaledBitmapAlias.fRowBytes = unscaledBitmap.rowBytes();
+ unscaledBitmapAlias.fFormat = SkMaskFormat_for_SkBitmapConfig(unscaledBitmap.config());
+ copyFTBitmap(face->glyph->bitmap, unscaledBitmapAlias);
+
+ // Wrap the glyph's mask in a bitmap, unless the glyph's mask is BW or LCD.
+ // BW requires an A8 target for resizing, which can then be down sampled.
+ // LCD should use a 4x A8 target, which will then be down sampled.
+ // For simplicity, LCD uses A8 and is replicated.
+ int bitmapRowBytes = 0;
+ if (SkMask::kBW_Format != maskFormat && SkMask::kLCD16_Format != maskFormat) {
+ bitmapRowBytes = glyph.rowBytes();
+ }
+ SkBitmap dstBitmap;
+ dstBitmap.setConfig(SkBitmapConfig_for_SkMaskFormat(maskFormat),
+ glyph.fWidth, glyph.fHeight, bitmapRowBytes);
+ if (SkMask::kBW_Format == maskFormat || SkMask::kLCD16_Format == maskFormat) {
+ dstBitmap.allocPixels();
} else {
- SkDEBUGFAIL("unknown glyph bitmap transform needed");
+ dstBitmap.setPixels(glyph.fImage);
}
+
+ // Scale unscaledBitmap into dstBitmap.
+ SkCanvas canvas(dstBitmap);
+ canvas.clear(SK_ColorTRANSPARENT);
+ canvas.scale(SkIntToScalar(glyph.fWidth) / SkIntToScalar(face->glyph->bitmap.width),
+ SkIntToScalar(glyph.fHeight) / SkIntToScalar(face->glyph->bitmap.rows));
+ SkPaint paint;
+ paint.setFilterLevel(SkPaint::kLow_FilterLevel);
+ canvas.drawBitmap(unscaledBitmap, 0, 0, &paint);
+
+ // If the destination is BW or LCD, convert from A8.
+ if (SkMask::kBW_Format == maskFormat) {
+ // Copy the A8 dstBitmap into the A1 glyph.fImage.
+ SkMask dstMask;
+ glyph.toMask(&dstMask);
+ packA8ToA1(dstMask, dstBitmap.getAddr8(0, 0), dstBitmap.rowBytes());
+ } else if (SkMask::kLCD16_Format == maskFormat) {
+ // Copy the A8 dstBitmap into the LCD16 glyph.fImage.
+ uint8_t* src = dstBitmap.getAddr8(0, 0);
+ uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage);
+ for (int y = dstBitmap.height(); y --> 0;) {
+ for (int x = 0; x < dstBitmap.width(); ++x) {
+ dst[x] = grayToRGB16(src[x]);
+ }
+ dst = (uint16_t*)((char*)dst + glyph.rowBytes());
+ src += dstBitmap.rowBytes();
+ }
+ }
+
} break;
- default:
- SkDEBUGFAIL("unknown glyph format");
- memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
- return;
+ default:
+ SkDEBUGFAIL("unknown glyph format");
+ memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
+ return;
}
// We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum,
diff --git a/ports/SkFontHost_mac.cpp b/ports/SkFontHost_mac.cpp
index 3c1a2748..fe3fd069 100755
--- a/ports/SkFontHost_mac.cpp
+++ b/ports/SkFontHost_mac.cpp
@@ -2107,7 +2107,13 @@ static SkTypeface* createFromDesc(CFStringRef cfFamilyName,
return face;
}
- AutoCFRelease<CTFontRef> ctNamed(CTFontCreateWithName(cfFamilyName, 1, NULL));
+ AutoCFRelease<CFDictionaryRef> fontFamilyNameDictionary(
+ CFDictionaryCreate(kCFAllocatorDefault,
+ (const void**)&kCTFontFamilyNameAttribute, (const void**)&cfFamilyName,
+ 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+ AutoCFRelease<CTFontDescriptorRef> fontDescriptor(
+ CTFontDescriptorCreateWithAttributes(fontFamilyNameDictionary));
+ AutoCFRelease<CTFontRef> ctNamed(CTFontCreateWithFontDescriptor(fontDescriptor, 0, NULL));
CTFontRef ctFont = CTFontCreateCopyWithAttributes(ctNamed, 1, NULL, desc);
if (NULL == ctFont) {
return NULL;
diff --git a/ports/SkFontHost_win_dw.cpp b/ports/SkFontHost_win_dw.cpp
index 89e85b73..00623623 100644
--- a/ports/SkFontHost_win_dw.cpp
+++ b/ports/SkFontHost_win_dw.cpp
@@ -21,6 +21,7 @@
#include "SkGlyph.h"
#include "SkHRESULT.h"
#include "SkMaskGamma.h"
+#include "SkOnce.h"
#include "SkOTTable_head.h"
#include "SkOTTable_hhea.h"
#include "SkOTTable_OS_2.h"
@@ -44,6 +45,7 @@ static bool isLCD(const SkScalerContext::Rec& rec) {
/** Prefer to use this type to prevent template proliferation. */
typedef SkAutoSTMalloc<16, WCHAR> SkSMallocWCHAR;
+/** Converts a utf8 string to a WCHAR string. */
static HRESULT cstring_to_wchar(const char* skname, SkSMallocWCHAR* name) {
int wlen = MultiByteToWideChar(CP_UTF8, 0, skname, -1, NULL, 0);
if (0 == wlen) {
@@ -58,6 +60,7 @@ static HRESULT cstring_to_wchar(const char* skname, SkSMallocWCHAR* name) {
return S_OK;
}
+/** Converts a WCHAR string to a utf8 string. */
static HRESULT wchar_to_skstring(WCHAR* name, SkString* skname) {
int len = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL);
if (0 == len) {
@@ -74,6 +77,35 @@ static HRESULT wchar_to_skstring(WCHAR* name, SkString* skname) {
///////////////////////////////////////////////////////////////////////////////
+static void create_dwrite_factory(IDWriteFactory** factory) {
+ typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc;
+ DWriteCreateFactoryProc dWriteCreateFactoryProc = reinterpret_cast<DWriteCreateFactoryProc>(
+ GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory"));
+
+ if (!dWriteCreateFactoryProc) {
+ HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
+ if (!IS_ERROR(hr)) {
+ hr = ERROR_PROC_NOT_FOUND;
+ }
+ HRVM(hr, "Could not get DWriteCreateFactory proc.");
+ }
+
+ HRVM(dWriteCreateFactoryProc(DWRITE_FACTORY_TYPE_SHARED,
+ __uuidof(IDWriteFactory),
+ reinterpret_cast<IUnknown**>(factory)),
+ "Could not create DirectWrite factory.");
+}
+
+static IDWriteFactory* get_dwrite_factory() {
+ static IDWriteFactory* gDWriteFactory = NULL;
+ SK_DECLARE_STATIC_ONCE(once);
+ SkOnce(&once, create_dwrite_factory, &gDWriteFactory);
+
+ return gDWriteFactory;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
class StreamFontFileLoader;
class SkFontMgr_DirectWrite : public SkFontMgr {
@@ -173,40 +205,9 @@ private:
SkTDArray<uint8_t> fBits;
};
-static HRESULT get_dwrite_factory(IDWriteFactory** factory) {
- static IDWriteFactory* gDWriteFactory = NULL;
-
- if (gDWriteFactory != NULL) {
- *factory = gDWriteFactory;
- return S_OK;
- }
-
- typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc;
- DWriteCreateFactoryProc dWriteCreateFactoryProc =
- reinterpret_cast<DWriteCreateFactoryProc>(
- GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory")
- )
- ;
- if (!dWriteCreateFactoryProc) {
- HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
- if (!IS_ERROR(hr)) {
- hr = ERROR_PROC_NOT_FOUND;
- }
- return hr;
- }
-
- HRM(dWriteCreateFactoryProc(DWRITE_FACTORY_TYPE_SHARED,
- __uuidof(IDWriteFactory),
- reinterpret_cast<IUnknown**>(&gDWriteFactory)),
- "Could not create DirectWrite factory.");
-
- *factory = gDWriteFactory;
- return S_OK;
-}
-
const void* DWriteOffscreen::draw(const SkGlyph& glyph, bool isBW) {
- IDWriteFactory* factory;
- HRNM(get_dwrite_factory(&factory), "Could not get factory.");
+ IDWriteFactory* factory = get_dwrite_factory();
+ SkASSERT(factory != NULL);
if (fWidth < glyph.fWidth || fHeight < glyph.fHeight) {
fWidth = SkMax32(fWidth, glyph.fWidth);
@@ -553,8 +554,8 @@ public:
~DWriteFontTypeface() {
if (fDWriteFontCollectionLoader.get() == NULL) return;
- IDWriteFactory* factory;
- HRVM(get_dwrite_factory(&factory), "Could not get factory.");
+ IDWriteFactory* factory = get_dwrite_factory();
+ SkASSERT(factory != NULL);
HRV(factory->UnregisterFontCollectionLoader(fDWriteFontCollectionLoader.get()));
HRV(factory->UnregisterFontFileLoader(fDWriteFontFileLoader.get()));
}
@@ -806,8 +807,8 @@ void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
run.isSideways = FALSE;
run.glyphOffsets = &offset;
- IDWriteFactory* factory;
- HRVM(get_dwrite_factory(&factory), "Could not get factory.");
+ IDWriteFactory* factory = get_dwrite_factory();
+ SkASSERT(factory != NULL);
const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
DWRITE_RENDERING_MODE renderingMode;
@@ -1272,8 +1273,10 @@ private:
};
static SkTypeface* create_from_stream(SkStream* stream, int ttcIndex) {
- IDWriteFactory* factory;
- HRN(get_dwrite_factory(&factory));
+ IDWriteFactory* factory = get_dwrite_factory();
+ if (NULL == factory) {
+ return NULL;
+ }
SkTScopedComPtr<StreamFontFileLoader> fontFileLoader;
HRN(StreamFontFileLoader::Create(stream, &fontFileLoader));
@@ -1373,8 +1376,8 @@ void DWriteFontTypeface::onFilterRec(SkScalerContext::Rec* rec) const {
rec->setHinting(h);
#if SK_FONT_HOST_USE_SYSTEM_SETTINGS
- IDWriteFactory* factory;
- if (SUCCEEDED(get_dwrite_factory(&factory))) {
+ IDWriteFactory* factory = get_dwrite_factory();
+ if (factory != NULL) {
SkTScopedComPtr<IDWriteRenderingParams> defaultRenderingParams;
if (SUCCEEDED(factory->CreateRenderingParams(&defaultRenderingParams))) {
float gamma = defaultRenderingParams->GetGamma();
@@ -1880,8 +1883,10 @@ static HRESULT GetGetUserDefaultLocaleNameProc(GetUserDefaultLocaleNameProc* pro
}
SkFontMgr* SkFontMgr_New_DirectWrite() {
- IDWriteFactory* factory;
- HRNM(get_dwrite_factory(&factory), "Could not get factory.");
+ IDWriteFactory* factory = get_dwrite_factory();
+ if (NULL == factory) {
+ return NULL;
+ }
SkTScopedComPtr<IDWriteFontCollection> sysFontCollection;
HRNM(factory->GetSystemFontCollection(&sysFontCollection, FALSE),
diff --git a/ports/SkImageDecoder_empty.cpp b/ports/SkImageDecoder_empty.cpp
index 8a45dfac..ae0fc363 100644
--- a/ports/SkImageDecoder_empty.cpp
+++ b/ports/SkImageDecoder_empty.cpp
@@ -7,7 +7,6 @@
*/
#include "SkBitmap.h"
-#include "SkBitmapFactory.h"
#include "SkImage.h"
#include "SkImageDecoder.h"
#include "SkImageEncoder.h"
@@ -84,11 +83,6 @@ SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator*) {
void SkImageDecoder::setSampleSize(int) {}
-bool SkImageDecoder::DecodeMemoryToTarget(const void*, size_t, SkImageInfo*,
- const SkBitmapFactory::Target*) {
- return false;
-}
-
SkBitmap::Config SkImageDecoder::GetDeviceConfig() {
return SkBitmap::kNo_Config;
}
diff --git a/text/SkTextLayout.cpp b/text/SkTextLayout.cpp
index 4e531cf2..6f8bca56 100644
--- a/text/SkTextLayout.cpp
+++ b/text/SkTextLayout.cpp
@@ -7,8 +7,6 @@
*/
#include "SkTextLayout.h"
-SK_DEFINE_INST_COUNT(SkTextStyle)
-
SkTextStyle::SkTextStyle() {
fPaint.setAntiAlias(true);
}
diff --git a/utils/SkBoundaryPatch.cpp b/utils/SkBoundaryPatch.cpp
index fd1545d2..e5fcc405 100644
--- a/utils/SkBoundaryPatch.cpp
+++ b/utils/SkBoundaryPatch.cpp
@@ -7,8 +7,6 @@
*/
#include "SkBoundaryPatch.h"
-SK_DEFINE_INST_COUNT(SkBoundary)
-
SkBoundaryPatch::SkBoundaryPatch() : fBoundary(NULL) {}
SkBoundaryPatch::~SkBoundaryPatch() {
diff --git a/utils/SkCanvasStack.cpp b/utils/SkCanvasStack.cpp
index db5a8b27..8951149b 100644
--- a/utils/SkCanvasStack.cpp
+++ b/utils/SkCanvasStack.cpp
@@ -35,7 +35,7 @@ void SkCanvasStack::pushCanvas(SkCanvas* canvas, const SkIPoint& origin) {
localBounds.offset(origin - fCanvasData[i-1].origin);
fCanvasData[i-1].requiredClip.op(localBounds, SkRegion::kDifference_Op);
- fList[i-i]->clipRegion(fCanvasData[i-1].requiredClip);
+ fList[i-1]->clipRegion(fCanvasData[i-1].requiredClip);
}
}
SkASSERT(fList.count() == fCanvasData.count());
diff --git a/utils/SkDumpCanvas.cpp b/utils/SkDumpCanvas.cpp
index 0e1a2321..dabf0d79 100644
--- a/utils/SkDumpCanvas.cpp
+++ b/utils/SkDumpCanvas.cpp
@@ -24,8 +24,6 @@
#include "SkPathEffect.h"
#include "SkMaskFilter.h"
-SK_DEFINE_INST_COUNT(SkDumpCanvas::Dumper)
-
static void toString(const SkRect& r, SkString* str) {
str->appendf("[%g,%g %g:%g]",
SkScalarToFloat(r.fLeft), SkScalarToFloat(r.fTop),
diff --git a/utils/SkLayer.cpp b/utils/SkLayer.cpp
index 126dd921..525917ff 100644
--- a/utils/SkLayer.cpp
+++ b/utils/SkLayer.cpp
@@ -15,8 +15,6 @@
static int gLayerAllocCount;
#endif
-SK_DEFINE_INST_COUNT(SkLayer)
-
///////////////////////////////////////////////////////////////////////////////
SkLayer::SkLayer() {
diff --git a/utils/SkUnitMappers.cpp b/utils/SkUnitMappers.cpp
index ceff9ca0..5976e9de 100644
--- a/utils/SkUnitMappers.cpp
+++ b/utils/SkUnitMappers.cpp
@@ -8,8 +8,6 @@
#include "SkUnitMappers.h"
#include "SkFlattenableBuffers.h"
-SK_DEFINE_INST_COUNT(SkUnitMapper)
-
SkDiscreteMapper::SkDiscreteMapper(int segments) {
if (segments < 2) {
fSegments = 0;
diff --git a/utils/android/ashmem.h b/utils/android/ashmem.h
index 278192b4..94ffe1a3 100644
--- a/utils/android/ashmem.h
+++ b/utils/android/ashmem.h
@@ -16,6 +16,12 @@ extern "C" {
int ashmem_create_region(const char *name, size_t size);
int ashmem_set_prot_region(int fd, int prot);
+
+/**
+ * @return ASHMEM_NOT_PURGED if the memory was not purged.
+ * ASHMEM_WAS_PURGED if the memory was purged.
+ * -1 on error.
+ */
int ashmem_pin_region(int fd, size_t offset, size_t len);
int ashmem_unpin_region(int fd, size_t offset, size_t len);
int ashmem_get_size_region(int fd);
diff --git a/utils/debugger/SkDebugCanvas.cpp b/utils/debugger/SkDebugCanvas.cpp
index d1a9f0c9..e491f3b8 100644
--- a/utils/debugger/SkDebugCanvas.cpp
+++ b/utils/debugger/SkDebugCanvas.cpp
@@ -22,18 +22,15 @@ static SkBitmap make_noconfig_bm(int width, int height) {
SkDebugCanvas::SkDebugCanvas(int width, int height)
: INHERITED(make_noconfig_bm(width, height))
+ , fWidth(width)
+ , fHeight(height)
+ , fFilter(false)
+ , fIndex(0)
, fOverdrawViz(false)
, fOverdrawFilter(NULL)
, fOverrideTexFiltering(false)
, fTexOverrideFilter(NULL)
, fOutstandingSaveCount(0) {
- // TODO(chudy): Free up memory from all draw commands in destructor.
- fWidth = width;
- fHeight = height;
- // do we need fBm anywhere?
- fBm.setConfig(SkBitmap::kNo_Config, fWidth, fHeight);
- fFilter = false;
- fIndex = 0;
fUserMatrix.reset();
// SkPicturePlayback uses the base-class' quickReject calls to cull clipped
@@ -58,6 +55,7 @@ SkDebugCanvas::SkDebugCanvas(int width, int height)
SkDebugCanvas::~SkDebugCanvas() {
fCommandVector.deleteAll();
SkSafeUnref(fOverdrawFilter);
+ SkSafeUnref(fTexOverrideFilter);
}
void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) {
@@ -65,14 +63,9 @@ void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) {
}
void SkDebugCanvas::draw(SkCanvas* canvas) {
- if(!fCommandVector.isEmpty()) {
- for (int i = 0; i < fCommandVector.count(); i++) {
- if (fCommandVector[i]->isVisible()) {
- fCommandVector[i]->execute(canvas);
- }
- }
+ if (!fCommandVector.isEmpty()) {
+ drawTo(canvas, fCommandVector.count() - 1);
}
- fIndex = fCommandVector.count() - 1;
}
void SkDebugCanvas::applyUserTransform(SkCanvas* canvas) {
@@ -177,18 +170,19 @@ private:
void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
SkASSERT(!fCommandVector.isEmpty());
SkASSERT(index < fCommandVector.count());
- int i;
+ int i = 0;
// This only works assuming the canvas and device are the same ones that
// were previously drawn into because they need to preserve all saves
// and restores.
- if (fIndex < index) {
+ // The visibility filter also requires a full re-draw - otherwise we can
+ // end up drawing the filter repeatedly.
+ if (fIndex < index && !fFilter) {
i = fIndex + 1;
} else {
for (int j = 0; j < fOutstandingSaveCount; j++) {
canvas->restore();
}
- i = 0;
canvas->clear(SK_ColorTRANSPARENT);
canvas->resetMatrix();
SkRect rect = SkRect::MakeWH(SkIntToScalar(fWidth),
diff --git a/utils/debugger/SkDebugCanvas.h b/utils/debugger/SkDebugCanvas.h
index 3df31513..262619e7 100644
--- a/utils/debugger/SkDebugCanvas.h
+++ b/utils/debugger/SkDebugCanvas.h
@@ -42,15 +42,6 @@ public:
void draw(SkCanvas* canvas);
/**
- Executes the draw calls in the specified range.
- @param canvas The canvas being drawn to
- @param i The beginning of the range
- @param j The end of the range
- TODO(chudy): Implement
- */
- void drawRange(SkCanvas* canvas, int i, int j);
-
- /**
Executes the draw calls up to the specified index.
@param canvas The canvas being drawn to
@param index The index of the final command being executed
@@ -244,9 +235,8 @@ public:
private:
SkTDArray<SkDrawCommand*> fCommandVector;
- int fHeight;
int fWidth;
- SkBitmap fBm;
+ int fHeight;
bool fFilter;
int fIndex;
SkMatrix fUserMatrix;
diff --git a/utils/debugger/SkObjectParser.cpp b/utils/debugger/SkObjectParser.cpp
index 54ae0773..ebbd4001 100644
--- a/utils/debugger/SkObjectParser.cpp
+++ b/utils/debugger/SkObjectParser.cpp
@@ -26,9 +26,9 @@ SkString* SkObjectParser::BitmapToString(const SkBitmap& bitmap) {
mBitmap->appendS32(bitmap.height());
const char* gConfigStrings[] = {
- "None", "A1", "A8", "Index8", "RGB565", "ARGB4444", "ARGB8888"
+ "None", "A8", "Index8", "RGB565", "ARGB4444", "ARGB8888"
};
- SkASSERT(SkBitmap::kConfigCount == 7);
+ SkASSERT(SkBitmap::kConfigCount == SK_ARRAY_COUNT(gConfigStrings));
mBitmap->append(" Config: ");
mBitmap->append(gConfigStrings[bitmap.config()]);
diff --git a/utils/win/SkAutoCoInitialize.cpp b/utils/win/SkAutoCoInitialize.cpp
index dd6e9368..89115bfe 100644
--- a/utils/win/SkAutoCoInitialize.cpp
+++ b/utils/win/SkAutoCoInitialize.cpp
@@ -8,7 +8,7 @@
#define WIN32_LEAN_AND_MEAN
-#include <Windows.h>
+#include <windows.h>
#include <ole2.h>
#include "SkAutoCoInitialize.h"
diff --git a/utils/win/SkIStream.cpp b/utils/win/SkIStream.cpp
index 0386ea78..74d814cc 100644
--- a/utils/win/SkIStream.cpp
+++ b/utils/win/SkIStream.cpp
@@ -8,7 +8,7 @@
#define WIN32_LEAN_AND_MEAN
-#include <Windows.h>
+#include <windows.h>
#include <ole2.h>
#include "SkIStream.h"
#include "SkStream.h"
diff --git a/views/SkEventSink.cpp b/views/SkEventSink.cpp
index b6a3a6ee..7763adef 100644
--- a/views/SkEventSink.cpp
+++ b/views/SkEventSink.cpp
@@ -14,8 +14,6 @@
#include "SkThread.h"
#include "SkTime.h"
-SK_DEFINE_INST_COUNT(SkEventSink)
-
class SkEventSink_Globals {
public:
SkEventSink_Globals() {
diff --git a/views/SkView.cpp b/views/SkView.cpp
index e3e05f91..f211ad96 100644
--- a/views/SkView.cpp
+++ b/views/SkView.cpp
@@ -8,9 +8,6 @@
#include "SkView.h"
#include "SkCanvas.h"
-SK_DEFINE_INST_COUNT(SkView::Artist)
-SK_DEFINE_INST_COUNT(SkView::Layout)
-
////////////////////////////////////////////////////////////////////////
SkView::SkView(uint32_t flags) : fFlags(SkToU8(flags))
diff --git a/views/animated/SkWidgetViews.cpp b/views/animated/SkWidgetViews.cpp
index 45e98688..8e7f5175 100644
--- a/views/animated/SkWidgetViews.cpp
+++ b/views/animated/SkWidgetViews.cpp
@@ -24,8 +24,6 @@ enum SkinEnum {
};
*/
-SK_DEFINE_INST_COUNT(SkListSource)
-
const char* get_skin_enum_path(SkinEnum se)
{
SkASSERT((unsigned)se < kSkinEnumCount);
diff --git a/views/win/skia_win.cpp b/views/win/skia_win.cpp
index 2d66bd82..72ff54fe 100644
--- a/views/win/skia_win.cpp
+++ b/views/win/skia_win.cpp
@@ -5,7 +5,7 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
-#include <Windows.h>
+#include <windows.h>
#include <tchar.h>
#include "SkApplication.h"