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