diff --git a/gyp/effects.gyp b/gyp/effects.gyp index 63b8636500..6cc790c377 100644 --- a/gyp/effects.gyp +++ b/gyp/effects.gyp @@ -9,7 +9,7 @@ 'dependencies': [ 'core.gyp:*', 'images.gyp:*', - 'utils.gyp:*', + 'utils.gyp:utils', ], 'includes': [ 'effects.gypi', diff --git a/gyp/gpu.gyp b/gyp/gpu.gyp index c69a4867d6..8569b5a924 100644 --- a/gyp/gpu.gyp +++ b/gyp/gpu.gyp @@ -85,7 +85,7 @@ 'standalone_static_library': 1, 'dependencies': [ 'core.gyp:*', - 'utils.gyp:*', + 'utils.gyp:utils', 'etc1.gyp:libetc1', 'ktx.gyp:libSkKTX', ], diff --git a/gyp/utils.gyp b/gyp/utils.gyp index 19816f88e4..d3d14d86e1 100644 --- a/gyp/utils.gyp +++ b/gyp/utils.gyp @@ -124,5 +124,23 @@ ], }, }, + { + 'target_name': 'android_utils', + 'product_name': 'skia_android_utils', + 'type': 'static_library', + 'standalone_static_library': 1, + 'dependencies': [ + 'core.gyp:*', + ], + 'sources': [ + '../src/utils/android/SkAndroidSDKCanvas.h', + '../src/utils/android/SkAndroidSDKCanvas.cpp', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../src/utils/android', + ], + }, + }, ], } diff --git a/src/utils/android/SkAndroidSDKCanvas.cpp b/src/utils/android/SkAndroidSDKCanvas.cpp new file mode 100644 index 0000000000..d02fd72620 --- /dev/null +++ b/src/utils/android/SkAndroidSDKCanvas.cpp @@ -0,0 +1,316 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkAndroidSDKCanvas.h" + +#include "SkColorFilter.h" +#include "SkPathEffect.h" +#include "SkShader.h" + +namespace { + +/** Discard SkShaders not exposed by the Android Java API. */ + +void CheckShader(SkPaint* paint) { + SkShader* shader = paint->getShader(); + if (!shader) { + return; + } + + if (shader->asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType) { + return; + } + if (shader->asACompose(NULL)) { + return; + } + SkShader::GradientType gtype = shader->asAGradient(NULL); + if (gtype == SkShader::kLinear_GradientType || + gtype == SkShader::kRadial_GradientType || + gtype == SkShader::kSweep_GradientType) { + return; + } + paint->setShader(NULL); +} + +void Filter(SkPaint* paint) { + + uint32_t flags = paint->getFlags(); + flags &= ~SkPaint::kLCDRenderText_Flag; + paint->setFlags(flags); + + // Android doesn't support Xfermodes above kLighten_Mode + SkXfermode::Mode mode; + SkXfermode::AsMode(paint->getXfermode(), &mode); + if (mode > SkXfermode::kLighten_Mode) { + paint->setXfermode(NULL); + } + + // Force bilinear scaling or none + if (paint->getFilterQuality() != kNone_SkFilterQuality) { + paint->setFilterQuality(kLow_SkFilterQuality); + } + + CheckShader(paint); + + // Android SDK only supports mode & matrix color filters + // (and, again, no modes above kLighten_Mode). + SkColorFilter* cf = paint->getColorFilter(); + if (cf) { + SkColor color; + SkXfermode::Mode mode; + SkScalar srcColorMatrix[20]; + bool isMode = cf->asColorMode(&color, &mode); + if (isMode && mode > SkXfermode::kLighten_Mode) { + paint->setColorFilter( + SkColorFilter::CreateModeFilter(color, SkXfermode::kSrcOver_Mode)); + } else if (!isMode && !cf->asColorMatrix(srcColorMatrix)) { + paint->setColorFilter(NULL); + } + } + +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + SkPathEffect* pe = paint->getPathEffect(); + if (pe && !pe->exposedInAndroidJavaAPI()) { + paint->setPathEffect(NULL); + } +#endif + + // TODO: Android doesn't support all the flags that can be passed to + // blur filters; we need plumbing to get them out. + + paint->setImageFilter(NULL); + paint->setLooper(NULL); +}; + +} // namespace + +#define FILTER(p) \ + SkPaint filteredPaint(p); \ + Filter(&filteredPaint); + +#define FILTER_PTR(p) \ + SkTLazy lazyPaint; \ + SkPaint* filteredPaint = (SkPaint*) p; \ + if (p) { \ + filteredPaint = lazyPaint.set(*p); \ + Filter(filteredPaint); \ + } + + +SkAndroidSDKCanvas::SkAndroidSDKCanvas() : fProxyTarget(NULL) { } + +void SkAndroidSDKCanvas::reset(SkCanvas* newTarget) { fProxyTarget = newTarget; } + +void SkAndroidSDKCanvas::onDrawPaint(const SkPaint& paint) { + FILTER(paint); + fProxyTarget->drawPaint(filteredPaint); +} +void SkAndroidSDKCanvas::onDrawPoints(PointMode pMode, + size_t count, + const SkPoint pts[], + const SkPaint& paint) { + FILTER(paint); + fProxyTarget->drawPoints(pMode, count, pts, filteredPaint); +} +void SkAndroidSDKCanvas::onDrawOval(const SkRect& r, const SkPaint& paint) { + FILTER(paint); + fProxyTarget->drawOval(r, filteredPaint); +} +void SkAndroidSDKCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) { + FILTER(paint); + fProxyTarget->drawRect(r, filteredPaint); +} +void SkAndroidSDKCanvas::onDrawRRect(const SkRRect& r, const SkPaint& paint) { + FILTER(paint); + fProxyTarget->drawRRect(r, filteredPaint); +} +void SkAndroidSDKCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { + FILTER(paint); + fProxyTarget->drawPath(path, filteredPaint); +} +void SkAndroidSDKCanvas::onDrawBitmap(const SkBitmap& bitmap, + SkScalar left, + SkScalar top, + const SkPaint* paint) { + FILTER_PTR(paint); + fProxyTarget->drawBitmap(bitmap, left, top, filteredPaint); +} +void SkAndroidSDKCanvas::onDrawBitmapRect(const SkBitmap& bitmap, + const SkRect* src, + const SkRect& dst, + const SkPaint* paint, + DrawBitmapRectFlags flags) { + FILTER_PTR(paint); + fProxyTarget->drawBitmapRectToRect(bitmap, src, dst, filteredPaint, flags); +} +void SkAndroidSDKCanvas::onDrawBitmapNine(const SkBitmap& bitmap, + const SkIRect& center, + const SkRect& dst, + const SkPaint* paint) { + FILTER_PTR(paint); + fProxyTarget->drawBitmapNine(bitmap, center, dst, filteredPaint); +} +void SkAndroidSDKCanvas::onDrawSprite(const SkBitmap& bitmap, + int left, + int top, + const SkPaint* paint) { + FILTER_PTR(paint); + fProxyTarget->drawSprite(bitmap, left, top, filteredPaint); +} +void SkAndroidSDKCanvas::onDrawVertices(VertexMode vMode, + int vertexCount, + const SkPoint vertices[], + const SkPoint texs[], const SkColor colors[], SkXfermode* xMode, + const uint16_t indices[], int indexCount, + const SkPaint& paint) { + FILTER(paint); + fProxyTarget->drawVertices(vMode, vertexCount, vertices, texs, colors, + xMode, indices, indexCount, filteredPaint); +} + +void SkAndroidSDKCanvas::onDrawDRRect(const SkRRect& outer, + const SkRRect& inner, + const SkPaint& paint) { + FILTER(paint); + fProxyTarget->drawDRRect(outer, inner, filteredPaint); +} + +void SkAndroidSDKCanvas::onDrawText(const void* text, + size_t byteLength, + SkScalar x, + SkScalar y, + const SkPaint& paint) { + FILTER(paint); + fProxyTarget->drawText(text, byteLength, x, y, filteredPaint); +} +void SkAndroidSDKCanvas::onDrawPosText(const void* text, + size_t byteLength, + const SkPoint pos[], + const SkPaint& paint) { + FILTER(paint); + fProxyTarget->drawPosText(text, byteLength, pos, filteredPaint); +} +void SkAndroidSDKCanvas::onDrawPosTextH(const void* text, + size_t byteLength, + const SkScalar xpos[], + SkScalar constY, + const SkPaint& paint) { + FILTER(paint); + fProxyTarget->drawPosTextH(text, byteLength, xpos, constY, filteredPaint); +} +void SkAndroidSDKCanvas::onDrawTextOnPath(const void* text, + size_t byteLength, + const SkPath& path, + const SkMatrix* matrix, + const SkPaint& paint) { + FILTER(paint); + fProxyTarget->drawTextOnPath(text, byteLength, path, matrix, filteredPaint); +} +void SkAndroidSDKCanvas::onDrawTextBlob(const SkTextBlob* blob, + SkScalar x, + SkScalar y, + const SkPaint& paint) { + FILTER(paint); + fProxyTarget->drawTextBlob(blob, x, y, filteredPaint); +} + +void SkAndroidSDKCanvas::onDrawPatch(const SkPoint cubics[12], + const SkColor colors[4], + const SkPoint texCoords[4], + SkXfermode* xmode, + const SkPaint& paint) { + FILTER(paint); + fProxyTarget->drawPatch(cubics, colors, texCoords, xmode, filteredPaint); +} + + +void SkAndroidSDKCanvas::onDrawImage(const SkImage* image, + SkScalar x, + SkScalar y, + const SkPaint* paint) { + FILTER_PTR(paint); + fProxyTarget->drawImage(image, x, y, filteredPaint); +} + +void SkAndroidSDKCanvas::onDrawImageRect(const SkImage* image, + const SkRect* in, + const SkRect& out, + const SkPaint* paint) { + FILTER_PTR(paint); + fProxyTarget->drawImageRect(image, in, out, filteredPaint); +} + +void SkAndroidSDKCanvas::onDrawPicture(const SkPicture* picture, + const SkMatrix* matrix, + const SkPaint* paint) { + FILTER_PTR(paint); + fProxyTarget->drawPicture(picture, matrix, filteredPaint); +} + +void SkAndroidSDKCanvas::onDrawDrawable(SkDrawable* drawable) { + fProxyTarget->drawDrawable(drawable); +} + +SkISize SkAndroidSDKCanvas::getBaseLayerSize() const { + return fProxyTarget->getBaseLayerSize(); +} +bool SkAndroidSDKCanvas::getClipBounds(SkRect* rect) const { + return fProxyTarget->getClipBounds(rect); +} +bool SkAndroidSDKCanvas::getClipDeviceBounds(SkIRect* rect) const { + return fProxyTarget->getClipDeviceBounds(rect); +} + +bool SkAndroidSDKCanvas::isClipEmpty() const { return fProxyTarget->isClipEmpty(); } +bool SkAndroidSDKCanvas::isClipRect() const { return fProxyTarget->isClipRect(); } + +SkSurface* SkAndroidSDKCanvas::onNewSurface(const SkImageInfo& info, + const SkSurfaceProps& props) { + return fProxyTarget->newSurface(info, &props); +} + +const void* SkAndroidSDKCanvas::onPeekPixels(SkImageInfo* info, size_t* data) { + return fProxyTarget->peekPixels(info, data); +} + +void* SkAndroidSDKCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* data) { + return fProxyTarget->accessTopLayerPixels(info, data); +} + +void SkAndroidSDKCanvas::willSave() { fProxyTarget->save(); } +void SkAndroidSDKCanvas::willRestore() { fProxyTarget->restore(); } +void SkAndroidSDKCanvas::didRestore() { } +void SkAndroidSDKCanvas::didConcat(const SkMatrix& m) { + fProxyTarget->concat(m); +} +void SkAndroidSDKCanvas::didSetMatrix(const SkMatrix& m) { fProxyTarget->setMatrix(m); } + +void SkAndroidSDKCanvas::onClipRect(const SkRect& rect, + SkRegion::Op op, + ClipEdgeStyle style) { + fProxyTarget->clipRect(rect, op, style); +} + +void SkAndroidSDKCanvas::onClipRRect(const SkRRect& rrect, + SkRegion::Op op, + ClipEdgeStyle style) { + fProxyTarget->clipRRect(rrect, op, style); +} + +void SkAndroidSDKCanvas::onClipPath(const SkPath& path, + SkRegion::Op op, + ClipEdgeStyle style) { + fProxyTarget->clipPath(path, op, style); +} + +void SkAndroidSDKCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) { + fProxyTarget->clipRegion(region, op); +} + +void SkAndroidSDKCanvas::onDiscard() { fProxyTarget->discard(); } + + diff --git a/src/utils/android/SkAndroidSDKCanvas.h b/src/utils/android/SkAndroidSDKCanvas.h new file mode 100644 index 0000000000..fc046189f7 --- /dev/null +++ b/src/utils/android/SkAndroidSDKCanvas.h @@ -0,0 +1,106 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAndroidSDKCanvas_DEFINED +#define SkAndroidSDKCanvas_DEFINED + +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkPath.h" +#include "SkRect.h" + +/** SkDrawFilter is likely to be deprecated; this is a proxy + canvas that does the same thing: alter SkPaint fields. + + onDraw*() functions may have their SkPaint modified, and are then + passed on to the same function on proxyTarget. THIS BREAKS CONSTNESS! + + This still suffers one of the same architectural flaws as SkDrawFilter: + TextBlob paints are incomplete when filter is called. +*/ + +class SkAndroidSDKCanvas : public SkCanvas { +public: + SkAndroidSDKCanvas(); + void reset(SkCanvas* newTarget); + +protected: + + // FILTERING + + void onDrawPaint(const SkPaint& paint) SK_OVERRIDE; + void onDrawPoints(PointMode pMode, size_t count, const SkPoint pts[], + const SkPaint& paint) SK_OVERRIDE; + void onDrawOval(const SkRect& r, const SkPaint& paint) SK_OVERRIDE; + void onDrawRect(const SkRect& r, const SkPaint& paint) SK_OVERRIDE; + void onDrawRRect(const SkRRect& r, const SkPaint& paint) SK_OVERRIDE; + void onDrawPath(const SkPath& path, const SkPaint& paint) SK_OVERRIDE; + void onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, + const SkPaint* paint) SK_OVERRIDE; + void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, + const SkPaint* paint, DrawBitmapRectFlags flags) SK_OVERRIDE; + void onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, + const SkRect& dst, const SkPaint* paint) SK_OVERRIDE; + void onDrawSprite(const SkBitmap& bitmap, int left, int top, + const SkPaint* paint) SK_OVERRIDE; + void onDrawVertices(VertexMode vMode, int vertexCount, const SkPoint vertices[], + const SkPoint texs[], const SkColor colors[], SkXfermode* xMode, + const uint16_t indices[], int indexCount, + const SkPaint& paint) SK_OVERRIDE; + + void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, + const SkPaint& paint) SK_OVERRIDE; + + void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, + const SkPaint& paint) SK_OVERRIDE; + void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], + const SkPaint& paint) SK_OVERRIDE; + void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], + SkScalar constY, const SkPaint& paint) SK_OVERRIDE; + void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, + const SkMatrix* matrix, const SkPaint& paint) SK_OVERRIDE; + void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) SK_OVERRIDE; + + void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkXfermode* xmode, + const SkPaint& paint) SK_OVERRIDE; + + void onDrawImage(const SkImage*, SkScalar, SkScalar, const SkPaint*) SK_OVERRIDE; + void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*) + SK_OVERRIDE; + void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*); + + // PASS THROUGH + + void onDrawDrawable(SkDrawable*) SK_OVERRIDE; + SkISize getBaseLayerSize() const SK_OVERRIDE; + bool getClipBounds(SkRect*) const SK_OVERRIDE; + bool getClipDeviceBounds(SkIRect*) const SK_OVERRIDE; + bool isClipEmpty() const SK_OVERRIDE; + bool isClipRect() const SK_OVERRIDE; + SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) SK_OVERRIDE; + const void* onPeekPixels(SkImageInfo*, size_t*) SK_OVERRIDE; + void* onAccessTopLayerPixels(SkImageInfo*, size_t*) SK_OVERRIDE; + void willSave() SK_OVERRIDE; + void willRestore() SK_OVERRIDE; + void didRestore() SK_OVERRIDE; + void didConcat(const SkMatrix&) SK_OVERRIDE; + void didSetMatrix(const SkMatrix&) SK_OVERRIDE; + void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE; + void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE; + void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE; + void onClipRegion(const SkRegion&, SkRegion::Op) SK_OVERRIDE; + void onDiscard() SK_OVERRIDE; + +protected: + SkCanvas* fProxyTarget; +}; + +#endif // SkAndroidSDKCanvas_DEFINED +