OLD | NEW |
| (Empty) |
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 #include "SkAnnotation.h" | |
10 #include "SkBitmapHeap.h" | |
11 #include "SkCanvas.h" | |
12 #include "SkColorFilter.h" | |
13 #include "SkData.h" | |
14 #include "SkDrawLooper.h" | |
15 #include "SkGPipe.h" | |
16 #include "SkGPipePriv.h" | |
17 #include "SkImageFilter.h" | |
18 #include "SkMaskFilter.h" | |
19 #include "SkRSXform.h" | |
20 #include "SkWriteBuffer.h" | |
21 #include "SkPaint.h" | |
22 #include "SkPatchUtils.h" | |
23 #include "SkPathEffect.h" | |
24 #include "SkPictureFlat.h" | |
25 #include "SkPtrRecorder.h" | |
26 #include "SkRasterizer.h" | |
27 #include "SkRRect.h" | |
28 #include "SkShader.h" | |
29 #include "SkStream.h" | |
30 #include "SkTextBlob.h" | |
31 #include "SkTSearch.h" | |
32 #include "SkTypeface.h" | |
33 #include "SkWriter32.h" | |
34 | |
35 enum { | |
36 kSizeOfFlatRRect = sizeof(SkRect) + 4 * sizeof(SkVector) | |
37 }; | |
38 | |
39 static bool is_cross_process(uint32_t flags) { | |
40 return SkToBool(flags & SkGPipeWriter::kCrossProcess_Flag); | |
41 } | |
42 | |
43 static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) { | |
44 SkASSERT(paintFlat < kCount_PaintFlats); | |
45 switch (paintFlat) { | |
46 case kColorFilter_PaintFlat: return paint.getColorFilter(); | |
47 case kDrawLooper_PaintFlat: return paint.getLooper(); | |
48 case kMaskFilter_PaintFlat: return paint.getMaskFilter(); | |
49 case kPathEffect_PaintFlat: return paint.getPathEffect(); | |
50 case kRasterizer_PaintFlat: return paint.getRasterizer(); | |
51 case kShader_PaintFlat: return paint.getShader(); | |
52 case kImageFilter_PaintFlat: return paint.getImageFilter(); | |
53 case kXfermode_PaintFlat: return paint.getXfermode(); | |
54 } | |
55 SkDEBUGFAIL("never gets here"); | |
56 return nullptr; | |
57 } | |
58 | |
59 static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) { | |
60 SkASSERT(typeface); | |
61 SkDynamicMemoryWStream stream; | |
62 typeface->serialize(&stream); | |
63 size_t size = stream.getOffset(); | |
64 if (writer) { | |
65 writer->write32(SkToU32(size)); | |
66 SkAutoDataUnref data(stream.copyToData()); | |
67 writer->writePad(data->data(), size); | |
68 } | |
69 return 4 + SkAlign4(size); | |
70 } | |
71 | |
72 /////////////////////////////////////////////////////////////////////////////// | |
73 | |
74 class FlattenableHeap : public SkFlatController { | |
75 public: | |
76 FlattenableHeap(int numFlatsToKeep, SkNamedFactorySet* fset, bool isCrossPro
cess) | |
77 : INHERITED(isCrossProcess ? SkWriteBuffer::kCrossProcess_Flag : 0) | |
78 , fNumFlatsToKeep(numFlatsToKeep) { | |
79 SkASSERT((isCrossProcess && fset != nullptr) || (!isCrossProcess && null
ptr == fset)); | |
80 if (isCrossProcess) { | |
81 this->setNamedFactorySet(fset); | |
82 } | |
83 } | |
84 | |
85 ~FlattenableHeap() { | |
86 fPointers.freeAll(); | |
87 } | |
88 | |
89 void* allocThrow(size_t bytes) override; | |
90 | |
91 void unalloc(void* ptr) override; | |
92 | |
93 void setBitmapStorage(SkBitmapHeap* heap) { | |
94 this->setBitmapHeap(heap); | |
95 } | |
96 | |
97 const SkFlatData* flatToReplace() const; | |
98 | |
99 // Mark an SkFlatData as one that should not be returned by flatToReplace. | |
100 // Takes the result of SkFlatData::index() as its parameter. | |
101 void markFlatForKeeping(int index) { | |
102 *fFlatsThatMustBeKept.append() = index; | |
103 } | |
104 | |
105 void markAllFlatsSafeToDelete() { | |
106 fFlatsThatMustBeKept.reset(); | |
107 } | |
108 | |
109 private: | |
110 // Keep track of the indices (i.e. the result of SkFlatData::index()) of | |
111 // flats that must be kept, since they are on the current paint. | |
112 SkTDArray<int> fFlatsThatMustBeKept; | |
113 SkTDArray<void*> fPointers; | |
114 const int fNumFlatsToKeep; | |
115 | |
116 typedef SkFlatController INHERITED; | |
117 }; | |
118 | |
119 void FlattenableHeap::unalloc(void* ptr) { | |
120 int indexToRemove = fPointers.rfind(ptr); | |
121 if (indexToRemove >= 0) { | |
122 sk_free(ptr); | |
123 fPointers.remove(indexToRemove); | |
124 } | |
125 } | |
126 | |
127 void* FlattenableHeap::allocThrow(size_t bytes) { | |
128 void* ptr = sk_malloc_throw(bytes); | |
129 *fPointers.append() = ptr; | |
130 return ptr; | |
131 } | |
132 | |
133 const SkFlatData* FlattenableHeap::flatToReplace() const { | |
134 // First, determine whether we should replace one. | |
135 if (fPointers.count() > fNumFlatsToKeep) { | |
136 // Look through the flattenable heap. | |
137 // TODO: Return the LRU flat. | |
138 for (int i = 0; i < fPointers.count(); i++) { | |
139 SkFlatData* potential = (SkFlatData*)fPointers[i]; | |
140 // Make sure that it is not one that must be kept. | |
141 bool mustKeep = false; | |
142 for (int j = 0; j < fFlatsThatMustBeKept.count(); j++) { | |
143 if (potential->index() == fFlatsThatMustBeKept[j]) { | |
144 mustKeep = true; | |
145 break; | |
146 } | |
147 } | |
148 if (!mustKeep) { | |
149 return potential; | |
150 } | |
151 } | |
152 } | |
153 return nullptr; | |
154 } | |
155 | |
156 /////////////////////////////////////////////////////////////////////////////// | |
157 | |
158 struct SkFlattenableTraits { | |
159 static void Flatten(SkWriteBuffer& buffer, const SkFlattenable& flattenable)
{ | |
160 buffer.writeFlattenable(&flattenable); | |
161 } | |
162 // No need to define unflatten if we never call it. | |
163 }; | |
164 typedef SkFlatDictionary<SkFlattenable, SkFlattenableTraits> FlatDictionary; | |
165 | |
166 /////////////////////////////////////////////////////////////////////////////// | |
167 | |
168 /** | |
169 * If SkBitmaps are to be flattened to send to the reader, this class is | |
170 * provided to the SkBitmapHeap to tell the SkGPipeCanvas to do so. | |
171 */ | |
172 class BitmapShuttle : public SkBitmapHeap::ExternalStorage { | |
173 public: | |
174 BitmapShuttle(SkGPipeCanvas*); | |
175 | |
176 ~BitmapShuttle(); | |
177 | |
178 bool insert(const SkBitmap& bitmap, int32_t slot) override; | |
179 | |
180 /** | |
181 * Remove the SkGPipeCanvas used for insertion. After this, calls to | |
182 * insert will crash. | |
183 */ | |
184 void removeCanvas(); | |
185 | |
186 private: | |
187 SkGPipeCanvas* fCanvas; | |
188 }; | |
189 | |
190 /////////////////////////////////////////////////////////////////////////////// | |
191 | |
192 class SkGPipeCanvas : public SkCanvas { | |
193 public: | |
194 SkGPipeCanvas(SkGPipeController*, SkWriter32*, uint32_t flags, | |
195 uint32_t width, uint32_t height); | |
196 virtual ~SkGPipeCanvas(); | |
197 | |
198 /** | |
199 * Called when nothing else is to be written to the stream. Any repeated | |
200 * calls are ignored. | |
201 * | |
202 * @param notifyReaders Whether to send a message to the reader(s) that | |
203 * the writer is through sending commands. Should generally be true, | |
204 * unless there is an error which prevents further messages from | |
205 * being sent. | |
206 */ | |
207 void finish(bool notifyReaders) { | |
208 if (fDone) { | |
209 return; | |
210 } | |
211 if (notifyReaders && this->needOpBytes()) { | |
212 this->writeOp(kDone_DrawOp); | |
213 this->doNotify(); | |
214 } | |
215 if (shouldFlattenBitmaps(fFlags)) { | |
216 // The following circular references exist: | |
217 // fFlattenableHeap -> fWriteBuffer -> fBitmapStorage -> fExternalSt
orage -> fCanvas | |
218 // fBitmapHeap -> fExternalStorage -> fCanvas | |
219 // fFlattenableHeap -> fBitmapStorage -> fExternalStorage -> fCanvas | |
220 | |
221 // Break them all by destroying the final link to this SkGPipeCanvas
. | |
222 fBitmapShuttle->removeCanvas(); | |
223 } | |
224 fDone = true; | |
225 } | |
226 | |
227 void flushRecording(bool detachCurrentBlock); | |
228 size_t freeMemoryIfPossible(size_t bytesToFree); | |
229 | |
230 size_t storageAllocatedForRecording() { | |
231 size_t bytesAllocated = 0; | |
232 if (nullptr != fBitmapHeap) { | |
233 bytesAllocated += fBitmapHeap->bytesAllocated(); | |
234 } | |
235 if (nullptr != fImageHeap) { | |
236 bytesAllocated += fImageHeap->bytesInCache(); | |
237 } | |
238 return bytesAllocated; | |
239 } | |
240 | |
241 /** | |
242 * Flatten an SkBitmap to send to the reader, where it will be referenced | |
243 * according to slot. | |
244 */ | |
245 bool shuttleBitmap(const SkBitmap&, int32_t slot); | |
246 | |
247 void resetImageHeap(); | |
248 | |
249 protected: | |
250 void willSave() override; | |
251 SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; | |
252 void willRestore() override; | |
253 | |
254 void didConcat(const SkMatrix&) override; | |
255 void didSetMatrix(const SkMatrix&) override; | |
256 | |
257 void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; | |
258 void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, | |
259 const SkPaint&) override; | |
260 void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], | |
261 const SkPaint&) override; | |
262 void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos
[], | |
263 SkScalar constY, const SkPaint&) override; | |
264 void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& pat
h, | |
265 const SkMatrix* matrix, const SkPaint&) override; | |
266 void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, | |
267 const SkPaint& paint) override; | |
268 void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], | |
269 const SkPoint texCoords[4], SkXfermode* xmode, | |
270 const SkPaint& paint) override; | |
271 void onDrawPaint(const SkPaint&) override; | |
272 void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPain
t&) override; | |
273 void onDrawRect(const SkRect&, const SkPaint&) override; | |
274 void onDrawOval(const SkRect&, const SkPaint&) override; | |
275 void onDrawRRect(const SkRRect&, const SkPaint&) override; | |
276 void onDrawPath(const SkPath&, const SkPaint&) override; | |
277 void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPain
t*) override; | |
278 void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst,
const SkPaint*, | |
279 SrcRectConstraint) override; | |
280 void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*
) override; | |
281 void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, | |
282 const SkPaint*, SrcRectConstraint) override; | |
283 void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& ds
t, | |
284 const SkPaint*) override; | |
285 void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect&
dst, | |
286 const SkPaint*) override; | |
287 void onDrawVertices(VertexMode vmode, int vertexCount, | |
288 const SkPoint vertices[], const SkPoint texs[], | |
289 const SkColor colors[], SkXfermode* xmode, | |
290 const uint16_t indices[], int indexCount, | |
291 const SkPaint&) override; | |
292 void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const Sk
Color[], | |
293 int count, SkXfermode::Mode, const SkRect* cull, const SkPa
int*) override; | |
294 void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override; | |
295 void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override; | |
296 void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override; | |
297 void onClipRegion(const SkRegion&, SkRegion::Op) override; | |
298 | |
299 void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) overri
de; | |
300 | |
301 private: | |
302 void recordTranslate(const SkMatrix&); | |
303 void recordScale(const SkMatrix&); | |
304 void recordConcat(const SkMatrix&); | |
305 | |
306 SkNamedFactorySet* fFactorySet; | |
307 SkBitmapHeap* fBitmapHeap; | |
308 SkImageHeap* fImageHeap; | |
309 SkGPipeController* fController; | |
310 SkWriter32& fWriter; | |
311 size_t fBlockSize; // amount allocated for writer | |
312 size_t fBytesNotified; | |
313 bool fDone; | |
314 const uint32_t fFlags; | |
315 | |
316 SkRefCntSet fTypefaceSet; | |
317 | |
318 uint32_t getTypefaceID(SkTypeface*); | |
319 | |
320 inline void writeOp(DrawOps op, unsigned flags, unsigned data) { | |
321 fWriter.write32(DrawOp_packOpFlagData(op, flags, data)); | |
322 } | |
323 | |
324 inline void writeOp(DrawOps op) { | |
325 fWriter.write32(DrawOp_packOpFlagData(op, 0, 0)); | |
326 } | |
327 | |
328 bool needOpBytes(size_t size = 0); | |
329 | |
330 inline void doNotify() { | |
331 if (!fDone) { | |
332 size_t bytes = fWriter.bytesWritten() - fBytesNotified; | |
333 if (bytes > 0) { | |
334 fController->notifyWritten(bytes); | |
335 fBytesNotified += bytes; | |
336 } | |
337 } | |
338 } | |
339 | |
340 typedef SkAutoSTMalloc<128, uint8_t> TypefaceBuffer; | |
341 size_t getInProcessTypefaces(const SkRefCntSet& typefaceSet, TypefaceBuffer*
); | |
342 size_t getCrossProcessTypefaces(const SkRefCntSet& typefaceSet, TypefaceBuff
er*); | |
343 | |
344 // Should be called after any calls to an SkFlatDictionary::findAndReplace | |
345 // if a new SkFlatData was added when in cross process mode | |
346 void flattenFactoryNames(); | |
347 | |
348 FlattenableHeap fFlattenableHeap; | |
349 FlatDictionary fFlatDictionary; | |
350 SkAutoTUnref<BitmapShuttle> fBitmapShuttle; | |
351 int fCurrFlatIndex[kCount_PaintFlats]; | |
352 | |
353 int flattenToIndex(SkFlattenable* obj, PaintFlats); | |
354 | |
355 // Common code used by drawBitmap*. Behaves differently depending on the | |
356 // type of SkBitmapHeap being used, which is determined by the flags used. | |
357 bool commonDrawBitmap(const SkBitmap&, DrawOps, unsigned flags, size_t bytes
, const SkPaint*); | |
358 bool commonDrawImage(const SkImage*, DrawOps, unsigned flags, size_t bytes,
const SkPaint*); | |
359 | |
360 SkPaint fPaint; | |
361 void writePaint(const SkPaint&); | |
362 | |
363 class AutoPipeNotify { | |
364 public: | |
365 AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {} | |
366 ~AutoPipeNotify() { fCanvas->doNotify(); } | |
367 private: | |
368 SkGPipeCanvas* fCanvas; | |
369 }; | |
370 friend class AutoPipeNotify; | |
371 | |
372 typedef SkCanvas INHERITED; | |
373 }; | |
374 | |
375 void SkGPipeCanvas::flattenFactoryNames() { | |
376 const char* name; | |
377 while ((name = fFactorySet->getNextAddedFactoryName()) != nullptr) { | |
378 size_t len = strlen(name); | |
379 if (this->needOpBytes(SkWriter32::WriteStringSize(name, len))) { | |
380 this->writeOp(kDef_Factory_DrawOp); | |
381 fWriter.writeString(name, len); | |
382 } | |
383 } | |
384 } | |
385 | |
386 bool SkGPipeCanvas::shuttleBitmap(const SkBitmap& bm, int32_t slot) { | |
387 SkASSERT(shouldFlattenBitmaps(fFlags)); | |
388 SkWriteBuffer buffer; | |
389 buffer.setNamedFactoryRecorder(fFactorySet); | |
390 buffer.writeBitmap(bm); | |
391 this->flattenFactoryNames(); | |
392 size_t size = buffer.bytesWritten(); | |
393 if (this->needOpBytes(size)) { | |
394 this->writeOp(kDef_Bitmap_DrawOp, 0, slot); | |
395 void* dst = static_cast<void*>(fWriter.reserve(size)); | |
396 buffer.writeToMemory(dst); | |
397 return true; | |
398 } | |
399 return false; | |
400 } | |
401 | |
402 // return 0 for nullptr (or unflattenable obj), or index-base-1 | |
403 // return ~(index-base-1) if an old flattenable was replaced | |
404 int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) { | |
405 SkASSERT(!fDone && fBitmapHeap != nullptr); | |
406 if (nullptr == obj) { | |
407 return 0; | |
408 } | |
409 | |
410 fBitmapHeap->deferAddingOwners(); | |
411 bool added, replaced; | |
412 const SkFlatData* flat = fFlatDictionary.findAndReplace(*obj, fFlattenableHe
ap.flatToReplace(), | |
413 &added, &replaced); | |
414 fBitmapHeap->endAddingOwnersDeferral(added); | |
415 int index = flat->index(); | |
416 if (added) { | |
417 if (is_cross_process(fFlags)) { | |
418 this->flattenFactoryNames(); | |
419 } | |
420 size_t flatSize = flat->flatSize(); | |
421 if (this->needOpBytes(flatSize)) { | |
422 this->writeOp(kDef_Flattenable_DrawOp, paintflat, index); | |
423 fWriter.write(flat->data(), flatSize); | |
424 } | |
425 } | |
426 if (replaced) { | |
427 index = ~index; | |
428 } | |
429 return index; | |
430 } | |
431 | |
432 /////////////////////////////////////////////////////////////////////////////// | |
433 | |
434 #define MIN_BLOCK_SIZE (16 * 1024) | |
435 #define BITMAPS_TO_KEEP 5 | |
436 #define FLATTENABLES_TO_KEEP 10 | |
437 | |
438 SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller, | |
439 SkWriter32* writer, | |
440 uint32_t flags, | |
441 uint32_t width, | |
442 uint32_t height) | |
443 : SkCanvas(width, height) | |
444 , fFactorySet(is_cross_process(flags) ? new SkNamedFactorySet : nullptr) | |
445 , fWriter(*writer) | |
446 , fFlags(flags) | |
447 , fFlattenableHeap(FLATTENABLES_TO_KEEP, fFactorySet, is_cross_process(flags
)) | |
448 , fFlatDictionary(&fFlattenableHeap) { | |
449 fController = controller; | |
450 fDone = false; | |
451 fBlockSize = 0; // need first block from controller | |
452 fBytesNotified = 0; | |
453 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex)); | |
454 | |
455 // Tell the reader the appropriate flags to use. | |
456 if (this->needOpBytes()) { | |
457 this->writeOp(kReportFlags_DrawOp, fFlags, 0); | |
458 } | |
459 | |
460 if (shouldFlattenBitmaps(flags)) { | |
461 fBitmapShuttle.reset(new BitmapShuttle(this)); | |
462 fBitmapHeap = new SkBitmapHeap(fBitmapShuttle.get(), BITMAPS_TO_KEEP); | |
463 } else { | |
464 fBitmapHeap = new SkBitmapHeap(BITMAPS_TO_KEEP, controller->numberOfRead
ers()); | |
465 if (this->needOpBytes(sizeof(void*))) { | |
466 this->writeOp(kShareBitmapHeap_DrawOp); | |
467 fWriter.writePtr(static_cast<void*>(fBitmapHeap)); | |
468 } | |
469 } | |
470 fFlattenableHeap.setBitmapStorage(fBitmapHeap); | |
471 | |
472 fImageHeap = new SkImageHeap; | |
473 if (this->needOpBytes(sizeof(void*))) { | |
474 this->writeOp(kShareImageHeap_DrawOp); | |
475 fWriter.writePtr(static_cast<void*>(fImageHeap)); | |
476 } | |
477 | |
478 this->doNotify(); | |
479 } | |
480 | |
481 SkGPipeCanvas::~SkGPipeCanvas() { | |
482 this->finish(true); | |
483 SkSafeUnref(fFactorySet); | |
484 SkSafeUnref(fBitmapHeap); | |
485 SkSafeUnref(fImageHeap); | |
486 } | |
487 | |
488 bool SkGPipeCanvas::needOpBytes(size_t needed) { | |
489 if (fDone) { | |
490 return false; | |
491 } | |
492 | |
493 needed += 4; // size of DrawOp atom | |
494 needed = SkAlign4(needed); | |
495 if (fWriter.bytesWritten() + needed > fBlockSize) { | |
496 // Before we wipe out any data that has already been written, read it ou
t. | |
497 this->doNotify(); | |
498 | |
499 // If we're going to allocate a new block, allocate enough to make it wo
rthwhile. | |
500 needed = SkTMax<size_t>(MIN_BLOCK_SIZE, needed); | |
501 | |
502 void* block = fController->requestBlock(needed, &fBlockSize); | |
503 if (nullptr == block) { | |
504 // Do not notify the readers, which would call this function again. | |
505 this->finish(false); | |
506 return false; | |
507 } | |
508 SkASSERT(SkIsAlign4(fBlockSize)); | |
509 fWriter.reset(block, fBlockSize); | |
510 fBytesNotified = 0; | |
511 } | |
512 return true; | |
513 } | |
514 | |
515 uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) { | |
516 uint32_t id = 0; // 0 means default/null typeface | |
517 if (face) { | |
518 id = fTypefaceSet.find(face); | |
519 if (0 == id) { | |
520 id = fTypefaceSet.add(face); | |
521 size_t size = writeTypeface(nullptr, face); | |
522 if (this->needOpBytes(size)) { | |
523 this->writeOp(kDef_Typeface_DrawOp); | |
524 writeTypeface(&fWriter, face); | |
525 } | |
526 } | |
527 } | |
528 return id; | |
529 } | |
530 | |
531 /////////////////////////////////////////////////////////////////////////////// | |
532 | |
533 #define NOTIFY_SETUP(canvas) \ | |
534 AutoPipeNotify apn(canvas) | |
535 | |
536 void SkGPipeCanvas::willSave() { | |
537 NOTIFY_SETUP(this); | |
538 if (this->needOpBytes()) { | |
539 this->writeOp(kSave_DrawOp); | |
540 } | |
541 | |
542 this->INHERITED::willSave(); | |
543 } | |
544 | |
545 SkCanvas::SaveLayerStrategy SkGPipeCanvas::getSaveLayerStrategy(const SaveLayerR
ec& rec) { | |
546 NOTIFY_SETUP(this); | |
547 size_t size = 0; | |
548 unsigned opFlags = 0; | |
549 | |
550 if (rec.fBounds) { | |
551 opFlags |= kSaveLayer_HasBounds_DrawOpFlag; | |
552 size += sizeof(SkRect); | |
553 } | |
554 if (rec.fPaint) { | |
555 opFlags |= kSaveLayer_HasPaint_DrawOpFlag; | |
556 this->writePaint(*rec.fPaint); | |
557 } | |
558 | |
559 if (this->needOpBytes(size)) { | |
560 this->writeOp(kSaveLayer_DrawOp, opFlags, rec.fSaveLayerFlags); | |
561 if (rec.fBounds) { | |
562 fWriter.writeRect(*rec.fBounds); | |
563 } | |
564 } | |
565 | |
566 (void)this->INHERITED::getSaveLayerStrategy(rec); | |
567 // we don't create a layer | |
568 return kNoLayer_SaveLayerStrategy; | |
569 } | |
570 | |
571 void SkGPipeCanvas::willRestore() { | |
572 NOTIFY_SETUP(this); | |
573 if (this->needOpBytes()) { | |
574 this->writeOp(kRestore_DrawOp); | |
575 } | |
576 | |
577 this->INHERITED::willRestore(); | |
578 } | |
579 | |
580 void SkGPipeCanvas::recordTranslate(const SkMatrix& m) { | |
581 if (this->needOpBytes(2 * sizeof(SkScalar))) { | |
582 this->writeOp(kTranslate_DrawOp); | |
583 fWriter.writeScalar(m.getTranslateX()); | |
584 fWriter.writeScalar(m.getTranslateY()); | |
585 } | |
586 } | |
587 | |
588 void SkGPipeCanvas::recordScale(const SkMatrix& m) { | |
589 if (this->needOpBytes(2 * sizeof(SkScalar))) { | |
590 this->writeOp(kScale_DrawOp); | |
591 fWriter.writeScalar(m.getScaleX()); | |
592 fWriter.writeScalar(m.getScaleY()); | |
593 } | |
594 } | |
595 | |
596 void SkGPipeCanvas::recordConcat(const SkMatrix& m) { | |
597 if (this->needOpBytes(m.writeToMemory(nullptr))) { | |
598 this->writeOp(kConcat_DrawOp); | |
599 fWriter.writeMatrix(m); | |
600 } | |
601 } | |
602 | |
603 void SkGPipeCanvas::didConcat(const SkMatrix& matrix) { | |
604 if (!matrix.isIdentity()) { | |
605 NOTIFY_SETUP(this); | |
606 switch (matrix.getType()) { | |
607 case SkMatrix::kTranslate_Mask: | |
608 this->recordTranslate(matrix); | |
609 break; | |
610 case SkMatrix::kScale_Mask: | |
611 this->recordScale(matrix); | |
612 break; | |
613 default: | |
614 this->recordConcat(matrix); | |
615 break; | |
616 } | |
617 } | |
618 | |
619 this->INHERITED::didConcat(matrix); | |
620 } | |
621 | |
622 void SkGPipeCanvas::didSetMatrix(const SkMatrix& matrix) { | |
623 NOTIFY_SETUP(this); | |
624 if (this->needOpBytes(matrix.writeToMemory(nullptr))) { | |
625 this->writeOp(kSetMatrix_DrawOp); | |
626 fWriter.writeMatrix(matrix); | |
627 } | |
628 this->INHERITED::didSetMatrix(matrix); | |
629 } | |
630 | |
631 void SkGPipeCanvas::onClipRect(const SkRect& rect, SkRegion::Op rgnOp, | |
632 ClipEdgeStyle edgeStyle) { | |
633 NOTIFY_SETUP(this); | |
634 if (this->needOpBytes(sizeof(SkRect))) { | |
635 unsigned flags = 0; | |
636 if (kSoft_ClipEdgeStyle == edgeStyle) { | |
637 flags = kClip_HasAntiAlias_DrawOpFlag; | |
638 } | |
639 this->writeOp(kClipRect_DrawOp, flags, rgnOp); | |
640 fWriter.writeRect(rect); | |
641 } | |
642 this->INHERITED::onClipRect(rect, rgnOp, edgeStyle); | |
643 } | |
644 | |
645 void SkGPipeCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op rgnOp, | |
646 ClipEdgeStyle edgeStyle) { | |
647 NOTIFY_SETUP(this); | |
648 if (this->needOpBytes(kSizeOfFlatRRect)) { | |
649 unsigned flags = 0; | |
650 if (kSoft_ClipEdgeStyle == edgeStyle) { | |
651 flags = kClip_HasAntiAlias_DrawOpFlag; | |
652 } | |
653 this->writeOp(kClipRRect_DrawOp, flags, rgnOp); | |
654 fWriter.writeRRect(rrect); | |
655 } | |
656 this->INHERITED::onClipRRect(rrect, rgnOp, edgeStyle); | |
657 } | |
658 | |
659 void SkGPipeCanvas::onClipPath(const SkPath& path, SkRegion::Op rgnOp, | |
660 ClipEdgeStyle edgeStyle) { | |
661 NOTIFY_SETUP(this); | |
662 if (this->needOpBytes(path.writeToMemory(nullptr))) { | |
663 unsigned flags = 0; | |
664 if (kSoft_ClipEdgeStyle == edgeStyle) { | |
665 flags = kClip_HasAntiAlias_DrawOpFlag; | |
666 } | |
667 this->writeOp(kClipPath_DrawOp, flags, rgnOp); | |
668 fWriter.writePath(path); | |
669 } | |
670 // we just pass on the bounds of the path | |
671 this->INHERITED::onClipRect(path.getBounds(), rgnOp, edgeStyle); | |
672 } | |
673 | |
674 void SkGPipeCanvas::onClipRegion(const SkRegion& region, SkRegion::Op rgnOp) { | |
675 NOTIFY_SETUP(this); | |
676 if (this->needOpBytes(region.writeToMemory(nullptr))) { | |
677 this->writeOp(kClipRegion_DrawOp, 0, rgnOp); | |
678 fWriter.writeRegion(region); | |
679 } | |
680 this->INHERITED::onClipRegion(region, rgnOp); | |
681 } | |
682 | |
683 /////////////////////////////////////////////////////////////////////////////// | |
684 | |
685 void SkGPipeCanvas::onDrawPaint(const SkPaint& paint) { | |
686 NOTIFY_SETUP(this); | |
687 this->writePaint(paint); | |
688 if (this->needOpBytes()) { | |
689 this->writeOp(kDrawPaint_DrawOp); | |
690 } | |
691 } | |
692 | |
693 void SkGPipeCanvas::onDrawPoints(PointMode mode, size_t count, | |
694 const SkPoint pts[], const SkPaint& paint) { | |
695 if (count) { | |
696 NOTIFY_SETUP(this); | |
697 this->writePaint(paint); | |
698 if (this->needOpBytes(4 + count * sizeof(SkPoint))) { | |
699 this->writeOp(kDrawPoints_DrawOp, mode, 0); | |
700 fWriter.write32(SkToU32(count)); | |
701 fWriter.write(pts, count * sizeof(SkPoint)); | |
702 } | |
703 } | |
704 } | |
705 | |
706 void SkGPipeCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) { | |
707 NOTIFY_SETUP(this); | |
708 this->writePaint(paint); | |
709 if (this->needOpBytes(sizeof(SkRect))) { | |
710 this->writeOp(kDrawOval_DrawOp); | |
711 fWriter.writeRect(rect); | |
712 } | |
713 } | |
714 | |
715 void SkGPipeCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) { | |
716 NOTIFY_SETUP(this); | |
717 this->writePaint(paint); | |
718 if (this->needOpBytes(sizeof(SkRect))) { | |
719 this->writeOp(kDrawRect_DrawOp); | |
720 fWriter.writeRect(rect); | |
721 } | |
722 } | |
723 | |
724 void SkGPipeCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { | |
725 NOTIFY_SETUP(this); | |
726 this->writePaint(paint); | |
727 if (this->needOpBytes(kSizeOfFlatRRect)) { | |
728 this->writeOp(kDrawRRect_DrawOp); | |
729 fWriter.writeRRect(rrect); | |
730 } | |
731 } | |
732 | |
733 void SkGPipeCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, | |
734 const SkPaint& paint) { | |
735 NOTIFY_SETUP(this); | |
736 this->writePaint(paint); | |
737 if (this->needOpBytes(kSizeOfFlatRRect * 2)) { | |
738 this->writeOp(kDrawDRRect_DrawOp); | |
739 fWriter.writeRRect(outer); | |
740 fWriter.writeRRect(inner); | |
741 } | |
742 } | |
743 | |
744 void SkGPipeCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { | |
745 NOTIFY_SETUP(this); | |
746 this->writePaint(paint); | |
747 if (this->needOpBytes(path.writeToMemory(nullptr))) { | |
748 this->writeOp(kDrawPath_DrawOp); | |
749 fWriter.writePath(path); | |
750 } | |
751 } | |
752 | |
753 bool SkGPipeCanvas::commonDrawBitmap(const SkBitmap& bm, DrawOps op, | |
754 unsigned flags, | |
755 size_t opBytesNeeded, | |
756 const SkPaint* paint) { | |
757 if (fDone) { | |
758 return false; | |
759 } | |
760 | |
761 if (paint != nullptr) { | |
762 flags |= kDrawBitmap_HasPaint_DrawOpFlag; | |
763 this->writePaint(*paint); | |
764 } | |
765 // This needs to run first so its calls to needOpBytes() and its writes | |
766 // don't interlace with the needOpBytes() and write below. | |
767 SkASSERT(fBitmapHeap != nullptr); | |
768 int32_t bitmapIndex = fBitmapHeap->insert(bm); | |
769 if (SkBitmapHeap::INVALID_SLOT == bitmapIndex) { | |
770 return false; | |
771 } | |
772 | |
773 if (this->needOpBytes(opBytesNeeded)) { | |
774 this->writeOp(op, flags, bitmapIndex); | |
775 return true; | |
776 } | |
777 return false; | |
778 } | |
779 | |
780 void SkGPipeCanvas::onDrawBitmap(const SkBitmap& bm, SkScalar left, SkScalar top
, | |
781 const SkPaint* paint) { | |
782 NOTIFY_SETUP(this); | |
783 size_t opBytesNeeded = sizeof(SkScalar) * 2; | |
784 | |
785 if (this->commonDrawBitmap(bm, kDrawBitmap_DrawOp, 0, opBytesNeeded, paint))
{ | |
786 fWriter.writeScalar(left); | |
787 fWriter.writeScalar(top); | |
788 } | |
789 } | |
790 | |
791 void SkGPipeCanvas::onDrawBitmapRect(const SkBitmap& bm, const SkRect* src, cons
t SkRect& dst, | |
792 const SkPaint* paint, SrcRectConstraint con
straint) { | |
793 NOTIFY_SETUP(this); | |
794 size_t opBytesNeeded = sizeof(SkRect); | |
795 bool hasSrc = src != nullptr; | |
796 unsigned flags; | |
797 if (hasSrc) { | |
798 flags = kDrawBitmap_HasSrcRect_DrawOpFlag; | |
799 opBytesNeeded += sizeof(int32_t) * 4; | |
800 } else { | |
801 flags = 0; | |
802 } | |
803 if (kFast_SrcRectConstraint == constraint) { | |
804 flags |= kDrawBitmap_Bleed_DrawOpFlag; | |
805 } | |
806 | |
807 if (this->commonDrawBitmap(bm, kDrawBitmapRect_DrawOp, flags, opBytesNeeded,
paint)) { | |
808 if (hasSrc) { | |
809 fWriter.writeRect(*src); | |
810 } | |
811 fWriter.writeRect(dst); | |
812 } | |
813 } | |
814 | |
815 void SkGPipeCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center, | |
816 const SkRect& dst, const SkPaint* paint) { | |
817 NOTIFY_SETUP(this); | |
818 size_t opBytesNeeded = sizeof(int32_t) * 4 + sizeof(SkRect); | |
819 | |
820 if (this->commonDrawBitmap(bm, kDrawBitmapNine_DrawOp, 0, opBytesNeeded, pai
nt)) { | |
821 fWriter.write32(center.fLeft); | |
822 fWriter.write32(center.fTop); | |
823 fWriter.write32(center.fRight); | |
824 fWriter.write32(center.fBottom); | |
825 fWriter.writeRect(dst); | |
826 } | |
827 } | |
828 | |
829 bool SkGPipeCanvas::commonDrawImage(const SkImage* image, DrawOps op, unsigned f
lags, | |
830 size_t opBytesNeeded, const SkPaint* paint)
{ | |
831 if (fDone) { | |
832 return false; | |
833 } | |
834 | |
835 if (paint != nullptr) { | |
836 flags |= kDrawBitmap_HasPaint_DrawOpFlag; | |
837 this->writePaint(*paint); | |
838 } | |
839 // This needs to run first so its calls to needOpBytes() and its writes | |
840 // don't interlace with the needOpBytes() and write below. | |
841 int32_t slot = fImageHeap->insert(image); | |
842 SkASSERT(slot != 0); | |
843 if (this->needOpBytes(opBytesNeeded)) { | |
844 this->writeOp(op, flags, slot); | |
845 return true; | |
846 } | |
847 return false; | |
848 } | |
849 | |
850 void SkGPipeCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, | |
851 const SkPaint* paint) { | |
852 NOTIFY_SETUP(this); | |
853 if (this->commonDrawImage(image, kDrawImage_DrawOp, 0, sizeof(SkScalar) * 2,
paint)) { | |
854 fWriter.writeScalar(x); | |
855 fWriter.writeScalar(y); | |
856 } | |
857 } | |
858 | |
859 void SkGPipeCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, con
st SkRect& dst, | |
860 const SkPaint* paint, SrcRectConstraint cons
traint) { | |
861 NOTIFY_SETUP(this); | |
862 unsigned flags = 0; | |
863 size_t opBytesNeeded = sizeof(SkRect); // dst | |
864 if (src) { | |
865 flags |= kDrawBitmap_HasSrcRect_DrawOpFlag; | |
866 opBytesNeeded += sizeof(SkRect); // src | |
867 } | |
868 if (this->commonDrawImage(image, kDrawImageRect_DrawOp, flags, opBytesNeeded
, paint)) { | |
869 if (src) { | |
870 fWriter.writeRect(*src); | |
871 } | |
872 fWriter.writeRect(dst); | |
873 fWriter.writeInt(constraint); | |
874 } | |
875 } | |
876 | |
877 void SkGPipeCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center,
const SkRect& dst, | |
878 const SkPaint* paint) { | |
879 NOTIFY_SETUP(this); | |
880 size_t opBytesNeeded = sizeof(SkIRect) + sizeof(SkRect); // center + dst | |
881 if (this->commonDrawImage(image, kDrawImageNine_DrawOp, 0, opBytesNeeded, pa
int)) { | |
882 fWriter.writeIRect(center); | |
883 fWriter.writeRect(dst); | |
884 } | |
885 } | |
886 | |
887 void SkGPipeCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x,
SkScalar y, | |
888 const SkPaint& paint) { | |
889 if (byteLength) { | |
890 NOTIFY_SETUP(this); | |
891 this->writePaint(paint); | |
892 if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar)))
{ | |
893 this->writeOp(kDrawText_DrawOp); | |
894 fWriter.write32(SkToU32(byteLength)); | |
895 fWriter.writePad(text, byteLength); | |
896 fWriter.writeScalar(x); | |
897 fWriter.writeScalar(y); | |
898 } | |
899 } | |
900 } | |
901 | |
902 void SkGPipeCanvas::onDrawPosText(const void* text, size_t byteLength, const SkP
oint pos[], | |
903 const SkPaint& paint) { | |
904 if (byteLength) { | |
905 NOTIFY_SETUP(this); | |
906 this->writePaint(paint); | |
907 int count = paint.textToGlyphs(text, byteLength, nullptr); | |
908 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPo
int))) { | |
909 this->writeOp(kDrawPosText_DrawOp); | |
910 fWriter.write32(SkToU32(byteLength)); | |
911 fWriter.writePad(text, byteLength); | |
912 fWriter.write32(count); | |
913 fWriter.write(pos, count * sizeof(SkPoint)); | |
914 } | |
915 } | |
916 } | |
917 | |
918 void SkGPipeCanvas::onDrawPosTextH(const void* text, size_t byteLength, const Sk
Scalar xpos[], | |
919 SkScalar constY, const SkPaint& paint) { | |
920 if (byteLength) { | |
921 NOTIFY_SETUP(this); | |
922 this->writePaint(paint); | |
923 int count = paint.textToGlyphs(text, byteLength, nullptr); | |
924 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkSc
alar) + 4)) { | |
925 this->writeOp(kDrawPosTextH_DrawOp); | |
926 fWriter.write32(SkToU32(byteLength)); | |
927 fWriter.writePad(text, byteLength); | |
928 fWriter.write32(count); | |
929 fWriter.write(xpos, count * sizeof(SkScalar)); | |
930 fWriter.writeScalar(constY); | |
931 } | |
932 } | |
933 } | |
934 | |
935 void SkGPipeCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const
SkPath& path, | |
936 const SkMatrix* matrix, const SkPaint& pain
t) { | |
937 if (byteLength) { | |
938 NOTIFY_SETUP(this); | |
939 unsigned flags = 0; | |
940 size_t size = 4 + SkAlign4(byteLength) + path.writeToMemory(nullptr); | |
941 if (matrix) { | |
942 flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag; | |
943 size += matrix->writeToMemory(nullptr); | |
944 } | |
945 this->writePaint(paint); | |
946 if (this->needOpBytes(size)) { | |
947 this->writeOp(kDrawTextOnPath_DrawOp, flags, 0); | |
948 | |
949 fWriter.write32(SkToU32(byteLength)); | |
950 fWriter.writePad(text, byteLength); | |
951 | |
952 fWriter.writePath(path); | |
953 if (matrix) { | |
954 fWriter.writeMatrix(*matrix); | |
955 } | |
956 } | |
957 } | |
958 } | |
959 | |
960 size_t SkGPipeCanvas::getInProcessTypefaces(const SkRefCntSet& typefaceSet, | |
961 TypefaceBuffer* buffer) { | |
962 // When in-process, we simply write out the typeface pointers. | |
963 size_t size = typefaceSet.count() * sizeof(SkTypeface*); | |
964 buffer->reset(size); | |
965 typefaceSet.copyToArray(reinterpret_cast<SkRefCnt**>(buffer->get())); | |
966 | |
967 return size; | |
968 } | |
969 | |
970 size_t SkGPipeCanvas::getCrossProcessTypefaces(const SkRefCntSet& typefaceSet, | |
971 TypefaceBuffer* buffer) { | |
972 // For cross-process we use typeface IDs. | |
973 size_t size = typefaceSet.count() * sizeof(uint32_t); | |
974 buffer->reset(size); | |
975 | |
976 uint32_t* idBuffer = reinterpret_cast<uint32_t*>(buffer->get()); | |
977 SkRefCntSet::Iter iter(typefaceSet); | |
978 int i = 0; | |
979 | |
980 for (void* setPtr = iter.next(); setPtr; setPtr = iter.next()) { | |
981 idBuffer[i++] = this->getTypefaceID(reinterpret_cast<SkTypeface*>(setPtr
)); | |
982 } | |
983 | |
984 SkASSERT(i == typefaceSet.count()); | |
985 | |
986 return size; | |
987 } | |
988 | |
989 void SkGPipeCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar
y, | |
990 const SkPaint& paint) { | |
991 NOTIFY_SETUP(this); | |
992 this->writePaint(paint); | |
993 | |
994 // FIXME: this is inefficient but avoids duplicating the blob serialization
logic. | |
995 SkRefCntSet typefaceSet; | |
996 SkWriteBuffer blobBuffer; | |
997 blobBuffer.setTypefaceRecorder(&typefaceSet); | |
998 blob->flatten(blobBuffer); | |
999 | |
1000 // Unlike most draw ops (which only use one paint/typeface), text blobs may
reference | |
1001 // an arbitrary number of typefaces. Since the one-paint-per-op model is not
applicable, | |
1002 // we need to serialize these explicitly. | |
1003 TypefaceBuffer typefaceBuffer; | |
1004 size_t typefaceSize = is_cross_process(fFlags) | |
1005 ? this->getCrossProcessTypefaces(typefaceSet, &typefaceBuffer) | |
1006 : this->getInProcessTypefaces(typefaceSet, &typefaceBuffer); | |
1007 | |
1008 // blob byte count + typeface count + x + y + blob data + an index (cross-pr
ocess) | |
1009 // or pointer (in-process) for each typeface | |
1010 size_t size = 2 * sizeof(uint32_t) | |
1011 + 2 * sizeof(SkScalar) | |
1012 + blobBuffer.bytesWritten() | |
1013 + typefaceSize; | |
1014 | |
1015 if (this->needOpBytes(size)) { | |
1016 this->writeOp(kDrawTextBlob_DrawOp); | |
1017 SkDEBUGCODE(size_t initialOffset = fWriter.bytesWritten();) | |
1018 | |
1019 fWriter.writeScalar(x); | |
1020 fWriter.writeScalar(y); | |
1021 | |
1022 fWriter.write32(typefaceSet.count()); | |
1023 fWriter.write(typefaceBuffer.get(), typefaceSize); | |
1024 | |
1025 fWriter.write32(SkToU32(blobBuffer.bytesWritten())); | |
1026 uint32_t* pad = fWriter.reservePad(blobBuffer.bytesWritten()); | |
1027 blobBuffer.writeToMemory(pad); | |
1028 | |
1029 SkASSERT(initialOffset + size == fWriter.bytesWritten()); | |
1030 } | |
1031 } | |
1032 | |
1033 void SkGPipeCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matr
ix, | |
1034 const SkPaint* paint) { | |
1035 // we want to playback the picture into individual draw calls | |
1036 // | |
1037 // todo: do we always have to unroll? If the pipe is not cross-process, seem
s like | |
1038 // we could just ref the picture and move on...? <reed, scroggo> | |
1039 // | |
1040 this->INHERITED::onDrawPicture(picture, matrix, paint); | |
1041 } | |
1042 | |
1043 void SkGPipeCanvas::onDrawVertices(VertexMode vmode, int vertexCount, | |
1044 const SkPoint vertices[], const SkPoint texs[
], | |
1045 const SkColor colors[], SkXfermode* xfer, | |
1046 const uint16_t indices[], int indexCount, | |
1047 const SkPaint& paint) { | |
1048 if (0 == vertexCount) { | |
1049 return; | |
1050 } | |
1051 | |
1052 NOTIFY_SETUP(this); | |
1053 this->writePaint(paint); | |
1054 | |
1055 unsigned flags = 0; // packs with the op, so needs no extra space | |
1056 | |
1057 size_t size = 0; | |
1058 size += 4; // vmode | |
1059 size += 4; // vertex count | |
1060 size += vertexCount * sizeof(SkPoint); // vertices | |
1061 | |
1062 if (texs) { | |
1063 flags |= kDrawVertices_HasTexs_DrawOpFlag; | |
1064 size += vertexCount * sizeof(SkPoint); | |
1065 } | |
1066 if (colors) { | |
1067 flags |= kDrawVertices_HasColors_DrawOpFlag; | |
1068 size += vertexCount * sizeof(SkColor); | |
1069 } | |
1070 if (xfer && !SkXfermode::IsMode(xfer, SkXfermode::kModulate_Mode)) { | |
1071 flags |= kDrawVertices_HasXfermode_DrawOpFlag; | |
1072 size += sizeof(int32_t); // SkXfermode::Mode | |
1073 } | |
1074 if (indices && indexCount > 0) { | |
1075 flags |= kDrawVertices_HasIndices_DrawOpFlag; | |
1076 size += 4; // index count | |
1077 size += SkAlign4(indexCount * sizeof(uint16_t)); // indices | |
1078 } | |
1079 | |
1080 if (this->needOpBytes(size)) { | |
1081 this->writeOp(kDrawVertices_DrawOp, flags, 0); | |
1082 fWriter.write32(vmode); | |
1083 fWriter.write32(vertexCount); | |
1084 fWriter.write(vertices, vertexCount * sizeof(SkPoint)); | |
1085 if (flags & kDrawVertices_HasTexs_DrawOpFlag) { | |
1086 fWriter.write(texs, vertexCount * sizeof(SkPoint)); | |
1087 } | |
1088 if (flags & kDrawVertices_HasColors_DrawOpFlag) { | |
1089 fWriter.write(colors, vertexCount * sizeof(SkColor)); | |
1090 } | |
1091 if (flags & kDrawVertices_HasXfermode_DrawOpFlag) { | |
1092 SkXfermode::Mode mode = SkXfermode::kModulate_Mode; | |
1093 SkAssertResult(xfer->asMode(&mode)); | |
1094 fWriter.write32(mode); | |
1095 } | |
1096 if (flags & kDrawVertices_HasIndices_DrawOpFlag) { | |
1097 fWriter.write32(indexCount); | |
1098 fWriter.writePad(indices, indexCount * sizeof(uint16_t)); | |
1099 } | |
1100 } | |
1101 } | |
1102 | |
1103 void SkGPipeCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], c
onst SkRect tex[], | |
1104 const SkColor colors[], int count, SkXfermode::M
ode mode, | |
1105 const SkRect* cull, const SkPaint* paint) { | |
1106 NOTIFY_SETUP(this); | |
1107 unsigned flags = 0; // packs with the op, so needs no extra space | |
1108 | |
1109 if (paint) { | |
1110 flags |= kDrawAtlas_HasPaint_DrawOpFlag; | |
1111 this->writePaint(*paint); | |
1112 } | |
1113 | |
1114 size_t size = 4; // image-slot | |
1115 size += 4; // count | |
1116 size += 4; // mode | |
1117 size += count * sizeof(SkRSXform); // xform | |
1118 size += count * sizeof(SkRect); // tex | |
1119 if (colors) { | |
1120 flags |= kDrawAtlas_HasColors_DrawOpFlag; | |
1121 size += count * sizeof(SkColor); // colors | |
1122 } | |
1123 if (cull) { | |
1124 flags |= kDrawAtlas_HasCull_DrawOpFlag; | |
1125 size += sizeof(SkRect); // cull | |
1126 } | |
1127 | |
1128 if (this->needOpBytes(size)) { | |
1129 this->writeOp(kDrawAtlas_DrawOp, flags, 0); | |
1130 int32_t slot = fImageHeap->insert(atlas); | |
1131 fWriter.write32(slot); | |
1132 fWriter.write32(count); | |
1133 fWriter.write32(mode); | |
1134 fWriter.write(xform, count * sizeof(SkRSXform)); | |
1135 fWriter.write(tex, count * sizeof(SkRect)); | |
1136 if (colors) { | |
1137 fWriter.write(colors, count * sizeof(SkColor)); | |
1138 } | |
1139 if (cull) { | |
1140 fWriter.writeRect(*cull); | |
1141 } | |
1142 } | |
1143 } | |
1144 | |
1145 void SkGPipeCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4
], | |
1146 const SkPoint texCoords[4], SkXfermode* xmode, | |
1147 const SkPaint& paint) { | |
1148 NOTIFY_SETUP(this); | |
1149 | |
1150 size_t size = SkPatchUtils::kNumCtrlPts * sizeof(SkPoint); | |
1151 unsigned flags = 0; | |
1152 if (colors) { | |
1153 flags |= kDrawVertices_HasColors_DrawOpFlag; | |
1154 size += SkPatchUtils::kNumCorners * sizeof(SkColor); | |
1155 } | |
1156 if (texCoords) { | |
1157 flags |= kDrawVertices_HasTexs_DrawOpFlag; | |
1158 size += SkPatchUtils::kNumCorners * sizeof(SkPoint); | |
1159 } | |
1160 if (xmode) { | |
1161 SkXfermode::Mode mode; | |
1162 if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) { | |
1163 flags |= kDrawVertices_HasXfermode_DrawOpFlag; | |
1164 size += sizeof(int32_t); | |
1165 } | |
1166 } | |
1167 | |
1168 this->writePaint(paint); | |
1169 if (this->needOpBytes(size)) { | |
1170 this->writeOp(kDrawPatch_DrawOp, flags, 0); | |
1171 | |
1172 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint)); | |
1173 | |
1174 if (colors) { | |
1175 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor)); | |
1176 } | |
1177 | |
1178 if (texCoords) { | |
1179 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint)
); | |
1180 } | |
1181 | |
1182 if (flags & kDrawVertices_HasXfermode_DrawOpFlag) { | |
1183 SkXfermode::Mode mode = SkXfermode::kModulate_Mode; | |
1184 SkAssertResult(xmode->asMode(&mode)); | |
1185 fWriter.write32(mode); | |
1186 } | |
1187 } | |
1188 } | |
1189 | |
1190 void SkGPipeCanvas::flushRecording(bool detachCurrentBlock) { | |
1191 this->doNotify(); | |
1192 if (detachCurrentBlock) { | |
1193 // force a new block to be requested for the next recorded command | |
1194 fBlockSize = 0; | |
1195 } | |
1196 } | |
1197 | |
1198 void SkGPipeCanvas::resetImageHeap() { | |
1199 if (fImageHeap) { | |
1200 fImageHeap->reset(); | |
1201 } | |
1202 } | |
1203 | |
1204 size_t SkGPipeCanvas::freeMemoryIfPossible(size_t bytesToFree) { | |
1205 return (nullptr == fBitmapHeap) ? 0 : fBitmapHeap->freeMemoryIfPossible(byte
sToFree); | |
1206 } | |
1207 | |
1208 /////////////////////////////////////////////////////////////////////////////// | |
1209 | |
1210 template <typename T> uint32_t castToU32(T value) { | |
1211 union { | |
1212 T fSrc; | |
1213 uint32_t fDst; | |
1214 } data; | |
1215 data.fSrc = value; | |
1216 return data.fDst; | |
1217 } | |
1218 | |
1219 void SkGPipeCanvas::writePaint(const SkPaint& paint) { | |
1220 if (fDone) { | |
1221 return; | |
1222 } | |
1223 SkPaint& base = fPaint; | |
1224 uint32_t storage[32]; | |
1225 uint32_t* ptr = storage; | |
1226 | |
1227 if (base.getFlags() != paint.getFlags()) { | |
1228 *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags()); | |
1229 base.setFlags(paint.getFlags()); | |
1230 } | |
1231 if (base.getColor() != paint.getColor()) { | |
1232 *ptr++ = PaintOp_packOp(kColor_PaintOp); | |
1233 *ptr++ = paint.getColor(); | |
1234 base.setColor(paint.getColor()); | |
1235 } | |
1236 if (base.getFilterQuality() != paint.getFilterQuality()) { | |
1237 *ptr++ = PaintOp_packOpData(kFilterLevel_PaintOp, paint.getFilterQuality
()); | |
1238 base.setFilterQuality(paint.getFilterQuality()); | |
1239 } | |
1240 if (base.getStyle() != paint.getStyle()) { | |
1241 *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle()); | |
1242 base.setStyle(paint.getStyle()); | |
1243 } | |
1244 if (base.getStrokeJoin() != paint.getStrokeJoin()) { | |
1245 *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin()); | |
1246 base.setStrokeJoin(paint.getStrokeJoin()); | |
1247 } | |
1248 if (base.getStrokeCap() != paint.getStrokeCap()) { | |
1249 *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap()); | |
1250 base.setStrokeCap(paint.getStrokeCap()); | |
1251 } | |
1252 if (base.getStrokeWidth() != paint.getStrokeWidth()) { | |
1253 *ptr++ = PaintOp_packOp(kWidth_PaintOp); | |
1254 *ptr++ = castToU32(paint.getStrokeWidth()); | |
1255 base.setStrokeWidth(paint.getStrokeWidth()); | |
1256 } | |
1257 if (base.getStrokeMiter() != paint.getStrokeMiter()) { | |
1258 *ptr++ = PaintOp_packOp(kMiter_PaintOp); | |
1259 *ptr++ = castToU32(paint.getStrokeMiter()); | |
1260 base.setStrokeMiter(paint.getStrokeMiter()); | |
1261 } | |
1262 if (base.getTextEncoding() != paint.getTextEncoding()) { | |
1263 *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding()); | |
1264 base.setTextEncoding(paint.getTextEncoding()); | |
1265 } | |
1266 if (base.getHinting() != paint.getHinting()) { | |
1267 *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting()); | |
1268 base.setHinting(paint.getHinting()); | |
1269 } | |
1270 if (base.getTextAlign() != paint.getTextAlign()) { | |
1271 *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign()); | |
1272 base.setTextAlign(paint.getTextAlign()); | |
1273 } | |
1274 if (base.getTextSize() != paint.getTextSize()) { | |
1275 *ptr++ = PaintOp_packOp(kTextSize_PaintOp); | |
1276 *ptr++ = castToU32(paint.getTextSize()); | |
1277 base.setTextSize(paint.getTextSize()); | |
1278 } | |
1279 if (base.getTextScaleX() != paint.getTextScaleX()) { | |
1280 *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp); | |
1281 *ptr++ = castToU32(paint.getTextScaleX()); | |
1282 base.setTextScaleX(paint.getTextScaleX()); | |
1283 } | |
1284 if (base.getTextSkewX() != paint.getTextSkewX()) { | |
1285 *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp); | |
1286 *ptr++ = castToU32(paint.getTextSkewX()); | |
1287 base.setTextSkewX(paint.getTextSkewX()); | |
1288 } | |
1289 | |
1290 if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) { | |
1291 if (is_cross_process(fFlags)) { | |
1292 uint32_t id = this->getTypefaceID(paint.getTypeface()); | |
1293 *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id); | |
1294 } else if (this->needOpBytes(sizeof(void*))) { | |
1295 // Add to the set for ref counting. | |
1296 fTypefaceSet.add(paint.getTypeface()); | |
1297 // It is safe to write the typeface to the stream before the rest | |
1298 // of the paint unless we ever send a kReset_PaintOp, which we | |
1299 // currently never do. | |
1300 this->writeOp(kSetTypeface_DrawOp); | |
1301 fWriter.writePtr(paint.getTypeface()); | |
1302 } | |
1303 base.setTypeface(paint.getTypeface()); | |
1304 } | |
1305 | |
1306 // This is a new paint, so all old flats can be safely purged, if necessary. | |
1307 fFlattenableHeap.markAllFlatsSafeToDelete(); | |
1308 for (int i = 0; i < kCount_PaintFlats; i++) { | |
1309 int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i)
; | |
1310 bool replaced = index < 0; | |
1311 if (replaced) { | |
1312 index = ~index; | |
1313 } | |
1314 // Store the index of any flat that needs to be kept. 0 means no flat. | |
1315 if (index > 0) { | |
1316 fFlattenableHeap.markFlatForKeeping(index); | |
1317 } | |
1318 SkASSERT(index >= 0 && index <= fFlatDictionary.count()); | |
1319 if (index != fCurrFlatIndex[i] || replaced) { | |
1320 *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index); | |
1321 fCurrFlatIndex[i] = index; | |
1322 } | |
1323 } | |
1324 | |
1325 size_t size = (char*)ptr - (char*)storage; | |
1326 if (size && this->needOpBytes(size)) { | |
1327 this->writeOp(kPaintOp_DrawOp, 0, SkToU32(size)); | |
1328 fWriter.write(storage, size); | |
1329 for (size_t i = 0; i < size/4; i++) { | |
1330 // SkDebugf("[%d] %08X\n", i, storage[i]); | |
1331 } | |
1332 } | |
1333 | |
1334 // | |
1335 // Do these after we've written kPaintOp_DrawOp | |
1336 | |
1337 if (base.getAnnotation() != paint.getAnnotation()) { | |
1338 if (nullptr == paint.getAnnotation()) { | |
1339 if (this->needOpBytes()) { | |
1340 this->writeOp(kSetAnnotation_DrawOp, 0, 0); | |
1341 } | |
1342 } else { | |
1343 SkWriteBuffer buffer; | |
1344 paint.getAnnotation()->writeToBuffer(buffer); | |
1345 const size_t size = buffer.bytesWritten(); | |
1346 if (this->needOpBytes(size)) { | |
1347 this->writeOp(kSetAnnotation_DrawOp, 0, SkToU32(size)); | |
1348 buffer.writeToMemory(fWriter.reserve(size)); | |
1349 } | |
1350 } | |
1351 base.setAnnotation(paint.getAnnotation()); | |
1352 } | |
1353 } | |
1354 | |
1355 /////////////////////////////////////////////////////////////////////////////// | |
1356 | |
1357 #include "SkGPipe.h" | |
1358 | |
1359 SkGPipeController::~SkGPipeController() { | |
1360 SkSafeUnref(fCanvas); | |
1361 } | |
1362 | |
1363 void SkGPipeController::setCanvas(SkGPipeCanvas* canvas) { | |
1364 SkRefCnt_SafeAssign(fCanvas, canvas); | |
1365 } | |
1366 | |
1367 void SkGPipeController::purgeCaches() | |
1368 { | |
1369 fCanvas->resetImageHeap(); | |
1370 // Other caches are self-purging with a small MRU pool | |
1371 // We could purge them as well, but it is not clear whether | |
1372 // that would be a win. | |
1373 } | |
1374 | |
1375 /////////////////////////////////////////////////////////////////////////////// | |
1376 | |
1377 SkGPipeWriter::SkGPipeWriter() | |
1378 : fWriter(0) { | |
1379 fCanvas = nullptr; | |
1380 } | |
1381 | |
1382 SkGPipeWriter::~SkGPipeWriter() { | |
1383 this->endRecording(); | |
1384 } | |
1385 | |
1386 SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller, uint32_t
flags, | |
1387 uint32_t width, uint32_t height) { | |
1388 if (nullptr == fCanvas) { | |
1389 fWriter.reset(nullptr, 0); | |
1390 fCanvas = new SkGPipeCanvas(controller, &fWriter, flags, width, height); | |
1391 } | |
1392 controller->setCanvas(fCanvas); | |
1393 return fCanvas; | |
1394 } | |
1395 | |
1396 void SkGPipeWriter::endRecording() { | |
1397 if (fCanvas) { | |
1398 fCanvas->finish(true); | |
1399 fCanvas->unref(); | |
1400 fCanvas = nullptr; | |
1401 } | |
1402 } | |
1403 | |
1404 void SkGPipeWriter::flushRecording(bool detachCurrentBlock) { | |
1405 if (fCanvas) { | |
1406 fCanvas->flushRecording(detachCurrentBlock); | |
1407 } | |
1408 } | |
1409 | |
1410 size_t SkGPipeWriter::freeMemoryIfPossible(size_t bytesToFree) { | |
1411 if (fCanvas) { | |
1412 return fCanvas->freeMemoryIfPossible(bytesToFree); | |
1413 } | |
1414 return 0; | |
1415 } | |
1416 | |
1417 size_t SkGPipeWriter::storageAllocatedForRecording() const { | |
1418 return nullptr == fCanvas ? 0 : fCanvas->storageAllocatedForRecording(); | |
1419 } | |
1420 | |
1421 /////////////////////////////////////////////////////////////////////////////// | |
1422 | |
1423 BitmapShuttle::BitmapShuttle(SkGPipeCanvas* canvas) { | |
1424 SkASSERT(canvas != nullptr); | |
1425 fCanvas = canvas; | |
1426 fCanvas->ref(); | |
1427 } | |
1428 | |
1429 BitmapShuttle::~BitmapShuttle() { | |
1430 this->removeCanvas(); | |
1431 } | |
1432 | |
1433 bool BitmapShuttle::insert(const SkBitmap& bitmap, int32_t slot) { | |
1434 SkASSERT(fCanvas != nullptr); | |
1435 return fCanvas->shuttleBitmap(bitmap, slot); | |
1436 } | |
1437 | |
1438 void BitmapShuttle::removeCanvas() { | |
1439 if (nullptr == fCanvas) { | |
1440 return; | |
1441 } | |
1442 fCanvas->unref(); | |
1443 fCanvas = nullptr; | |
1444 } | |
1445 | |
1446 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | |
1447 | |
1448 SkImageHeap::SkImageHeap() : fBytesInCache (0) {} | |
1449 | |
1450 SkImageHeap::~SkImageHeap() { | |
1451 fArray.unrefAll(); | |
1452 } | |
1453 | |
1454 void SkImageHeap::reset() { | |
1455 fArray.unrefAll(); | |
1456 fArray.rewind(); | |
1457 fBytesInCache = 0; | |
1458 } | |
1459 | |
1460 const SkImage* SkImageHeap::get(int32_t slot) const { | |
1461 SkASSERT(slot > 0); | |
1462 return fArray[slot - 1]; | |
1463 } | |
1464 | |
1465 int32_t SkImageHeap::find(const SkImage* img) const { | |
1466 int index = fArray.find(img); | |
1467 if (index >= 0) { | |
1468 return index + 1; // found | |
1469 } | |
1470 return 0; // not found | |
1471 } | |
1472 | |
1473 int32_t SkImageHeap::insert(const SkImage* img) { | |
1474 int32_t slot = this->find(img); | |
1475 if (slot) { | |
1476 return slot; | |
1477 } | |
1478 // TODO: SkImage does not expose bytes per pixel, 4 is just a best guess. | |
1479 fBytesInCache += img->width() * img->height() * 4; | |
1480 *fArray.append() = SkRef(img); | |
1481 return fArray.count(); // slot is always index+1 | |
1482 } | |
1483 | |
OLD | NEW |