Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkPicture.cpp
1
2 /*
3  * Copyright 2007 The Android Open Source Project
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
10 #include "SkPictureFlat.h"
11 #include "SkPictureData.h"
12 #include "SkPicturePlayback.h"
13 #include "SkPictureRecord.h"
14 #include "SkPictureRecorder.h"
15
16 #include "SkBitmapDevice.h"
17 #include "SkCanvas.h"
18 #include "SkChunkAlloc.h"
19 #include "SkDrawPictureCallback.h"
20 #include "SkPaintPriv.h"
21 #include "SkPathEffect.h"
22 #include "SkPicture.h"
23 #include "SkRegion.h"
24 #include "SkShader.h"
25 #include "SkStream.h"
26 #include "SkTDArray.h"
27 #include "SkTLogic.h"
28 #include "SkTSearch.h"
29 #include "SkTime.h"
30
31 #include "SkReader32.h"
32 #include "SkWriter32.h"
33 #include "SkRTree.h"
34
35 #if SK_SUPPORT_GPU
36 #include "GrContext.h"
37 #endif
38
39 #include "SkRecord.h"
40 #include "SkRecordDraw.h"
41 #include "SkRecordOpts.h"
42 #include "SkRecorder.h"
43
44 template <typename T> int SafeCount(const T* obj) {
45     return obj ? obj->count() : 0;
46 }
47
48 ///////////////////////////////////////////////////////////////////////////////
49
50 namespace {
51
52 // Some commands have a paint, some have an optional paint.  Either way, get back a pointer.
53 static const SkPaint* AsPtr(const SkPaint& p) { return &p; }
54 static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; }
55
56 /** SkRecords visitor to determine whether an instance may require an
57     "external" bitmap to rasterize. May return false positives.
58     Does not return true for bitmap text.
59
60     Expected use is to determine whether images need to be decoded before
61     rasterizing a particular SkRecord.
62  */
63 struct BitmapTester {
64     // Helpers.  These create HasMember_bitmap and HasMember_paint.
65     SK_CREATE_MEMBER_DETECTOR(bitmap);
66     SK_CREATE_MEMBER_DETECTOR(paint);
67
68
69     // Main entry for visitor:
70     // If the command is a DrawPicture, recurse.
71     // If the command has a bitmap directly, return true.
72     // If the command has a paint and the paint has a bitmap, return true.
73     // Otherwise, return false.
74     bool operator()(const SkRecords::DrawPicture& op) { return op.picture->willPlayBackBitmaps(); }
75
76     template <typename T>
77     bool operator()(const T& r) { return CheckBitmap(r); }
78
79
80     // If the command has a bitmap, of course we're going to play back bitmaps.
81     template <typename T>
82     static SK_WHEN(HasMember_bitmap<T>, bool) CheckBitmap(const T&) { return true; }
83
84     // If not, look for one in its paint (if it has a paint).
85     template <typename T>
86     static SK_WHEN(!HasMember_bitmap<T>, bool) CheckBitmap(const T& r) { return CheckPaint(r); }
87
88     // If we have a paint, dig down into the effects looking for a bitmap.
89     template <typename T>
90     static SK_WHEN(HasMember_paint<T>, bool) CheckPaint(const T& r) {
91         const SkPaint* paint = AsPtr(r.paint);
92         if (paint) {
93             const SkShader* shader = paint->getShader();
94             if (shader &&
95                 shader->asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType) {
96                 return true;
97             }
98         }
99         return false;
100     }
101
102     // If we don't have a paint, that non-paint has no bitmap.
103     template <typename T>
104     static SK_WHEN(!HasMember_paint<T>, bool) CheckPaint(const T&) { return false; }
105 };
106
107 bool WillPlaybackBitmaps(const SkRecord& record) {
108     BitmapTester tester;
109     for (unsigned i = 0; i < record.count(); i++) {
110         if (record.visit<bool>(i, tester)) {
111             return true;
112         }
113     }
114     return false;
115 }
116
117 // SkRecord visitor to find recorded text.
118 struct TextHunter {
119     // All ops with text have that text as a char array member named "text".
120     SK_CREATE_MEMBER_DETECTOR(text);
121     bool operator()(const SkRecords::DrawPicture& op) { return op.picture->hasText(); }
122     template <typename T> SK_WHEN(HasMember_text<T>,  bool) operator()(const T&) { return true;  }
123     template <typename T> SK_WHEN(!HasMember_text<T>, bool) operator()(const T&) { return false; }
124 };
125
126 } // namespace
127
128 /** SkRecords visitor to determine heuristically whether or not a SkPicture
129     will be performant when rasterized on the GPU.
130  */
131 struct SkPicture::PathCounter {
132     SK_CREATE_MEMBER_DETECTOR(paint);
133
134     PathCounter()
135         : numPaintWithPathEffectUses (0)
136         , numFastPathDashEffects (0)
137         , numAAConcavePaths (0)
138         , numAAHairlineConcavePaths (0)
139         , numAADFEligibleConcavePaths(0) {
140     }
141
142     // Recurse into nested pictures.
143     void operator()(const SkRecords::DrawPicture& op) {
144         const SkPicture::Analysis& analysis = op.picture->fAnalysis;
145         numPaintWithPathEffectUses += analysis.fNumPaintWithPathEffectUses;
146         numFastPathDashEffects     += analysis.fNumFastPathDashEffects;
147         numAAConcavePaths          += analysis.fNumAAConcavePaths;
148         numAAHairlineConcavePaths  += analysis.fNumAAHairlineConcavePaths;
149         numAADFEligibleConcavePaths  += analysis.fNumAADFEligibleConcavePaths;
150     }
151
152     void checkPaint(const SkPaint* paint) {
153         if (paint && paint->getPathEffect()) {
154             numPaintWithPathEffectUses++;
155         }
156     }
157
158     void operator()(const SkRecords::DrawPoints& op) {
159         this->checkPaint(&op.paint);
160         const SkPathEffect* effect = op.paint.getPathEffect();
161         if (effect) {
162             SkPathEffect::DashInfo info;
163             SkPathEffect::DashType dashType = effect->asADash(&info);
164             if (2 == op.count && SkPaint::kRound_Cap != op.paint.getStrokeCap() &&
165                 SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) {
166                 numFastPathDashEffects++;
167             }
168         }
169     }
170
171     void operator()(const SkRecords::DrawPath& op) {
172         this->checkPaint(&op.paint);
173         if (op.paint.isAntiAlias() && !op.path.isConvex()) {
174             numAAConcavePaths++;
175
176             SkPaint::Style paintStyle = op.paint.getStyle();
177             const SkRect& pathBounds = op.path.getBounds();
178             if (SkPaint::kStroke_Style == paintStyle &&
179                 0 == op.paint.getStrokeWidth()) {
180                 numAAHairlineConcavePaths++;
181             } else if (SkPaint::kFill_Style == paintStyle && pathBounds.width() < 64.f &&
182                        pathBounds.height() < 64.f && !op.path.isVolatile()) {
183                 numAADFEligibleConcavePaths++;
184             }
185         }
186     }
187
188     template <typename T>
189     SK_WHEN(HasMember_paint<T>, void) operator()(const T& op) {
190         this->checkPaint(AsPtr(op.paint));
191     }
192
193     template <typename T>
194     SK_WHEN(!HasMember_paint<T>, void) operator()(const T& op) { /* do nothing */ }
195
196     int numPaintWithPathEffectUses;
197     int numFastPathDashEffects;
198     int numAAConcavePaths;
199     int numAAHairlineConcavePaths;
200     int numAADFEligibleConcavePaths;
201 };
202
203 SkPicture::Analysis::Analysis(const SkRecord& record) {
204     fWillPlaybackBitmaps = WillPlaybackBitmaps(record);
205
206     PathCounter counter;
207     for (unsigned i = 0; i < record.count(); i++) {
208         record.visit<void>(i, counter);
209     }
210     fNumPaintWithPathEffectUses = counter.numPaintWithPathEffectUses;
211     fNumFastPathDashEffects     = counter.numFastPathDashEffects;
212     fNumAAConcavePaths          = counter.numAAConcavePaths;
213     fNumAAHairlineConcavePaths  = counter.numAAHairlineConcavePaths;
214     fNumAADFEligibleConcavePaths  = counter.numAADFEligibleConcavePaths;
215
216     fHasText = false;
217     TextHunter text;
218     for (unsigned i = 0; i < record.count(); i++) {
219         if (record.visit<bool>(i, text)) {
220             fHasText = true;
221             break;
222         }
223     }
224 }
225
226 bool SkPicture::Analysis::suitableForGpuRasterization(const char** reason,
227                                                       int sampleCount) const {
228     // TODO: the heuristic used here needs to be refined
229     static const int kNumPaintWithPathEffectsUsesTol = 1;
230     static const int kNumAAConcavePathsTol = 5;
231
232     int numNonDashedPathEffects = fNumPaintWithPathEffectUses -
233                                   fNumFastPathDashEffects;
234     bool suitableForDash = (0 == fNumPaintWithPathEffectUses) ||
235                            (numNonDashedPathEffects < kNumPaintWithPathEffectsUsesTol
236                                && 0 == sampleCount);
237
238     bool ret = suitableForDash &&
239                (fNumAAConcavePaths - fNumAAHairlineConcavePaths - fNumAADFEligibleConcavePaths)
240                    < kNumAAConcavePathsTol;
241
242     if (!ret && reason) {
243         if (!suitableForDash) {
244             if (0 != sampleCount) {
245                 *reason = "Can't use multisample on dash effect.";
246             } else {
247                 *reason = "Too many non dashed path effects.";
248             }
249         } else if ((fNumAAConcavePaths - fNumAAHairlineConcavePaths - fNumAADFEligibleConcavePaths)
250                     >= kNumAAConcavePathsTol)
251             *reason = "Too many anti-aliased concave paths.";
252         else
253             *reason = "Unknown reason for GPU unsuitability.";
254     }
255     return ret;
256 }
257
258 ///////////////////////////////////////////////////////////////////////////////
259
260 // fRecord OK
261 SkPicture::SkPicture(SkScalar width, SkScalar height,
262                      const SkPictureRecord& record,
263                      bool deepCopyOps)
264     : fCullWidth(width)
265     , fCullHeight(height)
266     , fAnalysis() {
267     this->needsNewGenID();
268
269     SkPictInfo info;
270     this->createHeader(&info);
271     fData.reset(SkNEW_ARGS(SkPictureData, (record, info, deepCopyOps)));
272 }
273
274 // Create an SkPictureData-backed SkPicture from an SkRecord.
275 // This for compatibility with serialization code only.  This is not cheap.
276 SkPicture* SkPicture::Backport(const SkRecord& src, const SkRect& cullRect) {
277     SkPictureRecord rec(SkISize::Make(cullRect.width(), cullRect.height()), 0/*flags*/);
278     rec.beginRecording();
279         SkRecordDraw(src, &rec, NULL/*bbh*/, NULL/*callback*/);
280     rec.endRecording();
281     return SkNEW_ARGS(SkPicture, (cullRect.width(), cullRect.height(), rec, false/*deepCopyOps*/));
282 }
283
284 // fRecord OK
285 SkPicture::~SkPicture() {
286     this->callDeletionListeners();
287 }
288
289 // fRecord OK
290 void SkPicture::EXPERIMENTAL_addAccelData(const SkPicture::AccelData* data) const {
291     fAccelData.reset(SkRef(data));
292 }
293
294 // fRecord OK
295 const SkPicture::AccelData* SkPicture::EXPERIMENTAL_getAccelData(
296         SkPicture::AccelData::Key key) const {
297     if (fAccelData.get() && fAccelData->getKey() == key) {
298         return fAccelData.get();
299     }
300     return NULL;
301 }
302
303 // fRecord OK
304 SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() {
305     static int32_t gNextID = 0;
306
307     int32_t id = sk_atomic_inc(&gNextID);
308     if (id >= 1 << (8 * sizeof(Domain))) {
309         SK_CRASH();
310     }
311
312     return static_cast<Domain>(id);
313 }
314
315 ///////////////////////////////////////////////////////////////////////////////
316
317 // fRecord OK
318 void SkPicture::playback(SkCanvas* canvas, SkDrawPictureCallback* callback) const {
319     SkASSERT(canvas);
320     SkASSERT(fData.get() || fRecord.get());
321
322     if (fData.get()) {
323         SkPicturePlayback playback(this);
324         playback.draw(canvas, callback);
325     }
326     if (fRecord.get()) {
327         // If the query contains the whole picture, don't bother with the BBH.
328         SkRect clipBounds = { 0, 0, 0, 0 };
329         (void)canvas->getClipBounds(&clipBounds);
330         const bool useBBH = !clipBounds.contains(this->cullRect());
331
332         SkRecordDraw(*fRecord, canvas, useBBH ? fBBH.get() : NULL, callback);
333     }
334 }
335
336 ///////////////////////////////////////////////////////////////////////////////
337
338 #include "SkStream.h"
339
340 static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
341
342 // fRecord OK
343 bool SkPicture::IsValidPictInfo(const SkPictInfo& info) {
344     if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) {
345         return false;
346     }
347
348     if (info.fVersion < MIN_PICTURE_VERSION ||
349         info.fVersion > CURRENT_PICTURE_VERSION) {
350         return false;
351     }
352
353     return true;
354 }
355
356 // fRecord OK
357 bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
358     if (NULL == stream) {
359         return false;
360     }
361
362     // Check magic bytes.
363     SkPictInfo info;
364     SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
365
366     if (!stream->read(&info.fMagic, sizeof(kMagic))) {
367         return false;
368     }
369
370     info.fVersion = stream->readU32();
371
372 #ifndef V35_COMPATIBILITY_CODE
373     if (info.fVersion < 35) {
374         info.fCullRect.fLeft = 0;
375         info.fCullRect.fTop = 0;
376         info.fCullRect.fRight = SkIntToScalar(stream->readU32());
377         info.fCullRect.fBottom = SkIntToScalar(stream->readU32());
378     } else {
379 #endif
380         info.fCullRect.fLeft = stream->readScalar();
381         info.fCullRect.fTop = stream->readScalar();
382         info.fCullRect.fRight = stream->readScalar();
383         info.fCullRect.fBottom = stream->readScalar();
384 #ifndef V35_COMPATIBILITY_CODE
385     }
386 #endif
387
388     info.fFlags = stream->readU32();
389
390     if (!IsValidPictInfo(info)) {
391         return false;
392     }
393
394     if (pInfo != NULL) {
395         *pInfo = info;
396     }
397     return true;
398 }
399
400 // fRecord OK
401 bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo) {
402     // Check magic bytes.
403     SkPictInfo info;
404     SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
405
406     if (!buffer->readByteArray(&info.fMagic, sizeof(kMagic))) {
407         return false;
408     }
409
410     info.fVersion = buffer->readUInt();
411
412 #ifndef V35_COMPATIBILITY_CODE
413     if (info.fVersion < 35) {
414         info.fCullRect.fLeft = 0;
415         info.fCullRect.fTop = 0;
416         info.fCullRect.fRight = SkIntToScalar(buffer->readUInt());
417         info.fCullRect.fBottom = SkIntToScalar(buffer->readUInt());
418     } else {
419 #endif
420         buffer->readRect(&info.fCullRect);
421 #ifndef V35_COMPATIBILITY_CODE
422     }
423 #endif
424
425     info.fFlags = buffer->readUInt();
426
427     if (!IsValidPictInfo(info)) {
428         return false;
429     }
430
431     if (pInfo != NULL) {
432         *pInfo = info;
433     }
434     return true;
435 }
436
437 // fRecord OK
438 SkPicture::SkPicture(SkPictureData* data, SkScalar width, SkScalar height)
439     : fData(data)
440     , fCullWidth(width)
441     , fCullHeight(height)
442     , fAnalysis() {
443     this->needsNewGenID();
444 }
445
446 SkPicture* SkPicture::Forwardport(const SkPicture& src) {
447     SkAutoTDelete<SkRecord> record(SkNEW(SkRecord));
448     SkRecorder canvas(record.get(), src.cullRect().width(), src.cullRect().height());
449     src.playback(&canvas);
450     return SkNEW_ARGS(SkPicture, (src.cullRect().width(), src.cullRect().height(),
451                                   record.detach(), NULL/*bbh*/));
452 }
453
454 // fRecord OK
455 SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
456     SkPictInfo info;
457
458     if (!InternalOnly_StreamIsSKP(stream, &info)) {
459         return NULL;
460     }
461
462     // Check to see if there is a playback to recreate.
463     if (stream->readBool()) {
464         SkPictureData* data = SkPictureData::CreateFromStream(stream, info, proc);
465         if (NULL == data) {
466             return NULL;
467         }
468         const SkPicture src(data, info.fCullRect.width(), info.fCullRect.height());
469         return Forwardport(src);
470     }
471
472     return NULL;
473 }
474
475 // fRecord OK
476 SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) {
477     SkPictInfo info;
478
479     if (!InternalOnly_BufferIsSKP(&buffer, &info)) {
480         return NULL;
481     }
482
483     // Check to see if there is a playback to recreate.
484     if (buffer.readBool()) {
485         SkPictureData* data = SkPictureData::CreateFromBuffer(buffer, info);
486         if (NULL == data) {
487             return NULL;
488         }
489         const SkPicture src(data, info.fCullRect.width(), info.fCullRect.height());
490         return Forwardport(src);
491     }
492
493     return NULL;
494 }
495
496 // fRecord OK
497 void SkPicture::createHeader(SkPictInfo* info) const {
498     // Copy magic bytes at the beginning of the header
499     SkASSERT(sizeof(kMagic) == 8);
500     SkASSERT(sizeof(kMagic) == sizeof(info->fMagic));
501     memcpy(info->fMagic, kMagic, sizeof(kMagic));
502
503     // Set picture info after magic bytes in the header
504     info->fVersion = CURRENT_PICTURE_VERSION;
505     info->fCullRect = this->cullRect();
506     info->fFlags = SkPictInfo::kCrossProcess_Flag;
507     // TODO: remove this flag, since we're always float (now)
508     info->fFlags |= SkPictInfo::kScalarIsFloat_Flag;
509
510     if (8 == sizeof(void*)) {
511         info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
512     }
513 }
514
515 // fRecord OK
516 void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const {
517     const SkPictureData* data = fData.get();
518
519     // If we're a new-format picture, backport to old format for serialization.
520     SkAutoTDelete<SkPicture> oldFormat;
521     if (NULL == data && fRecord.get()) {
522         oldFormat.reset(Backport(*fRecord, this->cullRect()));
523         data = oldFormat->fData.get();
524         SkASSERT(data);
525     }
526
527     SkPictInfo info;
528     this->createHeader(&info);
529     SkASSERT(sizeof(SkPictInfo) == 32);
530     stream->write(&info, sizeof(info));
531
532     if (data) {
533         stream->writeBool(true);
534         data->serialize(stream, encoder);
535     } else {
536         stream->writeBool(false);
537     }
538 }
539
540 // fRecord OK
541 void SkPicture::flatten(SkWriteBuffer& buffer) const {
542     const SkPictureData* data = fData.get();
543
544     // If we're a new-format picture, backport to old format for serialization.
545     SkAutoTDelete<SkPicture> oldFormat;
546     if (NULL == data && fRecord.get()) {
547         oldFormat.reset(Backport(*fRecord, this->cullRect()));
548         data = oldFormat->fData.get();
549         SkASSERT(data);
550     }
551
552     SkPictInfo info;
553     this->createHeader(&info);
554     buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic));
555     buffer.writeUInt(info.fVersion);
556     buffer.writeRect(info.fCullRect);
557     buffer.writeUInt(info.fFlags);
558
559     if (data) {
560         buffer.writeBool(true);
561         data->flatten(buffer);
562     } else {
563         buffer.writeBool(false);
564     }
565 }
566
567 #if SK_SUPPORT_GPU
568 // fRecord OK
569 bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **reason) const {
570     if (fRecord.get()) {
571         return fAnalysis.suitableForGpuRasterization(reason, 0);
572     }
573     if (NULL == fData.get()) {
574         if (reason) {
575             *reason = "Missing internal data.";
576         }
577         return false;
578     }
579
580     return fData->suitableForGpuRasterization(context, reason);
581 }
582 #endif
583
584 // fRecord OK
585 bool SkPicture::hasText() const {
586     if (fRecord.get()) {
587         return fAnalysis.fHasText;
588     }
589     if (fData.get()) {
590         return fData->hasText();
591     }
592     SkFAIL("Unreachable");
593     return false;
594 }
595
596 // fRecord OK
597 bool SkPicture::willPlayBackBitmaps() const {
598     if (fRecord.get()) {
599         return fAnalysis.fWillPlaybackBitmaps;
600     }
601     if (fData.get()) {
602         return fData->containsBitmaps();
603     }
604     SkFAIL("Unreachable");
605     return false;
606 }
607
608 // fRecord OK
609 static int32_t next_picture_generation_id() {
610     static int32_t  gPictureGenerationID = 0;
611     // do a loop in case our global wraps around, as we never want to
612     // return a 0
613     int32_t genID;
614     do {
615         genID = sk_atomic_inc(&gPictureGenerationID) + 1;
616     } while (SK_InvalidGenID == genID);
617     return genID;
618 }
619
620 // fRecord OK
621 uint32_t SkPicture::uniqueID() const {
622     if (SK_InvalidGenID == fUniqueID) {
623         fUniqueID = next_picture_generation_id();
624     }
625     return fUniqueID;
626 }
627
628
629 static SkRecord* optimized(SkRecord* r) {
630     SkRecordOptimize(r);
631     return r;
632 }
633
634 // fRecord OK
635 SkPicture::SkPicture(SkScalar width, SkScalar height, SkRecord* record, SkBBoxHierarchy* bbh)
636     : fCullWidth(width)
637     , fCullHeight(height)
638     , fRecord(optimized(record))
639     , fBBH(SkSafeRef(bbh))
640     , fAnalysis(*fRecord) {
641     // TODO: delay as much of this work until just before first playback?
642     if (fBBH.get()) {
643         SkRecordFillBounds(this->cullRect(), *fRecord, fBBH.get());
644     }
645     this->needsNewGenID();
646 }
647
648 // Note that we are assuming that this entry point will only be called from
649 // one thread. Currently the only client of this method is
650 // SkGpuDevice::EXPERIMENTAL_optimize which should be only called from a single
651 // thread.
652 void SkPicture::addDeletionListener(DeletionListener* listener) const {
653     SkASSERT(listener);
654
655     *fDeletionListeners.append() = SkRef(listener);
656 }
657
658 void SkPicture::callDeletionListeners() {
659     for (int i = 0; i < fDeletionListeners.count(); ++i) {
660         fDeletionListeners[i]->onDeletion(this->uniqueID());
661     }
662
663     fDeletionListeners.unrefAll();
664 }
665
666 // fRecord OK
667 int SkPicture::approximateOpCount() const {
668     SkASSERT(fRecord.get() || fData.get());
669     if (fRecord.get()) {
670         return fRecord->count();
671     }
672     if (fData.get()) {
673         return fData->opCount();
674     }
675     return 0;
676 }