1 2 /* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 #ifndef SkPicturePlayback_DEFINED 10 #define SkPicturePlayback_DEFINED 11 12 #include "SkBitmap.h" 13 #include "SkPathHeap.h" 14 #include "SkPicture.h" 15 #include "SkPictureFlat.h" 16 17 #ifdef SK_BUILD_FOR_ANDROID 18 #include "SkThread.h" 19 #endif 20 21 class SkData; 22 class SkPictureRecord; 23 class SkReader32; 24 class SkStream; 25 class SkWStream; 26 class SkBBoxHierarchy; 27 class SkMatrix; 28 class SkPaint; 29 class SkPath; 30 class SkPictureStateTree; 31 class SkReadBuffer; 32 class SkRegion; 33 34 struct SkPictInfo { 35 enum Flags { 36 kCrossProcess_Flag = 1 << 0, 37 kScalarIsFloat_Flag = 1 << 1, 38 kPtrIs64Bit_Flag = 1 << 2, 39 }; 40 41 char fMagic[8]; 42 uint32_t fVersion; 43 uint32_t fWidth; 44 uint32_t fHeight; 45 uint32_t fFlags; 46 }; 47 48 #define SK_PICT_READER_TAG SkSetFourByteTag('r', 'e', 'a', 'd') 49 #define SK_PICT_FACTORY_TAG SkSetFourByteTag('f', 'a', 'c', 't') 50 #define SK_PICT_TYPEFACE_TAG SkSetFourByteTag('t', 'p', 'f', 'c') 51 #define SK_PICT_PICTURE_TAG SkSetFourByteTag('p', 'c', 't', 'r') 52 53 // This tag specifies the size of the ReadBuffer, needed for the following tags 54 #define SK_PICT_BUFFER_SIZE_TAG SkSetFourByteTag('a', 'r', 'a', 'y') 55 // these are all inside the ARRAYS tag 56 #define SK_PICT_BITMAP_BUFFER_TAG SkSetFourByteTag('b', 't', 'm', 'p') 57 #define SK_PICT_PAINT_BUFFER_TAG SkSetFourByteTag('p', 'n', 't', ' ') 58 #define SK_PICT_PATH_BUFFER_TAG SkSetFourByteTag('p', 't', 'h', ' ') 59 60 // Always write this guy last (with no length field afterwards) 61 #define SK_PICT_EOF_TAG SkSetFourByteTag('e', 'o', 'f', ' ') 62 63 // SkPictureContentInfo is not serialized! It is intended solely for use 64 // with suitableForGpuRasterization. 65 class SkPictureContentInfo { 66 public: 67 SkPictureContentInfo() { this->reset(); } 68 69 SkPictureContentInfo(const SkPictureContentInfo& src) { this->set(src); } 70 71 void set(const SkPictureContentInfo& src) { 72 fNumPaintWithPathEffectUses = src.fNumPaintWithPathEffectUses; 73 fNumFastPathDashEffects = src.fNumFastPathDashEffects; 74 fNumAAConcavePaths = src.fNumAAConcavePaths; 75 fNumAAHairlineConcavePaths = src.fNumAAHairlineConcavePaths; 76 } 77 78 void reset() { 79 fNumPaintWithPathEffectUses = 0; 80 fNumFastPathDashEffects = 0; 81 fNumAAConcavePaths = 0; 82 fNumAAHairlineConcavePaths = 0; 83 } 84 85 void swap(SkPictureContentInfo* other) { 86 SkTSwap(fNumPaintWithPathEffectUses, other->fNumPaintWithPathEffectUses); 87 SkTSwap(fNumFastPathDashEffects, other->fNumFastPathDashEffects); 88 SkTSwap(fNumAAConcavePaths, other->fNumAAConcavePaths); 89 SkTSwap(fNumAAHairlineConcavePaths, other->fNumAAHairlineConcavePaths); 90 } 91 92 void incPaintWithPathEffectUses() { ++fNumPaintWithPathEffectUses; } 93 int numPaintWithPathEffectUses() const { return fNumPaintWithPathEffectUses; } 94 95 void incFastPathDashEffects() { ++fNumFastPathDashEffects; } 96 int numFastPathDashEffects() const { return fNumFastPathDashEffects; } 97 98 void incAAConcavePaths() { ++fNumAAConcavePaths; } 99 int numAAConcavePaths() const { return fNumAAConcavePaths; } 100 101 void incAAHairlineConcavePaths() { 102 ++fNumAAHairlineConcavePaths; 103 SkASSERT(fNumAAHairlineConcavePaths <= fNumAAConcavePaths); 104 } 105 int numAAHairlineConcavePaths() const { return fNumAAHairlineConcavePaths; } 106 107 private: 108 // This field is incremented every time a paint with a path effect is 109 // used (i.e., it is not a de-duplicated count) 110 int fNumPaintWithPathEffectUses; 111 // This field is incremented every time a paint with a path effect that is 112 // dashed, we are drawing a line, and we can use the gpu fast path 113 int fNumFastPathDashEffects; 114 // This field is incremented every time an anti-aliased drawPath call is 115 // issued with a concave path 116 int fNumAAConcavePaths; 117 // This field is incremented every time a drawPath call is 118 // issued for a hairline stroked concave path. 119 int fNumAAHairlineConcavePaths; 120 }; 121 122 /** 123 * Container for data that is needed to deep copy a SkPicture. The container 124 * enables the data to be generated once and reused for subsequent copies. 125 */ 126 struct SkPictCopyInfo { 127 SkPictCopyInfo() : initialized(false), controller(1024) {} 128 129 bool initialized; 130 SkChunkFlatController controller; 131 SkTDArray<SkFlatData*> paintData; 132 }; 133 134 class SkPicturePlayback { 135 public: 136 SkPicturePlayback(const SkPicturePlayback& src, 137 SkPictCopyInfo* deepCopyInfo = NULL); 138 SkPicturePlayback(const SkPictureRecord& record, const SkPictInfo&, bool deepCopyOps); 139 static SkPicturePlayback* CreateFromStream(SkStream*, 140 const SkPictInfo&, 141 SkPicture::InstallPixelRefProc); 142 static SkPicturePlayback* CreateFromBuffer(SkReadBuffer&, 143 const SkPictInfo&); 144 145 virtual ~SkPicturePlayback(); 146 147 const SkPicture::OperationList& getActiveOps(const SkIRect& queryRect); 148 149 void setUseBBH(bool useBBH) { fUseBBH = useBBH; } 150 151 void draw(SkCanvas& canvas, SkDrawPictureCallback*); 152 153 void serialize(SkWStream*, SkPicture::EncodeBitmap) const; 154 void flatten(SkWriteBuffer&) const; 155 156 void dumpSize() const; 157 158 bool containsBitmaps() const; 159 160 #ifdef SK_BUILD_FOR_ANDROID 161 // Can be called in the middle of playback (the draw() call). WIll abort the 162 // drawing and return from draw() after the "current" op code is done 163 void abort() { fAbortCurrentPlayback = true; } 164 #endif 165 166 size_t curOpID() const { return fCurOffset; } 167 void resetOpID() { fCurOffset = 0; } 168 169 protected: 170 explicit SkPicturePlayback(const SkPictInfo& info); 171 172 bool parseStream(SkStream*, SkPicture::InstallPixelRefProc); 173 bool parseBuffer(SkReadBuffer& buffer); 174 #ifdef SK_DEVELOPER 175 virtual bool preDraw(int opIndex, int type); 176 virtual void postDraw(int opIndex); 177 #endif 178 179 private: 180 class TextContainer { 181 public: 182 size_t length() { return fByteLength; } 183 const void* text() { return (const void*) fText; } 184 size_t fByteLength; 185 const char* fText; 186 }; 187 188 const SkBitmap& getBitmap(SkReader32& reader) { 189 const int index = reader.readInt(); 190 if (SkBitmapHeap::INVALID_SLOT == index) { 191 #ifdef SK_DEBUG 192 SkDebugf("An invalid bitmap was recorded!\n"); 193 #endif 194 return fBadBitmap; 195 } 196 return (*fBitmaps)[index]; 197 } 198 199 void getMatrix(SkReader32& reader, SkMatrix* matrix) { 200 reader.readMatrix(matrix); 201 } 202 203 const SkPath& getPath(SkReader32& reader) { 204 int index = reader.readInt() - 1; 205 return (*fPathHeap.get())[index]; 206 } 207 208 const SkPicture* getPicture(SkReader32& reader) { 209 int index = reader.readInt(); 210 SkASSERT(index > 0 && index <= fPictureCount); 211 return fPictureRefs[index - 1]; 212 } 213 214 const SkPaint* getPaint(SkReader32& reader) { 215 int index = reader.readInt(); 216 if (index == 0) { 217 return NULL; 218 } 219 return &(*fPaints)[index - 1]; 220 } 221 222 const SkRect* getRectPtr(SkReader32& reader) { 223 if (reader.readBool()) { 224 return &reader.skipT<SkRect>(); 225 } else { 226 return NULL; 227 } 228 } 229 230 const SkIRect* getIRectPtr(SkReader32& reader) { 231 if (reader.readBool()) { 232 return &reader.skipT<SkIRect>(); 233 } else { 234 return NULL; 235 } 236 } 237 238 void getRegion(SkReader32& reader, SkRegion* region) { 239 reader.readRegion(region); 240 } 241 242 void getText(SkReader32& reader, TextContainer* text) { 243 size_t length = text->fByteLength = reader.readInt(); 244 text->fText = (const char*)reader.skip(length); 245 } 246 247 void init(); 248 249 #ifdef SK_DEBUG_SIZE 250 public: 251 int size(size_t* sizePtr); 252 int bitmaps(size_t* size); 253 int paints(size_t* size); 254 int paths(size_t* size); 255 #endif 256 257 #ifdef SK_DEBUG_DUMP 258 private: 259 void dumpBitmap(const SkBitmap& bitmap) const; 260 void dumpMatrix(const SkMatrix& matrix) const; 261 void dumpPaint(const SkPaint& paint) const; 262 void dumpPath(const SkPath& path) const; 263 void dumpPicture(const SkPicture& picture) const; 264 void dumpRegion(const SkRegion& region) const; 265 int dumpDrawType(char* bufferPtr, char* buffer, DrawType drawType); 266 int dumpInt(char* bufferPtr, char* buffer, char* name); 267 int dumpRect(char* bufferPtr, char* buffer, char* name); 268 int dumpPoint(char* bufferPtr, char* buffer, char* name); 269 void dumpPointArray(char** bufferPtrPtr, char* buffer, int count); 270 int dumpPtr(char* bufferPtr, char* buffer, char* name, void* ptr); 271 int dumpRectPtr(char* bufferPtr, char* buffer, char* name); 272 int dumpScalar(char* bufferPtr, char* buffer, char* name); 273 void dumpText(char** bufferPtrPtr, char* buffer); 274 void dumpStream(); 275 276 public: 277 void dump() const; 278 #endif 279 280 #if SK_SUPPORT_GPU 281 /** 282 * sampleCount is the number of samples-per-pixel or zero if non-MSAA. 283 * It is defaulted to be zero. 284 */ 285 bool suitableForGpuRasterization(GrContext* context, const char **reason, 286 int sampleCount = 0) const; 287 288 /** 289 * Calls getRecommendedSampleCount with GrPixelConfig and dpi to calculate sampleCount 290 * and then calls the above version of suitableForGpuRasterization 291 */ 292 bool suitableForGpuRasterization(GrContext* context, const char **reason, 293 GrPixelConfig config, SkScalar dpi) const; 294 #endif 295 296 private: // these help us with reading/writing 297 bool parseStreamTag(SkStream*, uint32_t tag, uint32_t size, SkPicture::InstallPixelRefProc); 298 bool parseBufferTag(SkReadBuffer&, uint32_t tag, uint32_t size); 299 void flattenToBuffer(SkWriteBuffer&) const; 300 301 private: 302 friend class SkPicture; 303 friend class SkGpuDevice; // for access to setDrawLimits & setReplacements 304 305 // Only used by getBitmap() if the passed in index is SkBitmapHeap::INVALID_SLOT. This empty 306 // bitmap allows playback to draw nothing and move on. 307 SkBitmap fBadBitmap; 308 309 SkAutoTUnref<SkBitmapHeap> fBitmapHeap; 310 311 SkTRefArray<SkBitmap>* fBitmaps; 312 SkTRefArray<SkPaint>* fPaints; 313 314 SkData* fOpData; // opcodes and parameters 315 316 SkAutoTUnref<const SkPathHeap> fPathHeap; // reference counted 317 318 const SkPicture** fPictureRefs; 319 int fPictureCount; 320 321 SkBBoxHierarchy* fBoundingHierarchy; 322 SkPictureStateTree* fStateTree; 323 324 SkPictureContentInfo fContentInfo; 325 326 // Limit the opcode playback to be between the offsets 'start' and 'stop'. 327 // The opcode at 'start' should be a saveLayer while the opcode at 328 // 'stop' should be a restore. Neither of those commands will be issued. 329 // Set both start & stop to 0 to disable draw limiting 330 // Draw limiting cannot be enabled at the same time as draw replacing 331 void setDrawLimits(size_t start, size_t stop) { 332 SkASSERT(NULL == fReplacements); 333 fStart = start; 334 fStop = stop; 335 } 336 337 // PlaybackReplacements collects op ranges that can be replaced with 338 // a single drawBitmap call (using a precomputed bitmap). 339 class PlaybackReplacements { 340 public: 341 // All the operations between fStart and fStop (inclusive) will be replaced with 342 // a single drawBitmap call using fPos, fBM and fPaint. 343 // fPaint will be NULL if the picture's paint wasn't copyable 344 struct ReplacementInfo { 345 size_t fStart; 346 size_t fStop; 347 SkIPoint fPos; 348 SkBitmap* fBM; 349 const SkPaint* fPaint; // Note: this object doesn't own the paint 350 }; 351 352 ~PlaybackReplacements() { this->freeAll(); } 353 354 // Add a new replacement range. The replacement ranges should be 355 // sorted in increasing order and non-overlapping (esp. no nested 356 // saveLayers). 357 ReplacementInfo* push(); 358 359 private: 360 friend class SkPicturePlayback; // for access to lookupByStart 361 362 // look up a replacement range by its start offset 363 ReplacementInfo* lookupByStart(size_t start); 364 365 void freeAll(); 366 367 #ifdef SK_DEBUG 368 void validate() const; 369 #endif 370 371 SkTDArray<ReplacementInfo> fReplacements; 372 }; 373 374 // Replace all the draw ops in the replacement ranges in 'replacements' with 375 // the associated drawBitmap call 376 // Draw replacing cannot be enabled at the same time as draw limiting 377 void setReplacements(PlaybackReplacements* replacements) { 378 SkASSERT(fStart == 0 && fStop == 0); 379 fReplacements = replacements; 380 } 381 382 bool fUseBBH; 383 size_t fStart; 384 size_t fStop; 385 PlaybackReplacements* fReplacements; 386 387 class CachedOperationList : public SkPicture::OperationList { 388 public: 389 CachedOperationList() { 390 fCacheQueryRect.setEmpty(); 391 } 392 393 virtual bool valid() const { return true; } 394 virtual int numOps() const SK_OVERRIDE { return fOps.count(); } 395 virtual uint32_t offset(int index) const SK_OVERRIDE; 396 virtual const SkMatrix& matrix(int index) const SK_OVERRIDE; 397 398 // The query rect for which the cached active ops are valid 399 SkIRect fCacheQueryRect; 400 401 // The operations which are active within 'fCachedQueryRect' 402 SkTDArray<void*> fOps; 403 404 private: 405 typedef SkPicture::OperationList INHERITED; 406 }; 407 408 CachedOperationList* fCachedActiveOps; 409 410 SkTypefacePlayback fTFPlayback; 411 SkFactoryPlayback* fFactoryPlayback; 412 413 // The offset of the current operation when within the draw method 414 size_t fCurOffset; 415 416 const SkPictInfo fInfo; 417 418 static void WriteFactories(SkWStream* stream, const SkFactorySet& rec); 419 static void WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec); 420 421 void initForPlayback() const; 422 423 #ifdef SK_BUILD_FOR_ANDROID 424 SkMutex fDrawMutex; 425 bool fAbortCurrentPlayback; 426 #endif 427 }; 428 429 #endif 430