Home | History | Annotate | Download | only in core
      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 "SkPatchUtils.h"
      9 #include "SkPicture.h"
     10 #include "SkPictureUtils.h"
     11 #include "SkRecorder.h"
     12 
     13 SkDrawableList::~SkDrawableList() {
     14     fArray.unrefAll();
     15 }
     16 
     17 SkPicture::SnapshotArray* SkDrawableList::newDrawableSnapshot() {
     18     const int count = fArray.count();
     19     if (0 == count) {
     20         return NULL;
     21     }
     22     SkAutoTMalloc<const SkPicture*> pics(count);
     23     for (int i = 0; i < count; ++i) {
     24         pics[i] = fArray[i]->newPictureSnapshot();
     25     }
     26     return SkNEW_ARGS(SkPicture::SnapshotArray, (pics.detach(), count));
     27 }
     28 
     29 void SkDrawableList::append(SkDrawable* drawable) {
     30     *fArray.append() = SkRef(drawable);
     31 }
     32 
     33 ///////////////////////////////////////////////////////////////////////////////////////////////
     34 
     35 SkRecorder::SkRecorder(SkRecord* record, int width, int height)
     36     : SkCanvas(SkIRect::MakeWH(width, height), SkCanvas::kConservativeRasterClip_InitFlag)
     37     , fApproxBytesUsedBySubPictures(0)
     38     , fRecord(record) {}
     39 
     40 SkRecorder::SkRecorder(SkRecord* record, const SkRect& bounds)
     41     : SkCanvas(bounds.roundOut(), SkCanvas::kConservativeRasterClip_InitFlag)
     42     , fApproxBytesUsedBySubPictures(0)
     43     , fRecord(record) {}
     44 
     45 void SkRecorder::reset(SkRecord* record, const SkRect& bounds) {
     46     this->forgetRecord();
     47     fRecord = record;
     48     this->resetForNextPicture(bounds.roundOut());
     49 }
     50 
     51 void SkRecorder::forgetRecord() {
     52     fDrawableList.reset(NULL);
     53     fApproxBytesUsedBySubPictures = 0;
     54     fRecord = NULL;
     55 }
     56 
     57 // To make appending to fRecord a little less verbose.
     58 #define APPEND(T, ...) \
     59         SkNEW_PLACEMENT_ARGS(fRecord->append<SkRecords::T>(), SkRecords::T, (__VA_ARGS__))
     60 
     61 // For methods which must call back into SkCanvas.
     62 #define INHERITED(method, ...) this->SkCanvas::method(__VA_ARGS__)
     63 
     64 // The structs we're creating all copy their constructor arguments.  Given the way the SkRecords
     65 // framework works, sometimes they happen to technically be copied twice, which is fine and elided
     66 // into a single copy unless the class has a non-trivial copy constructor.  For classes with
     67 // non-trivial copy constructors, we skip the first copy (and its destruction) by wrapping the value
     68 // with delay_copy(), forcing the argument to be passed by const&.
     69 //
     70 // This is used below for SkBitmap, SkPaint, SkPath, and SkRegion, which all have non-trivial copy
     71 // constructors and destructors.  You'll know you've got a good candidate T if you see ~T() show up
     72 // unexpectedly on a profile of record time.  Otherwise don't bother.
     73 template <typename T>
     74 class Reference {
     75 public:
     76     Reference(const T& x) : fX(x) {}
     77     operator const T&() const { return fX; }
     78 private:
     79     const T& fX;
     80 };
     81 
     82 template <typename T>
     83 static Reference<T> delay_copy(const T& x) { return Reference<T>(x); }
     84 
     85 // Use copy() only for optional arguments, to be copied if present or skipped if not.
     86 // (For most types we just pass by value and let copy constructors do their thing.)
     87 template <typename T>
     88 T* SkRecorder::copy(const T* src) {
     89     if (NULL == src) {
     90         return NULL;
     91     }
     92     return SkNEW_PLACEMENT_ARGS(fRecord->alloc<T>(), T, (*src));
     93 }
     94 
     95 // This copy() is for arrays.
     96 // It will work with POD or non-POD, though currently we only use it for POD.
     97 template <typename T>
     98 T* SkRecorder::copy(const T src[], size_t count) {
     99     if (NULL == src) {
    100         return NULL;
    101     }
    102     T* dst = fRecord->alloc<T>(count);
    103     for (size_t i = 0; i < count; i++) {
    104         SkNEW_PLACEMENT_ARGS(dst + i, T, (src[i]));
    105     }
    106     return dst;
    107 }
    108 
    109 // Specialization for copying strings, using memcpy.
    110 // This measured around 2x faster for copying code points,
    111 // but I found no corresponding speedup for other arrays.
    112 template <>
    113 char* SkRecorder::copy(const char src[], size_t count) {
    114     if (NULL == src) {
    115         return NULL;
    116     }
    117     char* dst = fRecord->alloc<char>(count);
    118     memcpy(dst, src, count);
    119     return dst;
    120 }
    121 
    122 // As above, assuming and copying a terminating \0.
    123 template <>
    124 char* SkRecorder::copy(const char* src) {
    125     return this->copy(src, strlen(src)+1);
    126 }
    127 
    128 
    129 void SkRecorder::onDrawPaint(const SkPaint& paint) {
    130     APPEND(DrawPaint, delay_copy(paint));
    131 }
    132 
    133 void SkRecorder::onDrawPoints(PointMode mode,
    134                               size_t count,
    135                               const SkPoint pts[],
    136                               const SkPaint& paint) {
    137     APPEND(DrawPoints, delay_copy(paint), mode, SkToUInt(count), this->copy(pts, count));
    138 }
    139 
    140 void SkRecorder::onDrawRect(const SkRect& rect, const SkPaint& paint) {
    141     APPEND(DrawRect, delay_copy(paint), rect);
    142 }
    143 
    144 void SkRecorder::onDrawOval(const SkRect& oval, const SkPaint& paint) {
    145     APPEND(DrawOval, delay_copy(paint), oval);
    146 }
    147 
    148 void SkRecorder::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
    149     APPEND(DrawRRect, delay_copy(paint), rrect);
    150 }
    151 
    152 void SkRecorder::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
    153     APPEND(DrawDRRect, delay_copy(paint), outer, inner);
    154 }
    155 
    156 void SkRecorder::onDrawDrawable(SkDrawable* drawable) {
    157     if (!fDrawableList) {
    158         fDrawableList.reset(SkNEW(SkDrawableList));
    159     }
    160     fDrawableList->append(drawable);
    161     APPEND(DrawDrawable, drawable->getBounds(), fDrawableList->count() - 1);
    162 }
    163 
    164 void SkRecorder::onDrawPath(const SkPath& path, const SkPaint& paint) {
    165     APPEND(DrawPath, delay_copy(paint), delay_copy(path));
    166 }
    167 
    168 void SkRecorder::onDrawBitmap(const SkBitmap& bitmap,
    169                               SkScalar left,
    170                               SkScalar top,
    171                               const SkPaint* paint) {
    172     APPEND(DrawBitmap, this->copy(paint), delay_copy(bitmap), left, top);
    173 }
    174 
    175 void SkRecorder::onDrawBitmapRect(const SkBitmap& bitmap,
    176                                   const SkRect* src,
    177                                   const SkRect& dst,
    178                                   const SkPaint* paint,
    179                                   DrawBitmapRectFlags flags) {
    180     if (kBleed_DrawBitmapRectFlag == flags) {
    181         APPEND(DrawBitmapRectToRectBleed,
    182                this->copy(paint), delay_copy(bitmap), this->copy(src), dst);
    183         return;
    184     }
    185     SkASSERT(kNone_DrawBitmapRectFlag == flags);
    186     APPEND(DrawBitmapRectToRect,
    187            this->copy(paint), delay_copy(bitmap), this->copy(src), dst);
    188 }
    189 
    190 void SkRecorder::onDrawBitmapNine(const SkBitmap& bitmap,
    191                                   const SkIRect& center,
    192                                   const SkRect& dst,
    193                                   const SkPaint* paint) {
    194     APPEND(DrawBitmapNine, this->copy(paint), delay_copy(bitmap), center, dst);
    195 }
    196 
    197 void SkRecorder::onDrawImage(const SkImage* image, SkScalar left, SkScalar top,
    198                              const SkPaint* paint) {
    199     APPEND(DrawImage, this->copy(paint), image, left, top);
    200 }
    201 
    202 void SkRecorder::onDrawImageRect(const SkImage* image, const SkRect* src,
    203                                  const SkRect& dst,
    204                                  const SkPaint* paint) {
    205     APPEND(DrawImageRect, this->copy(paint), image, this->copy(src), dst);
    206 }
    207 
    208 void SkRecorder::onDrawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
    209     APPEND(DrawSprite, this->copy(paint), delay_copy(bitmap), left, top);
    210 }
    211 
    212 void SkRecorder::onDrawText(const void* text, size_t byteLength,
    213                             SkScalar x, SkScalar y, const SkPaint& paint) {
    214     APPEND(DrawText,
    215            delay_copy(paint), this->copy((const char*)text, byteLength), byteLength, x, y);
    216 }
    217 
    218 void SkRecorder::onDrawPosText(const void* text, size_t byteLength,
    219                                const SkPoint pos[], const SkPaint& paint) {
    220     const unsigned points = paint.countText(text, byteLength);
    221     APPEND(DrawPosText,
    222            delay_copy(paint),
    223            this->copy((const char*)text, byteLength),
    224            byteLength,
    225            this->copy(pos, points));
    226 }
    227 
    228 void SkRecorder::onDrawPosTextH(const void* text, size_t byteLength,
    229                                 const SkScalar xpos[], SkScalar constY, const SkPaint& paint) {
    230     const unsigned points = paint.countText(text, byteLength);
    231     APPEND(DrawPosTextH,
    232            delay_copy(paint),
    233            this->copy((const char*)text, byteLength),
    234            SkToUInt(byteLength),
    235            constY,
    236            this->copy(xpos, points));
    237 }
    238 
    239 void SkRecorder::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
    240                                   const SkMatrix* matrix, const SkPaint& paint) {
    241     APPEND(DrawTextOnPath,
    242            delay_copy(paint),
    243            this->copy((const char*)text, byteLength),
    244            byteLength,
    245            delay_copy(path),
    246            matrix ? *matrix : SkMatrix::I());
    247 }
    248 
    249 void SkRecorder::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
    250                                 const SkPaint& paint) {
    251     APPEND(DrawTextBlob, delay_copy(paint), blob, x, y);
    252 }
    253 
    254 void SkRecorder::onDrawPicture(const SkPicture* pic, const SkMatrix* matrix, const SkPaint* paint) {
    255     fApproxBytesUsedBySubPictures += SkPictureUtils::ApproximateBytesUsed(pic);
    256     APPEND(DrawPicture, this->copy(paint), pic, matrix ? *matrix : SkMatrix::I());
    257 }
    258 
    259 void SkRecorder::onDrawVertices(VertexMode vmode,
    260                                 int vertexCount, const SkPoint vertices[],
    261                                 const SkPoint texs[], const SkColor colors[],
    262                                 SkXfermode* xmode,
    263                                 const uint16_t indices[], int indexCount, const SkPaint& paint) {
    264     APPEND(DrawVertices, delay_copy(paint),
    265                          vmode,
    266                          vertexCount,
    267                          this->copy(vertices, vertexCount),
    268                          texs ? this->copy(texs, vertexCount) : NULL,
    269                          colors ? this->copy(colors, vertexCount) : NULL,
    270                          xmode,
    271                          this->copy(indices, indexCount),
    272                          indexCount);
    273 }
    274 
    275 void SkRecorder::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
    276                              const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
    277     APPEND(DrawPatch, delay_copy(paint),
    278            cubics ? this->copy(cubics, SkPatchUtils::kNumCtrlPts) : NULL,
    279            colors ? this->copy(colors, SkPatchUtils::kNumCorners) : NULL,
    280            texCoords ? this->copy(texCoords, SkPatchUtils::kNumCorners) : NULL,
    281            xmode);
    282 }
    283 
    284 void SkRecorder::willSave() {
    285     APPEND(Save);
    286 }
    287 
    288 SkCanvas::SaveLayerStrategy SkRecorder::willSaveLayer(const SkRect* bounds,
    289                                                       const SkPaint* paint,
    290                                                       SkCanvas::SaveFlags flags) {
    291     APPEND(SaveLayer, this->copy(bounds), this->copy(paint), flags);
    292     return SkCanvas::kNoLayer_SaveLayerStrategy;
    293 }
    294 
    295 void SkRecorder::didRestore() {
    296     APPEND(Restore, this->devBounds(), this->getTotalMatrix());
    297 }
    298 
    299 void SkRecorder::didConcat(const SkMatrix& matrix) {
    300     this->didSetMatrix(this->getTotalMatrix());
    301 }
    302 
    303 void SkRecorder::didSetMatrix(const SkMatrix& matrix) {
    304     SkDEVCODE(if (matrix != this->getTotalMatrix()) {
    305         matrix.dump();
    306         this->getTotalMatrix().dump();
    307         SkASSERT(matrix == this->getTotalMatrix());
    308     })
    309     APPEND(SetMatrix, matrix);
    310 }
    311 
    312 void SkRecorder::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
    313     INHERITED(onClipRect, rect, op, edgeStyle);
    314     SkRecords::RegionOpAndAA opAA(op, kSoft_ClipEdgeStyle == edgeStyle);
    315     APPEND(ClipRect, this->devBounds(), rect, opAA);
    316 }
    317 
    318 void SkRecorder::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
    319     INHERITED(onClipRRect, rrect, op, edgeStyle);
    320     SkRecords::RegionOpAndAA opAA(op, kSoft_ClipEdgeStyle == edgeStyle);
    321     APPEND(ClipRRect, this->devBounds(), rrect, opAA);
    322 }
    323 
    324 void SkRecorder::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
    325     INHERITED(onClipPath, path, op, edgeStyle);
    326     SkRecords::RegionOpAndAA opAA(op, kSoft_ClipEdgeStyle == edgeStyle);
    327     APPEND(ClipPath, this->devBounds(), delay_copy(path), opAA);
    328 }
    329 
    330 void SkRecorder::onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) {
    331     INHERITED(onClipRegion, deviceRgn, op);
    332     APPEND(ClipRegion, this->devBounds(), delay_copy(deviceRgn), op);
    333 }
    334 
    335 void SkRecorder::beginCommentGroup(const char* description) {
    336     APPEND(BeginCommentGroup, this->copy(description));
    337 }
    338 
    339 void SkRecorder::addComment(const char* key, const char* value) {
    340     APPEND(AddComment, this->copy(key), this->copy(value));
    341 }
    342 
    343 void SkRecorder::endCommentGroup() {
    344     APPEND(EndCommentGroup);
    345 }
    346 
    347