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