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