diff options
50 files changed, 866 insertions, 440 deletions
diff --git a/bench/RectBench.cpp b/bench/RectBench.cpp index 6f34eb5..3874bb3 100644 --- a/bench/RectBench.cpp +++ b/bench/RectBench.cpp @@ -89,14 +89,20 @@ public: protected: virtual void onDraw(SkCanvas* canvas) { - static const SkScalar gSizes[] = { + SkScalar gSizes[] = { SkIntToScalar(7), 0 }; + size_t sizes = SK_ARRAY_COUNT(gSizes); + + if (this->hasStrokeWidth()) { + gSizes[0] = this->getStrokeWidth(); + sizes = 1; + } SkPaint paint; paint.setStrokeCap(SkPaint::kRound_Cap); - - for (size_t i = 0; i < SK_ARRAY_COUNT(gSizes); i++) { + + for (size_t i = 0; i < sizes; i++) { paint.setStrokeWidth(gSizes[i]); this->setupPaint(&paint); canvas->drawPoints(fMode, N * 2, @@ -132,4 +138,3 @@ static BenchRegistry gRRectReg2(RRectFactory2); static BenchRegistry gPointsReg(PointsFactory); static BenchRegistry gLinesReg(LinesFactory); static BenchRegistry gPolygonReg(PolygonFactory); - diff --git a/bench/SkBenchmark.cpp b/bench/SkBenchmark.cpp index e8bea6e..230a7af 100644 --- a/bench/SkBenchmark.cpp +++ b/bench/SkBenchmark.cpp @@ -9,6 +9,7 @@ SkBenchmark::SkBenchmark(void* defineDict) { fForceAlpha = 0xFF; fForceAA = true; fDither = SkTriState::kDefault; + fHasStrokeWidth = false; } const char* SkBenchmark::getName() { diff --git a/bench/SkBenchmark.h b/bench/SkBenchmark.h index bc9794a..945db80 100644 --- a/bench/SkBenchmark.h +++ b/bench/SkBenchmark.h @@ -42,6 +42,19 @@ public: fDither = state; } + void setStrokeWidth(SkScalar width) { + strokeWidth = width; + fHasStrokeWidth = true; + } + + SkScalar getStrokeWidth() { + return strokeWidth; + } + + bool hasStrokeWidth() { + return fHasStrokeWidth; + } + const char* findDefine(const char* key) const; bool findDefine32(const char* key, int32_t* value) const; bool findDefineScalar(const char* key, SkScalar* value) const; @@ -60,9 +73,10 @@ private: bool fForceAA; bool fForceFilter; SkTriState::State fDither; + bool fHasStrokeWidth; + SkScalar strokeWidth; }; typedef SkTRegistry<SkBenchmark*, void*> BenchRegistry; #endif - diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp index 7443604..2f8b006 100644 --- a/bench/benchmain.cpp +++ b/bench/benchmain.cpp @@ -201,6 +201,8 @@ int main (int argc, char * const argv[]) { bool doClip = false; bool doPict = false; const char* matchStr = NULL; + bool hasStrokeWidth = false; + float strokeWidth; SkString outDir; SkBitmap::Config outConfig = SkBitmap::kNo_Config; @@ -260,6 +262,19 @@ int main (int argc, char * const argv[]) { return -1; } forceAlpha = wantAlpha ? 0x80 : 0xFF; + } else if (strcmp(*argv, "-strokeWidth") == 0) { + argv++; + if (argv < stop) { + const char *strokeWidthStr = *argv; + if (sscanf(strokeWidthStr, "%f", &strokeWidth) != 1) { + log_error("bad arg for -strokeWidth\n"); + return -1; + } + hasStrokeWidth = true; + } else { + log_error("missing arg for -strokeWidth\n"); + return -1; + } } else if (strcmp(*argv, "-match") == 0) { argv++; if (argv < stop) { @@ -314,6 +329,9 @@ int main (int argc, char * const argv[]) { bench->setForceAA(forceAA); bench->setForceFilter(forceFilter); bench->setDither(forceDither); + if (hasStrokeWidth) { + bench->setStrokeWidth(strokeWidth); + } // only run benchmarks if their name contains matchStr if (matchStr && strstr(bench->getName(), matchStr) == NULL) { diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index bfa0d10..b5ccca6 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -29,6 +29,7 @@ class SkBounder; class SkDevice; +class SkDeviceFactory; class SkDraw; class SkDrawFilter; class SkPicture; @@ -51,29 +52,37 @@ class SkShape; */ class SkCanvas : public SkRefCnt { public: - /** Construct a canvas with the specified bitmap to draw into. + /** Construct a canvas with the given device factory. + @param factory Specify the factory for generating additional devices. + The factory may be null, in which case + SkRasterDeviceFactory will be used. + */ + explicit SkCanvas(SkDeviceFactory* factory = NULL); + + /** Construct a canvas with the specified device to draw into. The device + factory will be retrieved from the passed device. + @param device Specifies a device for the canvas to draw into. + */ + explicit SkCanvas(SkDevice* device); + + /** Deprecated - Construct a canvas with the specified bitmap to draw into. @param bitmap Specifies a bitmap for the canvas to draw into. Its structure are copied to the canvas. */ explicit SkCanvas(const SkBitmap& bitmap); - /** Construct a canvas with the specified device to draw into. - @param device Specifies a device for the canvas to draw into. The - device may be null. - */ - explicit SkCanvas(SkDevice* device = NULL); virtual ~SkCanvas(); /////////////////////////////////////////////////////////////////////////// - /** If this subclass of SkCanvas supports GL viewports, return true and set - size (if not null) to the size of the viewport. If it is not supported, - ignore vp and return false. + /** If the Device supports GL viewports, return true and set size (if not + null) to the size of the viewport. If it is not supported, ignore size + and return false. */ virtual bool getViewport(SkIPoint* size) const; - - /** If this subclass of SkCanvas supports GL viewports, return true and set - the viewport to the specified x and y dimensions. If it is not - supported, ignore x and y and return false. + + /** If the Device supports GL viewports, return true and set the viewport + to the specified x and y dimensions. If it is not supported, ignore x + and y and return false. */ virtual bool setViewport(int x, int y); @@ -88,15 +97,16 @@ public: device, its reference count is decremented. The new device is returned. */ SkDevice* setDevice(SkDevice* device); - - /** Specify a bitmap for the canvas to draw into. This is a help method for - setDevice(), and it creates a device for the bitmap by calling - createDevice(). The structure of the bitmap is copied into the device. + + /** Deprecated - Specify a bitmap for the canvas to draw into. This is a + helper method for setDevice(), and it creates a device for the bitmap by + calling createDevice(). The structure of the bitmap is copied into the + device. */ virtual SkDevice* setBitmapDevice(const SkBitmap& bitmap); /////////////////////////////////////////////////////////////////////////// - + enum SaveFlags { /** save the matrix state, restoring it on restore() */ kMatrix_SaveFlag = 0x01, @@ -758,6 +768,7 @@ private: SkBounder* fBounder; SkDevice* fLastDeviceToGainFocus; + SkDeviceFactory* fDeviceFactory; void prepareForDeviceDraw(SkDevice*); diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h index 0d724ba..dbc8fcf 100644 --- a/include/core/SkDevice.h +++ b/include/core/SkDevice.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,26 +22,53 @@ #include "SkCanvas.h" #include "SkColor.h" +class SkDevice; class SkDraw; struct SkIRect; class SkMatrix; class SkRegion; +/** \class SkDeviceFactory + + Devices that extend SkDevice should also provide a SkDeviceFactory class + to pass into SkCanvas. Doing so will eliminate the need to extend + SkCanvas as well. +*/ +class SkDeviceFactory { +public: + virtual ~SkDeviceFactory(); + virtual SkDevice* newDevice(SkBitmap::Config config, int width, int height, + bool isOpaque, bool isForLayer) = 0; +}; + +class SkRasterDeviceFactory : public SkDeviceFactory { +public: + virtual SkDevice* newDevice(SkBitmap::Config config, int width, int height, + bool isOpaque, bool isForLayer); +}; + class SkDevice : public SkRefCnt { public: SkDevice(); - /** Construct a new device, extracting the width/height/config/isOpaque values from - the bitmap. If transferPixelOwnership is true, and the bitmap claims to own its - own pixels (getOwnsPixels() == true), then transfer this responsibility to the - device, and call setOwnsPixels(false) on the bitmap. - - Subclasses may override the destructor, which is virtual, even though this class - doesn't have one. SkRefCnt does. - + /** Construct a new device, extracting the width/height/config/isOpaque + values from the bitmap. Subclasses may override the destructor, which + is virtual, even though this class doesn't have one. SkRefCnt does. + @param bitmap A copy of this bitmap is made and stored in the device */ SkDevice(const SkBitmap& bitmap); + virtual SkDeviceFactory* getDeviceFactory() { + return SkNEW(SkRasterDeviceFactory); + } + + enum Capabilities { + kGL_Capability = 0x1, //!< mask indicating GL support + kVector_Capability = 0x2, //!< mask indicating a vector representation + kAll_Capabilities = 0x3 + }; + virtual uint32_t getDeviceCapabilities() { return 0; } + /** Return the width of the device (in pixels). */ int width() const { return fBitmap.width(); } diff --git a/include/core/SkGraphics.h b/include/core/SkGraphics.h index dd5808a..25c926f 100644 --- a/include/core/SkGraphics.h +++ b/include/core/SkGraphics.h @@ -33,7 +33,12 @@ public: Returns true if some amount was purged from the font cache. */ static bool SetFontCacheUsed(size_t usageInBytes); - + + /** Return the version numbers for the library. If the parameter is not + null, it is set to the version number. + */ + static void GetVersion(int32_t* major, int32_t* minor, int32_t* patch); + private: /** This is automatically called by SkGraphics::Init(), and must be implemented by the host OS. This allows the host OS to register a callback diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h index 5fef527..ea21ceb 100644 --- a/include/core/SkPaint.h +++ b/include/core/SkPaint.h @@ -806,6 +806,11 @@ public: void getTextPath(const void* text, size_t length, SkScalar x, SkScalar y, SkPath* path) const; + const SkGlyph& getUnicharMetrics(SkUnichar); + const void* findImage(const SkGlyph&); + + uint32_t getGenerationID() const; + private: SkTypeface* fTypeface; SkScalar fTextSize; @@ -830,6 +835,7 @@ private: unsigned fStyle : 2; unsigned fTextEncoding : 2; // 3 values unsigned fHinting : 2; + uint32_t fGenerationID; SkDrawCacheProc getDrawCacheProc() const; SkMeasureCacheProc getMeasureCacheProc(TextBufferDirection dir, @@ -842,7 +848,7 @@ private: void descriptorProc(const SkMatrix* deviceMatrix, void (*proc)(const SkDescriptor*, void*), - void* context) const; + void* context, bool ignoreGamma = false) const; const SkRect& computeStrokeFastBounds(const SkRect& orig, SkRect* storage) const; diff --git a/include/core/SkPath.h b/include/core/SkPath.h index 3afea09..eb5ff6d 100644 --- a/include/core/SkPath.h +++ b/include/core/SkPath.h @@ -571,6 +571,8 @@ public: */ void subdivide(SkScalar dist, bool bendLines, SkPath* dst = NULL) const; + uint32_t getGenerationID() const; + SkDEBUGCODE(void validate() const;) private: @@ -580,6 +582,7 @@ private: mutable uint8_t fBoundsIsDirty; uint8_t fFillType; uint8_t fIsConvex; + uint32_t fGenerationID; // called, if dirty, by getBounds() void computeBounds() const; diff --git a/src/core/SkPictureFlat.h b/include/core/SkPictureFlat.h index 2c0af5a..2c0af5a 100644 --- a/src/core/SkPictureFlat.h +++ b/include/core/SkPictureFlat.h diff --git a/include/core/SkRect.h b/include/core/SkRect.h index 879d81a..fbd9f7f 100644 --- a/include/core/SkRect.h +++ b/include/core/SkRect.h @@ -233,6 +233,18 @@ struct SkIRect { struct SkRect { SkScalar fLeft, fTop, fRight, fBottom; + static SkRect MakeEmpty() { + SkRect r; + r.setEmpty(); + return r; + } + + static SkRect MakeWH(SkScalar w, SkScalar h) { + SkRect r; + r.set(0, 0, w, h); + return r; + } + static SkRect MakeSize(const SkSize& size) { SkRect r; r.set(0, 0, size.width(), size.height()); @@ -250,7 +262,7 @@ struct SkRect { r.set(x, y, x + w, y + h); return r; } - + /** Return true if the rectangle's width or height are <= 0 */ bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } diff --git a/include/core/SkTypes.h b/include/core/SkTypes.h index fa21adc..1f8ecaa 100644 --- a/include/core/SkTypes.h +++ b/include/core/SkTypes.h @@ -30,6 +30,12 @@ /** \file SkTypes.h */ +/** See SkGraphics::GetVersion() to retrieve these at runtime + */ +#define SKIA_VERSION_MAJOR 1 +#define SKIA_VERSION_MINOR 0 +#define SKIA_VERSION_PATCH 0 + /* memory wrappers to be implemented by the porting layer (platform) */ diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h index 7a06467..d92d346 100644 --- a/include/core/SkXfermode.h +++ b/include/core/SkXfermode.h @@ -137,6 +137,8 @@ public: return false and ignore the mode parameter. */ static bool IsMode(SkXfermode*, Mode* mode); + + Mode fMode; protected: SkXfermode(SkFlattenableReadBuffer& rb) : SkFlattenable(rb) {} diff --git a/include/effects/SkPorterDuff.h b/include/effects/SkPorterDuff.h index 6f4ac20..4d7fb31 100644 --- a/include/effects/SkPorterDuff.h +++ b/include/effects/SkPorterDuff.h @@ -52,6 +52,7 @@ public: kMultiply_Mode, //!< [Sa * Da, Sc * Dc] kScreen_Mode, //!< [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] kAdd_Mode, //!< Saturate(S + D) + kOverlay_Mode, kModeCount }; diff --git a/include/utils/SkGLCanvas.h b/include/utils/SkGLCanvas.h index 40fc52d..eb99527 100644 --- a/include/utils/SkGLCanvas.h +++ b/include/utils/SkGLCanvas.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,31 +19,11 @@ #include "SkCanvas.h" -#ifdef SK_BUILD_FOR_MAC - #include <OpenGL/gl.h> -#elif defined(ANDROID) - #include <GLES/gl.h> -#endif - -class SkGLDevice; -class SkGLClipIter; - +// Deprecated. You should now use SkGLDevice and SkGLDeviceFactory with +// SkCanvas. class SkGLCanvas : public SkCanvas { public: - // notice, we do NOT allow the SkCanvas(bitmap) constructor, since that - // does not create a SkGLDevice, which we require SkGLCanvas(); - virtual ~SkGLCanvas(); - - // overrides from SkCanvas - - virtual bool getViewport(SkIPoint*) const; - virtual bool setViewport(int width, int height); - - virtual SkDevice* createDevice(SkBitmap::Config, int width, int height, - bool isOpaque, bool isForLayer); - - // settings for the global texture cache static size_t GetTextureCacheMaxCount(); static void SetTextureCacheMaxCount(size_t count); @@ -51,30 +31,9 @@ public: static size_t GetTextureCacheMaxSize(); static void SetTextureCacheMaxSize(size_t size); - /** Call glDeleteTextures for all textures (including those for text) - This should be called while the gl-context is still valid. Its purpose - is to free up gl resources. Note that if a bitmap or text is drawn after - this call, new caches will be created. - */ static void DeleteAllTextures(); - /** Forget all textures without calling delete (including those for text). - This should be called if the gl-context has changed, and the texture - IDs that have been cached are no longer valid. - */ static void AbandonAllTextures(); - -private: - SkIPoint fViewportSize; - - // need to disallow this guy - virtual SkDevice* setBitmapDevice(const SkBitmap& bitmap) { - sk_throw(); - return NULL; - } - - typedef SkCanvas INHERITED; }; #endif - diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp index bd4fece..c3fd7d0 100644 --- a/src/core/SkBitmapProcShader.cpp +++ b/src/core/SkBitmapProcShader.cpp @@ -137,6 +137,15 @@ bool SkBitmapProcShader::setContext(const SkBitmap& device, #define BUF_MAX 128 +#define TEST_BUFFER_OVERRITEx + +#ifdef TEST_BUFFER_OVERRITE + #define TEST_BUFFER_EXTRA 32 + #define TEST_PATTERN 0x88888888 +#else + #define TEST_BUFFER_EXTRA 0 +#endif + void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { const SkBitmapProcState& state = fState; if (state.fShaderProc32) { @@ -144,10 +153,10 @@ void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { return; } - uint32_t buffer[BUF_MAX]; + uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA]; SkBitmapProcState::MatrixProc mproc = state.fMatrixProc; SkBitmapProcState::SampleProc32 sproc = state.fSampleProc32; - int max = fState.maxCountForBufferSize(sizeof(buffer)); + int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX); SkASSERT(state.fBitmap->getPixels()); SkASSERT(state.fBitmap->pixelRef() == NULL || @@ -158,12 +167,24 @@ void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { if (n > max) { n = max; } + SkASSERT(n > 0 && n < BUF_MAX*2); +#ifdef TEST_BUFFER_OVERRITE + for (int i = 0; i < TEST_BUFFER_EXTRA; i++) { + buffer[BUF_MAX + i] = TEST_PATTERN; + } +#endif mproc(state, buffer, n, x, y); +#ifdef TEST_BUFFER_OVERRITE + for (int j = 0; j < TEST_BUFFER_EXTRA; j++) { + SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN); + } +#endif sproc(state, buffer, n, dstC); if ((count -= n) == 0) { break; } + SkASSERT(count > 0); x += n; dstC += n; } diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp index eabd966..e54818d 100644 --- a/src/core/SkBitmapProcState.cpp +++ b/src/core/SkBitmapProcState.cpp @@ -543,7 +543,6 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { */ int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const { int32_t size = static_cast<int32_t>(bufferSize); - int perElemShift; size &= ~3; // only care about 4-byte aligned chunks if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { @@ -551,11 +550,15 @@ int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const { if (size < 0) { size = 0; } - perElemShift = fDoFilter ? 2 : 1; + size >>= 1; } else { - perElemShift = fDoFilter ? 3 : 2; + size >>= 2; } - return size >> perElemShift; + if (fDoFilter) { + size >>= 1; + } + + return size; } diff --git a/src/core/SkBitmapProcState.h b/src/core/SkBitmapProcState.h index dd73c33..303696f 100644 --- a/src/core/SkBitmapProcState.h +++ b/src/core/SkBitmapProcState.h @@ -91,10 +91,11 @@ struct SkBitmapProcState { */ void platformProcs(); - /** Given the size of a buffer, to be used for calling the matrix and - sample procs, this return the maximum count that can be stored in the - buffer, taking into account that filtering and scale-vs-affine affect - this value. + /** Given the byte size of the index buffer to be passed to the matrix proc, + return the maximum number of resulting pixels that can be computed + (i.e. the number of SkPMColor values to be written by the sample proc). + This routine takes into account that filtering and scale-vs-affine + affect the amount of buffer space needed. Only valid to call after chooseProcs (setContext) has been called. It is safe to call this inside the shader's shadeSpan() method. diff --git a/src/core/SkBitmapProcState_matrixProcs.cpp b/src/core/SkBitmapProcState_matrixProcs.cpp index 6654312..d0bc8d8 100644 --- a/src/core/SkBitmapProcState_matrixProcs.cpp +++ b/src/core/SkBitmapProcState_matrixProcs.cpp @@ -368,7 +368,7 @@ static void clampx_nofilter_trans(const SkBitmapProcState& s, } // fill the remaining with the max value - sk_memset16(xptr, width - 1, count * sizeof(uint16_t)); + sk_memset16(xptr, width - 1, count); } static void repeatx_nofilter_trans(const SkBitmapProcState& s, diff --git a/src/core/SkBlitter_A8.cpp b/src/core/SkBlitter_A8.cpp index 18b0881..37ecdfc 100644 --- a/src/core/SkBlitter_A8.cpp +++ b/src/core/SkBlitter_A8.cpp @@ -271,7 +271,7 @@ SkA8_Shader_Blitter::SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint& SkA8_Shader_Blitter::~SkA8_Shader_Blitter() { - fXfermode->safeUnref(); + if (fXfermode) fXfermode->safeUnref(); sk_free(fBuffer); } @@ -377,7 +377,9 @@ void SkA8_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) while (--height >= 0) { fShader->shadeSpan(x, y, span, width); - fXfermode->xferA8(device, span, width, alpha); + if (fXfermode) { + fXfermode->xferA8(device, span, width, alpha); + } y += 1; device += fDevice.rowBytes(); diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 26e39b5..94c2439 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -404,8 +404,20 @@ SkDevice* SkCanvas::init(SkDevice* device) { return this->setDevice(device); } +SkCanvas::SkCanvas(SkDeviceFactory* factory) + : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)), + fDeviceFactory(factory) { + inc_canvas(); + + if (!factory) + fDeviceFactory = SkNEW(SkRasterDeviceFactory); + + this->init(NULL); +} + SkCanvas::SkCanvas(SkDevice* device) - : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { + : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)), + fDeviceFactory(device->getDeviceFactory()) { inc_canvas(); this->init(device); @@ -415,7 +427,9 @@ SkCanvas::SkCanvas(const SkBitmap& bitmap) : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) { inc_canvas(); - this->init(SkNEW_ARGS(SkDevice, (bitmap)))->unref(); + SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap)); + fDeviceFactory = device->getDeviceFactory(); + this->init(device)->unref(); } SkCanvas::~SkCanvas() { @@ -423,8 +437,9 @@ SkCanvas::~SkCanvas() { this->restoreToCount(1); // restore everything but the last this->internalRestore(); // restore the last, since we're going away - fBounder->safeUnref(); - + SkSafeUnref(fBounder); + SkDELETE(fDeviceFactory); + dec_canvas(); } @@ -521,11 +536,19 @@ SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) { ////////////////////////////////////////////////////////////////////////////// bool SkCanvas::getViewport(SkIPoint* size) const { - return false; + if ((getDevice()->getDeviceCapabilities() & SkDevice::kGL_Capability) == 0) + return false; + if (size) + size->set(getDevice()->width(), getDevice()->height()); + return true; } bool SkCanvas::setViewport(int width, int height) { - return false; + if ((getDevice()->getDeviceCapabilities() & SkDevice::kGL_Capability) == 0) + return false; + this->setDevice(createDevice(SkBitmap::kARGB_8888_Config, width, height, + false, false))->unref(); + return true; } void SkCanvas::updateDeviceCMCache() { @@ -1004,18 +1027,9 @@ const SkRegion& SkCanvas::getTotalClip() const { SkDevice* SkCanvas::createDevice(SkBitmap::Config config, int width, int height, bool isOpaque, bool isForLayer) { - SkBitmap bitmap; - - bitmap.setConfig(config, width, height); - bitmap.setIsOpaque(isOpaque); - - // should this happen in the device subclass? - bitmap.allocPixels(); - if (!bitmap.isOpaque()) { - bitmap.eraseARGB(0, 0, 0, 0); - } - return SkNEW_ARGS(SkDevice, (bitmap)); + return fDeviceFactory->newDevice(config, width, height, isOpaque, + isForLayer); } ////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index 8ce1bd8..b629e9a 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -2,6 +2,8 @@ #include "SkDraw.h" #include "SkRect.h" +SkDeviceFactory::~SkDeviceFactory() {} + SkDevice::SkDevice() {} SkDevice::SkDevice(const SkBitmap& bitmap) : fBitmap(bitmap) {} @@ -113,4 +115,16 @@ void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device, draw.drawSprite(device->accessBitmap(false), x, y, paint); } +SkDevice* SkRasterDeviceFactory::newDevice(SkBitmap::Config config, int width, + int height, bool isOpaque, + bool isForLayer) { + SkBitmap bitmap; + bitmap.setConfig(config, width, height); + bitmap.setIsOpaque(isOpaque); + + bitmap.allocPixels(); + if (!bitmap.isOpaque()) + bitmap.eraseARGB(0, 0, 0, 0); + return SkNEW_ARGS(SkDevice, (bitmap)); +} diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index 301c0e4..fb5e045 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -789,7 +789,7 @@ static bool map_radius(const SkMatrix& matrix, SkScalar* value) { matrix.mapVectors(dst, src, 2); SkScalar len0 = fast_len(dst[0]); SkScalar len1 = fast_len(dst[1]); - if (len0 < SK_Scalar1 && len1 < SK_Scalar1) { + if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) { *value = SkScalarAve(len0, len1); return true; } diff --git a/src/core/SkGraphics.cpp b/src/core/SkGraphics.cpp index 65a16e2..40f0ea3 100644 --- a/src/core/SkGraphics.cpp +++ b/src/core/SkGraphics.cpp @@ -374,3 +374,15 @@ bool SkGraphics::SetFontCacheUsed(size_t usageInBytes) { return SkGlyphCache::SetCacheUsed(usageInBytes); } +void SkGraphics::GetVersion(int32_t* major, int32_t* minor, int32_t* patch) { + if (major) { + *major = SKIA_VERSION_MAJOR; + } + if (minor) { + *minor = SKIA_VERSION_MINOR; + } + if (patch) { + *patch = SKIA_VERSION_PATCH; + } +} + diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index da818c4..40d3ae8 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -63,6 +63,7 @@ SkPaint::SkPaint() { fStyle = kFill_Style; fTextEncoding = kUTF8_TextEncoding; fHinting = kNormal_Hinting; + fGenerationID = 0; } SkPaint::SkPaint(const SkPaint& src) @@ -114,6 +115,7 @@ SkPaint& SkPaint::operator=(const SkPaint& src) fLooper->safeUnref(); memcpy(this, &src, sizeof(src)); + fGenerationID++; return *this; } @@ -128,72 +130,117 @@ void SkPaint::reset() SkPaint init; *this = init; + fGenerationID++; +} + +uint32_t SkPaint::getGenerationID() const { + return fGenerationID; } void SkPaint::setFlags(uint32_t flags) { - fFlags = flags; + if (fFlags != flags) { + fFlags = flags; + fGenerationID++; + } } void SkPaint::setAntiAlias(bool doAA) { - this->setFlags(SkSetClearMask(fFlags, doAA, kAntiAlias_Flag)); + if (doAA != isAntiAlias()) { + this->setFlags(SkSetClearMask(fFlags, doAA, kAntiAlias_Flag)); + fGenerationID++; + } } void SkPaint::setDither(bool doDither) { - this->setFlags(SkSetClearMask(fFlags, doDither, kDither_Flag)); + if (doDither != isDither()) { + this->setFlags(SkSetClearMask(fFlags, doDither, kDither_Flag)); + fGenerationID++; + } } void SkPaint::setSubpixelText(bool doSubpixel) { - this->setFlags(SkSetClearMask(fFlags, doSubpixel, kSubpixelText_Flag)); + if (doSubpixel != isSubpixelText()) { + this->setFlags(SkSetClearMask(fFlags, doSubpixel, kSubpixelText_Flag)); + fGenerationID++; + } } void SkPaint::setLCDRenderText(bool doLCDRender) { - this->setFlags(SkSetClearMask(fFlags, doLCDRender, kLCDRenderText_Flag)); + if (doLCDRender != isLCDRenderText()) { + this->setFlags(SkSetClearMask(fFlags, doLCDRender, kLCDRenderText_Flag)); + fGenerationID++; + } } void SkPaint::setEmbeddedBitmapText(bool doEmbeddedBitmapText) { - this->setFlags(SkSetClearMask(fFlags, doEmbeddedBitmapText, kEmbeddedBitmapText_Flag)); + if (doEmbeddedBitmapText != isEmbeddedBitmapText()) { + this->setFlags(SkSetClearMask(fFlags, doEmbeddedBitmapText, kEmbeddedBitmapText_Flag)); + fGenerationID++; + } } void SkPaint::setLinearText(bool doLinearText) { - this->setFlags(SkSetClearMask(fFlags, doLinearText, kLinearText_Flag)); + if (doLinearText != isLinearText()) { + this->setFlags(SkSetClearMask(fFlags, doLinearText, kLinearText_Flag)); + fGenerationID++; + } } void SkPaint::setUnderlineText(bool doUnderline) { - this->setFlags(SkSetClearMask(fFlags, doUnderline, kUnderlineText_Flag)); + if (doUnderline != isUnderlineText()) { + this->setFlags(SkSetClearMask(fFlags, doUnderline, kUnderlineText_Flag)); + fGenerationID++; + } } void SkPaint::setStrikeThruText(bool doStrikeThru) { - this->setFlags(SkSetClearMask(fFlags, doStrikeThru, kStrikeThruText_Flag)); + if (doStrikeThru != isStrikeThruText()) { + this->setFlags(SkSetClearMask(fFlags, doStrikeThru, kStrikeThruText_Flag)); + fGenerationID++; + } } void SkPaint::setFakeBoldText(bool doFakeBold) { - this->setFlags(SkSetClearMask(fFlags, doFakeBold, kFakeBoldText_Flag)); + if (doFakeBold != isFakeBoldText()) { + this->setFlags(SkSetClearMask(fFlags, doFakeBold, kFakeBoldText_Flag)); + fGenerationID++; + } } void SkPaint::setDevKernText(bool doDevKern) { - this->setFlags(SkSetClearMask(fFlags, doDevKern, kDevKernText_Flag)); + if (doDevKern != isDevKernText()) { + this->setFlags(SkSetClearMask(fFlags, doDevKern, kDevKernText_Flag)); + fGenerationID++; + } } void SkPaint::setFilterBitmap(bool doFilter) { - this->setFlags(SkSetClearMask(fFlags, doFilter, kFilterBitmap_Flag)); + if (doFilter != isFilterBitmap()) { + this->setFlags(SkSetClearMask(fFlags, doFilter, kFilterBitmap_Flag)); + fGenerationID++; + } } void SkPaint::setStyle(Style style) { - if ((unsigned)style < kStyleCount) - fStyle = style; + if ((unsigned)style < kStyleCount) { + if ((unsigned)style != fStyle) { + fStyle = style; + fGenerationID++; + } + } #ifdef SK_DEBUG else SkDebugf("SkPaint::setStyle(%d) out of range\n", style); @@ -202,23 +249,38 @@ void SkPaint::setStyle(Style style) void SkPaint::setColor(SkColor color) { - fColor = color; + if (color != fColor) { + fColor = color; + fGenerationID++; + } } void SkPaint::setAlpha(U8CPU a) { - fColor = SkColorSetARGB(a, SkColorGetR(fColor), SkColorGetG(fColor), SkColorGetB(fColor)); + U8CPU oldA = SkColorGetA(fColor); + if (a != oldA) { + fColor = SkColorSetARGB(a, SkColorGetR(fColor), SkColorGetG(fColor), SkColorGetB(fColor)); + fGenerationID++; + } } void SkPaint::setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { + SkColor oldColor = fColor; fColor = SkColorSetARGB(a, r, g, b); + if (oldColor != fColor) { + fGenerationID++; + } } void SkPaint::setStrokeWidth(SkScalar width) { - if (width >= 0) - fWidth = width; + if (width >= 0) { + if (width != fWidth) { + fWidth = width; + fGenerationID++; + } + } #ifdef SK_DEBUG else SkDebugf("SkPaint::setStrokeWidth() called with negative value\n"); @@ -227,8 +289,12 @@ void SkPaint::setStrokeWidth(SkScalar width) void SkPaint::setStrokeMiter(SkScalar limit) { - if (limit >= 0) - fMiterLimit = limit; + if (limit >= 0) { + if (limit != fMiterLimit) { + fMiterLimit = limit; + fGenerationID++; + } + } #ifdef SK_DEBUG else SkDebugf("SkPaint::setStrokeMiter() called with negative value\n"); @@ -237,8 +303,12 @@ void SkPaint::setStrokeMiter(SkScalar limit) void SkPaint::setStrokeCap(Cap ct) { - if ((unsigned)ct < kCapCount) - fCapType = SkToU8(ct); + if ((unsigned)ct < kCapCount) { + if ((unsigned)ct != fCapType) { + fCapType = SkToU8(ct); + fGenerationID++; + } + } #ifdef SK_DEBUG else SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct); @@ -247,8 +317,12 @@ void SkPaint::setStrokeCap(Cap ct) void SkPaint::setStrokeJoin(Join jt) { - if ((unsigned)jt < kJoinCount) - fJoinType = SkToU8(jt); + if ((unsigned)jt < kJoinCount) { + if ((unsigned)jt != fJoinType) { + fJoinType = SkToU8(jt); + fGenerationID++; + } + } #ifdef SK_DEBUG else SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt); @@ -259,8 +333,12 @@ void SkPaint::setStrokeJoin(Join jt) void SkPaint::setTextAlign(Align align) { - if ((unsigned)align < kAlignCount) - fTextAlign = SkToU8(align); + if ((unsigned)align < kAlignCount) { + if ((unsigned)align != fTextAlign) { + fTextAlign = SkToU8(align); + fGenerationID++; + } + } #ifdef SK_DEBUG else SkDebugf("SkPaint::setTextAlign(%d) out of range\n", align); @@ -269,8 +347,12 @@ void SkPaint::setTextAlign(Align align) void SkPaint::setTextSize(SkScalar ts) { - if (ts > 0) - fTextSize = ts; + if (ts > 0) { + if (ts != fTextSize) { + fTextSize = ts; + fGenerationID++; + } + } #ifdef SK_DEBUG else SkDebugf("SkPaint::setTextSize() called with non-positive value\n"); @@ -279,18 +361,28 @@ void SkPaint::setTextSize(SkScalar ts) void SkPaint::setTextScaleX(SkScalar scaleX) { - fTextScaleX = scaleX; + if (scaleX != fTextScaleX) { + fTextScaleX = scaleX; + fGenerationID++; + } } void SkPaint::setTextSkewX(SkScalar skewX) { - fTextSkewX = skewX; + if (skewX != fTextSkewX) { + fTextSkewX = skewX; + fGenerationID++; + } } void SkPaint::setTextEncoding(TextEncoding encoding) { - if ((unsigned)encoding <= kGlyphID_TextEncoding) - fTextEncoding = encoding; + if ((unsigned)encoding <= kGlyphID_TextEncoding) { + if ((unsigned)encoding != fTextEncoding) { + fTextEncoding = encoding; + fGenerationID++; + } + } #ifdef SK_DEBUG else SkDebugf("SkPaint::setTextEncoding(%d) out of range\n", encoding); @@ -302,18 +394,21 @@ void SkPaint::setTextEncoding(TextEncoding encoding) SkTypeface* SkPaint::setTypeface(SkTypeface* font) { SkRefCnt_SafeAssign(fTypeface, font); + fGenerationID++; return font; } SkRasterizer* SkPaint::setRasterizer(SkRasterizer* r) { SkRefCnt_SafeAssign(fRasterizer, r); + fGenerationID++; return r; } SkDrawLooper* SkPaint::setLooper(SkDrawLooper* looper) { SkRefCnt_SafeAssign(fLooper, looper); + fGenerationID++; return looper; } @@ -322,6 +417,29 @@ SkDrawLooper* SkPaint::setLooper(SkDrawLooper* looper) #include "SkGlyphCache.h" #include "SkUtils.h" +const SkGlyph& SkPaint::getUnicharMetrics(SkUnichar text) { + SkAutoGlyphCache autoCache(*this, NULL); + SkGlyphCache* cache = autoCache.getCache(); + + return cache->getUnicharMetrics(text); +} + +static void DetachDescProc(const SkDescriptor* desc, void* context) +{ + *((SkGlyphCache**)context) = SkGlyphCache::DetachCache(desc); +} + +const void* SkPaint::findImage(const SkGlyph& glyph) { + // See ::detachCache() + SkGlyphCache* cache; + descriptorProc(NULL, DetachDescProc, &cache, true); + + const void* image = cache->findImage(glyph); + + SkGlyphCache::AttachCache(cache); + return image; +} + int SkPaint::textToGlyphs(const void* textData, size_t byteLength, uint16_t glyphs[]) const { if (byteLength == 0) { @@ -1330,11 +1448,15 @@ void SkScalerContext::MakeRec(const SkPaint& paint, void SkPaint::descriptorProc(const SkMatrix* deviceMatrix, void (*proc)(const SkDescriptor*, void*), - void* context) const + void* context, bool ignoreGamma) const { SkScalerContext::Rec rec; SkScalerContext::MakeRec(*this, deviceMatrix, &rec); + if (ignoreGamma) { + rec.fFlags &= ~(SkScalerContext::kGammaForBlack_Flag | + SkScalerContext::kGammaForWhite_Flag); + } size_t descSize = sizeof(rec); int entryCount = 1; @@ -1389,11 +1511,6 @@ void SkPaint::descriptorProc(const SkMatrix* deviceMatrix, proc(desc, context); } -static void DetachDescProc(const SkDescriptor* desc, void* context) -{ - *((SkGlyphCache**)context) = SkGlyphCache::DetachCache(desc); -} - SkGlyphCache* SkPaint::detachCache(const SkMatrix* deviceMatrix) const { SkGlyphCache* cache; @@ -1548,18 +1665,27 @@ void SkPaint::unflatten(SkFlattenableReadBuffer& buffer) { SkShader* SkPaint::setShader(SkShader* shader) { + if (shader != fShader) { + fGenerationID++; + } SkRefCnt_SafeAssign(fShader, shader); return shader; } SkColorFilter* SkPaint::setColorFilter(SkColorFilter* filter) { + if (filter != fColorFilter) { + fGenerationID++; + } SkRefCnt_SafeAssign(fColorFilter, filter); return filter; } SkXfermode* SkPaint::setXfermode(SkXfermode* mode) { + if (mode != fXfermode) { + fGenerationID++; + } SkRefCnt_SafeAssign(fXfermode, mode); return mode; } @@ -1567,17 +1693,24 @@ SkXfermode* SkPaint::setXfermode(SkXfermode* mode) SkXfermode* SkPaint::setXfermodeMode(SkXfermode::Mode mode) { SkSafeUnref(fXfermode); fXfermode = SkXfermode::Create(mode); + fGenerationID++; return fXfermode; } SkPathEffect* SkPaint::setPathEffect(SkPathEffect* effect) { + if (effect != fPathEffect) { + fGenerationID++; + } SkRefCnt_SafeAssign(fPathEffect, effect); return effect; } SkMaskFilter* SkPaint::setMaskFilter(SkMaskFilter* filter) { + if (filter != fMaskFilter) { + fGenerationID++; + } SkRefCnt_SafeAssign(fMaskFilter, filter); return filter; } diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp index 9c0b8af..62edb32 100644 --- a/src/core/SkPath.cpp +++ b/src/core/SkPath.cpp @@ -97,6 +97,7 @@ static void compute_pt_bounds(SkRect* bounds, const SkTDArray<SkPoint>& pts) { SkPath::SkPath() : fBoundsIsDirty(true), fFillType(kWinding_FillType) { fIsConvex = false; + fGenerationID = 0; } SkPath::SkPath(const SkPath& src) { @@ -118,6 +119,7 @@ SkPath& SkPath::operator=(const SkPath& src) { fFillType = src.fFillType; fBoundsIsDirty = src.fBoundsIsDirty; fIsConvex = src.fIsConvex; + fGenerationID++; } SkDEBUGCODE(this->validate();) return *this; @@ -140,14 +142,20 @@ void SkPath::swap(SkPath& other) { SkTSwap<uint8_t>(fFillType, other.fFillType); SkTSwap<uint8_t>(fBoundsIsDirty, other.fBoundsIsDirty); SkTSwap<uint8_t>(fIsConvex, other.fIsConvex); + fGenerationID++; } } +uint32_t SkPath::getGenerationID() const { + return fGenerationID; +} + void SkPath::reset() { SkDEBUGCODE(this->validate();) fPts.reset(); fVerbs.reset(); + fGenerationID++; fBoundsIsDirty = true; } @@ -156,6 +164,7 @@ void SkPath::rewind() { fPts.rewind(); fVerbs.rewind(); + fGenerationID++; fBoundsIsDirty = true; } @@ -212,6 +221,7 @@ void SkPath::setLastPt(SkScalar x, SkScalar y) { this->moveTo(x, y); } else { fPts[count - 1].set(x, y); + fGenerationID++; } } @@ -249,6 +259,7 @@ void SkPath::moveTo(SkScalar x, SkScalar y) { } pt->set(x, y); + fGenerationID++; fBoundsIsDirty = true; } @@ -268,6 +279,7 @@ void SkPath::lineTo(SkScalar x, SkScalar y) { fPts.append()->set(x, y); *fVerbs.append() = kLine_Verb; + fGenerationID++; fBoundsIsDirty = true; } @@ -290,6 +302,7 @@ void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { pts[1].set(x2, y2); *fVerbs.append() = kQuad_Verb; + fGenerationID++; fBoundsIsDirty = true; } @@ -313,6 +326,7 @@ void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, pts[2].set(x3, y3); *fVerbs.append() = kCubic_Verb; + fGenerationID++; fBoundsIsDirty = true; } @@ -334,6 +348,7 @@ void SkPath::close() { case kQuad_Verb: case kCubic_Verb: *fVerbs.append() = kClose_Verb; + fGenerationID++; break; default: // don't add a close if the prev wasn't a primitive @@ -936,6 +951,7 @@ void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const { matrix.mapRect(&dst->fBounds, fBounds); dst->fBoundsIsDirty = false; } else { + dst->fGenerationID++; dst->fBoundsIsDirty = true; } @@ -1243,6 +1259,7 @@ void SkPath::unflatten(SkFlattenableReadBuffer& buffer) { buffer.read(fPts.begin(), sizeof(SkPoint) * fPts.count()); buffer.read(fVerbs.begin(), fVerbs.count()); + fGenerationID++; fBoundsIsDirty = true; SkDEBUGCODE(this->validate();) diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp index f488565..c73e21c 100644 --- a/src/core/SkPicturePlayback.cpp +++ b/src/core/SkPicturePlayback.cpp @@ -528,6 +528,8 @@ void SkPicturePlayback::draw(SkCanvas& canvas) { SkipClipRec skipRect, skipRegion, skipPath; #endif + SkAutoMutexAcquire autoMutex(fDrawMutex); + TextContainer text; fReader.rewind(); diff --git a/src/core/SkPicturePlayback.h b/src/core/SkPicturePlayback.h index ae9641a..f5bf038 100644 --- a/src/core/SkPicturePlayback.h +++ b/src/core/SkPicturePlayback.h @@ -12,6 +12,7 @@ #include "SkRegion.h" #include "SkPictureFlat.h" #include "SkShape.h" +#include "SkThread.h" class SkPictureRecord; class SkStream; @@ -172,6 +173,7 @@ private: SkRefCntPlayback fRCPlayback; SkTypefacePlayback fTFPlayback; SkFactoryPlayback* fFactoryPlayback; + SkMutex fDrawMutex; }; #endif diff --git a/src/core/SkRegion.cpp b/src/core/SkRegion.cpp index 032dc81..a5a1555 100644 --- a/src/core/SkRegion.cpp +++ b/src/core/SkRegion.cpp @@ -783,7 +783,13 @@ static int operate( const SkRegion::RunType a_runs[], SkRegion::RunType dst[], SkRegion::Op op) { - const SkRegion::RunType sentinel = SkRegion::kRunTypeSentinel; + const SkRegion::RunType gSentinel[] = { + SkRegion::kRunTypeSentinel, + // just need a 2nd value, since spanRec.init() reads 2 values, even + // though if the first value is the sentinel, it ignores the 2nd value. + // w/o the 2nd value here, we might read uninitialized memory. + 0, + }; int a_top = *a_runs++; int a_bot = *a_runs++; @@ -803,8 +809,8 @@ static int operate( const SkRegion::RunType a_runs[], while (a_bot < SkRegion::kRunTypeSentinel || b_bot < SkRegion::kRunTypeSentinel) { int top, bot SK_INIT_TO_AVOID_WARNING; - const SkRegion::RunType* run0 = &sentinel; - const SkRegion::RunType* run1 = &sentinel; + const SkRegion::RunType* run0 = gSentinel; + const SkRegion::RunType* run1 = gSentinel; bool a_flush = false; bool b_flush = false; int inside; @@ -854,7 +860,7 @@ static int operate( const SkRegion::RunType a_runs[], } if (top > prevBot) - oper.addSpan(top, &sentinel, &sentinel); + oper.addSpan(top, gSentinel, gSentinel); // if ((unsigned)(inside - oper.fMin) <= (unsigned)(oper.fMax - oper.fMin)) { diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp index 8d1531a..7ed77b2 100644 --- a/src/core/SkXfermode.cpp +++ b/src/core/SkXfermode.cpp @@ -315,10 +315,12 @@ void SkProcXfermode::xferA8(SK_RESTRICT SkAlpha dst[], SkProcXfermode::SkProcXfermode(SkFlattenableReadBuffer& buffer) : SkXfermode(buffer) { fProc = (SkXfermodeProc)buffer.readFunctionPtr(); + fMode = (Mode) buffer.readInt(); } void SkProcXfermode::flatten(SkFlattenableWriteBuffer& buffer) { buffer.writeFunctionPtr((void*)fProc); + buffer.writeInt(fMode); } /////////////////////////////////////////////////////////////////////////////// @@ -941,30 +943,36 @@ SkXfermode* SkXfermode::Create(Mode mode) { SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount); SkASSERT((unsigned)mode < kModeCount); + SkXfermode* xferMode = NULL; switch (mode) { case kClear_Mode: - return SkNEW(SkClearXfermode); + xferMode = SkNEW(SkClearXfermode); + break; case kSrc_Mode: - return SkNEW(SkSrcXfermode); + xferMode = SkNEW(SkSrcXfermode); + break; case kSrcOver_Mode: return NULL; case kDstIn_Mode: - return SkNEW(SkDstInXfermode); + xferMode = SkNEW(SkDstInXfermode); + break; case kDstOut_Mode: - return SkNEW(SkDstOutXfermode); + xferMode = SkNEW(SkDstOutXfermode); + break; // use the table default: { const ProcCoeff& rec = gProcCoeffs[mode]; if ((unsigned)rec.fSC < SkXfermode::kCoeffCount && (unsigned)rec.fDC < SkXfermode::kCoeffCount) { - return SkNEW_ARGS(SkProcCoeffXfermode, (rec.fProc, - rec.fSC, - rec.fDC)); + xferMode = SkNEW_ARGS(SkProcCoeffXfermode, (rec.fProc, rec.fSC, rec.fDC)); } else { - return SkNEW_ARGS(SkProcXfermode, (rec.fProc)); + xferMode = SkNEW_ARGS(SkProcXfermode, (rec.fProc)); } + break; } } + xferMode->fMode = mode; + return xferMode; } bool SkXfermode::IsMode(SkXfermode* xfer, Mode* mode) { diff --git a/src/effects/SkBlurDrawLooper.cpp b/src/effects/SkBlurDrawLooper.cpp index 6ad0136..6ad4451 100644 --- a/src/effects/SkBlurDrawLooper.cpp +++ b/src/effects/SkBlurDrawLooper.cpp @@ -52,10 +52,17 @@ void SkBlurDrawLooper::init(SkCanvas* canvas, SkPaint* paint) bool SkBlurDrawLooper::next() { + SkColor blurColor; + SkAlpha alpha; switch (fState) { case kBeforeEdge: fSavedColor = fPaint->getColor(); - fPaint->setColor(fBlurColor); + blurColor = fBlurColor; + alpha = SkColorGetA(blurColor); + if (alpha == 255) { + blurColor = SkColorSetA(blurColor, fPaint->getAlpha()); + } + fPaint->setColor(blurColor); fPaint->setMaskFilter(fBlur); fCanvas->save(SkCanvas::kMatrix_SaveFlag); fCanvas->translate(fDx, fDy); diff --git a/src/effects/SkPorterDuff.cpp b/src/effects/SkPorterDuff.cpp index 58447ad..d0264ba 100644 --- a/src/effects/SkPorterDuff.cpp +++ b/src/effects/SkPorterDuff.cpp @@ -29,7 +29,8 @@ static const struct Pair { MAKE_PAIR(Lighten), MAKE_PAIR(Multiply), MAKE_PAIR(Screen), - { SkPorterDuff::kAdd_Mode, SkXfermode::kPlus_Mode } + { SkPorterDuff::kAdd_Mode, SkXfermode::kPlus_Mode }, + MAKE_PAIR(Overlay), }; static bool find_pdmode(SkXfermode::Mode src, SkPorterDuff::Mode* dst) { diff --git a/src/gl/SkGLCanvas.cpp b/src/gl/SkGLCanvas.cpp index f7bc96d..17e6016 100644 --- a/src/gl/SkGLCanvas.cpp +++ b/src/gl/SkGLCanvas.cpp @@ -1,180 +1,50 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include "SkGLCanvas.h" #include "SkGLDevice.h" -#include "SkBlitter.h" -#include "SkDraw.h" -#include "SkDrawProcs.h" -#include "SkGL.h" -#include "SkGlyphCache.h" -#include "SkTemplates.h" -#include "SkUtils.h" -#include "SkXfermode.h" - -#ifdef SK_GL_DEVICE_FBO - #define USE_FBO_DEVICE - #include "SkGLDevice_FBO.h" -#else - #define USE_SWLAYER_DEVICE - #include "SkGLDevice_SWLayer.h" -#endif - -// maximum number of entries in our texture cache (before purging) -#define kTexCountMax_Default 256 -// maximum number of bytes used (by gl) for the texture cache (before purging) -#define kTexSizeMax_Default (4 * 1024 * 1024) - -/////////////////////////////////////////////////////////////////////////////// - -SkGLCanvas::SkGLCanvas() { - glEnable(GL_TEXTURE_2D); - glEnable(GL_SCISSOR_TEST); - glEnableClientState(GL_VERTEX_ARRAY); - - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - fViewportSize.set(0, 0); -} - -SkGLCanvas::~SkGLCanvas() { - // call this now, while our override of restore() is in effect - this->restoreToCount(1); -} - -/////////////////////////////////////////////////////////////////////////////// - -bool SkGLCanvas::getViewport(SkIPoint* size) const { - if (size) { - *size = fViewportSize; - } - return true; -} - -bool SkGLCanvas::setViewport(int width, int height) { - fViewportSize.set(width, height); - - const bool isOpaque = false; // should this be a parameter to setViewport? - const bool isForLayer = false; // viewport is the base layer - SkDevice* device = this->createDevice(SkBitmap::kARGB_8888_Config, width, - height, isOpaque, isForLayer); - this->setDevice(device)->unref(); - - return true; -} - -SkDevice* SkGLCanvas::createDevice(SkBitmap::Config, int width, int height, - bool isOpaque, bool isForLayer) { - SkBitmap bitmap; - - bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); - bitmap.setIsOpaque(isOpaque); - -#ifdef USE_FBO_DEVICE - return SkNEW_ARGS(SkGLDevice_FBO, (bitmap, isForLayer)); -#elif defined(USE_SWLAYER_DEVICE) - if (isForLayer) { - bitmap.allocPixels(); - if (!bitmap.isOpaque()) { - bitmap.eraseColor(0); - } - return SkNEW_ARGS(SkGLDevice_SWLayer, (bitmap)); - } else { - return SkNEW_ARGS(SkGLDevice, (bitmap, isForLayer)); - } -#else - return SkNEW_ARGS(SkGLDevice, (bitmap, isForLayer)); -#endif -} -/////////////////////////////////////////////////////////////////////////////// - -#include "SkTextureCache.h" -#include "SkThread.h" - -static SkMutex gTextureCacheMutex; -static SkTextureCache gTextureCache(kTexCountMax_Default, kTexSizeMax_Default); - -SkGLDevice::TexCache* SkGLDevice::LockTexCache(const SkBitmap& bitmap, - GLuint* name, SkPoint* size) { - SkAutoMutexAcquire amc(gTextureCacheMutex); - - SkTextureCache::Entry* entry = gTextureCache.lock(bitmap); - if (NULL != entry) { - if (name) { - *name = entry->name(); - } - if (size) { - *size = entry->texSize(); - } - } - return (TexCache*)entry; -} - -void SkGLDevice::UnlockTexCache(TexCache* cache) { - SkAutoMutexAcquire amc(gTextureCacheMutex); - gTextureCache.unlock((SkTextureCache::Entry*)cache); -} - -// public exposure of texture cache settings +SkGLCanvas::SkGLCanvas() : SkCanvas(SkNEW(SkGLDeviceFactory)) {} +// static size_t SkGLCanvas::GetTextureCacheMaxCount() { - SkAutoMutexAcquire amc(gTextureCacheMutex); - return gTextureCache.getMaxCount(); -} - -size_t SkGLCanvas::GetTextureCacheMaxSize() { - SkAutoMutexAcquire amc(gTextureCacheMutex); - return gTextureCache.getMaxSize(); + return SkGLDevice::GetTextureCacheMaxCount(); } +// static void SkGLCanvas::SetTextureCacheMaxCount(size_t count) { - SkAutoMutexAcquire amc(gTextureCacheMutex); - gTextureCache.setMaxCount(count); + SkGLDevice::SetTextureCacheMaxCount(count); } -void SkGLCanvas::SetTextureCacheMaxSize(size_t size) { - SkAutoMutexAcquire amc(gTextureCacheMutex); - gTextureCache.setMaxSize(size); +// static +size_t SkGLCanvas::GetTextureCacheMaxSize() { + return SkGLDevice::GetTextureCacheMaxSize(); } -/////////////////////////////////////////////////////////////////////////////// - -#include "SkGLTextCache.h" - -static bool deleteCachesProc(SkGlyphCache* cache, void* texturesAreValid) { - void* auxData; - if (cache->getAuxProcData(SkGLDevice::GlyphCacheAuxProc, &auxData)) { - bool valid = texturesAreValid != NULL; - SkGLTextCache* textCache = static_cast<SkGLTextCache*>(auxData); - // call this before delete, in case valid is false - textCache->deleteAllStrikes(valid); - // now free the memory for the cache itself - SkDELETE(textCache); - // now remove the entry in the glyphcache (does not call the proc) - cache->removeAuxProc(SkGLDevice::GlyphCacheAuxProc); - } - return false; // keep going +// static +void SkGLCanvas::SetTextureCacheMaxSize(size_t size) { + SkGLDevice::SetTextureCacheMaxSize(size); } +// static void SkGLCanvas::DeleteAllTextures() { - // free the textures in our cache - - gTextureCacheMutex.acquire(); - gTextureCache.deleteAllCaches(true); - gTextureCacheMutex.release(); - - // now free the textures in the font cache - - SkGlyphCache::VisitAllCaches(deleteCachesProc, reinterpret_cast<void*>(true)); + SkGLDevice::DeleteAllTextures(); } +// static void SkGLCanvas::AbandonAllTextures() { - // abandon the textures in our cache - - gTextureCacheMutex.acquire(); - gTextureCache.deleteAllCaches(false); - gTextureCacheMutex.release(); - - // abandon the textures in the font cache - - SkGlyphCache::VisitAllCaches(deleteCachesProc, reinterpret_cast<void*>(false)); + SkGLDevice::AbandonAllTextures(); } - diff --git a/src/gl/SkGLDevice.cpp b/src/gl/SkGLDevice.cpp index d839498..ad4377c 100644 --- a/src/gl/SkGLDevice.cpp +++ b/src/gl/SkGLDevice.cpp @@ -4,6 +4,19 @@ #include "SkRegion.h" #include "SkThread.h" +#ifdef SK_GL_DEVICE_FBO + #define USE_FBO_DEVICE + #include "SkGLDevice_FBO.h" +#else + #define USE_SWLAYER_DEVICE + #include "SkGLDevice_SWLayer.h" +#endif + +// maximum number of entries in our texture cache (before purging) +#define kTexCountMax_Default 256 +// maximum number of bytes used (by gl) for the texture cache (before purging) +#define kTexSizeMax_Default (4 * 1024 * 1024) + static void TRACE_DRAW(const char func[], SkGLDevice* device, const SkDraw& draw) { // SkDebugf("--- <%s> %p %p\n", func, canvas, draw.fDevice); @@ -69,8 +82,39 @@ private: /////////////////////////////////////////////////////////////////////////////// +SkDevice* SkGLDeviceFactory::newDevice(SkBitmap::Config config, int width, + int height, bool isOpaque, + bool isForLayer) { + SkBitmap bitmap; + + bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); + bitmap.setIsOpaque(isOpaque); + +#ifdef USE_FBO_DEVICE + return SkNEW_ARGS(SkGLDevice_FBO, (bitmap, isForLayer)); +#elif defined(USE_SWLAYER_DEVICE) + if (isForLayer) { + bitmap.allocPixels(); + if (!bitmap.isOpaque()) { + bitmap.eraseColor(0); + } + return SkNEW_ARGS(SkGLDevice_SWLayer, (bitmap)); + } else { + return SkNEW_ARGS(SkGLDevice, (bitmap, isForLayer)); + } +#else + return SkNEW_ARGS(SkGLDevice, (bitmap, isForLayer)); +#endif +} + SkGLDevice::SkGLDevice(const SkBitmap& bitmap, bool offscreen) : SkDevice(bitmap), fClipIter(bitmap.height()) { + glEnable(GL_TEXTURE_2D); + glEnable(GL_SCISSOR_TEST); + glEnableClientState(GL_VERTEX_ARRAY); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + fDrawProcs = NULL; } @@ -811,3 +855,99 @@ void SkGLDevice::drawTextOnPath(const SkDraw& draw, const void* text, SkGL_unimpl("drawTextOnPath"); } +/////////////////////////////////////////////////////////////////////////////// + +#include "SkTextureCache.h" +#include "SkThread.h" + +static SkMutex gTextureCacheMutex; +static SkTextureCache gTextureCache(kTexCountMax_Default, kTexSizeMax_Default); + +SkGLDevice::TexCache* SkGLDevice::LockTexCache(const SkBitmap& bitmap, + GLuint* name, SkPoint* size) { + SkAutoMutexAcquire amc(gTextureCacheMutex); + + SkTextureCache::Entry* entry = gTextureCache.lock(bitmap); + if (NULL != entry) { + if (name) { + *name = entry->name(); + } + if (size) { + *size = entry->texSize(); + } + } + return (TexCache*)entry; +} + +void SkGLDevice::UnlockTexCache(TexCache* cache) { + SkAutoMutexAcquire amc(gTextureCacheMutex); + gTextureCache.unlock((SkTextureCache::Entry*)cache); +} + +// public exposure of texture cache settings + +size_t SkGLDevice::GetTextureCacheMaxCount() { + SkAutoMutexAcquire amc(gTextureCacheMutex); + return gTextureCache.getMaxCount(); +} + +size_t SkGLDevice::GetTextureCacheMaxSize() { + SkAutoMutexAcquire amc(gTextureCacheMutex); + return gTextureCache.getMaxSize(); +} + +void SkGLDevice::SetTextureCacheMaxCount(size_t count) { + SkAutoMutexAcquire amc(gTextureCacheMutex); + gTextureCache.setMaxCount(count); +} + +void SkGLDevice::SetTextureCacheMaxSize(size_t size) { + SkAutoMutexAcquire amc(gTextureCacheMutex); + gTextureCache.setMaxSize(size); +} + +/////////////////////////////////////////////////////////////////////////////// + +#include "SkGLTextCache.h" + +static bool deleteCachesProc(SkGlyphCache* cache, void* texturesAreValid) { + void* auxData; + if (cache->getAuxProcData(SkGLDevice::GlyphCacheAuxProc, &auxData)) { + bool valid = texturesAreValid != NULL; + SkGLTextCache* textCache = static_cast<SkGLTextCache*>(auxData); + // call this before delete, in case valid is false + textCache->deleteAllStrikes(valid); + // now free the memory for the cache itself + SkDELETE(textCache); + // now remove the entry in the glyphcache (does not call the proc) + cache->removeAuxProc(SkGLDevice::GlyphCacheAuxProc); + } + return false; // keep going +} + +void SkGLDevice::DeleteAllTextures() { + // free the textures in our cache + + gTextureCacheMutex.acquire(); + gTextureCache.deleteAllCaches(true); + gTextureCacheMutex.release(); + + // now free the textures in the font cache + + SkGlyphCache::VisitAllCaches(deleteCachesProc, reinterpret_cast<void*>(true) +); +} + +void SkGLDevice::AbandonAllTextures() { + // abandon the textures in our cache + + gTextureCacheMutex.acquire(); + gTextureCache.deleteAllCaches(false); + gTextureCacheMutex.release(); + + // abandon the textures in the font cache + + SkGlyphCache::VisitAllCaches(deleteCachesProc, reinterpret_cast<void*>(false +)); +} + diff --git a/src/gl/SkGLDevice.h b/src/gl/SkGLDevice.h index 0fc9e47..a939b07 100644 --- a/src/gl/SkGLDevice.h +++ b/src/gl/SkGLDevice.h @@ -5,6 +5,18 @@ #include "SkGL.h" #include "SkRegion.h" +#ifdef SK_BUILD_FOR_MAC + #include <OpenGL/gl.h> +#elif defined(ANDROID) + #include <GLES/gl.h> +#endif + +class SkGLDeviceFactory : public SkDeviceFactory { +public: + virtual SkDevice* newDevice(SkBitmap::Config config, int width, int height, + bool isOpaque, bool isForLayer); +}; + struct SkGLDrawProcs; class SkGLDevice : public SkDevice { @@ -12,6 +24,12 @@ public: SkGLDevice(const SkBitmap& bitmap, bool offscreen); virtual ~SkGLDevice(); + virtual SkDeviceFactory* getDeviceFactory() { + return SkNEW(SkGLDeviceFactory); + } + + virtual uint32_t getDeviceCapabilities() { return kGL_Capability; } + // used to identify GLTextCache data in the glyphcache static void GlyphCacheAuxProc(void* data); @@ -63,6 +81,27 @@ public: virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y, const SkPaint&); + // settings for the global texture cache + + static size_t GetTextureCacheMaxCount(); + static void SetTextureCacheMaxCount(size_t count); + + static size_t GetTextureCacheMaxSize(); + static void SetTextureCacheMaxSize(size_t size); + + /** Call glDeleteTextures for all textures (including those for text) + This should be called while the gl-context is still valid. Its purpose + is to free up gl resources. Note that if a bitmap or text is drawn after + this call, new caches will be created. + */ + static void DeleteAllTextures(); + + /** Forget all textures without calling delete (including those for text). + This should be called if the gl-context has changed, and the texture + IDs that have been cached are no longer valid. + */ + static void AbandonAllTextures(); + protected: /** Return the current glmatrix, from a previous call to setMatrixClip */ const SkMatrix& matrix() const { return fMatrix; } diff --git a/src/images/SkFlipPixelRef.cpp b/src/images/SkFlipPixelRef.cpp index 6f96b03..39e1a12 100644 --- a/src/images/SkFlipPixelRef.cpp +++ b/src/images/SkFlipPixelRef.cpp @@ -125,4 +125,3 @@ void SkFlipPixelRef::CopyBitsFromAddr(const SkBitmap& dst, const SkRegion& clip, iter.next(); } } - diff --git a/src/images/SkImageDecoder_Factory.cpp b/src/images/SkImageDecoder_Factory.cpp index bd81d1f..e7c71e5 100644 --- a/src/images/SkImageDecoder_Factory.cpp +++ b/src/images/SkImageDecoder_Factory.cpp @@ -24,10 +24,15 @@ typedef SkTRegistry<SkImageDecoder*, SkStream*> DecodeReg; template DecodeReg* DecodeReg::gHead; +#ifdef SK_ENABLE_LIBPNG + extern SkImageDecoder* sk_libpng_dfactory(SkStream*); +#endif + SkImageDecoder* SkImageDecoder::Factory(SkStream* stream) { + SkImageDecoder* codec = NULL; const DecodeReg* curr = DecodeReg::Head(); while (curr) { - SkImageDecoder* codec = curr->factory()(stream); + codec = curr->factory()(stream); // we rewind here, because we promise later when we call "decode", that // the stream will be at its beginning. stream->rewind(); @@ -36,6 +41,13 @@ SkImageDecoder* SkImageDecoder::Factory(SkStream* stream) { } curr = curr->next(); } +#ifdef SK_ENABLE_LIBPNG + codec = sk_libpng_dfactory(stream); + stream->rewind(); + if (codec) { + return codec; + } +#endif return NULL; } diff --git a/src/images/SkImageDecoder_libico.cpp b/src/images/SkImageDecoder_libico.cpp index ef5b7ac..52e9e4f 100644 --- a/src/images/SkImageDecoder_libico.cpp +++ b/src/images/SkImageDecoder_libico.cpp @@ -351,7 +351,7 @@ static void editPixelBit24(const int pixelNo, const unsigned char* buf, int alphaBit = (alphaByte & m) >> shift; //alphaBit == 1 => alpha = 0 int alpha = (alphaBit-1) & 0xFF; - *address = SkPackARGB32(alpha, red & alpha, green & alpha, blue & alpha); + *address = SkPreMultiplyARGB(alpha, red, green, blue); } static void editPixelBit32(const int pixelNo, const unsigned char* buf, @@ -364,7 +364,7 @@ static void editPixelBit32(const int pixelNo, const unsigned char* buf, int red = readByte(buf, xorOffset + 4*pixelNo + 2); int alphaBit = (alphaByte & m) >> shift; int alpha = readByte(buf, xorOffset + 4*pixelNo + 3) & ((alphaBit-1)&0xFF); - *address = SkPackARGB32(alpha, red & alpha, green & alpha, blue & alpha); + *address = SkPreMultiplyARGB(alpha, red, green, blue); } ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp index e3aefea..dc6ac5b 100644 --- a/src/images/SkImageDecoder_libjpeg.cpp +++ b/src/images/SkImageDecoder_libjpeg.cpp @@ -264,13 +264,9 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { if (config == SkBitmap::kARGB_8888_Config) { cinfo.out_color_space = JCS_RGBA_8888; } else if (config == SkBitmap::kRGB_565_Config) { - if (sampleSize == 1) { - // SkScaledBitmapSampler can't handle RGB_565 yet, - // so don't even try. - cinfo.out_color_space = JCS_RGB_565; - if (this->getDitherImage()) { - cinfo.dither_mode = JDITHER_ORDERED; - } + cinfo.out_color_space = JCS_RGB_565; + if (this->getDitherImage()) { + cinfo.dither_mode = JDITHER_ORDERED; } } #endif @@ -360,8 +356,8 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { #ifdef ANDROID_RGB } else if (JCS_RGBA_8888 == cinfo.out_color_space) { sc = SkScaledBitmapSampler::kRGBX; - //} else if (JCS_RGB_565 == cinfo.out_color_space) { - // sc = SkScaledBitmapSampler::kRGB_565; + } else if (JCS_RGB_565 == cinfo.out_color_space) { + sc = SkScaledBitmapSampler::kRGB_565; #endif } else if (1 == cinfo.out_color_components && JCS_GRAYSCALE == cinfo.out_color_space) { @@ -532,18 +528,18 @@ bool SkJPEGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect region) { config != SkBitmap::kRGB_565_Config) { config = SkBitmap::kARGB_8888_Config; } + + /* default format is RGB */ + cinfo->out_color_space = JCS_RGB; + #ifdef ANDROID_RGB cinfo->dither_mode = JDITHER_NONE; if (config == SkBitmap::kARGB_8888_Config) { cinfo->out_color_space = JCS_RGBA_8888; } else if (config == SkBitmap::kRGB_565_Config) { - if (requestedSampleSize == 1) { - // SkScaledBitmapSampler can't handle RGB_565 yet, - // so don't even try. - cinfo->out_color_space = JCS_RGB_565; - if (this->getDitherImage()) { - cinfo->dither_mode = JDITHER_ORDERED; - } + cinfo->out_color_space = JCS_RGB_565; + if (this->getDitherImage()) { + cinfo->dither_mode = JDITHER_ORDERED; } } #endif @@ -606,6 +602,8 @@ bool SkJPEGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect region) { #ifdef ANDROID_RGB } else if (JCS_RGBA_8888 == cinfo->out_color_space) { sc = SkScaledBitmapSampler::kRGBX; + } else if (JCS_RGB_565 == cinfo->out_color_space) { + sc = SkScaledBitmapSampler::kRGB_565; #endif } else if (1 == cinfo->out_color_components && JCS_GRAYSCALE == cinfo->out_color_space) { diff --git a/src/images/SkImageDecoder_libpng.cpp b/src/images/SkImageDecoder_libpng.cpp index 2b6a28e..e550767 100644 --- a/src/images/SkImageDecoder_libpng.cpp +++ b/src/images/SkImageDecoder_libpng.cpp @@ -62,10 +62,10 @@ public: delete index; } } - virtual bool buildTileIndex(SkStream *stream, - int *width, int *height, bool isShareable); protected: + virtual bool onBuildTileIndex(SkStream *stream, + int *width, int *height); virtual bool onDecodeRegion(SkBitmap* bitmap, SkIRect rect); virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode); @@ -419,33 +419,13 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, return true; } -bool SkPNGImageDecoder::buildTileIndex(SkStream* sk_stream, - int *width, int *height, bool isShareable) { +bool SkPNGImageDecoder::onBuildTileIndex(SkStream* sk_stream, int *width, + int *height) { png_structp png_ptr; png_infop info_ptr; this->index = new SkPNGImageIndex(); - if (!isShareable) { - size_t len, inputLen = 0; - size_t bufferSize = 4096; - void *tmp = sk_malloc_throw(bufferSize); - - while ((len = sk_stream->read((char*) tmp + inputLen, - bufferSize - inputLen)) != 0) { - inputLen += len; - if (inputLen == bufferSize) { - bufferSize *= 2; - tmp = sk_realloc_throw(tmp, bufferSize); - } - } - tmp = sk_realloc_throw(tmp, inputLen); - - SkMemoryStream *mem_stream = new SkMemoryStream(tmp, inputLen, true); - this->index->inputStream = mem_stream; - sk_stream = mem_stream; - } - if (onDecodeInit(sk_stream, &png_ptr, &info_ptr) == false) { return false; } @@ -1148,7 +1128,12 @@ bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, #include "SkTRegistry.h" -static SkImageDecoder* DFactory(SkStream* stream) { +#ifdef SK_ENABLE_LIBPNG + SkImageDecoder* sk_libpng_dfactory(SkStream*); + SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type); +#endif + +SkImageDecoder* sk_libpng_dfactory(SkStream* stream) { char buf[PNG_BYTES_TO_CHECK]; if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK && !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { @@ -1157,9 +1142,9 @@ static SkImageDecoder* DFactory(SkStream* stream) { return NULL; } -static SkImageEncoder* EFactory(SkImageEncoder::Type t) { +SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL; } -static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(EFactory); -static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(DFactory); +static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libpng_efactory); +static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libpng_dfactory); diff --git a/src/images/SkImageEncoder_Factory.cpp b/src/images/SkImageEncoder_Factory.cpp index d673167..0bb4d1a 100644 --- a/src/images/SkImageEncoder_Factory.cpp +++ b/src/images/SkImageEncoder_Factory.cpp @@ -21,15 +21,24 @@ typedef SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> EncodeReg; template EncodeReg* EncodeReg::gHead; +#ifdef SK_ENABLE_LIBPNG + extern SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type); +#endif + SkImageEncoder* SkImageEncoder::Create(Type t) { + SkImageEncoder* codec = NULL; const EncodeReg* curr = EncodeReg::Head(); while (curr) { - SkImageEncoder* codec = curr->factory()(t); - if (codec) { + if ((codec = curr->factory()(t)) != NULL) { return codec; } curr = curr->next(); } +#ifdef SK_ENABLE_LIBPNG + if ((codec = sk_libpng_efactory(t)) != NULL) { + return codec; + } +#endif return NULL; } diff --git a/src/images/SkImageRef_GlobalPool.cpp b/src/images/SkImageRef_GlobalPool.cpp index 33a3c46..1f44a84 100644 --- a/src/images/SkImageRef_GlobalPool.cpp +++ b/src/images/SkImageRef_GlobalPool.cpp @@ -80,4 +80,3 @@ void SkImageRef_GlobalPool::DumpPool() { SkAutoMutexAcquire ac(gImageRefMutex); gGlobalImageRefPool.dump(); } - diff --git a/src/images/SkScaledBitmapSampler.cpp b/src/images/SkScaledBitmapSampler.cpp index 3ba38f7..32b78ef 100644 --- a/src/images/SkScaledBitmapSampler.cpp +++ b/src/images/SkScaledBitmapSampler.cpp @@ -93,6 +93,18 @@ static bool Sample_RGBx_D565(void* SK_RESTRICT dstRow, return false; } +static bool Sample_D565_D565(void* SK_RESTRICT dstRow, + const uint8_t* SK_RESTRICT src, + int width, int deltaSrc, int, const SkPMColor[]) { + uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; + uint16_t* SK_RESTRICT castedSrc = (uint16_t*) src; + for (int x = 0; x < width; x++) { + dst[x] = castedSrc[0]; + castedSrc += deltaSrc >> 1; + } + return false; +} + static bool Sample_RGBx_D565_D(void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, int deltaSrc, int y, const SkPMColor[]) { @@ -335,21 +347,25 @@ bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, bool dither, Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBA_D8888, Sample_RGBA_D8888, Sample_Index_D8888, Sample_Index_D8888, + NULL, NULL, // 565 (no alpha distinction) Sample_Gray_D565, Sample_Gray_D565_D, Sample_RGBx_D565, Sample_RGBx_D565_D, Sample_RGBx_D565, Sample_RGBx_D565_D, Sample_Index_D565, Sample_Index_D565_D, + Sample_D565_D565, Sample_D565_D565, // 4444 Sample_Gray_D4444, Sample_Gray_D4444_D, Sample_RGBx_D4444, Sample_RGBx_D4444_D, Sample_RGBA_D4444, Sample_RGBA_D4444_D, Sample_Index_D4444, Sample_Index_D4444_D, + NULL, NULL, // Index8 NULL, NULL, NULL, NULL, NULL, NULL, Sample_Index_DI, Sample_Index_DI, + NULL, NULL, }; fCTable = ctable; @@ -379,6 +395,10 @@ bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, bool dither, fSrcPixelSize = 1; index += 6; break; + case SkScaledBitmapSampler::kRGB_565: + fSrcPixelSize = 2; + index += 8; + break; default: return false; } @@ -388,13 +408,13 @@ bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, bool dither, index += 0; break; case SkBitmap::kRGB_565_Config: - index += 8; + index += 10; break; case SkBitmap::kARGB_4444_Config: - index += 16; + index += 20; break; case SkBitmap::kIndex8_Config: - index += 24; + index += 30; break; default: return false; diff --git a/src/images/SkScaledBitmapSampler.h b/src/images/SkScaledBitmapSampler.h index 84a75ba..43f1669 100644 --- a/src/images/SkScaledBitmapSampler.h +++ b/src/images/SkScaledBitmapSampler.h @@ -21,7 +21,8 @@ public: kIndex, // 1 byte per pixel kRGB, // 3 bytes per pixel kRGBX, // 4 byes per pixel (ignore 4th) - kRGBA // 4 bytes per pixel + kRGBA, // 4 bytes per pixel + kRGB_565 // 2 bytes per pixel }; // Given a dst bitmap (with pixels already allocated) and a src-config, diff --git a/src/ports/SkImageRef_ashmem.cpp b/src/ports/SkImageRef_ashmem.cpp index a904bae..5dd3a59 100644 --- a/src/ports/SkImageRef_ashmem.cpp +++ b/src/ports/SkImageRef_ashmem.cpp @@ -1,5 +1,6 @@ #include "SkImageRef_ashmem.h" #include "SkImageDecoder.h" +#include "SkFlattenable.h" #include "SkThread.h" #include <sys/mman.h> @@ -201,3 +202,36 @@ void SkImageRef_ashmem::onUnlockPixels() { fBitmap.setPixels(NULL, NULL); } +void SkImageRef_ashmem::flatten(SkFlattenableWriteBuffer& buffer) const { + this->INHERITED::flatten(buffer); + const char* uri = getURI(); + if (uri) { + size_t len = strlen(uri); + buffer.write32(len); + buffer.writePad(uri, len); + } else { + buffer.write32(0); + } +} + +SkImageRef_ashmem::SkImageRef_ashmem(SkFlattenableReadBuffer& buffer) + : INHERITED(buffer) { + fRec.fFD = -1; + fRec.fAddr = NULL; + fRec.fSize = 0; + fRec.fPinned = false; + fCT = NULL; + size_t length = buffer.readU32(); + if (length) { + char* buf = (char*) malloc(length); + buffer.read(buf, length); + setURI(buf, length); + } +} + +SkPixelRef* SkImageRef_ashmem::Create(SkFlattenableReadBuffer& buffer) { + return SkNEW_ARGS(SkImageRef_ashmem, (buffer)); +} + +static SkPixelRef::Registrar reg("SkImageRef_ashmem", + SkImageRef_ashmem::Create); diff --git a/src/ports/SkImageRef_ashmem.h b/src/ports/SkImageRef_ashmem.h index 193a01d..2c485e3 100644 --- a/src/ports/SkImageRef_ashmem.h +++ b/src/ports/SkImageRef_ashmem.h @@ -15,6 +15,13 @@ public: SkImageRef_ashmem(SkStream*, SkBitmap::Config, int sampleSize = 1); virtual ~SkImageRef_ashmem(); + // overrides + virtual void flatten(SkFlattenableWriteBuffer&) const; + virtual Factory getFactory() const { + return Create; + } + static SkPixelRef* Create(SkFlattenableReadBuffer&); + protected: virtual bool onDecode(SkImageDecoder* codec, SkStream* stream, SkBitmap* bitmap, SkBitmap::Config config, @@ -24,6 +31,7 @@ protected: virtual void onUnlockPixels(); private: + SkImageRef_ashmem(SkFlattenableReadBuffer&); void closeFD(); SkColorTable* fCT; diff --git a/src/utils/SkCullPoints.cpp b/src/utils/SkCullPoints.cpp index 23d00b6..03bfa99 100644 --- a/src/utils/SkCullPoints.cpp +++ b/src/utils/SkCullPoints.cpp @@ -18,8 +18,7 @@ #include "SkCullPoints.h" #include "Sk64.h" -static bool cross_product_is_neg(const SkIPoint& v, int dx, int dy) -{ +static bool cross_product_is_neg(const SkIPoint& v, int dx, int dy) { #if 0 return v.fX * dy - v.fY * dx < 0; #else @@ -32,19 +31,20 @@ static bool cross_product_is_neg(const SkIPoint& v, int dx, int dy) #endif } -bool SkCullPoints::sect_test(int x0, int y0, int x1, int y1) const -{ +bool SkCullPoints::sect_test(int x0, int y0, int x1, int y1) const { const SkIRect& r = fR; - if (x0 < r.fLeft && x1 < r.fLeft || - x0 > r.fRight && x1 > r.fRight || - y0 < r.fTop && y1 < r.fTop || - y0 > r.fBottom && y1 > r.fBottom) + if ((x0 < r.fLeft && x1 < r.fLeft) || + (x0 > r.fRight && x1 > r.fRight) || + (y0 < r.fTop && y1 < r.fTop) || + (y0 > r.fBottom && y1 > r.fBottom)) { return false; + } // since the crossprod test is a little expensive, check for easy-in cases first - if (r.contains(x0, y0) || r.contains(x1, y1)) + if (r.contains(x0, y0) || r.contains(x1, y1)) { return true; + } // At this point we're not sure, so we do a crossprod test SkIPoint vec; @@ -53,16 +53,14 @@ bool SkCullPoints::sect_test(int x0, int y0, int x1, int y1) const vec.set(x1 - x0, y1 - y0); bool isNeg = cross_product_is_neg(vec, x0 - rAsQuad[0].fX, y0 - rAsQuad[0].fY); for (int i = 1; i < 4; i++) { - if (cross_product_is_neg(vec, x0 - rAsQuad[i].fX, y0 - rAsQuad[i].fY) != isNeg) - { + if (cross_product_is_neg(vec, x0 - rAsQuad[i].fX, y0 - rAsQuad[i].fY) != isNeg) { return true; } } return false; // we didn't intersect } -static void toQuad(const SkIRect& r, SkIPoint quad[4]) -{ +static void toQuad(const SkIRect& r, SkIPoint quad[4]) { SkASSERT(quad); quad[0].set(r.fLeft, r.fTop); @@ -71,34 +69,29 @@ static void toQuad(const SkIRect& r, SkIPoint quad[4]) quad[3].set(r.fLeft, r.fBottom); } -SkCullPoints::SkCullPoints() -{ +SkCullPoints::SkCullPoints() { SkIRect r; r.setEmpty(); this->reset(r); } -SkCullPoints::SkCullPoints(const SkIRect& r) -{ +SkCullPoints::SkCullPoints(const SkIRect& r) { this->reset(r); } -void SkCullPoints::reset(const SkIRect& r) -{ +void SkCullPoints::reset(const SkIRect& r) { fR = r; toQuad(fR, fAsQuad); fPrevPt.set(0, 0); fPrevResult = kNo_Result; } -void SkCullPoints::moveTo(int x, int y) -{ +void SkCullPoints::moveTo(int x, int y) { fPrevPt.set(x, y); fPrevResult = kNo_Result; // so we trigger a movetolineto later } -SkCullPoints::LineToResult SkCullPoints::lineTo(int x, int y, SkIPoint line[]) -{ +SkCullPoints::LineToResult SkCullPoints::lineTo(int x, int y, SkIPoint line[]) { SkASSERT(line != NULL); LineToResult result = kNo_Result; @@ -108,15 +101,15 @@ SkCullPoints::LineToResult SkCullPoints::lineTo(int x, int y, SkIPoint line[]) // need to upgrade sect_test to chop the result // and to correctly return kLineTo_Result when the result is connected // to the previous call-out - if (this->sect_test(x0, y0, x, y)) - { + if (this->sect_test(x0, y0, x, y)) { line[0].set(x0, y0); line[1].set(x, y); - if (fPrevResult != kNo_Result && fPrevPt.equals(x0, y0)) + if (fPrevResult != kNo_Result && fPrevPt.equals(x0, y0)) { result = kLineTo_Result; - else + } else { result = kMoveToLineTo_Result; + } } fPrevPt.set(x, y); @@ -130,28 +123,23 @@ SkCullPoints::LineToResult SkCullPoints::lineTo(int x, int y, SkIPoint line[]) #include "SkPath.h" SkCullPointsPath::SkCullPointsPath() - : fCP(), fPath(NULL) -{ + : fCP(), fPath(NULL) { } SkCullPointsPath::SkCullPointsPath(const SkIRect& r, SkPath* dst) - : fCP(r), fPath(dst) -{ + : fCP(r), fPath(dst) { } -void SkCullPointsPath::reset(const SkIRect& r, SkPath* dst) -{ +void SkCullPointsPath::reset(const SkIRect& r, SkPath* dst) { fCP.reset(r); fPath = dst; } - -void SkCullPointsPath::moveTo(int x, int y) -{ + +void SkCullPointsPath::moveTo(int x, int y) { fCP.moveTo(x, y); } -void SkCullPointsPath::lineTo(int x, int y) -{ +void SkCullPointsPath::lineTo(int x, int y) { SkIPoint pts[2]; switch (fCP.lineTo(x, y, pts)) { diff --git a/src/utils/SkDumpCanvas.cpp b/src/utils/SkDumpCanvas.cpp index 737307c..4ff7a50 100644 --- a/src/utils/SkDumpCanvas.cpp +++ b/src/utils/SkDumpCanvas.cpp @@ -121,8 +121,7 @@ static void toString(const SkBitmap& bm, SkString* str) { } static void toString(const void* text, size_t len, SkPaint::TextEncoding enc, - SkString* str, const SkPaint& paint, - const SkScalar xpos[] = NULL) { + SkString* str) { switch (enc) { case SkPaint::kUTF8_TextEncoding: str->printf("\"%.*s\"%s", SkMax32(len, 32), text, @@ -132,21 +131,9 @@ static void toString(const void* text, size_t len, SkPaint::TextEncoding enc, str->printf("\"%.*S\"%s", SkMax32(len, 32), text, len > 64 ? "..." : ""); break; - case SkPaint::kGlyphID_TextEncoding: { - const uint16_t* glyphs = (const uint16_t*)text; - const int max = 32; - SkUnichar uni[max]; - int count = SkMin32(len >> 1, max); - paint.glyphsToUnichars(glyphs, count, uni); - str->append("\""); - for (int i = 0; i < count; i++) { - str->appendUnichar(uni[i]); - } - if ((size_t)count < (len >> 1)) { - str->append("..."); - } - str->append("\""); - } break; + case SkPaint::kGlyphID_TextEncoding: + str->set("<glyphs>"); + break; } } @@ -331,7 +318,7 @@ void SkDumpCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, void SkDumpCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { SkString str; - toString(text, byteLength, paint.getTextEncoding(), &str, paint); + toString(text, byteLength, paint.getTextEncoding(), &str); this->dump(kDrawText_Verb, &paint, "drawText(%s [%d] %g %g)", str.c_str(), byteLength, SkScalarToFloat(x), SkScalarToFloat(y)); } @@ -339,7 +326,7 @@ void SkDumpCanvas::drawText(const void* text, size_t byteLength, SkScalar x, void SkDumpCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint) { SkString str; - toString(text, byteLength, paint.getTextEncoding(), &str, paint); + toString(text, byteLength, paint.getTextEncoding(), &str); this->dump(kDrawText_Verb, &paint, "drawPosText(%s [%d] %g %g ...)", str.c_str(), byteLength, SkScalarToFloat(pos[0].fX), SkScalarToFloat(pos[0].fY)); @@ -349,7 +336,7 @@ void SkDumpCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint& paint) { SkString str; - toString(text, byteLength, paint.getTextEncoding(), &str, paint, xpos); + toString(text, byteLength, paint.getTextEncoding(), &str); this->dump(kDrawText_Verb, &paint, "drawPosTextH(%s [%d] %g %g ...)", str.c_str(), byteLength, SkScalarToFloat(xpos[0]), SkScalarToFloat(constY)); @@ -359,7 +346,7 @@ void SkDumpCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) { SkString str; - toString(text, byteLength, paint.getTextEncoding(), &str, paint); + toString(text, byteLength, paint.getTextEncoding(), &str); this->dump(kDrawText_Verb, &paint, "drawTextOnPath(%s [%d])", str.c_str(), byteLength); } diff --git a/src/utils/SkNinePatch.cpp b/src/utils/SkNinePatch.cpp index 3d85edc..0b601eb 100644 --- a/src/utils/SkNinePatch.cpp +++ b/src/utils/SkNinePatch.cpp @@ -235,15 +235,27 @@ static void drawNineViaRects(SkCanvas* canvas, const SkRect& dst, const int32_t srcY[4] = { 0, margins.fTop, bitmap.height() - margins.fBottom, bitmap.height() }; - const SkScalar dstX[4] = { + SkScalar dstX[4] = { dst.fLeft, dst.fLeft + SkIntToScalar(margins.fLeft), dst.fRight - SkIntToScalar(margins.fRight), dst.fRight }; - const SkScalar dstY[4] = { + SkScalar dstY[4] = { dst.fTop, dst.fTop + SkIntToScalar(margins.fTop), dst.fBottom - SkIntToScalar(margins.fBottom), dst.fBottom }; - + + if (dstX[1] > dstX[2]) { + dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * SkIntToScalar(margins.fLeft) / + (SkIntToScalar(margins.fLeft) + SkIntToScalar(margins.fRight)); + dstX[2] = dstX[1]; + } + + if (dstY[1] > dstY[2]) { + dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * SkIntToScalar(margins.fTop) / + (SkIntToScalar(margins.fTop) + SkIntToScalar(margins.fBottom)); + dstY[2] = dstY[1]; + } + SkIRect s; SkRect d; for (int y = 0; y < 3; y++) { @@ -278,6 +290,17 @@ void SkNinePatch::DrawNine(SkCanvas* canvas, const SkRect& bounds, xDivs[1] = bitmap.width() - margins.fRight; yDivs[0] = margins.fTop; yDivs[1] = bitmap.height() - margins.fBottom; + + if (xDivs[0] > xDivs[1]) { + xDivs[0] = bitmap.width() * margins.fLeft / + (margins.fLeft + margins.fRight); + xDivs[1] = xDivs[0]; + } + if (yDivs[0] > yDivs[1]) { + yDivs[0] = bitmap.height() * margins.fTop / + (margins.fTop + margins.fBottom); + yDivs[1] = yDivs[0]; + } SkNinePatch::DrawMesh(canvas, bounds, bitmap, xDivs, 2, yDivs, 2, paint); diff --git a/tests/MathTest.cpp b/tests/MathTest.cpp index dec93de..4bfbd94 100644 --- a/tests/MathTest.cpp +++ b/tests/MathTest.cpp @@ -1,4 +1,5 @@ #include "Test.h" +#include "SkFloatingPoint.h" #include "SkPoint.h" #include "SkRandom.h" |