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 "SkPatchUtils.h" 11 #include "SkPicture.h" 12 #include "SkPictureUtils.h" 13 #include "SkRecorder.h" 14 15 //#define WRAP_BITMAP_AS_IMAGE 16 17 SkDrawableList::~SkDrawableList() { 18 fArray.unrefAll(); 19 } 20 21 SkBigPicture::SnapshotArray* SkDrawableList::newDrawableSnapshot() { 22 const int count = fArray.count(); 23 if (0 == count) { 24 return nullptr; 25 } 26 SkAutoTMalloc<const SkPicture*> pics(count); 27 for (int i = 0; i < count; ++i) { 28 pics[i] = fArray[i]->newPictureSnapshot(); 29 } 30 return new SkBigPicture::SnapshotArray(pics.detach(), count); 31 } 32 33 void SkDrawableList::append(SkDrawable* drawable) { 34 *fArray.append() = SkRef(drawable); 35 } 36 37 /////////////////////////////////////////////////////////////////////////////////////////////// 38 39 SkRecorder::SkRecorder(SkRecord* record, int width, int height, SkMiniRecorder* mr) 40 : SkCanvas(SkIRect::MakeWH(width, height), SkCanvas::kConservativeRasterClip_InitFlag) 41 , fDrawPictureMode(Record_DrawPictureMode) 42 , fApproxBytesUsedBySubPictures(0) 43 , fRecord(record) 44 , fMiniRecorder(mr) {} 45 46 SkRecorder::SkRecorder(SkRecord* record, const SkRect& bounds, SkMiniRecorder* mr) 47 : SkCanvas(bounds.roundOut(), SkCanvas::kConservativeRasterClip_InitFlag) 48 , fDrawPictureMode(Record_DrawPictureMode) 49 , fApproxBytesUsedBySubPictures(0) 50 , fRecord(record) 51 , fMiniRecorder(mr) {} 52 53 void SkRecorder::reset(SkRecord* record, const SkRect& bounds, 54 DrawPictureMode dpm, SkMiniRecorder* mr) { 55 this->forgetRecord(); 56 fDrawPictureMode = dpm; 57 fRecord = record; 58 this->resetForNextPicture(bounds.roundOut()); 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 SkCanvas. 79 #define INHERITED(method, ...) this->SkCanvas::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::onDrawOval(const SkRect& oval, const SkPaint& paint) { 149 APPEND(DrawOval, paint, oval); 150 } 151 152 void SkRecorder::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { 153 APPEND(DrawRRect, paint, rrect); 154 } 155 156 void SkRecorder::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { 157 APPEND(DrawDRRect, paint, outer, inner); 158 } 159 160 void SkRecorder::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) { 161 if (fDrawPictureMode == Record_DrawPictureMode) { 162 if (!fDrawableList) { 163 fDrawableList.reset(new SkDrawableList); 164 } 165 fDrawableList->append(drawable); 166 APPEND(DrawDrawable, this->copy(matrix), drawable->getBounds(), fDrawableList->count() - 1); 167 } else { 168 SkASSERT(fDrawPictureMode == Playback_DrawPictureMode); 169 drawable->draw(this, matrix); 170 } 171 } 172 173 void SkRecorder::onDrawPath(const SkPath& path, const SkPaint& paint) { 174 TRY_MINIRECORDER(drawPath, path, paint); 175 APPEND(DrawPath, paint, path); 176 } 177 178 void SkRecorder::onDrawBitmap(const SkBitmap& bitmap, 179 SkScalar left, 180 SkScalar top, 181 const SkPaint* paint) { 182 #ifdef WRAP_BITMAP_AS_IMAGE 183 SkAutoTUnref<SkImage> image(SkImage::NewFromBitmap(bitmap)); 184 if (image) { 185 this->onDrawImage(image, left, top, paint); 186 } 187 #else 188 APPEND(DrawBitmap, this->copy(paint), bitmap, left, top); 189 #endif 190 } 191 192 void SkRecorder::onDrawBitmapRect(const SkBitmap& bitmap, 193 const SkRect* src, 194 const SkRect& dst, 195 const SkPaint* paint, 196 SrcRectConstraint constraint) { 197 #ifdef WRAP_BITMAP_AS_IMAGE 198 // TODO: need a way to support the flags for images... 199 SkAutoTUnref<SkImage> image(SkImage::NewFromBitmap(bitmap)); 200 if (image) { 201 this->onDrawImageRect(image, src, dst, paint); 202 } 203 #else 204 TRY_MINIRECORDER(drawBitmapRect, bitmap, src, dst, paint, constraint); 205 if (kFast_SrcRectConstraint == constraint) { 206 APPEND(DrawBitmapRectFast, this->copy(paint), bitmap, this->copy(src), dst); 207 return; 208 } 209 SkASSERT(kStrict_SrcRectConstraint == constraint); 210 APPEND(DrawBitmapRect, this->copy(paint), bitmap, this->copy(src), dst); 211 #endif 212 } 213 214 void SkRecorder::onDrawBitmapNine(const SkBitmap& bitmap, 215 const SkIRect& center, 216 const SkRect& dst, 217 const SkPaint* paint) { 218 #ifdef WRAP_BITMAP_AS_IMAGE 219 SkAutoTUnref<SkImage> image(SkImage::NewFromBitmap(bitmap)); 220 if (image) { 221 this->onDrawImageNine(image, center, dst, paint); 222 } 223 #else 224 APPEND(DrawBitmapNine, this->copy(paint), bitmap, center, dst); 225 #endif 226 } 227 228 void SkRecorder::onDrawImage(const SkImage* image, SkScalar left, SkScalar top, 229 const SkPaint* paint) { 230 APPEND(DrawImage, this->copy(paint), image, left, top); 231 } 232 233 void SkRecorder::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, 234 const SkPaint* paint, SrcRectConstraint constraint) { 235 APPEND(DrawImageRect, this->copy(paint), image, this->copy(src), dst, constraint); 236 } 237 238 void SkRecorder::onDrawImageNine(const SkImage* image, const SkIRect& center, 239 const SkRect& dst, const SkPaint* paint) { 240 APPEND(DrawImageNine, this->copy(paint), image, center, dst); 241 } 242 243 void SkRecorder::onDrawText(const void* text, size_t byteLength, 244 SkScalar x, SkScalar y, const SkPaint& paint) { 245 APPEND(DrawText, 246 paint, this->copy((const char*)text, byteLength), byteLength, x, y); 247 } 248 249 void SkRecorder::onDrawPosText(const void* text, size_t byteLength, 250 const SkPoint pos[], const SkPaint& paint) { 251 const int points = paint.countText(text, byteLength); 252 APPEND(DrawPosText, 253 paint, 254 this->copy((const char*)text, byteLength), 255 byteLength, 256 this->copy(pos, points)); 257 } 258 259 void SkRecorder::onDrawPosTextH(const void* text, size_t byteLength, 260 const SkScalar xpos[], SkScalar constY, const SkPaint& paint) { 261 const int points = paint.countText(text, byteLength); 262 APPEND(DrawPosTextH, 263 paint, 264 this->copy((const char*)text, byteLength), 265 SkToUInt(byteLength), 266 constY, 267 this->copy(xpos, points)); 268 } 269 270 void SkRecorder::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, 271 const SkMatrix* matrix, const SkPaint& paint) { 272 APPEND(DrawTextOnPath, 273 paint, 274 this->copy((const char*)text, byteLength), 275 byteLength, 276 path, 277 matrix ? *matrix : SkMatrix::I()); 278 } 279 280 void SkRecorder::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 281 const SkPaint& paint) { 282 TRY_MINIRECORDER(drawTextBlob, blob, x, y, paint); 283 APPEND(DrawTextBlob, paint, blob, x, y); 284 } 285 286 void SkRecorder::onDrawPicture(const SkPicture* pic, const SkMatrix* matrix, const SkPaint* paint) { 287 if (fDrawPictureMode == Record_DrawPictureMode) { 288 fApproxBytesUsedBySubPictures += SkPictureUtils::ApproximateBytesUsed(pic); 289 APPEND(DrawPicture, this->copy(paint), pic, matrix ? *matrix : SkMatrix::I()); 290 } else { 291 SkASSERT(fDrawPictureMode == Playback_DrawPictureMode); 292 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, pic->cullRect()); 293 pic->playback(this); 294 } 295 } 296 297 void SkRecorder::onDrawVertices(VertexMode vmode, 298 int vertexCount, const SkPoint vertices[], 299 const SkPoint texs[], const SkColor colors[], 300 SkXfermode* xmode, 301 const uint16_t indices[], int indexCount, const SkPaint& paint) { 302 APPEND(DrawVertices, paint, 303 vmode, 304 vertexCount, 305 this->copy(vertices, vertexCount), 306 texs ? this->copy(texs, vertexCount) : nullptr, 307 colors ? this->copy(colors, vertexCount) : nullptr, 308 xmode, 309 this->copy(indices, indexCount), 310 indexCount); 311 } 312 313 void SkRecorder::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], 314 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) { 315 APPEND(DrawPatch, paint, 316 cubics ? this->copy(cubics, SkPatchUtils::kNumCtrlPts) : nullptr, 317 colors ? this->copy(colors, SkPatchUtils::kNumCorners) : nullptr, 318 texCoords ? this->copy(texCoords, SkPatchUtils::kNumCorners) : nullptr, 319 xmode); 320 } 321 322 void SkRecorder::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], 323 const SkColor colors[], int count, SkXfermode::Mode mode, 324 const SkRect* cull, const SkPaint* paint) { 325 APPEND(DrawAtlas, this->copy(paint), 326 atlas, 327 this->copy(xform, count), 328 this->copy(tex, count), 329 this->copy(colors, count), 330 count, 331 mode, 332 this->copy(cull)); 333 } 334 335 void SkRecorder::willSave() { 336 APPEND(Save); 337 } 338 339 SkCanvas::SaveLayerStrategy SkRecorder::getSaveLayerStrategy(const SaveLayerRec& rec) { 340 APPEND(SaveLayer, 341 this->copy(rec.fBounds), this->copy(rec.fPaint), rec.fBackdrop, rec.fSaveLayerFlags); 342 return SkCanvas::kNoLayer_SaveLayerStrategy; 343 } 344 345 void SkRecorder::didRestore() { 346 APPEND(Restore, this->devBounds(), this->getTotalMatrix()); 347 } 348 349 void SkRecorder::didConcat(const SkMatrix& matrix) { 350 APPEND(Concat, matrix); 351 } 352 353 void SkRecorder::didSetMatrix(const SkMatrix& matrix) { 354 APPEND(SetMatrix, matrix); 355 } 356 357 void SkRecorder::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 358 INHERITED(onClipRect, rect, op, edgeStyle); 359 SkRecords::RegionOpAndAA opAA(op, kSoft_ClipEdgeStyle == edgeStyle); 360 APPEND(ClipRect, this->devBounds(), rect, opAA); 361 } 362 363 void SkRecorder::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 364 INHERITED(onClipRRect, rrect, op, edgeStyle); 365 SkRecords::RegionOpAndAA opAA(op, kSoft_ClipEdgeStyle == edgeStyle); 366 APPEND(ClipRRect, this->devBounds(), rrect, opAA); 367 } 368 369 void SkRecorder::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 370 INHERITED(onClipPath, path, op, edgeStyle); 371 SkRecords::RegionOpAndAA opAA(op, kSoft_ClipEdgeStyle == edgeStyle); 372 APPEND(ClipPath, this->devBounds(), path, opAA); 373 } 374 375 void SkRecorder::onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) { 376 INHERITED(onClipRegion, deviceRgn, op); 377 APPEND(ClipRegion, this->devBounds(), deviceRgn, op); 378 } 379 380