1 /* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "GrRecordReplaceDraw.h" 9 #include "SkImage.h" 10 #include "SkRecordDraw.h" 11 12 GrReplacements::ReplacementInfo* GrReplacements::push() { 13 SkDEBUGCODE(this->validate()); 14 return fReplacements.push(); 15 } 16 17 void GrReplacements::freeAll() { 18 for (int i = 0; i < fReplacements.count(); ++i) { 19 fReplacements[i].fImage->unref(); 20 SkDELETE(fReplacements[i].fPaint); 21 } 22 fReplacements.reset(); 23 } 24 25 #ifdef SK_DEBUG 26 void GrReplacements::validate() const { 27 // Check that the ranges are monotonically increasing and non-overlapping 28 if (fReplacements.count() > 0) { 29 SkASSERT(fReplacements[0].fStart < fReplacements[0].fStop); 30 31 for (int i = 1; i < fReplacements.count(); ++i) { 32 SkASSERT(fReplacements[i].fStart < fReplacements[i].fStop); 33 SkASSERT(fReplacements[i - 1].fStop < fReplacements[i].fStart); 34 } 35 } 36 } 37 #endif 38 39 const GrReplacements::ReplacementInfo* 40 GrReplacements::lookupByStart(size_t start, int* searchStart) const { 41 SkDEBUGCODE(this->validate()); 42 for (int i = *searchStart; i < fReplacements.count(); ++i) { 43 if (start == fReplacements[i].fStart) { 44 *searchStart = i + 1; 45 return &fReplacements[i]; 46 } else if (start < fReplacements[i].fStart) { 47 return NULL; // the ranges are monotonically increasing and non-overlapping 48 } 49 } 50 51 return NULL; 52 } 53 54 static inline void draw_replacement_bitmap(const GrReplacements::ReplacementInfo* ri, 55 SkCanvas* canvas, 56 const SkMatrix& initialMatrix) { 57 SkRect src = SkRect::Make(ri->fSrcRect); 58 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(ri->fPos.fX), 59 SkIntToScalar(ri->fPos.fY), 60 SkIntToScalar(ri->fSrcRect.width()), 61 SkIntToScalar(ri->fSrcRect.height())); 62 63 canvas->save(); 64 canvas->setMatrix(initialMatrix); 65 canvas->drawImageRect(ri->fImage, &src, dst, ri->fPaint); 66 canvas->restore(); 67 } 68 69 void GrRecordReplaceDraw(const SkRecord& record, 70 SkCanvas* canvas, 71 const SkBBoxHierarchy* bbh, 72 const GrReplacements* replacements, 73 SkDrawPictureCallback* callback) { 74 SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/); 75 76 SkRecords::Draw draw(canvas); 77 const GrReplacements::ReplacementInfo* ri = NULL; 78 int searchStart = 0; 79 80 const SkMatrix initialMatrix = canvas->getTotalMatrix(); 81 82 if (bbh) { 83 // Draw only ops that affect pixels in the canvas's current clip. 84 // The SkRecord and BBH were recorded in identity space. This canvas 85 // is not necessarily in that same space. getClipBounds() returns us 86 // this canvas' clip bounds transformed back into identity space, which 87 // lets us query the BBH. 88 SkRect query = { 0, 0, 0, 0 }; 89 (void)canvas->getClipBounds(&query); 90 91 SkTDArray<void*> ops; 92 bbh->search(query, &ops); 93 94 for (int i = 0; i < ops.count(); i++) { 95 if (callback && callback->abortDrawing()) { 96 return; 97 } 98 ri = replacements->lookupByStart((uintptr_t)ops[i], &searchStart); 99 if (ri) { 100 draw_replacement_bitmap(ri, canvas, initialMatrix); 101 102 while ((uintptr_t)ops[i] < ri->fStop) { 103 ++i; 104 } 105 SkASSERT((uintptr_t)ops[i] == ri->fStop); 106 continue; 107 } 108 109 record.visit<void>((uintptr_t)ops[i], draw); 110 } 111 } else { 112 for (unsigned int i = 0; i < record.count(); ++i) { 113 if (callback && callback->abortDrawing()) { 114 return; 115 } 116 ri = replacements->lookupByStart(i, &searchStart); 117 if (ri) { 118 draw_replacement_bitmap(ri, canvas, initialMatrix); 119 i = ri->fStop; 120 continue; 121 } 122 123 record.visit<void>(i, draw); 124 } 125 } 126 } 127