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