1 /* 2 * Copyright 2011 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 <new> 9 10 #include "SkAutoMalloc.h" 11 #include "SkImageGenerator.h" 12 #include "SkPictureData.h" 13 #include "SkPictureRecord.h" 14 #include "SkReadBuffer.h" 15 #include "SkTextBlob.h" 16 #include "SkTypeface.h" 17 #include "SkWriteBuffer.h" 18 19 #if SK_SUPPORT_GPU 20 #include "GrContext.h" 21 #endif 22 23 template <typename T> int SafeCount(const T* obj) { 24 return obj ? obj->count() : 0; 25 } 26 27 SkPictureData::SkPictureData(const SkPictInfo& info) 28 : fInfo(info) { 29 this->init(); 30 } 31 32 void SkPictureData::initForPlayback() const { 33 // ensure that the paths bounds are pre-computed 34 for (int i = 0; i < fPaths.count(); i++) { 35 fPaths[i].updateBoundsCache(); 36 } 37 } 38 39 SkPictureData::SkPictureData(const SkPictureRecord& record, 40 const SkPictInfo& info) 41 : fInfo(info) { 42 43 this->init(); 44 45 fOpData = record.opData(); 46 47 fContentInfo.set(record.fContentInfo); 48 49 fPaints = record.fPaints; 50 51 fPaths.reset(record.fPaths.count()); 52 record.fPaths.foreach([this](const SkPath& path, int n) { 53 // These indices are logically 1-based, but we need to serialize them 54 // 0-based to keep the deserializing SkPictureData::getPath() working. 55 fPaths[n-1] = path; 56 }); 57 58 this->initForPlayback(); 59 60 const SkTDArray<const SkPicture* >& pictures = record.getPictureRefs(); 61 fPictureCount = pictures.count(); 62 if (fPictureCount > 0) { 63 fPictureRefs = new const SkPicture* [fPictureCount]; 64 for (int i = 0; i < fPictureCount; i++) { 65 fPictureRefs[i] = pictures[i]; 66 fPictureRefs[i]->ref(); 67 } 68 } 69 70 const SkTDArray<SkDrawable* >& drawables = record.getDrawableRefs(); 71 fDrawableCount = drawables.count(); 72 if (fDrawableCount > 0) { 73 fDrawableRefs = new SkDrawable* [fDrawableCount]; 74 for (int i = 0; i < fDrawableCount; i++) { 75 fDrawableRefs[i] = drawables[i]; 76 fDrawableRefs[i]->ref(); 77 } 78 } 79 80 // templatize to consolidate with similar picture logic? 81 const SkTDArray<const SkTextBlob*>& blobs = record.getTextBlobRefs(); 82 fTextBlobCount = blobs.count(); 83 if (fTextBlobCount > 0) { 84 fTextBlobRefs = new const SkTextBlob* [fTextBlobCount]; 85 for (int i = 0; i < fTextBlobCount; ++i) { 86 fTextBlobRefs[i] = SkRef(blobs[i]); 87 } 88 } 89 90 const SkTDArray<const SkVertices*>& verts = record.getVerticesRefs(); 91 fVerticesCount = verts.count(); 92 if (fVerticesCount > 0) { 93 fVerticesRefs = new const SkVertices* [fVerticesCount]; 94 for (int i = 0; i < fVerticesCount; ++i) { 95 fVerticesRefs[i] = SkRef(verts[i]); 96 } 97 } 98 99 const SkTDArray<const SkImage*>& imgs = record.getImageRefs(); 100 fImageCount = imgs.count(); 101 if (fImageCount > 0) { 102 fImageRefs = new const SkImage* [fImageCount]; 103 for (int i = 0; i < fImageCount; ++i) { 104 fImageRefs[i] = SkRef(imgs[i]); 105 } 106 } 107 } 108 109 void SkPictureData::init() { 110 fPictureRefs = nullptr; 111 fPictureCount = 0; 112 fDrawableRefs = nullptr; 113 fDrawableCount = 0; 114 fTextBlobRefs = nullptr; 115 fTextBlobCount = 0; 116 fVerticesRefs = nullptr; 117 fVerticesCount = 0; 118 fImageRefs = nullptr; 119 fImageCount = 0; 120 fFactoryPlayback = nullptr; 121 } 122 123 SkPictureData::~SkPictureData() { 124 for (int i = 0; i < fPictureCount; i++) { 125 fPictureRefs[i]->unref(); 126 } 127 delete[] fPictureRefs; 128 129 for (int i = 0; i < fDrawableCount; i++) { 130 fDrawableRefs[i]->unref(); 131 } 132 if (fDrawableCount > 0) { 133 SkASSERT(fDrawableRefs); 134 delete[] fDrawableRefs; 135 } 136 137 for (int i = 0; i < fTextBlobCount; i++) { 138 fTextBlobRefs[i]->unref(); 139 } 140 delete[] fTextBlobRefs; 141 142 for (int i = 0; i < fVerticesCount; i++) { 143 fVerticesRefs[i]->unref(); 144 } 145 delete[] fVerticesRefs; 146 147 for (int i = 0; i < fImageCount; i++) { 148 fImageRefs[i]->unref(); 149 } 150 delete[] fImageRefs; 151 152 delete fFactoryPlayback; 153 } 154 155 bool SkPictureData::containsBitmaps() const { 156 if (fBitmapImageCount > 0 || fImageCount > 0) { 157 return true; 158 } 159 for (int i = 0; i < fPictureCount; ++i) { 160 if (fPictureRefs[i]->willPlayBackBitmaps()) { 161 return true; 162 } 163 } 164 return false; 165 } 166 167 /////////////////////////////////////////////////////////////////////////////// 168 /////////////////////////////////////////////////////////////////////////////// 169 170 #include "SkStream.h" 171 172 static size_t compute_chunk_size(SkFlattenable::Factory* array, int count) { 173 size_t size = 4; // for 'count' 174 175 for (int i = 0; i < count; i++) { 176 const char* name = SkFlattenable::FactoryToName(array[i]); 177 if (nullptr == name || 0 == *name) { 178 size += SkWStream::SizeOfPackedUInt(0); 179 } else { 180 size_t len = strlen(name); 181 size += SkWStream::SizeOfPackedUInt(len); 182 size += len; 183 } 184 } 185 186 return size; 187 } 188 189 static void write_tag_size(SkWriteBuffer& buffer, uint32_t tag, size_t size) { 190 buffer.writeUInt(tag); 191 buffer.writeUInt(SkToU32(size)); 192 } 193 194 static void write_tag_size(SkWStream* stream, uint32_t tag, size_t size) { 195 stream->write32(tag); 196 stream->write32(SkToU32(size)); 197 } 198 199 void SkPictureData::WriteFactories(SkWStream* stream, const SkFactorySet& rec) { 200 int count = rec.count(); 201 202 SkAutoSTMalloc<16, SkFlattenable::Factory> storage(count); 203 SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get(); 204 rec.copyToArray(array); 205 206 size_t size = compute_chunk_size(array, count); 207 208 // TODO: write_tag_size should really take a size_t 209 write_tag_size(stream, SK_PICT_FACTORY_TAG, (uint32_t) size); 210 SkDEBUGCODE(size_t start = stream->bytesWritten()); 211 stream->write32(count); 212 213 for (int i = 0; i < count; i++) { 214 const char* name = SkFlattenable::FactoryToName(array[i]); 215 if (nullptr == name || 0 == *name) { 216 stream->writePackedUInt(0); 217 } else { 218 size_t len = strlen(name); 219 stream->writePackedUInt(len); 220 stream->write(name, len); 221 } 222 } 223 224 SkASSERT(size == (stream->bytesWritten() - start)); 225 } 226 227 void SkPictureData::WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec) { 228 int count = rec.count(); 229 230 write_tag_size(stream, SK_PICT_TYPEFACE_TAG, count); 231 232 SkAutoSTMalloc<16, SkTypeface*> storage(count); 233 SkTypeface** array = (SkTypeface**)storage.get(); 234 rec.copyToArray((SkRefCnt**)array); 235 236 for (int i = 0; i < count; i++) { 237 array[i]->serialize(stream); 238 } 239 } 240 241 void SkPictureData::flattenToBuffer(SkWriteBuffer& buffer) const { 242 int i, n; 243 244 if ((n = fPaints.count()) > 0) { 245 write_tag_size(buffer, SK_PICT_PAINT_BUFFER_TAG, n); 246 for (i = 0; i < n; i++) { 247 buffer.writePaint(fPaints[i]); 248 } 249 } 250 251 if ((n = fPaths.count()) > 0) { 252 write_tag_size(buffer, SK_PICT_PATH_BUFFER_TAG, n); 253 buffer.writeInt(n); 254 for (int i = 0; i < n; i++) { 255 buffer.writePath(fPaths[i]); 256 } 257 } 258 259 if (fTextBlobCount > 0) { 260 write_tag_size(buffer, SK_PICT_TEXTBLOB_BUFFER_TAG, fTextBlobCount); 261 for (i = 0; i < fTextBlobCount; ++i) { 262 fTextBlobRefs[i]->flatten(buffer); 263 } 264 } 265 266 if (fVerticesCount > 0) { 267 write_tag_size(buffer, SK_PICT_VERTICES_BUFFER_TAG, fVerticesCount); 268 for (i = 0; i < fVerticesCount; ++i) { 269 buffer.writeDataAsByteArray(fVerticesRefs[i]->encode().get()); 270 } 271 } 272 273 if (fImageCount > 0) { 274 write_tag_size(buffer, SK_PICT_IMAGE_BUFFER_TAG, fImageCount); 275 for (i = 0; i < fImageCount; ++i) { 276 buffer.writeImage(fImageRefs[i]); 277 } 278 } 279 } 280 281 void SkPictureData::serialize(SkWStream* stream, 282 SkPixelSerializer* pixelSerializer, 283 SkRefCntSet* topLevelTypeFaceSet) const { 284 // This can happen at pretty much any time, so might as well do it first. 285 write_tag_size(stream, SK_PICT_READER_TAG, fOpData->size()); 286 stream->write(fOpData->bytes(), fOpData->size()); 287 288 // We serialize all typefaces into the typeface section of the top-level picture. 289 SkRefCntSet localTypefaceSet; 290 SkRefCntSet* typefaceSet = topLevelTypeFaceSet ? topLevelTypeFaceSet : &localTypefaceSet; 291 292 // We delay serializing the bulk of our data until after we've serialized 293 // factories and typefaces by first serializing to an in-memory write buffer. 294 SkFactorySet factSet; // buffer refs factSet, so factSet must come first. 295 SkBinaryWriteBuffer buffer(SkBinaryWriteBuffer::kCrossProcess_Flag); 296 buffer.setFactoryRecorder(&factSet); 297 buffer.setPixelSerializer(sk_ref_sp(pixelSerializer)); 298 buffer.setTypefaceRecorder(typefaceSet); 299 this->flattenToBuffer(buffer); 300 301 // Dummy serialize our sub-pictures for the side effect of filling 302 // typefaceSet with typefaces from sub-pictures. 303 struct DevNull: public SkWStream { 304 DevNull() : fBytesWritten(0) {} 305 size_t fBytesWritten; 306 bool write(const void*, size_t size) override { fBytesWritten += size; return true; } 307 size_t bytesWritten() const override { return fBytesWritten; } 308 } devnull; 309 for (int i = 0; i < fPictureCount; i++) { 310 fPictureRefs[i]->serialize(&devnull, pixelSerializer, typefaceSet); 311 } 312 313 // We need to write factories before we write the buffer. 314 // We need to write typefaces before we write the buffer or any sub-picture. 315 WriteFactories(stream, factSet); 316 if (typefaceSet == &localTypefaceSet) { 317 WriteTypefaces(stream, *typefaceSet); 318 } 319 320 // Write the buffer. 321 write_tag_size(stream, SK_PICT_BUFFER_SIZE_TAG, buffer.bytesWritten()); 322 buffer.writeToStream(stream); 323 324 // Write sub-pictures by calling serialize again. 325 if (fPictureCount > 0) { 326 write_tag_size(stream, SK_PICT_PICTURE_TAG, fPictureCount); 327 for (int i = 0; i < fPictureCount; i++) { 328 fPictureRefs[i]->serialize(stream, pixelSerializer, typefaceSet); 329 } 330 } 331 332 stream->write32(SK_PICT_EOF_TAG); 333 } 334 335 void SkPictureData::flatten(SkWriteBuffer& buffer) const { 336 write_tag_size(buffer, SK_PICT_READER_TAG, fOpData->size()); 337 buffer.writeByteArray(fOpData->bytes(), fOpData->size()); 338 339 if (fPictureCount > 0) { 340 write_tag_size(buffer, SK_PICT_PICTURE_TAG, fPictureCount); 341 for (int i = 0; i < fPictureCount; i++) { 342 fPictureRefs[i]->flatten(buffer); 343 } 344 } 345 346 if (fDrawableCount > 0) { 347 write_tag_size(buffer, SK_PICT_DRAWABLE_TAG, fDrawableCount); 348 for (int i = 0; i < fDrawableCount; i++) { 349 buffer.writeFlattenable(fDrawableRefs[i]); 350 } 351 } 352 353 // Write this picture playback's data into a writebuffer 354 this->flattenToBuffer(buffer); 355 buffer.write32(SK_PICT_EOF_TAG); 356 } 357 358 /////////////////////////////////////////////////////////////////////////////// 359 360 /** 361 * Return the corresponding SkReadBuffer flags, given a set of 362 * SkPictInfo flags. 363 */ 364 static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) { 365 static const struct { 366 uint32_t fSrc; 367 uint32_t fDst; 368 } gSD[] = { 369 { SkPictInfo::kCrossProcess_Flag, SkReadBuffer::kCrossProcess_Flag }, 370 { SkPictInfo::kScalarIsFloat_Flag, SkReadBuffer::kScalarIsFloat_Flag }, 371 { SkPictInfo::kPtrIs64Bit_Flag, SkReadBuffer::kPtrIs64Bit_Flag }, 372 }; 373 374 uint32_t rbMask = 0; 375 for (size_t i = 0; i < SK_ARRAY_COUNT(gSD); ++i) { 376 if (pictInfoFlags & gSD[i].fSrc) { 377 rbMask |= gSD[i].fDst; 378 } 379 } 380 return rbMask; 381 } 382 383 bool SkPictureData::parseStreamTag(SkStream* stream, 384 uint32_t tag, 385 uint32_t size, 386 SkImageDeserializer* factory, 387 SkTypefacePlayback* topLevelTFPlayback) { 388 /* 389 * By the time we encounter BUFFER_SIZE_TAG, we need to have already seen 390 * its dependents: FACTORY_TAG and TYPEFACE_TAG. These two are not required 391 * but if they are present, they need to have been seen before the buffer. 392 * 393 * We assert that if/when we see either of these, that we have not yet seen 394 * the buffer tag, because if we have, then its too-late to deal with the 395 * factories or typefaces. 396 */ 397 SkDEBUGCODE(bool haveBuffer = false;) 398 399 switch (tag) { 400 case SK_PICT_READER_TAG: 401 SkASSERT(nullptr == fOpData); 402 fOpData = SkData::MakeFromStream(stream, size); 403 if (!fOpData) { 404 return false; 405 } 406 break; 407 case SK_PICT_FACTORY_TAG: { 408 SkASSERT(!haveBuffer); 409 size = stream->readU32(); 410 fFactoryPlayback = new SkFactoryPlayback(size); 411 for (size_t i = 0; i < size; i++) { 412 SkString str; 413 const size_t len = stream->readPackedUInt(); 414 str.resize(len); 415 if (stream->read(str.writable_str(), len) != len) { 416 return false; 417 } 418 fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str()); 419 } 420 } break; 421 case SK_PICT_TYPEFACE_TAG: { 422 SkASSERT(!haveBuffer); 423 const int count = SkToInt(size); 424 fTFPlayback.setCount(count); 425 for (int i = 0; i < count; i++) { 426 sk_sp<SkTypeface> tf(SkTypeface::MakeDeserialize(stream)); 427 if (!tf.get()) { // failed to deserialize 428 // fTFPlayback asserts it never has a null, so we plop in 429 // the default here. 430 tf = SkTypeface::MakeDefault(); 431 } 432 fTFPlayback.set(i, tf.get()); 433 } 434 } break; 435 case SK_PICT_PICTURE_TAG: { 436 fPictureCount = 0; 437 fPictureRefs = new const SkPicture* [size]; 438 for (uint32_t i = 0; i < size; i++) { 439 fPictureRefs[i] = SkPicture::MakeFromStream(stream, factory, topLevelTFPlayback).release(); 440 if (!fPictureRefs[i]) { 441 return false; 442 } 443 fPictureCount++; 444 } 445 } break; 446 case SK_PICT_BUFFER_SIZE_TAG: { 447 SkAutoMalloc storage(size); 448 if (stream->read(storage.get(), size) != size) { 449 return false; 450 } 451 452 /* Should we use SkValidatingReadBuffer instead? */ 453 SkReadBuffer buffer(storage.get(), size); 454 buffer.setFlags(pictInfoFlagsToReadBufferFlags(fInfo.fFlags)); 455 buffer.setVersion(fInfo.getVersion()); 456 457 if (!fFactoryPlayback) { 458 return false; 459 } 460 fFactoryPlayback->setupBuffer(buffer); 461 buffer.setImageDeserializer(factory); 462 463 if (fTFPlayback.count() > 0) { 464 // .skp files <= v43 have typefaces serialized with each sub picture. 465 fTFPlayback.setupBuffer(buffer); 466 } else { 467 // Newer .skp files serialize all typefaces with the top picture. 468 topLevelTFPlayback->setupBuffer(buffer); 469 } 470 471 while (!buffer.eof() && buffer.isValid()) { 472 tag = buffer.readUInt(); 473 size = buffer.readUInt(); 474 if (!this->parseBufferTag(buffer, tag, size)) { 475 return false; 476 } 477 } 478 if (!buffer.isValid()) { 479 return false; 480 } 481 SkDEBUGCODE(haveBuffer = true;) 482 } break; 483 } 484 return true; // success 485 } 486 487 static const SkImage* create_image_from_buffer(SkReadBuffer& buffer) { 488 return buffer.readImage().release(); 489 } 490 static const SkVertices* create_vertices_from_buffer(SkReadBuffer& buffer) { 491 auto data = buffer.readByteArrayAsData(); 492 return data ? SkVertices::Decode(data->data(), data->size()).release() : nullptr; 493 } 494 495 static const SkImage* create_bitmap_image_from_buffer(SkReadBuffer& buffer) { 496 return buffer.readBitmapAsImage().release(); 497 } 498 499 // Need a shallow wrapper to return const SkPicture* to match the other factories, 500 // as SkPicture::CreateFromBuffer() returns SkPicture* 501 static const SkPicture* create_picture_from_buffer(SkReadBuffer& buffer) { 502 return SkPicture::MakeFromBuffer(buffer).release(); 503 } 504 505 static const SkDrawable* create_drawable_from_buffer(SkReadBuffer& buffer) { 506 return (SkDrawable*) buffer.readFlattenable(SkFlattenable::kSkDrawable_Type); 507 } 508 509 template <typename T> 510 bool new_array_from_buffer(SkReadBuffer& buffer, uint32_t inCount, 511 const T*** array, int* outCount, const T* (*factory)(SkReadBuffer&)) { 512 if (!buffer.validate((0 == *outCount) && (nullptr == *array))) { 513 return false; 514 } 515 if (0 == inCount) { 516 return true; 517 } 518 if (!buffer.validate(SkTFitsIn<int>(inCount))) { 519 return false; 520 } 521 522 *outCount = inCount; 523 *array = new const T* [*outCount]; 524 bool success = true; 525 int i = 0; 526 for (; i < *outCount; i++) { 527 (*array)[i] = factory(buffer); 528 if (nullptr == (*array)[i]) { 529 success = false; 530 break; 531 } 532 } 533 if (!success) { 534 // Delete all of the blobs that were already created (up to but excluding i): 535 for (int j = 0; j < i; j++) { 536 (*array)[j]->unref(); 537 } 538 // Delete the array 539 delete[] * array; 540 *array = nullptr; 541 *outCount = 0; 542 return false; 543 } 544 return true; 545 } 546 547 bool SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t size) { 548 switch (tag) { 549 case SK_PICT_BITMAP_BUFFER_TAG: 550 if (!new_array_from_buffer(buffer, size, &fBitmapImageRefs, &fBitmapImageCount, 551 create_bitmap_image_from_buffer)) { 552 return false; 553 } 554 break; 555 case SK_PICT_PAINT_BUFFER_TAG: { 556 if (!buffer.validate(SkTFitsIn<int>(size))) { 557 return false; 558 } 559 const int count = SkToInt(size); 560 fPaints.reset(count); 561 for (int i = 0; i < count; ++i) { 562 buffer.readPaint(&fPaints[i]); 563 } 564 } break; 565 case SK_PICT_PATH_BUFFER_TAG: 566 if (size > 0) { 567 const int count = buffer.readInt(); 568 fPaths.reset(count); 569 for (int i = 0; i < count; i++) { 570 buffer.readPath(&fPaths[i]); 571 } 572 } break; 573 case SK_PICT_TEXTBLOB_BUFFER_TAG: 574 if (!new_array_from_buffer(buffer, size, &fTextBlobRefs, &fTextBlobCount, 575 SkTextBlob::CreateFromBuffer)) { 576 return false; 577 } 578 break; 579 case SK_PICT_VERTICES_BUFFER_TAG: 580 if (!new_array_from_buffer(buffer, size, &fVerticesRefs, &fVerticesCount, 581 create_vertices_from_buffer)) { 582 return false; 583 } 584 break; 585 case SK_PICT_IMAGE_BUFFER_TAG: 586 if (!new_array_from_buffer(buffer, size, &fImageRefs, &fImageCount, 587 create_image_from_buffer)) { 588 return false; 589 } 590 break; 591 case SK_PICT_READER_TAG: { 592 auto data(SkData::MakeUninitialized(size)); 593 if (!buffer.readByteArray(data->writable_data(), size) || 594 !buffer.validate(nullptr == fOpData)) { 595 return false; 596 } 597 SkASSERT(nullptr == fOpData); 598 fOpData = std::move(data); 599 } break; 600 case SK_PICT_PICTURE_TAG: 601 if (!new_array_from_buffer(buffer, size, &fPictureRefs, &fPictureCount, 602 create_picture_from_buffer)) { 603 return false; 604 } 605 break; 606 case SK_PICT_DRAWABLE_TAG: 607 if (!new_array_from_buffer(buffer, size, (const SkDrawable***)&fDrawableRefs, 608 &fDrawableCount, create_drawable_from_buffer)) { 609 return false; 610 } 611 break; 612 default: 613 // The tag was invalid. 614 return false; 615 } 616 return true; // success 617 } 618 619 SkPictureData* SkPictureData::CreateFromStream(SkStream* stream, 620 const SkPictInfo& info, 621 SkImageDeserializer* factory, 622 SkTypefacePlayback* topLevelTFPlayback) { 623 std::unique_ptr<SkPictureData> data(new SkPictureData(info)); 624 if (!topLevelTFPlayback) { 625 topLevelTFPlayback = &data->fTFPlayback; 626 } 627 628 if (!data->parseStream(stream, factory, topLevelTFPlayback)) { 629 return nullptr; 630 } 631 return data.release(); 632 } 633 634 SkPictureData* SkPictureData::CreateFromBuffer(SkReadBuffer& buffer, 635 const SkPictInfo& info) { 636 std::unique_ptr<SkPictureData> data(new SkPictureData(info)); 637 buffer.setVersion(info.getVersion()); 638 639 if (!data->parseBuffer(buffer)) { 640 return nullptr; 641 } 642 return data.release(); 643 } 644 645 bool SkPictureData::parseStream(SkStream* stream, 646 SkImageDeserializer* factory, 647 SkTypefacePlayback* topLevelTFPlayback) { 648 for (;;) { 649 uint32_t tag = stream->readU32(); 650 if (SK_PICT_EOF_TAG == tag) { 651 break; 652 } 653 654 uint32_t size = stream->readU32(); 655 if (!this->parseStreamTag(stream, tag, size, factory, topLevelTFPlayback)) { 656 return false; // we're invalid 657 } 658 } 659 return true; 660 } 661 662 bool SkPictureData::parseBuffer(SkReadBuffer& buffer) { 663 for (;;) { 664 uint32_t tag = buffer.readUInt(); 665 if (SK_PICT_EOF_TAG == tag) { 666 break; 667 } 668 669 uint32_t size = buffer.readUInt(); 670 if (!this->parseBufferTag(buffer, tag, size)) { 671 return false; // we're invalid 672 } 673 } 674 return true; 675 } 676 677 /////////////////////////////////////////////////////////////////////////////// 678 /////////////////////////////////////////////////////////////////////////////// 679 680 #if SK_SUPPORT_GPU 681 bool SkPictureData::suitableForGpuRasterization(GrContext* context, const char **reason, 682 int sampleCount) const { 683 return fContentInfo.suitableForGpuRasterization(context, reason, sampleCount); 684 } 685 686 bool SkPictureData::suitableForGpuRasterization(GrContext* context, const char **reason, 687 GrPixelConfig config, SkScalar dpi) const { 688 689 if (context != nullptr) { 690 return this->suitableForGpuRasterization(context, reason, 691 context->getRecommendedSampleCount(config, dpi)); 692 } else { 693 return this->suitableForGpuRasterization(nullptr, reason); 694 } 695 } 696 697 bool SkPictureData::suitableForLayerOptimization() const { 698 return fContentInfo.numLayers() > 0; 699 } 700 #endif 701 /////////////////////////////////////////////////////////////////////////////// 702