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 "SkRecorder.h"
      9 #include "SkPicture.h"
     10 
     11 // SkCanvas will fail in mysterious ways if it doesn't know the real width and height.
     12 SkRecorder::SkRecorder(SkRecord* record, int width, int height)
     13     : SkCanvas(width, height), fRecord(record) {}
     14 
     15 void SkRecorder::forgetRecord() {
     16     fRecord = NULL;
     17 }
     18 
     19 // To make appending to fRecord a little less verbose.
     20 #define APPEND(T, ...) \
     21         SkNEW_PLACEMENT_ARGS(fRecord->append<SkRecords::T>(), SkRecords::T, (__VA_ARGS__))
     22 
     23 // For methods which must call back into SkCanvas.
     24 #define INHERITED(method, ...) this->SkCanvas::method(__VA_ARGS__)
     25 
     26 // The structs we're creating all copy their constructor arguments.  Given the way the SkRecords
     27 // framework works, sometimes they happen to technically be copied twice, which is fine and elided
     28 // into a single copy unless the class has a non-trivial copy constructor.  For classes with
     29 // non-trivial copy constructors, we skip the first copy (and its destruction) by wrapping the value
     30 // with delay_copy(), forcing the argument to be passed by const&.
     31 //
     32 // This is used below for SkBitmap, SkPaint, SkPath, and SkRegion, which all have non-trivial copy
     33 // constructors and destructors.  You'll know you've got a good candidate T if you see ~T() show up
     34 // unexpectedly on a profile of record time.  Otherwise don't bother.
     35 template <typename T>
     36 class Reference {
     37 public:
     38     Reference(const T& x) : fX(x) {}
     39     operator const T&() const { return fX; }
     40 private:
     41     const T& fX;
     42 };
     43 
     44 template <typename T>
     45 static Reference<T> delay_copy(const T& x) { return Reference<T>(x); }
     46 
     47 // Use copy() only for optional arguments, to be copied if present or skipped if not.
     48 // (For most types we just pass by value and let copy constructors do their thing.)
     49 template <typename T>
     50 T* SkRecorder::copy(const T* src) {
     51     if (NULL == src) {
     52         return NULL;
     53     }
     54     return SkNEW_PLACEMENT_ARGS(fRecord->alloc<T>(), T, (*src));
     55 }
     56 
     57 // This copy() is for arrays.
     58 // It will work with POD or non-POD, though currently we only use it for POD.
     59 template <typename T>
     60 T* SkRecorder::copy(const T src[], unsigned count) {
     61     if (NULL == src) {
     62         return NULL;
     63     }
     64     T* dst = fRecord->alloc<T>(count);
     65     for (unsigned i = 0; i < count; i++) {
     66         SkNEW_PLACEMENT_ARGS(dst + i, T, (src[i]));
     67     }
     68     return dst;
     69 }
     70 
     71 // Specialization for copying strings, using memcpy.
     72 // This measured around 2x faster for copying code points,
     73 // but I found no corresponding speedup for other arrays.
     74 template <>
     75 char* SkRecorder::copy(const char src[], unsigned count) {
     76     if (NULL == src) {
     77         return NULL;
     78     }
     79     char* dst = fRecord->alloc<char>(count);
     80     memcpy(dst, src, count);
     81     return dst;
     82 }
     83 
     84 void SkRecorder::clear(SkColor color) {
     85     APPEND(Clear, color);
     86 }
     87 
     88 void SkRecorder::drawPaint(const SkPaint& paint) {
     89     APPEND(DrawPaint, delay_copy(paint));
     90 }
     91 
     92 void SkRecorder::drawPoints(PointMode mode,
     93                             size_t count,
     94                             const SkPoint pts[],
     95                             const SkPaint& paint) {
     96     APPEND(DrawPoints, delay_copy(paint), mode, count, this->copy(pts, count));
     97 }
     98 
     99 void SkRecorder::drawRect(const SkRect& rect, const SkPaint& paint) {
    100     APPEND(DrawRect, delay_copy(paint), rect);
    101 }
    102 
    103 void SkRecorder::drawOval(const SkRect& oval, const SkPaint& paint) {
    104     APPEND(DrawOval, delay_copy(paint), oval);
    105 }
    106 
    107 void SkRecorder::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
    108     APPEND(DrawRRect, delay_copy(paint), rrect);
    109 }
    110 
    111 void SkRecorder::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
    112     APPEND(DrawDRRect, delay_copy(paint), outer, inner);
    113 }
    114 
    115 void SkRecorder::drawPath(const SkPath& path, const SkPaint& paint) {
    116     APPEND(DrawPath, delay_copy(paint), delay_copy(path));
    117 }
    118 
    119 void SkRecorder::drawBitmap(const SkBitmap& bitmap,
    120                             SkScalar left,
    121                             SkScalar top,
    122                             const SkPaint* paint) {
    123     APPEND(DrawBitmap, this->copy(paint), delay_copy(bitmap), left, top);
    124 }
    125 
    126 void SkRecorder::drawBitmapRectToRect(const SkBitmap& bitmap,
    127                                       const SkRect* src,
    128                                       const SkRect& dst,
    129                                       const SkPaint* paint,
    130                                       DrawBitmapRectFlags flags) {
    131     APPEND(DrawBitmapRectToRect,
    132            this->copy(paint), delay_copy(bitmap), this->copy(src), dst, flags);
    133 }
    134 
    135 void SkRecorder::drawBitmapMatrix(const SkBitmap& bitmap,
    136                                   const SkMatrix& matrix,
    137                                   const SkPaint* paint) {
    138     APPEND(DrawBitmapMatrix, this->copy(paint), delay_copy(bitmap), matrix);
    139 }
    140 
    141 void SkRecorder::drawBitmapNine(const SkBitmap& bitmap,
    142                                 const SkIRect& center,
    143                                 const SkRect& dst,
    144                                 const SkPaint* paint) {
    145     APPEND(DrawBitmapNine, this->copy(paint), delay_copy(bitmap), center, dst);
    146 }
    147 
    148 void SkRecorder::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
    149     APPEND(DrawSprite, this->copy(paint), delay_copy(bitmap), left, top);
    150 }
    151 
    152 void SkRecorder::onDrawText(const void* text, size_t byteLength,
    153                             SkScalar x, SkScalar y, const SkPaint& paint) {
    154     APPEND(DrawText,
    155            delay_copy(paint), this->copy((const char*)text, byteLength), byteLength, x, y);
    156 }
    157 
    158 void SkRecorder::onDrawPosText(const void* text, size_t byteLength,
    159                                const SkPoint pos[], const SkPaint& paint) {
    160     const unsigned points = paint.countText(text, byteLength);
    161     APPEND(DrawPosText,
    162            delay_copy(paint),
    163            this->copy((const char*)text, byteLength),
    164            byteLength,
    165            this->copy(pos, points));
    166 }
    167 
    168 void SkRecorder::onDrawPosTextH(const void* text, size_t byteLength,
    169                                 const SkScalar xpos[], SkScalar constY, const SkPaint& paint) {
    170     const unsigned points = paint.countText(text, byteLength);
    171     APPEND(DrawPosTextH,
    172            delay_copy(paint),
    173            this->copy((const char*)text, byteLength),
    174            byteLength,
    175            this->copy(xpos, points),
    176            constY);
    177 }
    178 
    179 void SkRecorder::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
    180                                   const SkMatrix* matrix, const SkPaint& paint) {
    181     APPEND(DrawTextOnPath,
    182            delay_copy(paint),
    183            this->copy((const char*)text, byteLength),
    184            byteLength,
    185            delay_copy(path),
    186            this->copy(matrix));
    187 }
    188 
    189 void SkRecorder::onDrawPicture(const SkPicture* picture) {
    190     picture->draw(this);
    191 }
    192 
    193 void SkRecorder::drawVertices(VertexMode vmode,
    194                               int vertexCount, const SkPoint vertices[],
    195                               const SkPoint texs[], const SkColor colors[],
    196                               SkXfermode* xmode,
    197                               const uint16_t indices[], int indexCount, const SkPaint& paint) {
    198     APPEND(DrawVertices, delay_copy(paint),
    199                          vmode,
    200                          vertexCount,
    201                          this->copy(vertices, vertexCount),
    202                          texs ? this->copy(texs, vertexCount) : NULL,
    203                          colors ? this->copy(colors, vertexCount) : NULL,
    204                          xmode,
    205                          this->copy(indices, indexCount),
    206                          indexCount);
    207 }
    208 
    209 void SkRecorder::willSave(SkCanvas::SaveFlags flags) {
    210     APPEND(Save, flags);
    211     INHERITED(willSave, flags);
    212 }
    213 
    214 SkCanvas::SaveLayerStrategy SkRecorder::willSaveLayer(const SkRect* bounds,
    215                                                       const SkPaint* paint,
    216                                                       SkCanvas::SaveFlags flags) {
    217     APPEND(SaveLayer, this->copy(bounds), this->copy(paint), flags);
    218     INHERITED(willSaveLayer, bounds, paint, flags);
    219     return SkCanvas::kNoLayer_SaveLayerStrategy;
    220 }
    221 
    222 void SkRecorder::willRestore() {
    223     APPEND(Restore);
    224     INHERITED(willRestore);
    225 }
    226 
    227 void SkRecorder::onPushCull(const SkRect& rect) {
    228     APPEND(PushCull, rect);
    229 }
    230 
    231 void SkRecorder::onPopCull() {
    232     APPEND(PopCull);
    233 }
    234 
    235 void SkRecorder::didConcat(const SkMatrix& matrix) {
    236     APPEND(Concat, matrix);
    237     INHERITED(didConcat, matrix);
    238 }
    239 
    240 void SkRecorder::didSetMatrix(const SkMatrix& matrix) {
    241     APPEND(SetMatrix, matrix);
    242     INHERITED(didSetMatrix, matrix);
    243 }
    244 
    245 void SkRecorder::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
    246     APPEND(ClipRect, rect, op, edgeStyle == kSoft_ClipEdgeStyle);
    247     INHERITED(onClipRect, rect, op, edgeStyle);
    248 }
    249 
    250 void SkRecorder::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
    251     APPEND(ClipRRect, rrect, op, edgeStyle == kSoft_ClipEdgeStyle);
    252     INHERITED(updateClipConservativelyUsingBounds, rrect.getBounds(), op, false);
    253 }
    254 
    255 void SkRecorder::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
    256     APPEND(ClipPath, delay_copy(path), op, edgeStyle == kSoft_ClipEdgeStyle);
    257     INHERITED(updateClipConservativelyUsingBounds, path.getBounds(), op, path.isInverseFillType());
    258 }
    259 
    260 void SkRecorder::onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) {
    261     APPEND(ClipRegion, delay_copy(deviceRgn), op);
    262     INHERITED(onClipRegion, deviceRgn, op);
    263 }
    264