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