| OLD | NEW |
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 #include "SkAnnotation.h" | 9 #include "SkAnnotation.h" |
| 10 #include "SkBitmapDevice.h" | 10 #include "SkBitmapDevice.h" |
| 11 #include "SkBitmapHeap.h" | 11 #include "SkBitmapHeap.h" |
| 12 #include "SkCanvas.h" | 12 #include "SkCanvas.h" |
| 13 #include "SkColorFilter.h" | 13 #include "SkColorFilter.h" |
| 14 #include "SkData.h" | 14 #include "SkData.h" |
| 15 #include "SkDrawLooper.h" | 15 #include "SkDrawLooper.h" |
| 16 #include "SkGPipe.h" | 16 #include "SkGPipe.h" |
| 17 #include "SkGPipePriv.h" | 17 #include "SkGPipePriv.h" |
| 18 #include "SkImageFilter.h" | 18 #include "SkImageFilter.h" |
| 19 #include "SkMaskFilter.h" | 19 #include "SkMaskFilter.h" |
| 20 #include "SkWriteBuffer.h" | 20 #include "SkWriteBuffer.h" |
| 21 #include "SkPaint.h" | 21 #include "SkPaint.h" |
| 22 #include "SkPatchUtils.h" | 22 #include "SkPatchUtils.h" |
| 23 #include "SkPathEffect.h" | 23 #include "SkPathEffect.h" |
| 24 #include "SkPictureFlat.h" | 24 #include "SkPictureFlat.h" |
| 25 #include "SkPtrRecorder.h" |
| 25 #include "SkRasterizer.h" | 26 #include "SkRasterizer.h" |
| 26 #include "SkRRect.h" | 27 #include "SkRRect.h" |
| 27 #include "SkShader.h" | 28 #include "SkShader.h" |
| 28 #include "SkStream.h" | 29 #include "SkStream.h" |
| 29 #include "SkTextBlob.h" | 30 #include "SkTextBlob.h" |
| 30 #include "SkTSearch.h" | 31 #include "SkTSearch.h" |
| 31 #include "SkTypeface.h" | 32 #include "SkTypeface.h" |
| 32 #include "SkWriter32.h" | 33 #include "SkWriter32.h" |
| 33 | 34 |
| 34 enum { | 35 enum { |
| 35 kSizeOfFlatRRect = sizeof(SkRect) + 4 * sizeof(SkVector) | 36 kSizeOfFlatRRect = sizeof(SkRect) + 4 * sizeof(SkVector) |
| 36 }; | 37 }; |
| 37 | 38 |
| 38 static bool isCrossProcess(uint32_t flags) { | 39 static bool is_cross_process(uint32_t flags) { |
| 39 return SkToBool(flags & SkGPipeWriter::kCrossProcess_Flag); | 40 return SkToBool(flags & SkGPipeWriter::kCrossProcess_Flag); |
| 40 } | 41 } |
| 41 | 42 |
| 42 static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) { | 43 static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) { |
| 43 SkASSERT(paintFlat < kCount_PaintFlats); | 44 SkASSERT(paintFlat < kCount_PaintFlats); |
| 44 switch (paintFlat) { | 45 switch (paintFlat) { |
| 45 case kColorFilter_PaintFlat: return paint.getColorFilter(); | 46 case kColorFilter_PaintFlat: return paint.getColorFilter(); |
| 46 case kDrawLooper_PaintFlat: return paint.getLooper(); | 47 case kDrawLooper_PaintFlat: return paint.getLooper(); |
| 47 case kMaskFilter_PaintFlat: return paint.getMaskFilter(); | 48 case kMaskFilter_PaintFlat: return paint.getMaskFilter(); |
| 48 case kPathEffect_PaintFlat: return paint.getPathEffect(); | 49 case kPathEffect_PaintFlat: return paint.getPathEffect(); |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 331 inline void doNotify() { | 332 inline void doNotify() { |
| 332 if (!fDone) { | 333 if (!fDone) { |
| 333 size_t bytes = fWriter.bytesWritten() - fBytesNotified; | 334 size_t bytes = fWriter.bytesWritten() - fBytesNotified; |
| 334 if (bytes > 0) { | 335 if (bytes > 0) { |
| 335 fController->notifyWritten(bytes); | 336 fController->notifyWritten(bytes); |
| 336 fBytesNotified += bytes; | 337 fBytesNotified += bytes; |
| 337 } | 338 } |
| 338 } | 339 } |
| 339 } | 340 } |
| 340 | 341 |
| 342 typedef SkAutoSTMalloc<128, uint8_t> TypefaceBuffer; |
| 343 size_t getInProcessTypefaces(const SkRefCntSet& typefaceSet, TypefaceBuffer*
); |
| 344 size_t getCrossProcessTypefaces(const SkRefCntSet& typefaceSet, TypefaceBuff
er*); |
| 345 |
| 341 // Should be called after any calls to an SkFlatDictionary::findAndReplace | 346 // Should be called after any calls to an SkFlatDictionary::findAndReplace |
| 342 // if a new SkFlatData was added when in cross process mode | 347 // if a new SkFlatData was added when in cross process mode |
| 343 void flattenFactoryNames(); | 348 void flattenFactoryNames(); |
| 344 | 349 |
| 345 FlattenableHeap fFlattenableHeap; | 350 FlattenableHeap fFlattenableHeap; |
| 346 FlatDictionary fFlatDictionary; | 351 FlatDictionary fFlatDictionary; |
| 347 SkAutoTUnref<BitmapShuttle> fBitmapShuttle; | 352 SkAutoTUnref<BitmapShuttle> fBitmapShuttle; |
| 348 int fCurrFlatIndex[kCount_PaintFlats]; | 353 int fCurrFlatIndex[kCount_PaintFlats]; |
| 349 | 354 |
| 350 int flattenToIndex(SkFlattenable* obj, PaintFlats); | 355 int flattenToIndex(SkFlattenable* obj, PaintFlats); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 404 return 0; | 409 return 0; |
| 405 } | 410 } |
| 406 | 411 |
| 407 fBitmapHeap->deferAddingOwners(); | 412 fBitmapHeap->deferAddingOwners(); |
| 408 bool added, replaced; | 413 bool added, replaced; |
| 409 const SkFlatData* flat = fFlatDictionary.findAndReplace(*obj, fFlattenableHe
ap.flatToReplace(), | 414 const SkFlatData* flat = fFlatDictionary.findAndReplace(*obj, fFlattenableHe
ap.flatToReplace(), |
| 410 &added, &replaced); | 415 &added, &replaced); |
| 411 fBitmapHeap->endAddingOwnersDeferral(added); | 416 fBitmapHeap->endAddingOwnersDeferral(added); |
| 412 int index = flat->index(); | 417 int index = flat->index(); |
| 413 if (added) { | 418 if (added) { |
| 414 if (isCrossProcess(fFlags)) { | 419 if (is_cross_process(fFlags)) { |
| 415 this->flattenFactoryNames(); | 420 this->flattenFactoryNames(); |
| 416 } | 421 } |
| 417 size_t flatSize = flat->flatSize(); | 422 size_t flatSize = flat->flatSize(); |
| 418 if (this->needOpBytes(flatSize)) { | 423 if (this->needOpBytes(flatSize)) { |
| 419 this->writeOp(kDef_Flattenable_DrawOp, paintflat, index); | 424 this->writeOp(kDef_Flattenable_DrawOp, paintflat, index); |
| 420 fWriter.write(flat->data(), flatSize); | 425 fWriter.write(flat->data(), flatSize); |
| 421 } | 426 } |
| 422 } | 427 } |
| 423 if (replaced) { | 428 if (replaced) { |
| 424 index = ~index; | 429 index = ~index; |
| 425 } | 430 } |
| 426 return index; | 431 return index; |
| 427 } | 432 } |
| 428 | 433 |
| 429 /////////////////////////////////////////////////////////////////////////////// | 434 /////////////////////////////////////////////////////////////////////////////// |
| 430 | 435 |
| 431 #define MIN_BLOCK_SIZE (16 * 1024) | 436 #define MIN_BLOCK_SIZE (16 * 1024) |
| 432 #define BITMAPS_TO_KEEP 5 | 437 #define BITMAPS_TO_KEEP 5 |
| 433 #define FLATTENABLES_TO_KEEP 10 | 438 #define FLATTENABLES_TO_KEEP 10 |
| 434 | 439 |
| 435 SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller, | 440 SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller, |
| 436 SkWriter32* writer, uint32_t flags, | 441 SkWriter32* writer, uint32_t flags, |
| 437 uint32_t width, uint32_t height) | 442 uint32_t width, uint32_t height) |
| 438 : SkCanvas(width, height) | 443 : SkCanvas(width, height) |
| 439 , fFactorySet(isCrossProcess(flags) ? SkNEW(SkNamedFactorySet) : NULL) | 444 , fFactorySet(is_cross_process(flags) ? SkNEW(SkNamedFactorySet) : NULL) |
| 440 , fWriter(*writer) | 445 , fWriter(*writer) |
| 441 , fFlags(flags) | 446 , fFlags(flags) |
| 442 , fFlattenableHeap(FLATTENABLES_TO_KEEP, fFactorySet, isCrossProcess(flags)) | 447 , fFlattenableHeap(FLATTENABLES_TO_KEEP, fFactorySet, is_cross_process(flags
)) |
| 443 , fFlatDictionary(&fFlattenableHeap) | 448 , fFlatDictionary(&fFlattenableHeap) |
| 444 { | 449 { |
| 445 fController = controller; | 450 fController = controller; |
| 446 fDone = false; | 451 fDone = false; |
| 447 fBlockSize = 0; // need first block from controller | 452 fBlockSize = 0; // need first block from controller |
| 448 fBytesNotified = 0; | 453 fBytesNotified = 0; |
| 449 fFirstSaveLayerStackLevel = kNoSaveLayer; | 454 fFirstSaveLayerStackLevel = kNoSaveLayer; |
| 450 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex)); | 455 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex)); |
| 451 | 456 |
| 452 // Tell the reader the appropriate flags to use. | 457 // Tell the reader the appropriate flags to use. |
| (...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 931 fWriter.writePad(text, byteLength); | 936 fWriter.writePad(text, byteLength); |
| 932 | 937 |
| 933 fWriter.writePath(path); | 938 fWriter.writePath(path); |
| 934 if (matrix) { | 939 if (matrix) { |
| 935 fWriter.writeMatrix(*matrix); | 940 fWriter.writeMatrix(*matrix); |
| 936 } | 941 } |
| 937 } | 942 } |
| 938 } | 943 } |
| 939 } | 944 } |
| 940 | 945 |
| 946 size_t SkGPipeCanvas::getInProcessTypefaces(const SkRefCntSet& typefaceSet, |
| 947 TypefaceBuffer* buffer) { |
| 948 // When in-process, we simply write out the typeface pointers. |
| 949 size_t size = typefaceSet.count() * sizeof(SkTypeface*); |
| 950 buffer->reset(size); |
| 951 typefaceSet.copyToArray(reinterpret_cast<SkRefCnt**>(buffer->get())); |
| 952 |
| 953 return size; |
| 954 } |
| 955 |
| 956 size_t SkGPipeCanvas::getCrossProcessTypefaces(const SkRefCntSet& typefaceSet, |
| 957 TypefaceBuffer* buffer) { |
| 958 // For cross-process we use typeface IDs. |
| 959 size_t size = typefaceSet.count() * sizeof(uint32_t); |
| 960 buffer->reset(size); |
| 961 |
| 962 uint32_t* idBuffer = reinterpret_cast<uint32_t*>(buffer->get()); |
| 963 SkRefCntSet::Iter iter(typefaceSet); |
| 964 int i = 0; |
| 965 |
| 966 for (void* setPtr = iter.next(); setPtr; setPtr = iter.next()) { |
| 967 idBuffer[i++] = this->getTypefaceID(reinterpret_cast<SkTypeface*>(setPtr
)); |
| 968 } |
| 969 |
| 970 SkASSERT(i == typefaceSet.count()); |
| 971 |
| 972 return size; |
| 973 } |
| 974 |
| 941 void SkGPipeCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar
y, | 975 void SkGPipeCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar
y, |
| 942 const SkPaint& paint) { | 976 const SkPaint& paint) { |
| 943 NOTIFY_SETUP(this); | 977 NOTIFY_SETUP(this); |
| 944 this->writePaint(paint); | 978 this->writePaint(paint); |
| 945 | 979 |
| 946 // FIXME: this is inefficient but avoids duplicating the blob serialization
logic. | 980 // FIXME: this is inefficient but avoids duplicating the blob serialization
logic. |
| 981 SkRefCntSet typefaceSet; |
| 947 SkWriteBuffer blobBuffer; | 982 SkWriteBuffer blobBuffer; |
| 983 blobBuffer.setTypefaceRecorder(&typefaceSet); |
| 948 blob->flatten(blobBuffer); | 984 blob->flatten(blobBuffer); |
| 949 | 985 |
| 950 size_t size = sizeof(uint32_t) + 2 * sizeof(SkScalar) + blobBuffer.bytesWrit
ten(); | 986 // Unlike most draw ops (which only use one paint/typeface), text blobs may
reference |
| 987 // an arbitrary number of typefaces. Since the one-paint-per-op model is not
applicable, |
| 988 // we need to serialize these explicitly. |
| 989 TypefaceBuffer typefaceBuffer; |
| 990 size_t typefaceSize = is_cross_process(fFlags) |
| 991 ? this->getCrossProcessTypefaces(typefaceSet, &typefaceBuffer) |
| 992 : this->getInProcessTypefaces(typefaceSet, &typefaceBuffer); |
| 993 |
| 994 // blob byte count + typeface count + x + y + blob data + an index (cross-pr
ocess) |
| 995 // or pointer (in-process) for each typeface |
| 996 size_t size = 2 * sizeof(uint32_t) |
| 997 + 2 * sizeof(SkScalar) |
| 998 + blobBuffer.bytesWritten() |
| 999 + typefaceSize; |
| 1000 |
| 951 if (this->needOpBytes(size)) { | 1001 if (this->needOpBytes(size)) { |
| 952 this->writeOp(kDrawTextBlob_DrawOp); | 1002 this->writeOp(kDrawTextBlob_DrawOp); |
| 1003 SkDEBUGCODE(size_t initialOffset = fWriter.bytesWritten();) |
| 1004 |
| 953 fWriter.writeScalar(x); | 1005 fWriter.writeScalar(x); |
| 954 fWriter.writeScalar(y); | 1006 fWriter.writeScalar(y); |
| 1007 |
| 1008 fWriter.write32(typefaceSet.count()); |
| 1009 fWriter.write(typefaceBuffer.get(), typefaceSize); |
| 1010 |
| 955 fWriter.write32(SkToU32(blobBuffer.bytesWritten())); | 1011 fWriter.write32(SkToU32(blobBuffer.bytesWritten())); |
| 956 uint32_t* pad = fWriter.reservePad(blobBuffer.bytesWritten()); | 1012 uint32_t* pad = fWriter.reservePad(blobBuffer.bytesWritten()); |
| 957 blobBuffer.writeToMemory(pad); | 1013 blobBuffer.writeToMemory(pad); |
| 1014 |
| 1015 SkASSERT(initialOffset + size == fWriter.bytesWritten()); |
| 958 } | 1016 } |
| 959 } | 1017 } |
| 960 | 1018 |
| 961 void SkGPipeCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matr
ix, | 1019 void SkGPipeCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matr
ix, |
| 962 const SkPaint* paint) { | 1020 const SkPaint* paint) { |
| 963 // we want to playback the picture into individual draw calls | 1021 // we want to playback the picture into individual draw calls |
| 964 // | 1022 // |
| 965 // todo: do we always have to unroll? If the pipe is not cross-process, seem
s like | 1023 // todo: do we always have to unroll? If the pipe is not cross-process, seem
s like |
| 966 // we could just ref the picture and move on...? <reed, scroggo> | 1024 // we could just ref the picture and move on...? <reed, scroggo> |
| 967 // | 1025 // |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1190 *ptr++ = castToU32(paint.getTextScaleX()); | 1248 *ptr++ = castToU32(paint.getTextScaleX()); |
| 1191 base.setTextScaleX(paint.getTextScaleX()); | 1249 base.setTextScaleX(paint.getTextScaleX()); |
| 1192 } | 1250 } |
| 1193 if (base.getTextSkewX() != paint.getTextSkewX()) { | 1251 if (base.getTextSkewX() != paint.getTextSkewX()) { |
| 1194 *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp); | 1252 *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp); |
| 1195 *ptr++ = castToU32(paint.getTextSkewX()); | 1253 *ptr++ = castToU32(paint.getTextSkewX()); |
| 1196 base.setTextSkewX(paint.getTextSkewX()); | 1254 base.setTextSkewX(paint.getTextSkewX()); |
| 1197 } | 1255 } |
| 1198 | 1256 |
| 1199 if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) { | 1257 if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) { |
| 1200 if (isCrossProcess(fFlags)) { | 1258 if (is_cross_process(fFlags)) { |
| 1201 uint32_t id = this->getTypefaceID(paint.getTypeface()); | 1259 uint32_t id = this->getTypefaceID(paint.getTypeface()); |
| 1202 *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id); | 1260 *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id); |
| 1203 } else if (this->needOpBytes(sizeof(void*))) { | 1261 } else if (this->needOpBytes(sizeof(void*))) { |
| 1204 // Add to the set for ref counting. | 1262 // Add to the set for ref counting. |
| 1205 fTypefaceSet.add(paint.getTypeface()); | 1263 fTypefaceSet.add(paint.getTypeface()); |
| 1206 // It is safe to write the typeface to the stream before the rest | 1264 // It is safe to write the typeface to the stream before the rest |
| 1207 // of the paint unless we ever send a kReset_PaintOp, which we | 1265 // of the paint unless we ever send a kReset_PaintOp, which we |
| 1208 // currently never do. | 1266 // currently never do. |
| 1209 this->writeOp(kSetTypeface_DrawOp); | 1267 this->writeOp(kSetTypeface_DrawOp); |
| 1210 fWriter.writePtr(paint.getTypeface()); | 1268 fWriter.writePtr(paint.getTypeface()); |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1336 return fCanvas->shuttleBitmap(bitmap, slot); | 1394 return fCanvas->shuttleBitmap(bitmap, slot); |
| 1337 } | 1395 } |
| 1338 | 1396 |
| 1339 void BitmapShuttle::removeCanvas() { | 1397 void BitmapShuttle::removeCanvas() { |
| 1340 if (NULL == fCanvas) { | 1398 if (NULL == fCanvas) { |
| 1341 return; | 1399 return; |
| 1342 } | 1400 } |
| 1343 fCanvas->unref(); | 1401 fCanvas->unref(); |
| 1344 fCanvas = NULL; | 1402 fCanvas = NULL; |
| 1345 } | 1403 } |
| OLD | NEW |