1 /* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkAndroidSDKCanvas.h" 9 10 #include "SkColorFilter.h" 11 #include "SkPaint.h" 12 #include "SkPathEffect.h" 13 #include "SkShader.h" 14 #include "SkTLazy.h" 15 16 namespace { 17 18 /** Discard SkShaders not exposed by the Android Java API. */ 19 20 void CheckShader(SkPaint* paint) { 21 SkShader* shader = paint->getShader(); 22 if (!shader) { 23 return; 24 } 25 26 if (shader->isABitmap()) { 27 return; 28 } 29 if (shader->asACompose(nullptr)) { 30 return; 31 } 32 SkShader::GradientType gtype = shader->asAGradient(nullptr); 33 if (gtype == SkShader::kLinear_GradientType || 34 gtype == SkShader::kRadial_GradientType || 35 gtype == SkShader::kSweep_GradientType) { 36 return; 37 } 38 paint->setShader(nullptr); 39 } 40 41 void Filter(SkPaint* paint) { 42 43 uint32_t flags = paint->getFlags(); 44 flags &= ~SkPaint::kLCDRenderText_Flag; 45 paint->setFlags(flags); 46 47 // Android doesn't support Xfermodes above kLighten_Mode 48 SkXfermode::Mode mode; 49 SkXfermode::AsMode(paint->getXfermode(), &mode); 50 if (mode > SkXfermode::kLighten_Mode) { 51 paint->setXfermode(nullptr); 52 } 53 54 // Force bilinear scaling or none 55 if (paint->getFilterQuality() != kNone_SkFilterQuality) { 56 paint->setFilterQuality(kLow_SkFilterQuality); 57 } 58 59 CheckShader(paint); 60 61 // Android SDK only supports mode & matrix color filters 62 // (and, again, no modes above kLighten_Mode). 63 SkColorFilter* cf = paint->getColorFilter(); 64 if (cf) { 65 SkColor color; 66 SkXfermode::Mode mode; 67 SkScalar srcColorMatrix[20]; 68 bool isMode = cf->asColorMode(&color, &mode); 69 if (isMode && mode > SkXfermode::kLighten_Mode) { 70 paint->setColorFilter( 71 SkColorFilter::CreateModeFilter(color, SkXfermode::kSrcOver_Mode)); 72 } else if (!isMode && !cf->asColorMatrix(srcColorMatrix)) { 73 paint->setColorFilter(nullptr); 74 } 75 } 76 77 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 78 SkPathEffect* pe = paint->getPathEffect(); 79 if (pe && !pe->exposedInAndroidJavaAPI()) { 80 paint->setPathEffect(nullptr); 81 } 82 #endif 83 84 // TODO: Android doesn't support all the flags that can be passed to 85 // blur filters; we need plumbing to get them out. 86 87 paint->setImageFilter(nullptr); 88 paint->setLooper(nullptr); 89 }; 90 91 } // namespace 92 93 #define FILTER(p) \ 94 SkPaint filteredPaint(p); \ 95 Filter(&filteredPaint); 96 97 #define FILTER_PTR(p) \ 98 SkTLazy<SkPaint> lazyPaint; \ 99 SkPaint* filteredPaint = (SkPaint*) p; \ 100 if (p) { \ 101 filteredPaint = lazyPaint.set(*p); \ 102 Filter(filteredPaint); \ 103 } 104 105 106 SkAndroidSDKCanvas::SkAndroidSDKCanvas() : fProxyTarget(nullptr) { } 107 108 void SkAndroidSDKCanvas::reset(SkCanvas* newTarget) { fProxyTarget = newTarget; } 109 110 void SkAndroidSDKCanvas::onDrawPaint(const SkPaint& paint) { 111 FILTER(paint); 112 fProxyTarget->drawPaint(filteredPaint); 113 } 114 void SkAndroidSDKCanvas::onDrawPoints(PointMode pMode, 115 size_t count, 116 const SkPoint pts[], 117 const SkPaint& paint) { 118 FILTER(paint); 119 fProxyTarget->drawPoints(pMode, count, pts, filteredPaint); 120 } 121 void SkAndroidSDKCanvas::onDrawOval(const SkRect& r, const SkPaint& paint) { 122 FILTER(paint); 123 fProxyTarget->drawOval(r, filteredPaint); 124 } 125 void SkAndroidSDKCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) { 126 FILTER(paint); 127 fProxyTarget->drawRect(r, filteredPaint); 128 } 129 void SkAndroidSDKCanvas::onDrawRRect(const SkRRect& r, const SkPaint& paint) { 130 FILTER(paint); 131 fProxyTarget->drawRRect(r, filteredPaint); 132 } 133 void SkAndroidSDKCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { 134 FILTER(paint); 135 fProxyTarget->drawPath(path, filteredPaint); 136 } 137 void SkAndroidSDKCanvas::onDrawBitmap(const SkBitmap& bitmap, 138 SkScalar left, 139 SkScalar top, 140 const SkPaint* paint) { 141 FILTER_PTR(paint); 142 fProxyTarget->drawBitmap(bitmap, left, top, filteredPaint); 143 } 144 void SkAndroidSDKCanvas::onDrawBitmapRect(const SkBitmap& bitmap, 145 const SkRect* src, 146 const SkRect& dst, 147 const SkPaint* paint, 148 SkCanvas::SrcRectConstraint constraint) { 149 FILTER_PTR(paint); 150 fProxyTarget->legacy_drawBitmapRect(bitmap, src, dst, filteredPaint, constraint); 151 } 152 void SkAndroidSDKCanvas::onDrawBitmapNine(const SkBitmap& bitmap, 153 const SkIRect& center, 154 const SkRect& dst, 155 const SkPaint* paint) { 156 FILTER_PTR(paint); 157 fProxyTarget->drawBitmapNine(bitmap, center, dst, filteredPaint); 158 } 159 void SkAndroidSDKCanvas::onDrawVertices(VertexMode vMode, 160 int vertexCount, 161 const SkPoint vertices[], 162 const SkPoint texs[], const SkColor colors[], SkXfermode* xMode, 163 const uint16_t indices[], int indexCount, 164 const SkPaint& paint) { 165 FILTER(paint); 166 fProxyTarget->drawVertices(vMode, vertexCount, vertices, texs, colors, 167 xMode, indices, indexCount, filteredPaint); 168 } 169 170 void SkAndroidSDKCanvas::onDrawDRRect(const SkRRect& outer, 171 const SkRRect& inner, 172 const SkPaint& paint) { 173 FILTER(paint); 174 fProxyTarget->drawDRRect(outer, inner, filteredPaint); 175 } 176 177 void SkAndroidSDKCanvas::onDrawText(const void* text, 178 size_t byteLength, 179 SkScalar x, 180 SkScalar y, 181 const SkPaint& paint) { 182 FILTER(paint); 183 fProxyTarget->drawText(text, byteLength, x, y, filteredPaint); 184 } 185 void SkAndroidSDKCanvas::onDrawPosText(const void* text, 186 size_t byteLength, 187 const SkPoint pos[], 188 const SkPaint& paint) { 189 FILTER(paint); 190 fProxyTarget->drawPosText(text, byteLength, pos, filteredPaint); 191 } 192 void SkAndroidSDKCanvas::onDrawPosTextH(const void* text, 193 size_t byteLength, 194 const SkScalar xpos[], 195 SkScalar constY, 196 const SkPaint& paint) { 197 FILTER(paint); 198 fProxyTarget->drawPosTextH(text, byteLength, xpos, constY, filteredPaint); 199 } 200 void SkAndroidSDKCanvas::onDrawTextOnPath(const void* text, 201 size_t byteLength, 202 const SkPath& path, 203 const SkMatrix* matrix, 204 const SkPaint& paint) { 205 FILTER(paint); 206 fProxyTarget->drawTextOnPath(text, byteLength, path, matrix, filteredPaint); 207 } 208 void SkAndroidSDKCanvas::onDrawTextBlob(const SkTextBlob* blob, 209 SkScalar x, 210 SkScalar y, 211 const SkPaint& paint) { 212 FILTER(paint); 213 fProxyTarget->drawTextBlob(blob, x, y, filteredPaint); 214 } 215 216 void SkAndroidSDKCanvas::onDrawPatch(const SkPoint cubics[12], 217 const SkColor colors[4], 218 const SkPoint texCoords[4], 219 SkXfermode* xmode, 220 const SkPaint& paint) { 221 FILTER(paint); 222 fProxyTarget->drawPatch(cubics, colors, texCoords, xmode, filteredPaint); 223 } 224 225 226 void SkAndroidSDKCanvas::onDrawImage(const SkImage* image, 227 SkScalar x, 228 SkScalar y, 229 const SkPaint* paint) { 230 FILTER_PTR(paint); 231 fProxyTarget->drawImage(image, x, y, filteredPaint); 232 } 233 234 void SkAndroidSDKCanvas::onDrawImageRect(const SkImage* image, 235 const SkRect* in, 236 const SkRect& out, 237 const SkPaint* paint, 238 SrcRectConstraint constraint) { 239 FILTER_PTR(paint); 240 fProxyTarget->legacy_drawImageRect(image, in, out, filteredPaint, constraint); 241 } 242 243 void SkAndroidSDKCanvas::onDrawPicture(const SkPicture* picture, 244 const SkMatrix* matrix, 245 const SkPaint* paint) { 246 FILTER_PTR(paint); 247 fProxyTarget->drawPicture(picture, matrix, filteredPaint); 248 } 249 250 void SkAndroidSDKCanvas::onDrawAtlas(const SkImage* atlas, 251 const SkRSXform xform[], 252 const SkRect tex[], 253 const SkColor colors[], 254 int count, 255 SkXfermode::Mode mode, 256 const SkRect* cullRect, 257 const SkPaint* paint) { 258 FILTER_PTR(paint); 259 fProxyTarget->drawAtlas(atlas, xform, tex, colors, count, mode, cullRect, 260 filteredPaint); 261 } 262 263 void SkAndroidSDKCanvas::onDrawImageNine(const SkImage* image, 264 const SkIRect& center, 265 const SkRect& dst, 266 const SkPaint* paint) { 267 FILTER_PTR(paint); 268 fProxyTarget->drawImageNine(image, center, dst, filteredPaint); 269 } 270 271 272 void SkAndroidSDKCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) { 273 fProxyTarget->drawDrawable(drawable, matrix); 274 } 275 276 SkISize SkAndroidSDKCanvas::getBaseLayerSize() const { 277 return fProxyTarget->getBaseLayerSize(); 278 } 279 bool SkAndroidSDKCanvas::getClipBounds(SkRect* rect) const { 280 return fProxyTarget->getClipBounds(rect); 281 } 282 bool SkAndroidSDKCanvas::getClipDeviceBounds(SkIRect* rect) const { 283 return fProxyTarget->getClipDeviceBounds(rect); 284 } 285 286 bool SkAndroidSDKCanvas::isClipEmpty() const { return fProxyTarget->isClipEmpty(); } 287 bool SkAndroidSDKCanvas::isClipRect() const { return fProxyTarget->isClipRect(); } 288 289 SkSurface* SkAndroidSDKCanvas::onNewSurface(const SkImageInfo& info, 290 const SkSurfaceProps& props) { 291 return fProxyTarget->newSurface(info, &props); 292 } 293 294 bool SkAndroidSDKCanvas::onPeekPixels(SkPixmap* pmap) { 295 SkASSERT(pmap); 296 SkImageInfo info; 297 size_t rowBytes; 298 const void* addr = fProxyTarget->peekPixels(&info, &rowBytes); 299 if (addr) { 300 pmap->reset(info, addr, rowBytes); 301 return true; 302 } 303 return false; 304 } 305 306 bool SkAndroidSDKCanvas::onAccessTopLayerPixels(SkPixmap* pmap) { 307 SkASSERT(pmap); 308 SkImageInfo info; 309 size_t rowBytes; 310 const void* addr = fProxyTarget->accessTopLayerPixels(&info, &rowBytes, nullptr); 311 if (addr) { 312 pmap->reset(info, addr, rowBytes); 313 return true; 314 } 315 return false; 316 } 317 318 void SkAndroidSDKCanvas::willSave() { 319 fProxyTarget->save(); 320 } 321 322 SkCanvas::SaveLayerStrategy SkAndroidSDKCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) { 323 fProxyTarget->saveLayer(rec); 324 return SkCanvas::kNoLayer_SaveLayerStrategy; 325 } 326 327 void SkAndroidSDKCanvas::willRestore() { 328 fProxyTarget->restore(); 329 } 330 331 void SkAndroidSDKCanvas::didRestore() { } 332 333 void SkAndroidSDKCanvas::didConcat(const SkMatrix& m) { 334 fProxyTarget->concat(m); 335 } 336 337 void SkAndroidSDKCanvas::didSetMatrix(const SkMatrix& m) { 338 fProxyTarget->setMatrix(m); 339 } 340 341 void SkAndroidSDKCanvas::onClipRect(const SkRect& rect, 342 SkRegion::Op op, 343 ClipEdgeStyle style) { 344 fProxyTarget->clipRect(rect, op, style); 345 } 346 347 void SkAndroidSDKCanvas::onClipRRect(const SkRRect& rrect, 348 SkRegion::Op op, 349 ClipEdgeStyle style) { 350 fProxyTarget->clipRRect(rrect, op, style); 351 } 352 353 void SkAndroidSDKCanvas::onClipPath(const SkPath& path, 354 SkRegion::Op op, 355 ClipEdgeStyle style) { 356 fProxyTarget->clipPath(path, op, style); 357 } 358 359 void SkAndroidSDKCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) { 360 fProxyTarget->clipRegion(region, op); 361 } 362 363 void SkAndroidSDKCanvas::onDiscard() { fProxyTarget->discard(); } 364 365 366