SkiaCanvas.cpp revision f276acd98457bcaabc9e79a17a736b3b484f005e
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "Canvas.h" 18 19#include <SkCanvas.h> 20#include <SkClipStack.h> 21#include <SkDevice.h> 22#include <SkDeque.h> 23#include <SkDrawFilter.h> 24#include <SkGraphics.h> 25#include <SkShader.h> 26#include <SkTArray.h> 27#include <SkTLazy.h> 28#include <SkTemplates.h> 29 30#include "VectorDrawable.h" 31 32#include <memory> 33 34namespace android { 35 36// Holds an SkCanvas reference plus additional native data. 37class SkiaCanvas : public Canvas { 38public: 39 explicit SkiaCanvas(const SkBitmap& bitmap); 40 41 /** 42 * Create a new SkiaCanvas. 43 * 44 * @param canvas SkCanvas to handle calls made to this SkiaCanvas. Must 45 * not be NULL. This constructor will ref() the SkCanvas, and unref() 46 * it in its destructor. 47 */ 48 explicit SkiaCanvas(SkCanvas* canvas) : mCanvas(canvas) { 49 SkASSERT(canvas); 50 canvas->ref(); 51 } 52 53 virtual SkCanvas* asSkCanvas() override { 54 return mCanvas.get(); 55 } 56 57 virtual void setBitmap(const SkBitmap& bitmap) override; 58 59 virtual bool isOpaque() override; 60 virtual int width() override; 61 virtual int height() override; 62 63 virtual void setHighContrastText(bool highContrastText) override { 64 mHighContrastText = highContrastText; 65 } 66 virtual bool isHighContrastText() override { return mHighContrastText; } 67 68 virtual int getSaveCount() const override; 69 virtual int save(SaveFlags::Flags flags) override; 70 virtual void restore() override; 71 virtual void restoreToCount(int saveCount) override; 72 73 virtual int saveLayer(float left, float top, float right, float bottom, 74 const SkPaint* paint, SaveFlags::Flags flags) override; 75 virtual int saveLayerAlpha(float left, float top, float right, float bottom, 76 int alpha, SaveFlags::Flags flags) override; 77 78 virtual void getMatrix(SkMatrix* outMatrix) const override; 79 virtual void setMatrix(const SkMatrix& matrix) override; 80 virtual void concat(const SkMatrix& matrix) override; 81 virtual void rotate(float degrees) override; 82 virtual void scale(float sx, float sy) override; 83 virtual void skew(float sx, float sy) override; 84 virtual void translate(float dx, float dy) override; 85 86 virtual bool getClipBounds(SkRect* outRect) const override; 87 virtual bool quickRejectRect(float left, float top, float right, float bottom) const override; 88 virtual bool quickRejectPath(const SkPath& path) const override; 89 virtual bool clipRect(float left, float top, float right, float bottom, 90 SkRegion::Op op) override; 91 virtual bool clipPath(const SkPath* path, SkRegion::Op op) override; 92 virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) override; 93 94 virtual SkDrawFilter* getDrawFilter() override; 95 virtual void setDrawFilter(SkDrawFilter* drawFilter) override; 96 97 virtual void drawColor(int color, SkXfermode::Mode mode) override; 98 virtual void drawPaint(const SkPaint& paint) override; 99 100 virtual void drawPoint(float x, float y, const SkPaint& paint) override; 101 virtual void drawPoints(const float* points, int count, const SkPaint& paint) override; 102 virtual void drawLine(float startX, float startY, float stopX, float stopY, 103 const SkPaint& paint) override; 104 virtual void drawLines(const float* points, int count, const SkPaint& paint) override; 105 virtual void drawRect(float left, float top, float right, float bottom, 106 const SkPaint& paint) override; 107 virtual void drawRegion(const SkRegion& region, const SkPaint& paint) override; 108 virtual void drawRoundRect(float left, float top, float right, float bottom, 109 float rx, float ry, const SkPaint& paint) override; 110 virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override; 111 virtual void drawOval(float left, float top, float right, float bottom, 112 const SkPaint& paint) override; 113 virtual void drawArc(float left, float top, float right, float bottom, 114 float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) override; 115 virtual void drawPath(const SkPath& path, const SkPaint& paint) override; 116 virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount, 117 const float* verts, const float* tex, const int* colors, 118 const uint16_t* indices, int indexCount, const SkPaint& paint) override; 119 120 virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, 121 const SkPaint* paint) override; 122 virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, 123 const SkPaint* paint) override; 124 virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop, 125 float srcRight, float srcBottom, float dstLeft, float dstTop, 126 float dstRight, float dstBottom, const SkPaint* paint) override; 127 virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight, 128 const float* vertices, const int* colors, const SkPaint* paint) override; 129 virtual void drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& chunk, 130 float dstLeft, float dstTop, float dstRight, float dstBottom, 131 const SkPaint* paint) override; 132 133 virtual void drawText(const uint16_t* text, const float* positions, int count, 134 const SkPaint& paint, float x, float y, 135 float boundsLeft, float boundsTop, float boundsRight, float boundsBottom, 136 float totalAdvance) override; 137 virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path, 138 float hOffset, float vOffset, const SkPaint& paint) override; 139 140 virtual bool drawTextAbsolutePos() const override { return true; } 141 virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override; 142 143private: 144 struct SaveRec { 145 int saveCount; 146 SaveFlags::Flags saveFlags; 147 }; 148 149 bool mHighContrastText = false; 150 151 void recordPartialSave(SaveFlags::Flags flags); 152 void saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, int frameSaveCount); 153 void applyClips(const SkTArray<SkClipStack::Element>& clips); 154 155 void drawPoints(const float* points, int count, const SkPaint& paint, 156 SkCanvas::PointMode mode); 157 158 SkAutoTUnref<SkCanvas> mCanvas; 159 std::unique_ptr<SkDeque> mSaveStack; // lazily allocated, tracks partial saves. 160}; 161 162Canvas* Canvas::create_canvas(const SkBitmap& bitmap) { 163 return new SkiaCanvas(bitmap); 164} 165 166Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas) { 167 return new SkiaCanvas(skiaCanvas); 168} 169 170SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) { 171 mCanvas.reset(new SkCanvas(bitmap)); 172} 173 174// ---------------------------------------------------------------------------- 175// Canvas state operations: Replace Bitmap 176// ---------------------------------------------------------------------------- 177 178class ClipCopier : public SkCanvas::ClipVisitor { 179public: 180 ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {} 181 182 virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) { 183 m_dstCanvas->clipRect(rect, op, antialias); 184 } 185 virtual void clipRRect(const SkRRect& rrect, SkRegion::Op op, bool antialias) { 186 m_dstCanvas->clipRRect(rrect, op, antialias); 187 } 188 virtual void clipPath(const SkPath& path, SkRegion::Op op, bool antialias) { 189 m_dstCanvas->clipPath(path, op, antialias); 190 } 191 192private: 193 SkCanvas* m_dstCanvas; 194}; 195 196void SkiaCanvas::setBitmap(const SkBitmap& bitmap) { 197 SkCanvas* newCanvas = new SkCanvas(bitmap); 198 199 if (!bitmap.isNull()) { 200 // Copy the canvas matrix & clip state. 201 newCanvas->setMatrix(mCanvas->getTotalMatrix()); 202 203 ClipCopier copier(newCanvas); 204 mCanvas->replayClips(&copier); 205 } 206 207 // unrefs the existing canvas 208 mCanvas.reset(newCanvas); 209 210 // clean up the old save stack 211 mSaveStack.reset(NULL); 212} 213 214// ---------------------------------------------------------------------------- 215// Canvas state operations 216// ---------------------------------------------------------------------------- 217 218bool SkiaCanvas::isOpaque() { 219 return mCanvas->imageInfo().isOpaque(); 220} 221 222int SkiaCanvas::width() { 223 return mCanvas->imageInfo().width(); 224} 225 226int SkiaCanvas::height() { 227 return mCanvas->imageInfo().height(); 228} 229 230// ---------------------------------------------------------------------------- 231// Canvas state operations: Save (layer) 232// ---------------------------------------------------------------------------- 233 234int SkiaCanvas::getSaveCount() const { 235 return mCanvas->getSaveCount(); 236} 237 238int SkiaCanvas::save(SaveFlags::Flags flags) { 239 int count = mCanvas->save(); 240 recordPartialSave(flags); 241 return count; 242} 243 244// The SkiaCanvas::restore operation layers on the capability to preserve 245// either (or both) the matrix and/or clip state after a SkCanvas::restore 246// operation. It does this by explicitly saving off the clip & matrix state 247// when requested and playing it back after the SkCanvas::restore. 248void SkiaCanvas::restore() { 249 const SaveRec* rec = (NULL == mSaveStack.get()) 250 ? NULL 251 : static_cast<SaveRec*>(mSaveStack->back()); 252 int currentSaveCount = mCanvas->getSaveCount(); 253 SkASSERT(NULL == rec || currentSaveCount >= rec->saveCount); 254 255 if (NULL == rec || rec->saveCount != currentSaveCount) { 256 // Fast path - no record for this frame. 257 mCanvas->restore(); 258 return; 259 } 260 261 bool preserveMatrix = !(rec->saveFlags & SaveFlags::Matrix); 262 bool preserveClip = !(rec->saveFlags & SaveFlags::Clip); 263 264 SkMatrix savedMatrix; 265 if (preserveMatrix) { 266 savedMatrix = mCanvas->getTotalMatrix(); 267 } 268 269 SkTArray<SkClipStack::Element> savedClips; 270 int topClipStackFrame = mCanvas->getClipStack()->getSaveCount(); 271 if (preserveClip) { 272 saveClipsForFrame(savedClips, topClipStackFrame); 273 } 274 275 mCanvas->restore(); 276 277 if (preserveMatrix) { 278 mCanvas->setMatrix(savedMatrix); 279 } 280 281 if (preserveClip && !savedClips.empty() && 282 topClipStackFrame != mCanvas->getClipStack()->getSaveCount()) { 283 // Only reapply the saved clips if the top clip stack frame was actually 284 // popped by restore(). If it wasn't, it means it doesn't belong to the 285 // restored canvas frame (SkCanvas lazy save/restore kicked in). 286 applyClips(savedClips); 287 } 288 289 mSaveStack->pop_back(); 290} 291 292void SkiaCanvas::restoreToCount(int restoreCount) { 293 while (mCanvas->getSaveCount() > restoreCount) { 294 this->restore(); 295 } 296} 297 298static inline SkCanvas::SaveLayerFlags layerFlags(SaveFlags::Flags flags) { 299 SkCanvas::SaveLayerFlags layerFlags = 0; 300 301 if (!(flags & SaveFlags::HasAlphaLayer)) { 302 layerFlags |= SkCanvas::kIsOpaque_SaveLayerFlag; 303 } 304 305 if (!(flags & SaveFlags::ClipToLayer)) { 306 layerFlags |= SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag; 307 } 308 309 return layerFlags; 310} 311 312int SkiaCanvas::saveLayer(float left, float top, float right, float bottom, 313 const SkPaint* paint, SaveFlags::Flags flags) { 314 const SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); 315 const SkCanvas::SaveLayerRec rec(&bounds, paint, layerFlags(flags)); 316 317 int count = mCanvas->saveLayer(rec); 318 recordPartialSave(flags); 319 return count; 320} 321 322int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom, 323 int alpha, SaveFlags::Flags flags) { 324 SkTLazy<SkPaint> alphaPaint; 325 if (static_cast<unsigned>(alpha) < 0xFF) { 326 alphaPaint.init()->setAlpha(alpha); 327 } 328 329 return this->saveLayer(left, top, right, bottom, alphaPaint.getMaybeNull(), 330 flags); 331} 332 333// ---------------------------------------------------------------------------- 334// functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags) 335// ---------------------------------------------------------------------------- 336 337void SkiaCanvas::recordPartialSave(SaveFlags::Flags flags) { 338 // A partial save is a save operation which doesn't capture the full canvas state. 339 // (either SaveFlags::Matrix or SaveFlags::Clip is missing). 340 341 // Mask-out non canvas state bits. 342 flags &= SaveFlags::MatrixClip; 343 344 if (flags == SaveFlags::MatrixClip) { 345 // not a partial save. 346 return; 347 } 348 349 if (NULL == mSaveStack.get()) { 350 mSaveStack.reset(new SkDeque(sizeof(struct SaveRec), 8)); 351 } 352 353 SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back()); 354 rec->saveCount = mCanvas->getSaveCount(); 355 rec->saveFlags = flags; 356} 357 358void SkiaCanvas::saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, 359 int saveCountToBackup) { 360 // Each SkClipStack::Element stores the index of the canvas save 361 // with which it is associated. Backup only those Elements that 362 // are associated with 'saveCountToBackup' 363 SkClipStack::Iter clipIterator(*mCanvas->getClipStack(), 364 SkClipStack::Iter::kTop_IterStart); 365 while (const SkClipStack::Element* elem = clipIterator.prev()) { 366 if (elem->getSaveCount() < saveCountToBackup) { 367 // done with the target save count. 368 break; 369 } 370 SkASSERT(elem->getSaveCount() == saveCountToBackup); 371 clips.push_back(*elem); 372 } 373} 374 375void SkiaCanvas::applyClips(const SkTArray<SkClipStack::Element>& clips) { 376 ClipCopier clipCopier(mCanvas); 377 378 // The clip stack stores clips in device space. 379 SkMatrix origMatrix = mCanvas->getTotalMatrix(); 380 mCanvas->resetMatrix(); 381 382 // We pushed the clips in reverse order. 383 for (int i = clips.count() - 1; i >= 0; --i) { 384 clips[i].replay(&clipCopier); 385 } 386 387 mCanvas->setMatrix(origMatrix); 388} 389 390// ---------------------------------------------------------------------------- 391// Canvas state operations: Matrix 392// ---------------------------------------------------------------------------- 393 394void SkiaCanvas::getMatrix(SkMatrix* outMatrix) const { 395 *outMatrix = mCanvas->getTotalMatrix(); 396} 397 398void SkiaCanvas::setMatrix(const SkMatrix& matrix) { 399 mCanvas->setMatrix(matrix); 400} 401 402void SkiaCanvas::concat(const SkMatrix& matrix) { 403 mCanvas->concat(matrix); 404} 405 406void SkiaCanvas::rotate(float degrees) { 407 mCanvas->rotate(degrees); 408} 409 410void SkiaCanvas::scale(float sx, float sy) { 411 mCanvas->scale(sx, sy); 412} 413 414void SkiaCanvas::skew(float sx, float sy) { 415 mCanvas->skew(sx, sy); 416} 417 418void SkiaCanvas::translate(float dx, float dy) { 419 mCanvas->translate(dx, dy); 420} 421 422// ---------------------------------------------------------------------------- 423// Canvas state operations: Clips 424// ---------------------------------------------------------------------------- 425 426// This function is a mirror of SkCanvas::getClipBounds except that it does 427// not outset the edge of the clip to account for anti-aliasing. There is 428// a skia bug to investigate pushing this logic into back into skia. 429// (see https://code.google.com/p/skia/issues/detail?id=1303) 430bool SkiaCanvas::getClipBounds(SkRect* outRect) const { 431 SkIRect ibounds; 432 if (!mCanvas->getClipDeviceBounds(&ibounds)) { 433 return false; 434 } 435 436 SkMatrix inverse; 437 // if we can't invert the CTM, we can't return local clip bounds 438 if (!mCanvas->getTotalMatrix().invert(&inverse)) { 439 if (outRect) { 440 outRect->setEmpty(); 441 } 442 return false; 443 } 444 445 if (NULL != outRect) { 446 SkRect r = SkRect::Make(ibounds); 447 inverse.mapRect(outRect, r); 448 } 449 return true; 450} 451 452bool SkiaCanvas::quickRejectRect(float left, float top, float right, float bottom) const { 453 SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); 454 return mCanvas->quickReject(bounds); 455} 456 457bool SkiaCanvas::quickRejectPath(const SkPath& path) const { 458 return mCanvas->quickReject(path); 459} 460 461bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { 462 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 463 mCanvas->clipRect(rect, op); 464 return !mCanvas->isClipEmpty(); 465} 466 467bool SkiaCanvas::clipPath(const SkPath* path, SkRegion::Op op) { 468 mCanvas->clipPath(*path, op); 469 return !mCanvas->isClipEmpty(); 470} 471 472bool SkiaCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) { 473 SkPath rgnPath; 474 if (region->getBoundaryPath(&rgnPath)) { 475 // The region is specified in device space. 476 SkMatrix savedMatrix = mCanvas->getTotalMatrix(); 477 mCanvas->resetMatrix(); 478 mCanvas->clipPath(rgnPath, op); 479 mCanvas->setMatrix(savedMatrix); 480 } else { 481 mCanvas->clipRect(SkRect::MakeEmpty(), op); 482 } 483 return !mCanvas->isClipEmpty(); 484} 485 486// ---------------------------------------------------------------------------- 487// Canvas state operations: Filters 488// ---------------------------------------------------------------------------- 489 490SkDrawFilter* SkiaCanvas::getDrawFilter() { 491 return mCanvas->getDrawFilter(); 492} 493 494void SkiaCanvas::setDrawFilter(SkDrawFilter* drawFilter) { 495 mCanvas->setDrawFilter(drawFilter); 496} 497 498// ---------------------------------------------------------------------------- 499// Canvas draw operations 500// ---------------------------------------------------------------------------- 501 502void SkiaCanvas::drawColor(int color, SkXfermode::Mode mode) { 503 mCanvas->drawColor(color, mode); 504} 505 506void SkiaCanvas::drawPaint(const SkPaint& paint) { 507 mCanvas->drawPaint(paint); 508} 509 510// ---------------------------------------------------------------------------- 511// Canvas draw operations: Geometry 512// ---------------------------------------------------------------------------- 513 514void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint, 515 SkCanvas::PointMode mode) { 516 // convert the floats into SkPoints 517 count >>= 1; // now it is the number of points 518 std::unique_ptr<SkPoint[]> pts(new SkPoint[count]); 519 for (int i = 0; i < count; i++) { 520 pts[i].set(points[0], points[1]); 521 points += 2; 522 } 523 mCanvas->drawPoints(mode, count, pts.get(), paint); 524} 525 526 527void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) { 528 mCanvas->drawPoint(x, y, paint); 529} 530 531void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) { 532 this->drawPoints(points, count, paint, SkCanvas::kPoints_PointMode); 533} 534 535void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY, 536 const SkPaint& paint) { 537 mCanvas->drawLine(startX, startY, stopX, stopY, paint); 538} 539 540void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) { 541 this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode); 542} 543 544void SkiaCanvas::drawRect(float left, float top, float right, float bottom, 545 const SkPaint& paint) { 546 mCanvas->drawRectCoords(left, top, right, bottom, paint); 547 548} 549 550void SkiaCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) { 551 SkRegion::Iterator it(region); 552 while (!it.done()) { 553 mCanvas->drawRect(SkRect::Make(it.rect()), paint); 554 it.next(); 555 } 556} 557 558void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, 559 float rx, float ry, const SkPaint& paint) { 560 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 561 mCanvas->drawRoundRect(rect, rx, ry, paint); 562} 563 564void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) { 565 mCanvas->drawCircle(x, y, radius, paint); 566} 567 568void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) { 569 SkRect oval = SkRect::MakeLTRB(left, top, right, bottom); 570 mCanvas->drawOval(oval, paint); 571} 572 573void SkiaCanvas::drawArc(float left, float top, float right, float bottom, 574 float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) { 575 SkRect arc = SkRect::MakeLTRB(left, top, right, bottom); 576 mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint); 577} 578 579void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 580 mCanvas->drawPath(path, paint); 581} 582 583void SkiaCanvas::drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount, 584 const float* verts, const float* texs, const int* colors, 585 const uint16_t* indices, int indexCount, const SkPaint& paint) { 586#ifndef SK_SCALAR_IS_FLOAT 587 SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid"); 588#endif 589 const int ptCount = vertexCount >> 1; 590 mCanvas->drawVertices(vertexMode, ptCount, (SkPoint*)verts, (SkPoint*)texs, 591 (SkColor*)colors, NULL, indices, indexCount, paint); 592} 593 594// ---------------------------------------------------------------------------- 595// Canvas draw operations: Bitmaps 596// ---------------------------------------------------------------------------- 597 598void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) { 599 mCanvas->drawBitmap(bitmap, left, top, paint); 600} 601 602void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { 603 SkAutoCanvasRestore acr(mCanvas, true); 604 mCanvas->concat(matrix); 605 mCanvas->drawBitmap(bitmap, 0, 0, paint); 606} 607 608void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop, 609 float srcRight, float srcBottom, float dstLeft, float dstTop, 610 float dstRight, float dstBottom, const SkPaint* paint) { 611 SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); 612 SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); 613 mCanvas->drawBitmapRect(bitmap, srcRect, dstRect, paint); 614} 615 616void SkiaCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight, 617 const float* vertices, const int* colors, const SkPaint* paint) { 618 619 const int ptCount = (meshWidth + 1) * (meshHeight + 1); 620 const int indexCount = meshWidth * meshHeight * 6; 621 622 /* Our temp storage holds 2 or 3 arrays. 623 texture points [ptCount * sizeof(SkPoint)] 624 optionally vertex points [ptCount * sizeof(SkPoint)] if we need a 625 copy to convert from float to fixed 626 indices [ptCount * sizeof(uint16_t)] 627 */ 628 ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[] 629 storageSize += indexCount * sizeof(uint16_t); // indices[] 630 631 632#ifndef SK_SCALAR_IS_FLOAT 633 SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid"); 634#endif 635 std::unique_ptr<char[]> storage(new char[storageSize]); 636 SkPoint* texs = (SkPoint*)storage.get(); 637 uint16_t* indices = (uint16_t*)(texs + ptCount); 638 639 // cons up texture coordinates and indices 640 { 641 const SkScalar w = SkIntToScalar(bitmap.width()); 642 const SkScalar h = SkIntToScalar(bitmap.height()); 643 const SkScalar dx = w / meshWidth; 644 const SkScalar dy = h / meshHeight; 645 646 SkPoint* texsPtr = texs; 647 SkScalar y = 0; 648 for (int i = 0; i <= meshHeight; i++) { 649 if (i == meshHeight) { 650 y = h; // to ensure numerically we hit h exactly 651 } 652 SkScalar x = 0; 653 for (int j = 0; j < meshWidth; j++) { 654 texsPtr->set(x, y); 655 texsPtr += 1; 656 x += dx; 657 } 658 texsPtr->set(w, y); 659 texsPtr += 1; 660 y += dy; 661 } 662 SkASSERT(texsPtr - texs == ptCount); 663 } 664 665 // cons up indices 666 { 667 uint16_t* indexPtr = indices; 668 int index = 0; 669 for (int i = 0; i < meshHeight; i++) { 670 for (int j = 0; j < meshWidth; j++) { 671 // lower-left triangle 672 *indexPtr++ = index; 673 *indexPtr++ = index + meshWidth + 1; 674 *indexPtr++ = index + meshWidth + 2; 675 // upper-right triangle 676 *indexPtr++ = index; 677 *indexPtr++ = index + meshWidth + 2; 678 *indexPtr++ = index + 1; 679 // bump to the next cell 680 index += 1; 681 } 682 // bump to the next row 683 index += 1; 684 } 685 SkASSERT(indexPtr - indices == indexCount); 686 SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize); 687 } 688 689 // double-check that we have legal indices 690#ifdef SK_DEBUG 691 { 692 for (int i = 0; i < indexCount; i++) { 693 SkASSERT((unsigned)indices[i] < (unsigned)ptCount); 694 } 695 } 696#endif 697 698 // cons-up a shader for the bitmap 699 SkPaint tmpPaint; 700 if (paint) { 701 tmpPaint = *paint; 702 } 703 SkShader* shader = SkShader::CreateBitmapShader(bitmap, 704 SkShader::kClamp_TileMode, 705 SkShader::kClamp_TileMode); 706 SkSafeUnref(tmpPaint.setShader(shader)); 707 708 mCanvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, (SkPoint*)vertices, 709 texs, (const SkColor*)colors, NULL, indices, 710 indexCount, tmpPaint); 711} 712 713void SkiaCanvas::drawNinePatch(const SkBitmap& bitmap, const Res_png_9patch& chunk, 714 float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) { 715 SkRect bounds = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); 716 NinePatch::Draw(mCanvas, bounds, bitmap, chunk, paint, nullptr); 717} 718 719void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) { 720 const SkBitmap& bitmap = vectorDrawable->getBitmapUpdateIfDirty(); 721 SkRect bounds = vectorDrawable->getBounds(); 722 drawBitmap(bitmap, 0, 0, bitmap.width(), bitmap.height(), 723 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 724 vectorDrawable->getPaint()); 725} 726 727// ---------------------------------------------------------------------------- 728// Canvas draw operations: Text 729// ---------------------------------------------------------------------------- 730 731void SkiaCanvas::drawText(const uint16_t* text, const float* positions, int count, 732 const SkPaint& paint, float x, float y, 733 float boundsLeft, float boundsTop, float boundsRight, float boundsBottom, 734 float totalAdvance) { 735 // Set align to left for drawing, as we don't want individual 736 // glyphs centered or right-aligned; the offset above takes 737 // care of all alignment. 738 SkPaint paintCopy(paint); 739 paintCopy.setTextAlign(SkPaint::kLeft_Align); 740 741 static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats"); 742 mCanvas->drawPosText(text, count << 1, reinterpret_cast<const SkPoint*>(positions), paintCopy); 743 drawTextDecorations(x, y, totalAdvance, paint); 744} 745 746void SkiaCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path, 747 float hOffset, float vOffset, const SkPaint& paint) { 748 mCanvas->drawTextOnPathHV(glyphs, count << 1, path, hOffset, vOffset, paint); 749} 750 751} // namespace android 752