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