Home | History | Annotate | Download | only in core
      1 /*
      2 **
      3 ** Copyright 2007, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #include "SkPictureFlat.h"
     19 #include "SkPicturePlayback.h"
     20 #include "SkPictureRecord.h"
     21 
     22 #include "SkCanvas.h"
     23 #include "SkChunkAlloc.h"
     24 #include "SkPicture.h"
     25 #include "SkRegion.h"
     26 #include "SkStream.h"
     27 #include "SkTDArray.h"
     28 #include "SkTSearch.h"
     29 #include "SkTime.h"
     30 
     31 #include "SkReader32.h"
     32 #include "SkWriter32.h"
     33 
     34 #define DUMP_BUFFER_SIZE 65536
     35 
     36 //#define ENABLE_TIME_DRAW    // dumps milliseconds for each draw
     37 
     38 
     39 #ifdef SK_DEBUG
     40 // enable SK_DEBUG_TRACE to trace DrawType elements when
     41 //     recorded and played back
     42 // #define SK_DEBUG_TRACE
     43 // enable SK_DEBUG_SIZE to see the size of picture components
     44 // #define SK_DEBUG_SIZE
     45 // enable SK_DEBUG_DUMP to see the contents of recorded elements
     46 // #define SK_DEBUG_DUMP
     47 // enable SK_DEBUG_VALIDATE to check internal structures for consistency
     48 // #define SK_DEBUG_VALIDATE
     49 #endif
     50 
     51 #if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP
     52 const char* DrawTypeToString(DrawType drawType) {
     53     switch (drawType) {
     54         case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break;
     55         case CLIP_PATH: return "CLIP_PATH";
     56         case CLIP_REGION: return "CLIP_REGION";
     57         case CLIP_RECT: return "CLIP_RECT";
     58         case CONCAT: return "CONCAT";
     59         case DRAW_BITMAP: return "DRAW_BITMAP";
     60         case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX";
     61         case DRAW_BITMAP_RECT: return "DRAW_BITMAP_RECT";
     62         case DRAW_PAINT: return "DRAW_PAINT";
     63         case DRAW_PATH: return "DRAW_PATH";
     64         case DRAW_PICTURE: return "DRAW_PICTURE";
     65         case DRAW_POINTS: return "DRAW_POINTS";
     66         case DRAW_POS_TEXT: return "DRAW_POS_TEXT";
     67         case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H";
     68         case DRAW_RECT_GENERAL: return "DRAW_RECT_GENERAL";
     69         case DRAW_RECT_SIMPLE: return "DRAW_RECT_SIMPLE";
     70         case DRAW_SPRITE: return "DRAW_SPRITE";
     71         case DRAW_TEXT: return "DRAW_TEXT";
     72         case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH";
     73         case RESTORE: return "RESTORE";
     74         case ROTATE: return "ROTATE";
     75         case SAVE: return "SAVE";
     76         case SAVE_LAYER: return "SAVE_LAYER";
     77         case SCALE: return "SCALE";
     78         case SKEW: return "SKEW";
     79         case TRANSLATE: return "TRANSLATE";
     80         default:
     81             SkDebugf("DrawType error 0x%08x\n", drawType);
     82             SkASSERT(0);
     83             break;
     84     }
     85     SkASSERT(0);
     86     return NULL;
     87 }
     88 #endif
     89 
     90 #ifdef SK_DEBUG_VALIDATE
     91 static void validateMatrix(const SkMatrix* matrix) {
     92     SkScalar scaleX = matrix->getScaleX();
     93     SkScalar scaleY = matrix->getScaleY();
     94     SkScalar skewX = matrix->getSkewX();
     95     SkScalar skewY = matrix->getSkewY();
     96     SkScalar perspX = matrix->getPerspX();
     97     SkScalar perspY = matrix->getPerspY();
     98     if (scaleX != 0 && skewX != 0)
     99         SkDebugf("scaleX != 0 && skewX != 0\n");
    100     SkASSERT(scaleX == 0 || skewX == 0);
    101     SkASSERT(scaleY == 0 || skewY == 0);
    102     SkASSERT(perspX == 0);
    103     SkASSERT(perspY == 0);
    104 }
    105 #endif
    106 
    107 
    108 ///////////////////////////////////////////////////////////////////////////////
    109 
    110 SkPicture::SkPicture() {
    111     fRecord = NULL;
    112     fPlayback = NULL;
    113     fWidth = fHeight = 0;
    114 }
    115 
    116 SkPicture::SkPicture(const SkPicture& src) : SkRefCnt() {
    117     fWidth = src.fWidth;
    118     fHeight = src.fHeight;
    119     fRecord = NULL;
    120 
    121     /*  We want to copy the src's playback. However, if that hasn't been built
    122         yet, we need to fake a call to endRecording() without actually calling
    123         it (since it is destructive, and we don't want to change src).
    124      */
    125     if (src.fPlayback) {
    126         fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback));
    127     } else if (src.fRecord) {
    128         // here we do a fake src.endRecording()
    129         fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fRecord));
    130     } else {
    131         fPlayback = NULL;
    132     }
    133 }
    134 
    135 SkPicture::~SkPicture() {
    136     SkSafeUnref(fRecord);
    137     SkDELETE(fPlayback);
    138 }
    139 
    140 void SkPicture::swap(SkPicture& other) {
    141     SkTSwap(fRecord, other.fRecord);
    142     SkTSwap(fPlayback, other.fPlayback);
    143     SkTSwap(fWidth, other.fWidth);
    144     SkTSwap(fHeight, other.fHeight);
    145 }
    146 
    147 ///////////////////////////////////////////////////////////////////////////////
    148 
    149 SkCanvas* SkPicture::beginRecording(int width, int height,
    150                                     uint32_t recordingFlags) {
    151     if (fPlayback) {
    152         SkDELETE(fPlayback);
    153         fPlayback = NULL;
    154     }
    155 
    156     if (NULL != fRecord) {
    157         fRecord->unref();
    158         fRecord = NULL;
    159     }
    160 
    161     fRecord = SkNEW_ARGS(SkPictureRecord, (recordingFlags));
    162 
    163     fWidth = width;
    164     fHeight = height;
    165 
    166     SkBitmap bm;
    167     bm.setConfig(SkBitmap::kNo_Config, width, height);
    168     fRecord->setBitmapDevice(bm);
    169 
    170     return fRecord;
    171 }
    172 
    173 SkCanvas* SkPicture::getRecordingCanvas() const {
    174     // will be null if we are not recording
    175     return fRecord;
    176 }
    177 
    178 void SkPicture::endRecording() {
    179     if (NULL == fPlayback) {
    180         if (NULL != fRecord) {
    181             fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
    182             fRecord->unref();
    183             fRecord = NULL;
    184         }
    185     }
    186     SkASSERT(NULL == fRecord);
    187 }
    188 
    189 void SkPicture::draw(SkCanvas* surface) {
    190     this->endRecording();
    191     if (fPlayback) {
    192         fPlayback->draw(*surface);
    193     }
    194 }
    195 
    196 ///////////////////////////////////////////////////////////////////////////////
    197 
    198 #include "SkStream.h"
    199 
    200 #define PICTURE_VERSION     1
    201 
    202 SkPicture::SkPicture(SkStream* stream) : SkRefCnt() {
    203     if (stream->readU32() != PICTURE_VERSION) {
    204         sk_throw();
    205     }
    206 
    207     fWidth = stream->readU32();
    208     fHeight = stream->readU32();
    209 
    210     fRecord = NULL;
    211     fPlayback = NULL;
    212 
    213     if (stream->readBool()) {
    214         fPlayback = SkNEW_ARGS(SkPicturePlayback, (stream));
    215     }
    216 }
    217 
    218 void SkPicture::serialize(SkWStream* stream) const {
    219     SkPicturePlayback* playback = fPlayback;
    220 
    221     if (NULL == playback && fRecord) {
    222         playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
    223     }
    224 
    225     stream->write32(PICTURE_VERSION);
    226     stream->write32(fWidth);
    227     stream->write32(fHeight);
    228     if (playback) {
    229         stream->writeBool(true);
    230         playback->serialize(stream);
    231         // delete playback if it is a local version (i.e. cons'd up just now)
    232         if (playback != fPlayback) {
    233             SkDELETE(playback);
    234         }
    235     } else {
    236         stream->writeBool(false);
    237     }
    238 }
    239 
    240 void SkPicture::abortPlayback() {
    241     if (NULL == fPlayback) {
    242         return;
    243     }
    244     fPlayback->abort();
    245 }
    246 
    247 
    248