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