/* * Copyright 2014 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "GrRecordReplaceDraw.h" #include "SkImage.h" #include "SkRecordDraw.h" GrReplacements::ReplacementInfo* GrReplacements::push() { SkDEBUGCODE(this->validate()); return fReplacements.push(); } void GrReplacements::freeAll() { for (int i = 0; i < fReplacements.count(); ++i) { fReplacements[i].fImage->unref(); } fReplacements.reset(); } #ifdef SK_DEBUG void GrReplacements::validate() const { // Check that the ranges are monotonically increasing and non-overlapping if (fReplacements.count() > 0) { SkASSERT(fReplacements[0].fStart < fReplacements[0].fStop); for (int i = 1; i < fReplacements.count(); ++i) { SkASSERT(fReplacements[i].fStart < fReplacements[i].fStop); SkASSERT(fReplacements[i - 1].fStop < fReplacements[i].fStart); } } } #endif const GrReplacements::ReplacementInfo* GrReplacements::lookupByStart(size_t start, int* searchStart) const { SkDEBUGCODE(this->validate()); for (int i = *searchStart; i < fReplacements.count(); ++i) { if (start == fReplacements[i].fStart) { *searchStart = i + 1; return &fReplacements[i]; } else if (start < fReplacements[i].fStart) { return NULL; // the ranges are monotonically increasing and non-overlapping } } return NULL; } static inline void draw_replacement_bitmap(const GrReplacements::ReplacementInfo* ri, SkCanvas* canvas) { SkRect src = SkRect::Make(ri->fSrcRect); SkRect dst = SkRect::MakeXYWH(SkIntToScalar(ri->fPos.fX), SkIntToScalar(ri->fPos.fY), SkIntToScalar(ri->fSrcRect.width()), SkIntToScalar(ri->fSrcRect.height())); ri->fImage->draw(canvas, &src, dst, ri->fPaint); } void GrRecordReplaceDraw(const SkRecord& record, SkCanvas* canvas, const SkBBoxHierarchy* bbh, const GrReplacements* replacements, SkDrawPictureCallback* callback) { SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/); SkRecords::Draw draw(canvas); const GrReplacements::ReplacementInfo* ri = NULL; int searchStart = 0; if (NULL != bbh) { // Draw only ops that affect pixels in the canvas's current clip. // The SkRecord and BBH were recorded in identity space. This canvas // is not necessarily in that same space. getClipBounds() returns us // this canvas' clip bounds transformed back into identity space, which // lets us query the BBH. SkRect query = { 0, 0, 0, 0 }; (void)canvas->getClipBounds(&query); SkTDArray ops; bbh->search(query, &ops); for (int i = 0; i < ops.count(); i++) { if (NULL != callback && callback->abortDrawing()) { return; } ri = replacements->lookupByStart((uintptr_t)ops[i], &searchStart); if (NULL != ri) { draw_replacement_bitmap(ri, canvas); while ((uintptr_t)ops[i] < ri->fStop) { ++i; } SkASSERT((uintptr_t)ops[i] == ri->fStop); continue; } record.visit((uintptr_t)ops[i], draw); } } else { for (unsigned int i = 0; i < record.count(); ++i) { if (NULL != callback && callback->abortDrawing()) { return; } ri = replacements->lookupByStart(i, &searchStart); if (NULL != ri) { draw_replacement_bitmap(ri, canvas); i = ri->fStop; continue; } record.visit(i, draw); } } }