1 /* 2 * Copyright 2011 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 "SkColorFilter.h" 9 #include "SkDevice.h" 10 #include "SkDraw.h" 11 #include "SkDrawFilter.h" 12 #include "SkImage_Base.h" 13 #include "SkMetaData.h" 14 #include "SkNinePatchIter.h" 15 #include "SkPatchUtils.h" 16 #include "SkPathMeasure.h" 17 #include "SkRasterClip.h" 18 #include "SkRSXform.h" 19 #include "SkShader.h" 20 #include "SkTextBlobRunIterator.h" 21 #include "SkTextToPathIter.h" 22 23 SkBaseDevice::SkBaseDevice(const SkSurfaceProps& surfaceProps) 24 : fSurfaceProps(surfaceProps) 25 #ifdef SK_DEBUG 26 , fAttachedToCanvas(false) 27 #endif 28 { 29 fOrigin.setZero(); 30 fMetaData = nullptr; 31 } 32 33 SkBaseDevice::~SkBaseDevice() { delete fMetaData; } 34 35 SkMetaData& SkBaseDevice::getMetaData() { 36 // metadata users are rare, so we lazily allocate it. If that changes we 37 // can decide to just make it a field in the device (rather than a ptr) 38 if (nullptr == fMetaData) { 39 fMetaData = new SkMetaData; 40 } 41 return *fMetaData; 42 } 43 44 SkImageInfo SkBaseDevice::imageInfo() const { 45 return SkImageInfo::MakeUnknown(); 46 } 47 48 const SkBitmap& SkBaseDevice::accessBitmap(bool changePixels) { 49 const SkBitmap& bitmap = this->onAccessBitmap(); 50 if (changePixels) { 51 bitmap.notifyPixelsChanged(); 52 } 53 return bitmap; 54 } 55 56 SkPixelGeometry SkBaseDevice::CreateInfo::AdjustGeometry(const SkImageInfo& info, 57 TileUsage tileUsage, 58 SkPixelGeometry geo, 59 bool preserveLCDText) { 60 switch (tileUsage) { 61 case kPossible_TileUsage: 62 // (we think) for compatibility with old clients, we assume this layer can support LCD 63 // even though they may not have marked it as opaque... seems like we should update 64 // our callers (reed/robertphilips). 65 break; 66 case kNever_TileUsage: 67 if (!preserveLCDText) { 68 geo = kUnknown_SkPixelGeometry; 69 } 70 break; 71 } 72 return geo; 73 } 74 75 void SkBaseDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer, 76 const SkRRect& inner, const SkPaint& paint) { 77 SkPath path; 78 path.addRRect(outer); 79 path.addRRect(inner); 80 path.setFillType(SkPath::kEvenOdd_FillType); 81 82 const SkMatrix* preMatrix = nullptr; 83 const bool pathIsMutable = true; 84 this->drawPath(draw, path, paint, preMatrix, pathIsMutable); 85 } 86 87 void SkBaseDevice::drawPatch(const SkDraw& draw, const SkPoint cubics[12], const SkColor colors[4], 88 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) { 89 SkPatchUtils::VertexData data; 90 91 SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, draw.fMatrix); 92 93 // It automatically adjusts lodX and lodY in case it exceeds the number of indices. 94 // If it fails to generate the vertices, then we do not draw. 95 if (SkPatchUtils::getVertexData(&data, cubics, colors, texCoords, lod.width(), lod.height())) { 96 this->drawVertices(draw, SkCanvas::kTriangles_VertexMode, data.fVertexCount, data.fPoints, 97 data.fTexCoords, data.fColors, xmode, data.fIndices, data.fIndexCount, 98 paint); 99 } 100 } 101 102 void SkBaseDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkScalar x, SkScalar y, 103 const SkPaint &paint, SkDrawFilter* drawFilter) { 104 105 SkPaint runPaint = paint; 106 107 SkTextBlobRunIterator it(blob); 108 for (;!it.done(); it.next()) { 109 size_t textLen = it.glyphCount() * sizeof(uint16_t); 110 const SkPoint& offset = it.offset(); 111 // applyFontToPaint() always overwrites the exact same attributes, 112 // so it is safe to not re-seed the paint for this reason. 113 it.applyFontToPaint(&runPaint); 114 115 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Type)) { 116 // A false return from filter() means we should abort the current draw. 117 runPaint = paint; 118 continue; 119 } 120 121 runPaint.setFlags(this->filterTextFlags(runPaint)); 122 123 switch (it.positioning()) { 124 case SkTextBlob::kDefault_Positioning: 125 this->drawText(draw, it.glyphs(), textLen, x + offset.x(), y + offset.y(), runPaint); 126 break; 127 case SkTextBlob::kHorizontal_Positioning: 128 this->drawPosText(draw, it.glyphs(), textLen, it.pos(), 1, 129 SkPoint::Make(x, y + offset.y()), runPaint); 130 break; 131 case SkTextBlob::kFull_Positioning: 132 this->drawPosText(draw, it.glyphs(), textLen, it.pos(), 2, 133 SkPoint::Make(x, y), runPaint); 134 break; 135 default: 136 SkFAIL("unhandled positioning mode"); 137 } 138 139 if (drawFilter) { 140 // A draw filter may change the paint arbitrarily, so we must re-seed in this case. 141 runPaint = paint; 142 } 143 } 144 } 145 146 void SkBaseDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x, SkScalar y, 147 const SkPaint& paint) { 148 // Default impl : turns everything into raster bitmap 149 SkBitmap bm; 150 if (as_IB(image)->getROPixels(&bm)) { 151 this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); 152 } 153 } 154 155 void SkBaseDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const SkRect* src, 156 const SkRect& dst, const SkPaint& paint, 157 SkCanvas::SrcRectConstraint constraint) { 158 // Default impl : turns everything into raster bitmap 159 SkBitmap bm; 160 if (as_IB(image)->getROPixels(&bm)) { 161 this->drawBitmapRect(draw, bm, src, dst, paint, constraint); 162 } 163 } 164 165 void SkBaseDevice::drawImageNine(const SkDraw& draw, const SkImage* image, const SkIRect& center, 166 const SkRect& dst, const SkPaint& paint) { 167 SkNinePatchIter iter(image->width(), image->height(), center, dst); 168 169 SkRect srcR, dstR; 170 while (iter.next(&srcR, &dstR)) { 171 this->drawImageRect(draw, image, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint); 172 } 173 } 174 175 void SkBaseDevice::drawBitmapNine(const SkDraw& draw, const SkBitmap& bitmap, const SkIRect& center, 176 const SkRect& dst, const SkPaint& paint) { 177 SkNinePatchIter iter(bitmap.width(), bitmap.height(), center, dst); 178 179 SkRect srcR, dstR; 180 while (iter.next(&srcR, &dstR)) { 181 this->drawBitmapRect(draw, bitmap, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint); 182 } 183 } 184 185 void SkBaseDevice::drawAtlas(const SkDraw& draw, const SkImage* atlas, const SkRSXform xform[], 186 const SkRect tex[], const SkColor colors[], int count, 187 SkXfermode::Mode mode, const SkPaint& paint) { 188 SkPath path; 189 path.setIsVolatile(true); 190 191 for (int i = 0; i < count; ++i) { 192 SkPoint quad[4]; 193 xform[i].toQuad(tex[i].width(), tex[i].height(), quad); 194 195 SkMatrix localM; 196 localM.setRSXform(xform[i]); 197 localM.preTranslate(-tex[i].left(), -tex[i].top()); 198 199 SkPaint pnt(paint); 200 SkAutoTUnref<SkShader> shader(atlas->newShader(SkShader::kClamp_TileMode, 201 SkShader::kClamp_TileMode, 202 &localM)); 203 if (!shader) { 204 break; 205 } 206 pnt.setShader(shader); 207 208 if (colors) { 209 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(colors[i], mode)); 210 pnt.setColorFilter(cf); 211 } 212 213 path.rewind(); 214 path.addPoly(quad, 4, true); 215 path.setConvexity(SkPath::kConvex_Convexity); 216 this->drawPath(draw, path, pnt, nullptr, true); 217 } 218 } 219 220 /////////////////////////////////////////////////////////////////////////////////////////////////// 221 222 bool SkBaseDevice::readPixels(const SkImageInfo& info, void* dstP, size_t rowBytes, int x, int y) { 223 #ifdef SK_DEBUG 224 SkASSERT(info.width() > 0 && info.height() > 0); 225 SkASSERT(dstP); 226 SkASSERT(rowBytes >= info.minRowBytes()); 227 SkASSERT(x >= 0 && y >= 0); 228 229 const SkImageInfo& srcInfo = this->imageInfo(); 230 SkASSERT(x + info.width() <= srcInfo.width()); 231 SkASSERT(y + info.height() <= srcInfo.height()); 232 #endif 233 return this->onReadPixels(info, dstP, rowBytes, x, y); 234 } 235 236 bool SkBaseDevice::writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, 237 int x, int y) { 238 #ifdef SK_DEBUG 239 SkASSERT(info.width() > 0 && info.height() > 0); 240 SkASSERT(pixels); 241 SkASSERT(rowBytes >= info.minRowBytes()); 242 SkASSERT(x >= 0 && y >= 0); 243 244 const SkImageInfo& dstInfo = this->imageInfo(); 245 SkASSERT(x + info.width() <= dstInfo.width()); 246 SkASSERT(y + info.height() <= dstInfo.height()); 247 #endif 248 return this->onWritePixels(info, pixels, rowBytes, x, y); 249 } 250 251 bool SkBaseDevice::onWritePixels(const SkImageInfo&, const void*, size_t, int, int) { 252 return false; 253 } 254 255 bool SkBaseDevice::onReadPixels(const SkImageInfo&, void*, size_t, int x, int y) { 256 return false; 257 } 258 259 bool SkBaseDevice::EXPERIMENTAL_drawPicture(SkCanvas*, const SkPicture*, const SkMatrix*, 260 const SkPaint*) { 261 // The base class doesn't perform any accelerated picture rendering 262 return false; 263 } 264 265 bool SkBaseDevice::accessPixels(SkPixmap* pmap) { 266 SkPixmap tempStorage; 267 if (nullptr == pmap) { 268 pmap = &tempStorage; 269 } 270 return this->onAccessPixels(pmap); 271 } 272 273 bool SkBaseDevice::peekPixels(SkPixmap* pmap) { 274 SkPixmap tempStorage; 275 if (nullptr == pmap) { 276 pmap = &tempStorage; 277 } 278 return this->onPeekPixels(pmap); 279 } 280 281 ////////////////////////////////////////////////////////////////////////////////////////// 282 283 static void morphpoints(SkPoint dst[], const SkPoint src[], int count, 284 SkPathMeasure& meas, const SkMatrix& matrix) { 285 SkMatrix::MapXYProc proc = matrix.getMapXYProc(); 286 287 for (int i = 0; i < count; i++) { 288 SkPoint pos; 289 SkVector tangent; 290 291 proc(matrix, src[i].fX, src[i].fY, &pos); 292 SkScalar sx = pos.fX; 293 SkScalar sy = pos.fY; 294 295 if (!meas.getPosTan(sx, &pos, &tangent)) { 296 // set to 0 if the measure failed, so that we just set dst == pos 297 tangent.set(0, 0); 298 } 299 300 /* This is the old way (that explains our approach but is way too slow 301 SkMatrix matrix; 302 SkPoint pt; 303 304 pt.set(sx, sy); 305 matrix.setSinCos(tangent.fY, tangent.fX); 306 matrix.preTranslate(-sx, 0); 307 matrix.postTranslate(pos.fX, pos.fY); 308 matrix.mapPoints(&dst[i], &pt, 1); 309 */ 310 dst[i].set(pos.fX - SkScalarMul(tangent.fY, sy), 311 pos.fY + SkScalarMul(tangent.fX, sy)); 312 } 313 } 314 315 /* TODO 316 317 Need differentially more subdivisions when the follow-path is curvy. Not sure how to 318 determine that, but we need it. I guess a cheap answer is let the caller tell us, 319 but that seems like a cop-out. Another answer is to get Rob Johnson to figure it out. 320 */ 321 static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas, 322 const SkMatrix& matrix) { 323 SkPath::Iter iter(src, false); 324 SkPoint srcP[4], dstP[3]; 325 SkPath::Verb verb; 326 327 while ((verb = iter.next(srcP)) != SkPath::kDone_Verb) { 328 switch (verb) { 329 case SkPath::kMove_Verb: 330 morphpoints(dstP, srcP, 1, meas, matrix); 331 dst->moveTo(dstP[0]); 332 break; 333 case SkPath::kLine_Verb: 334 // turn lines into quads to look bendy 335 srcP[0].fX = SkScalarAve(srcP[0].fX, srcP[1].fX); 336 srcP[0].fY = SkScalarAve(srcP[0].fY, srcP[1].fY); 337 morphpoints(dstP, srcP, 2, meas, matrix); 338 dst->quadTo(dstP[0], dstP[1]); 339 break; 340 case SkPath::kQuad_Verb: 341 morphpoints(dstP, &srcP[1], 2, meas, matrix); 342 dst->quadTo(dstP[0], dstP[1]); 343 break; 344 case SkPath::kCubic_Verb: 345 morphpoints(dstP, &srcP[1], 3, meas, matrix); 346 dst->cubicTo(dstP[0], dstP[1], dstP[2]); 347 break; 348 case SkPath::kClose_Verb: 349 dst->close(); 350 break; 351 default: 352 SkDEBUGFAIL("unknown verb"); 353 break; 354 } 355 } 356 } 357 358 void SkBaseDevice::drawTextOnPath(const SkDraw& draw, const void* text, size_t byteLength, 359 const SkPath& follow, const SkMatrix* matrix, 360 const SkPaint& paint) { 361 SkASSERT(byteLength == 0 || text != nullptr); 362 363 // nothing to draw 364 if (text == nullptr || byteLength == 0 || draw.fRC->isEmpty()) { 365 return; 366 } 367 368 SkTextToPathIter iter((const char*)text, byteLength, paint, true); 369 SkPathMeasure meas(follow, false); 370 SkScalar hOffset = 0; 371 372 // need to measure first 373 if (paint.getTextAlign() != SkPaint::kLeft_Align) { 374 SkScalar pathLen = meas.getLength(); 375 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 376 pathLen = SkScalarHalf(pathLen); 377 } 378 hOffset += pathLen; 379 } 380 381 const SkPath* iterPath; 382 SkScalar xpos; 383 SkMatrix scaledMatrix; 384 SkScalar scale = iter.getPathScale(); 385 386 scaledMatrix.setScale(scale, scale); 387 388 while (iter.next(&iterPath, &xpos)) { 389 if (iterPath) { 390 SkPath tmp; 391 SkMatrix m(scaledMatrix); 392 393 tmp.setIsVolatile(true); 394 m.postTranslate(xpos + hOffset, 0); 395 if (matrix) { 396 m.postConcat(*matrix); 397 } 398 morphpath(&tmp, *iterPath, meas, m); 399 this->drawPath(draw, tmp, iter.getPaint(), nullptr, true); 400 } 401 } 402 } 403 404 ////////////////////////////////////////////////////////////////////////////////////////// 405 406 void SkBaseDevice::drawBitmapAsSprite(const SkDraw& draw, const SkBitmap& bitmap, int x, int y, 407 const SkPaint& paint) { 408 SkImageFilter* filter = paint.getImageFilter(); 409 if (filter && !this->canHandleImageFilter(filter)) { 410 SkImageFilter::DeviceProxy proxy(this); 411 SkBitmap dst; 412 SkIPoint offset = SkIPoint::Make(0, 0); 413 SkMatrix matrix = *draw.fMatrix; 414 matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); 415 const SkIRect clipBounds = draw.fClip->getBounds().makeOffset(-x, -y); 416 SkAutoTUnref<SkImageFilter::Cache> cache(this->getImageFilterCache()); 417 SkImageFilter::Context ctx(matrix, clipBounds, cache.get()); 418 if (filter->filterImageDeprecated(&proxy, bitmap, ctx, &dst, &offset)) { 419 SkPaint tmpUnfiltered(paint); 420 tmpUnfiltered.setImageFilter(nullptr); 421 this->drawSprite(draw, dst, x + offset.x(), y + offset.y(), tmpUnfiltered); 422 } 423 } else { 424 this->drawSprite(draw, bitmap, x, y, paint); 425 } 426 } 427 428 uint32_t SkBaseDevice::filterTextFlags(const SkPaint& paint) const { 429 uint32_t flags = paint.getFlags(); 430 431 if (!paint.isLCDRenderText() || !paint.isAntiAlias()) { 432 return flags; 433 } 434 435 if (kUnknown_SkPixelGeometry == fSurfaceProps.pixelGeometry() 436 || this->onShouldDisableLCD(paint)) { 437 438 flags &= ~SkPaint::kLCDRenderText_Flag; 439 flags |= SkPaint::kGenA8FromLCD_Flag; 440 } 441 442 return flags; 443 } 444 445