1 /* 2 * Copyright 2014 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 "SkBigPicture.h" 9 #include "SkCanvasPriv.h" 10 #include "SkImage.h" 11 #include "SkPatchUtils.h" 12 #include "SkPicture.h" 13 #include "SkRecorder.h" 14 #include "SkSurface.h" 15 16 SkDrawableList::~SkDrawableList() { 17 fArray.unrefAll(); 18 } 19 20 SkBigPicture::SnapshotArray* SkDrawableList::newDrawableSnapshot() { 21 const int count = fArray.count(); 22 if (0 == count) { 23 return nullptr; 24 } 25 SkAutoTMalloc<const SkPicture*> pics(count); 26 for (int i = 0; i < count; ++i) { 27 pics[i] = fArray[i]->newPictureSnapshot(); 28 } 29 return new SkBigPicture::SnapshotArray(pics.release(), count); 30 } 31 32 void SkDrawableList::append(SkDrawable* drawable) { 33 *fArray.append() = SkRef(drawable); 34 } 35 36 /////////////////////////////////////////////////////////////////////////////////////////////// 37 38 SkRecorder::SkRecorder(SkRecord* record, int width, int height, SkMiniRecorder* mr) 39 : SkNoDrawCanvas(width, height) 40 , fDrawPictureMode(Record_DrawPictureMode) 41 , fApproxBytesUsedBySubPictures(0) 42 , fRecord(record) 43 , fMiniRecorder(mr) {} 44 45 SkRecorder::SkRecorder(SkRecord* record, const SkRect& bounds, SkMiniRecorder* mr) 46 : SkNoDrawCanvas(bounds.roundOut()) 47 , fDrawPictureMode(Record_DrawPictureMode) 48 , fApproxBytesUsedBySubPictures(0) 49 , fRecord(record) 50 , fMiniRecorder(mr) {} 51 52 void SkRecorder::reset(SkRecord* record, const SkRect& bounds, 53 DrawPictureMode dpm, SkMiniRecorder* mr) { 54 this->forgetRecord(); 55 fDrawPictureMode = dpm; 56 fRecord = record; 57 this->resetForNextPicture(bounds.roundOut()); 58 fMiniRecorder = mr; 59 } 60 61 void SkRecorder::forgetRecord() { 62 fDrawableList.reset(nullptr); 63 fApproxBytesUsedBySubPictures = 0; 64 fRecord = nullptr; 65 } 66 67 // To make appending to fRecord a little less verbose. 68 #define APPEND(T, ...) \ 69 if (fMiniRecorder) { \ 70 this->flushMiniRecorder(); \ 71 } \ 72 new (fRecord->append<SkRecords::T>()) SkRecords::T{__VA_ARGS__} 73 74 #define TRY_MINIRECORDER(method, ...) \ 75 if (fMiniRecorder && fMiniRecorder->method(__VA_ARGS__)) { return; } 76 77 // For methods which must call back into SkNoDrawCanvas. 78 #define INHERITED(method, ...) this->SkNoDrawCanvas::method(__VA_ARGS__) 79 80 // Use copy() only for optional arguments, to be copied if present or skipped if not. 81 // (For most types we just pass by value and let copy constructors do their thing.) 82 template <typename T> 83 T* SkRecorder::copy(const T* src) { 84 if (nullptr == src) { 85 return nullptr; 86 } 87 return new (fRecord->alloc<T>()) T(*src); 88 } 89 90 // This copy() is for arrays. 91 // It will work with POD or non-POD, though currently we only use it for POD. 92 template <typename T> 93 T* SkRecorder::copy(const T src[], size_t count) { 94 if (nullptr == src) { 95 return nullptr; 96 } 97 T* dst = fRecord->alloc<T>(count); 98 for (size_t i = 0; i < count; i++) { 99 new (dst + i) T(src[i]); 100 } 101 return dst; 102 } 103 104 // Specialization for copying strings, using memcpy. 105 // This measured around 2x faster for copying code points, 106 // but I found no corresponding speedup for other arrays. 107 template <> 108 char* SkRecorder::copy(const char src[], size_t count) { 109 if (nullptr == src) { 110 return nullptr; 111 } 112 char* dst = fRecord->alloc<char>(count); 113 memcpy(dst, src, count); 114 return dst; 115 } 116 117 // As above, assuming and copying a terminating \0. 118 template <> 119 char* SkRecorder::copy(const char* src) { 120 return this->copy(src, strlen(src)+1); 121 } 122 123 void SkRecorder::flushMiniRecorder() { 124 if (fMiniRecorder) { 125 SkMiniRecorder* mr = fMiniRecorder; 126 fMiniRecorder = nullptr; // Needs to happen before flushAndReset() or we recurse forever. 127 mr->flushAndReset(this); 128 } 129 } 130 131 void SkRecorder::onDrawPaint(const SkPaint& paint) { 132 APPEND(DrawPaint, paint); 133 } 134 135 void SkRecorder::onDrawPoints(PointMode mode, 136 size_t count, 137 const SkPoint pts[], 138 const SkPaint& paint) { 139 APPEND(DrawPoints, paint, mode, SkToUInt(count), this->copy(pts, count)); 140 } 141 142 void SkRecorder::onDrawRect(const SkRect& rect, const SkPaint& paint) { 143 TRY_MINIRECORDER(drawRect, rect, paint); 144 APPEND(DrawRect, paint, rect); 145 } 146 147 void SkRecorder::onDrawRegion(const SkRegion& region, const SkPaint& paint) { 148 APPEND(DrawRegion, paint, region); 149 } 150 151 void SkRecorder::onDrawOval(const SkRect& oval, const SkPaint& paint) { 152 APPEND(DrawOval, paint, oval); 153 } 154 155 void SkRecorder::onDrawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, 156 bool useCenter, const SkPaint& paint) { 157 APPEND(DrawArc, paint, oval, startAngle, sweepAngle, useCenter); 158 } 159 160 void SkRecorder::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { 161 APPEND(DrawRRect, paint, rrect); 162 } 163 164 void SkRecorder::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { 165 APPEND(DrawDRRect, paint, outer, inner); 166 } 167 168 void SkRecorder::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) { 169 if (fDrawPictureMode == Record_DrawPictureMode) { 170 if (!fDrawableList) { 171 fDrawableList.reset(new SkDrawableList); 172 } 173 fDrawableList->append(drawable); 174 APPEND(DrawDrawable, this->copy(matrix), drawable->getBounds(), fDrawableList->count() - 1); 175 } else { 176 SkASSERT(fDrawPictureMode == Playback_DrawPictureMode); 177 drawable->draw(this, matrix); 178 } 179 } 180 181 void SkRecorder::onDrawPath(const SkPath& path, const SkPaint& paint) { 182 TRY_MINIRECORDER(drawPath, path, paint); 183 APPEND(DrawPath, paint, path); 184 } 185 186 void SkRecorder::onDrawBitmap(const SkBitmap& bitmap, 187 SkScalar left, 188 SkScalar top, 189 const SkPaint* paint) { 190 sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap); 191 if (image) { 192 this->onDrawImage(image.get(), left, top, paint); 193 } 194 } 195 196 void SkRecorder::onDrawBitmapRect(const SkBitmap& bitmap, 197 const SkRect* src, 198 const SkRect& dst, 199 const SkPaint* paint, 200 SrcRectConstraint constraint) { 201 sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap); 202 if (image) { 203 this->onDrawImageRect(image.get(), src, dst, paint, constraint); 204 } 205 } 206 207 void SkRecorder::onDrawBitmapNine(const SkBitmap& bitmap, 208 const SkIRect& center, 209 const SkRect& dst, 210 const SkPaint* paint) { 211 sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap); 212 if (image) { 213 this->onDrawImageNine(image.get(), center, dst, paint); 214 } 215 } 216 217 void SkRecorder::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, 218 const SkRect& dst, const SkPaint* paint) { 219 sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap); 220 this->onDrawImageLattice(image.get(), lattice, dst, paint); 221 } 222 223 void SkRecorder::onDrawImage(const SkImage* image, SkScalar left, SkScalar top, 224 const SkPaint* paint) { 225 APPEND(DrawImage, this->copy(paint), sk_ref_sp(image), left, top); 226 } 227 228 void SkRecorder::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, 229 const SkPaint* paint, SrcRectConstraint constraint) { 230 APPEND(DrawImageRect, this->copy(paint), sk_ref_sp(image), this->copy(src), dst, constraint); 231 } 232 233 void SkRecorder::onDrawImageNine(const SkImage* image, const SkIRect& center, 234 const SkRect& dst, const SkPaint* paint) { 235 APPEND(DrawImageNine, this->copy(paint), sk_ref_sp(image), center, dst); 236 } 237 238 void SkRecorder::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, 239 const SkPaint* paint) { 240 int flagCount = lattice.fFlags ? (lattice.fXCount + 1) * (lattice.fYCount + 1) : 0; 241 SkASSERT(lattice.fBounds); 242 APPEND(DrawImageLattice, this->copy(paint), sk_ref_sp(image), 243 lattice.fXCount, this->copy(lattice.fXDivs, lattice.fXCount), 244 lattice.fYCount, this->copy(lattice.fYDivs, lattice.fYCount), 245 flagCount, this->copy(lattice.fFlags, flagCount), *lattice.fBounds, dst); 246 } 247 248 void SkRecorder::onDrawText(const void* text, size_t byteLength, 249 SkScalar x, SkScalar y, const SkPaint& paint) { 250 APPEND(DrawText, 251 paint, this->copy((const char*)text, byteLength), byteLength, x, y); 252 } 253 254 void SkRecorder::onDrawPosText(const void* text, size_t byteLength, 255 const SkPoint pos[], const SkPaint& paint) { 256 const int points = paint.countText(text, byteLength); 257 APPEND(DrawPosText, 258 paint, 259 this->copy((const char*)text, byteLength), 260 byteLength, 261 this->copy(pos, points)); 262 } 263 264 void SkRecorder::onDrawPosTextH(const void* text, size_t byteLength, 265 const SkScalar xpos[], SkScalar constY, const SkPaint& paint) { 266 const int points = paint.countText(text, byteLength); 267 APPEND(DrawPosTextH, 268 paint, 269 this->copy((const char*)text, byteLength), 270 SkToUInt(byteLength), 271 constY, 272 this->copy(xpos, points)); 273 } 274 275 void SkRecorder::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, 276 const SkMatrix* matrix, const SkPaint& paint) { 277 APPEND(DrawTextOnPath, 278 paint, 279 this->copy((const char*)text, byteLength), 280 byteLength, 281 path, 282 matrix ? *matrix : SkMatrix::I()); 283 } 284 285 void SkRecorder::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], 286 const SkRect* cull, const SkPaint& paint) { 287 APPEND(DrawTextRSXform, 288 paint, 289 this->copy((const char*)text, byteLength), 290 byteLength, 291 this->copy(xform, paint.countText(text, byteLength)), 292 this->copy(cull)); 293 } 294 295 void SkRecorder::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 296 const SkPaint& paint) { 297 TRY_MINIRECORDER(drawTextBlob, blob, x, y, paint); 298 APPEND(DrawTextBlob, paint, sk_ref_sp(blob), x, y); 299 } 300 301 void SkRecorder::onDrawPicture(const SkPicture* pic, const SkMatrix* matrix, const SkPaint* paint) { 302 if (fDrawPictureMode == Record_DrawPictureMode) { 303 fApproxBytesUsedBySubPictures += pic->approximateBytesUsed(); 304 APPEND(DrawPicture, this->copy(paint), sk_ref_sp(pic), matrix ? *matrix : SkMatrix::I()); 305 } else { 306 SkASSERT(fDrawPictureMode == Playback_DrawPictureMode); 307 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, pic->cullRect()); 308 pic->playback(this); 309 } 310 } 311 312 void SkRecorder::onDrawShadowedPicture(const SkPicture* pic, const SkMatrix* matrix, 313 const SkPaint* paint, const SkShadowParams& params) { 314 if (fDrawPictureMode == Record_DrawPictureMode) { 315 fApproxBytesUsedBySubPictures += pic->approximateBytesUsed(); 316 APPEND(DrawShadowedPicture, this->copy(paint), 317 sk_ref_sp(pic), 318 matrix ? *matrix : SkMatrix::I(), 319 params); 320 } else { 321 // TODO update pic->playback(this) to draw the shadowed pic 322 SkASSERT(fDrawPictureMode == Playback_DrawPictureMode); 323 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, pic->cullRect()); 324 pic->playback(this); 325 } 326 } 327 328 329 void SkRecorder::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode, 330 const SkPaint& paint) { 331 APPEND(DrawVertices, paint, sk_ref_sp(const_cast<SkVertices*>(vertices)), bmode); 332 } 333 334 void SkRecorder::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], 335 const SkPoint texCoords[4], SkBlendMode bmode, 336 const SkPaint& paint) { 337 APPEND(DrawPatch, paint, 338 cubics ? this->copy(cubics, SkPatchUtils::kNumCtrlPts) : nullptr, 339 colors ? this->copy(colors, SkPatchUtils::kNumCorners) : nullptr, 340 texCoords ? this->copy(texCoords, SkPatchUtils::kNumCorners) : nullptr, 341 bmode); 342 } 343 344 void SkRecorder::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], 345 const SkColor colors[], int count, SkBlendMode mode, 346 const SkRect* cull, const SkPaint* paint) { 347 APPEND(DrawAtlas, this->copy(paint), 348 sk_ref_sp(atlas), 349 this->copy(xform, count), 350 this->copy(tex, count), 351 this->copy(colors, count), 352 count, 353 mode, 354 this->copy(cull)); 355 } 356 357 void SkRecorder::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) { 358 APPEND(DrawAnnotation, rect, SkString(key), sk_ref_sp(value)); 359 } 360 361 void SkRecorder::willSave() { 362 APPEND(Save); 363 } 364 365 SkCanvas::SaveLayerStrategy SkRecorder::getSaveLayerStrategy(const SaveLayerRec& rec) { 366 APPEND(SaveLayer, this->copy(rec.fBounds) 367 , this->copy(rec.fPaint) 368 , sk_ref_sp(rec.fBackdrop) 369 , rec.fSaveLayerFlags); 370 return SkCanvas::kNoLayer_SaveLayerStrategy; 371 } 372 373 void SkRecorder::didRestore() { 374 APPEND(Restore, this->getDeviceClipBounds(), this->getTotalMatrix()); 375 } 376 377 void SkRecorder::didConcat(const SkMatrix& matrix) { 378 APPEND(Concat, matrix); 379 } 380 381 void SkRecorder::didSetMatrix(const SkMatrix& matrix) { 382 APPEND(SetMatrix, matrix); 383 } 384 385 void SkRecorder::didTranslate(SkScalar dx, SkScalar dy) { 386 APPEND(Translate, dx, dy); 387 } 388 389 void SkRecorder::didTranslateZ(SkScalar z) { 390 #ifdef SK_EXPERIMENTAL_SHADOWING 391 APPEND(TranslateZ, z); 392 #endif 393 } 394 395 void SkRecorder::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) { 396 INHERITED(onClipRect, rect, op, edgeStyle); 397 SkRecords::ClipOpAndAA opAA(op, kSoft_ClipEdgeStyle == edgeStyle); 398 APPEND(ClipRect, this->getDeviceClipBounds(), rect, opAA); 399 } 400 401 void SkRecorder::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) { 402 INHERITED(onClipRRect, rrect, op, edgeStyle); 403 SkRecords::ClipOpAndAA opAA(op, kSoft_ClipEdgeStyle == edgeStyle); 404 APPEND(ClipRRect, this->getDeviceClipBounds(), rrect, opAA); 405 } 406 407 void SkRecorder::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) { 408 INHERITED(onClipPath, path, op, edgeStyle); 409 SkRecords::ClipOpAndAA opAA(op, kSoft_ClipEdgeStyle == edgeStyle); 410 APPEND(ClipPath, this->getDeviceClipBounds(), path, opAA); 411 } 412 413 void SkRecorder::onClipRegion(const SkRegion& deviceRgn, SkClipOp op) { 414 INHERITED(onClipRegion, deviceRgn, op); 415 APPEND(ClipRegion, this->getDeviceClipBounds(), deviceRgn, op); 416 } 417 418 sk_sp<SkSurface> SkRecorder::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) { 419 return nullptr; 420 } 421