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 |