SkGLDevice.cpp revision 03202c9c3dfbf8c4feb0a1ee9b3680817e633f58
1#include "SkGLDevice.h" 2#include "SkGL.h" 3#include "SkDrawProcs.h" 4#include "SkRegion.h" 5#include "SkThread.h" 6 7static void TRACE_DRAW(const char func[], SkGLDevice* device, 8 const SkDraw& draw) { 9 // SkDebugf("--- <%s> %p %p\n", func, canvas, draw.fDevice); 10} 11 12struct SkGLDrawProcs : public SkDrawProcs { 13public: 14 void init(const SkRegion* clip, int height) { 15 fCurrQuad = 0; 16 fCurrTexture = 0; 17 fClip = clip; 18 fViewportHeight = height; 19 20 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 21 glTexCoordPointer(2, SK_TextGLType, 0, fTexs); 22 glDisableClientState(GL_COLOR_ARRAY); 23 glVertexPointer(2, SK_TextGLType, 0, fVerts); 24 } 25 26 GLenum texture() const { return fCurrTexture; } 27 28 void flush() { 29 if (fCurrQuad && fCurrTexture) { 30 this->drawQuads(); 31 } 32 fCurrQuad = 0; 33 } 34 35 void addQuad(GLuint texture, int x, int y, const SkGlyph& glyph, 36 SkFixed left, SkFixed right, SkFixed bottom) { 37 SkASSERT((size_t)fCurrQuad <= SK_ARRAY_COUNT(fVerts)); 38 39 if (fCurrTexture != texture || fCurrQuad == SK_ARRAY_COUNT(fVerts)) { 40 if (fCurrQuad && fCurrTexture) { 41 this->drawQuads(); 42 } 43 fCurrQuad = 0; 44 fCurrTexture = texture; 45 } 46 47 fVerts[fCurrQuad].setIRectFan(x, y, 48 x + glyph.fWidth, y + glyph.fHeight); 49 fTexs[fCurrQuad].setXRectFan(left, 0, right, bottom); 50 fCurrQuad += 4; 51 } 52 53 void drawQuads(); 54 55private: 56 enum { 57 MAX_QUADS = 32 58 }; 59 60 SkGLTextVertex fVerts[MAX_QUADS * 4]; 61 SkGLTextVertex fTexs[MAX_QUADS * 4]; 62 63 // these are initialized in setupForText 64 GLuint fCurrTexture; 65 int fCurrQuad; 66 int fViewportHeight; 67 const SkRegion* fClip; 68}; 69 70/////////////////////////////////////////////////////////////////////////////// 71 72SkGLDevice::SkGLDevice(const SkBitmap& bitmap, bool offscreen) 73 : SkDevice(bitmap), fClipIter(bitmap.height()) { 74 fDrawProcs = NULL; 75} 76 77SkGLDevice::~SkGLDevice() { 78 if (fDrawProcs) { 79 SkDELETE(fDrawProcs); 80 } 81} 82 83void SkGLDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip) { 84 this->INHERITED::setMatrixClip(matrix, clip); 85 86 fGLMatrix.set(matrix); 87 fMatrix = matrix; 88 fClip = clip; 89 fDirty = true; 90} 91 92SkGLDevice::TexOrientation SkGLDevice::bindDeviceAsTexture() { 93 return kNo_TexOrientation; 94} 95 96void SkGLDevice::gainFocus(SkCanvas* canvas) { 97 this->INHERITED::gainFocus(canvas); 98 99 const int w = this->width(); 100 const int h = this->height(); 101 glViewport(0, 0, w, h); 102 glMatrixMode(GL_PROJECTION); 103 glLoadIdentity(); 104 SkGL::Ortho(0, w, h, 0, -1, 1); 105 glMatrixMode(GL_MODELVIEW); 106 fDirty = true; 107} 108 109SkGLClipIter* SkGLDevice::updateMatrixClip() { 110 bool useIter = false; 111 112 // first handle the clip 113 if (fDirty || !fClip.isRect()) { 114 fClipIter.reset(fClip); 115 useIter = true; 116 } else if (fDirty) { 117 // no iter means caller is not respecting complex clips :( 118 SkGL::Scissor(fClip.getBounds(), this->height()); 119 } 120 // else we're just a rect, and we've already call scissor 121 122 // now handle the matrix 123 if (fDirty) { 124 MAKE_GL(glLoadMatrix)(fGLMatrix.fMat); 125#if 0 126 SkDebugf("--- gldevice update matrix %p %p\n", this, fFBO); 127 for (int y = 0; y < 4; y++) { 128 SkDebugf(" [ "); 129 for (int x = 0; x < 4; x++) { 130 SkDebugf("%g ", fGLMatrix.fMat[y*4 + x]); 131 } 132 SkDebugf("]\n"); 133 } 134#endif 135 fDirty = false; 136 } 137 138 return useIter ? &fClipIter : NULL; 139} 140 141/////////////////////////////////////////////////////////////////////////////// 142 143// must be in the same order as SkXfermode::Coeff in SkXfermode.h 144SkGLDevice::AutoPaintShader::AutoPaintShader(SkGLDevice* device, 145 const SkPaint& paint) { 146 fDevice = device; 147 fTexCache = device->setupGLPaintShader(paint); 148} 149 150SkGLDevice::AutoPaintShader::~AutoPaintShader() { 151 if (fTexCache) { 152 SkGLDevice::UnlockTexCache(fTexCache); 153 } 154} 155 156SkGLDevice::TexCache* SkGLDevice::setupGLPaintShader(const SkPaint& paint) { 157 SkGL::SetPaint(paint); 158 159 SkShader* shader = paint.getShader(); 160 if (NULL == shader) { 161 return NULL; 162 } 163 164 if (!shader->setContext(this->accessBitmap(false), paint, this->matrix())) { 165 return NULL; 166 } 167 168 SkBitmap bitmap; 169 SkMatrix matrix; 170 SkShader::TileMode tileModes[2]; 171 if (!shader->asABitmap(&bitmap, &matrix, tileModes)) { 172 return NULL; 173 } 174 175 bitmap.lockPixels(); 176 if (!bitmap.readyToDraw()) { 177 return NULL; 178 } 179 180 // see if we've already cached the bitmap from the shader 181 SkPoint max; 182 GLuint name; 183 TexCache* cache = SkGLDevice::LockTexCache(bitmap, &name, &max); 184 // the lock has already called glBindTexture for us 185 SkGL::SetTexParams(paint.isFilterBitmap(), tileModes[0], tileModes[1]); 186 187 // since our texture coords will be in local space, we wack the texture 188 // matrix to map them back into 0...1 before we load it 189 SkMatrix localM; 190 if (shader->getLocalMatrix(&localM)) { 191 SkMatrix inverse; 192 if (localM.invert(&inverse)) { 193 matrix.preConcat(inverse); 194 } 195 } 196 197 matrix.postScale(max.fX / bitmap.width(), max.fY / bitmap.height()); 198 glMatrixMode(GL_TEXTURE); 199 SkGL::LoadMatrix(matrix); 200 glMatrixMode(GL_MODELVIEW); 201 202 // since we're going to use a shader/texture, we don't want the color, 203 // just its alpha 204 SkGL::SetAlpha(paint.getAlpha()); 205 // report that we have setup the texture 206 return cache; 207} 208 209/////////////////////////////////////////////////////////////////////////////// 210/////////////////////////////////////////////////////////////////////////////// 211 212void SkGLDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { 213 TRACE_DRAW("coreDrawPaint", this, draw); 214 215 AutoPaintShader shader(this, paint); 216 SkGLVertex vertex[4]; 217 const SkGLVertex* texs = shader.useTex() ? vertex : NULL; 218 219 // set vert to be big enough to fill the space, but not super-huge, to we 220 // don't overflow fixed-point implementations 221 { 222 SkRect r; 223 r.set(this->clip().getBounds()); 224 SkMatrix inverse; 225 if (draw.fMatrix->invert(&inverse)) { 226 inverse.mapRect(&r); 227 } 228 vertex->setRectFan(r); 229 } 230 231 SkGL::DrawVertices(4, GL_TRIANGLE_FAN, vertex, texs, NULL, NULL, 232 this->updateMatrixClip()); 233} 234 235static const GLenum gPointMode2GL[] = { 236 GL_POINTS, 237 GL_LINES, 238 GL_LINE_STRIP 239}; 240 241void SkGLDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, 242 size_t count, const SkPoint pts[], const SkPaint& paint) { 243 TRACE_DRAW("coreDrawPoints", this, draw); 244 245 SkScalar width = paint.getStrokeWidth(); 246 if (width < 0) { 247 return; 248 } 249 250 /* We should really only use drawverts for hairlines, since gl and skia 251 treat the thickness differently... 252 */ 253 254 AutoPaintShader shader(this, paint); 255 256 if (width <= 0) { 257 width = SK_Scalar1; 258 } 259 260 if (SkCanvas::kPoints_PointMode == mode) { 261 glPointSize(SkScalarToFloat(width)); 262 } else { 263 glLineWidth(SkScalarToFloat(width)); 264 } 265 266 const SkGLVertex* verts; 267 268#if GLSCALAR_IS_SCALAR 269 verts = (const SkGLVertex*)pts; 270#else 271 SkAutoSTMalloc<32, SkGLVertex> storage(count); 272 SkGLVertex* v = storage.get(); 273 274 v->setPoints(pts, count); 275 verts = v; 276#endif 277 278 const SkGLVertex* texs = shader.useTex() ? verts : NULL; 279 280 SkGL::DrawVertices(count, gPointMode2GL[mode], verts, texs, NULL, NULL, 281 this->updateMatrixClip()); 282} 283 284void SkGLDevice::drawRect(const SkDraw& draw, const SkRect& rect, 285 const SkPaint& paint) { 286 TRACE_DRAW("coreDrawRect", this, draw); 287 288 if (paint.getStyle() == SkPaint::kStroke_Style) { 289 return; 290 } 291 292 if (paint.getStrokeJoin() != SkPaint::kMiter_Join) { 293 SkPath path; 294 path.addRect(rect); 295 this->drawPath(draw, path, paint); 296 return; 297 } 298 299 AutoPaintShader shader(this, paint); 300 301 SkGLVertex vertex[4]; 302 vertex->setRectFan(rect); 303 const SkGLVertex* texs = shader.useTex() ? vertex : NULL; 304 305 SkGL::DrawVertices(4, GL_TRIANGLE_FAN, vertex, texs, NULL, NULL, 306 this->updateMatrixClip()); 307} 308 309void SkGLDevice::drawPath(const SkDraw& draw, const SkPath& path, 310 const SkPaint& paint) { 311 TRACE_DRAW("coreDrawPath", this, draw); 312 if (paint.getStyle() == SkPaint::kStroke_Style) { 313 return; 314 } 315 316 AutoPaintShader shader(this, paint); 317 318 SkGL::FillPath(path, paint, shader.useTex(), this->updateMatrixClip()); 319} 320 321void SkGLDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, 322 const SkMatrix& m, const SkPaint& paint) { 323 TRACE_DRAW("coreDrawBitmap", this, draw); 324 325 SkAutoLockPixels alp(bitmap); 326 if (!bitmap.readyToDraw()) { 327 return; 328 } 329 330 SkGLClipIter* iter = this->updateMatrixClip(); 331 332 SkPoint max; 333 GLenum name; 334 SkAutoLockTexCache(bitmap, &name, &max); 335 // the lock has already called glBindTexture for us 336 SkGL::SetTexParamsClamp(paint.isFilterBitmap()); 337 338 glMatrixMode(GL_TEXTURE); 339 glLoadIdentity(); 340 glMatrixMode(GL_MODELVIEW); 341 glPushMatrix(); 342 SkGL::MultMatrix(m); 343 344 SkGLVertex pts[4], tex[4]; 345 346 pts->setIRectFan(0, 0, bitmap.width(), bitmap.height()); 347 tex->setRectFan(0, 0, max.fX, max.fY); 348 349 // now draw the mesh 350 SkGL::SetPaintAlpha(paint); 351 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 352 353 SkGL::DrawVertices(4, GL_TRIANGLE_FAN, pts, tex, NULL, NULL, iter); 354 355 glPopMatrix(); 356} 357 358// move this guy into SkGL, so we can call it from SkGLDevice 359static void gl_drawSprite(int x, int y, int w, int h, const SkPoint& max, 360 const SkPaint& paint, SkGLClipIter* iter) { 361 SkGL::SetTexParamsClamp(false); 362 363 glMatrixMode(GL_TEXTURE); 364 glLoadIdentity(); 365 glMatrixMode(GL_MODELVIEW); 366 glPushMatrix(); 367 glLoadIdentity(); 368 369 SkGLVertex pts[4], tex[4]; 370 371 // if h < 0, then the texture is bottom-to-top, but since our projection 372 // matrix always inverts Y, we have to re-invert our texture coord here 373 if (h < 0) { 374 h = -h; 375 tex->setRectFan(0, max.fY, max.fX, 0); 376 } else { 377 tex->setRectFan(0, 0, max.fX, max.fY); 378 } 379 pts->setIRectFan(x, y, x + w, y + h); 380 381 SkGL::SetPaintAlpha(paint); 382 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 383 384 // should look to use glDrawTexi() has we do for text... 385 SkGL::DrawVertices(4, GL_TRIANGLE_FAN, pts, tex, NULL, NULL, iter); 386 387 glPopMatrix(); 388} 389 390void SkGLDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, 391 int left, int top, const SkPaint& paint) { 392 TRACE_DRAW("coreDrawSprite", this, draw); 393 394 SkAutoLockPixels alp(bitmap); 395 if (!bitmap.readyToDraw()) { 396 return; 397 } 398 399 SkGLClipIter* iter = this->updateMatrixClip(); 400 401 SkPoint max; 402 GLuint name; 403 SkAutoLockTexCache(bitmap, &name, &max); 404 405 gl_drawSprite(left, top, bitmap.width(), bitmap.height(), max, paint, iter); 406} 407 408void SkGLDevice::drawDevice(const SkDraw& draw, SkDevice* dev, 409 int x, int y, const SkPaint& paint) { 410 TRACE_DRAW("coreDrawDevice", this, draw); 411 412 SkGLDevice::TexOrientation to = ((SkGLDevice*)dev)->bindDeviceAsTexture(); 413 if (SkGLDevice::kNo_TexOrientation != to) { 414 SkGLClipIter* iter = this->updateMatrixClip(); 415 416 const SkBitmap& bm = dev->accessBitmap(false); 417 int w = bm.width(); 418 int h = bm.height(); 419 SkPoint max; 420 421 max.set(SkFixedToScalar(w << (16 - SkNextLog2(bm.rowBytesAsPixels()))), 422 SkFixedToScalar(h << (16 - SkNextLog2(h)))); 423 424 if (SkGLDevice::kBottomToTop_TexOrientation == to) { 425 h = -h; 426 } 427 gl_drawSprite(x, y, w, h, max, paint, iter); 428 } 429} 430 431/////////////////////////////////////////////////////////////////////////////// 432 433static const GLenum gVertexModeToGL[] = { 434 GL_TRIANGLES, // kTriangles_VertexMode, 435 GL_TRIANGLE_STRIP, // kTriangleStrip_VertexMode, 436 GL_TRIANGLE_FAN // kTriangleFan_VertexMode 437}; 438 439#include "SkShader.h" 440 441void SkGLDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, 442 int vertexCount, const SkPoint vertices[], 443 const SkPoint texs[], const SkColor colors[], 444 SkXfermode* xmode, 445 const uint16_t indices[], int indexCount, 446 const SkPaint& paint) { 447 448 if (false) { 449 SkRect bounds; 450 SkIRect ibounds; 451 452 bounds.set(vertices, vertexCount); 453 bounds.round(&ibounds); 454 455 SkDebugf("---- drawverts: %d pts, texs=%d colors=%d indices=%d bounds [%d %d]\n", 456 vertexCount, texs!=0, colors!=0, indexCount, ibounds.width(), ibounds.height()); 457 } 458 459 SkGLClipIter* iter = this->updateMatrixClip(); 460 461 SkGL::SetPaint(paint); 462 463 const SkGLVertex* glVerts; 464 const SkGLVertex* glTexs = NULL; 465 466#if GLSCALAR_IS_SCALAR 467 glVerts = (const SkGLVertex*)vertices; 468#else 469 SkAutoSTMalloc<32, SkGLVertex> storage(vertexCount); 470 storage.get()->setPoints(vertices, vertexCount); 471 glVerts = storage.get(); 472#endif 473 474 uint8_t* colorArray = NULL; 475 if (colors) { 476 colorArray = (uint8_t*)sk_malloc_throw(vertexCount*4); 477 SkGL::SetRGBA(colorArray, colors, vertexCount); 478 } 479 SkAutoFree afca(colorArray); 480 481 SkGLVertex* texArray = NULL; 482 TexCache* cache = NULL; 483 484 if (texs && paint.getShader()) { 485 SkShader* shader = paint.getShader(); 486 487 // if (!shader->setContext(this->accessBitmap(), paint, *draw.fMatrix)) { 488 if (!shader->setContext(*draw.fBitmap, paint, *draw.fMatrix)) { 489 goto DONE; 490 } 491 492 SkBitmap bitmap; 493 SkMatrix matrix; 494 SkShader::TileMode tileModes[2]; 495 if (shader->asABitmap(&bitmap, &matrix, tileModes)) { 496 SkPoint max; 497 GLuint name; 498 cache = SkGLDevice::LockTexCache(bitmap, &name, &max); 499 if (NULL == cache) { 500 return; 501 } 502 503 matrix.postScale(max.fX / bitmap.width(), max.fY / bitmap.height()); 504 glMatrixMode(GL_TEXTURE); 505 SkGL::LoadMatrix(matrix); 506 glMatrixMode(GL_MODELVIEW); 507 508#if GLSCALAR_IS_SCALAR 509 glTexs = (const SkGLVertex*)texs; 510#else 511 texArray = (SkGLVertex*)sk_malloc_throw(vertexCount * sizeof(SkGLVertex)); 512 texArray->setPoints(texs, vertexCount); 513 glTexs = texArray; 514#endif 515 516 SkGL::SetPaintAlpha(paint); 517 SkGL::SetTexParams(paint.isFilterBitmap(), 518 tileModes[0], tileModes[1]); 519 } 520 } 521DONE: 522 SkAutoFree aftex(texArray); 523 524 SkGL::DrawVertices(indices ? indexCount : vertexCount, 525 gVertexModeToGL[vmode], 526 glVerts, glTexs, colorArray, indices, iter); 527 528 if (cache) { 529 SkGLDevice::UnlockTexCache(cache); 530 } 531} 532 533/////////////////////////////////////////////////////////////////////////////// 534 535#include "SkGlyphCache.h" 536#include "SkGLTextCache.h" 537 538void SkGLDevice::GlyphCacheAuxProc(void* data) { 539 SkDebugf("-------------- delete text texture cache\n"); 540 SkDELETE((SkGLTextCache*)data); 541} 542 543#ifdef SK_SCALAR_IS_FIXED 544#define SkDiv16ToScalar(numer, denom) (SkIntToFixed(numer) / (denom)) 545#else 546#define SkDiv16ToScalar(numer, denom) SkScalarDiv(numer, denom) 547#endif 548 549// stolen from SkDraw.cpp - D1G_NoBounder_RectClip 550static void SkGL_Draw1Glyph(const SkDraw1Glyph& state, const SkGlyph& glyph, 551 int x, int y) { 552 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 553 554 SkGLDrawProcs* procs = (SkGLDrawProcs*)state.fDraw->fProcs; 555 556 x += glyph.fLeft; 557 y += glyph.fTop; 558 559 // check if we're clipped out (nothing to draw) 560 SkIRect bounds; 561 bounds.set(x, y, x + glyph.fWidth, y + glyph.fHeight); 562 if (!SkIRect::Intersects(state.fClip->getBounds(), bounds)) { 563 return; 564 } 565 566 // now dig up our texture cache 567 568 SkGlyphCache* gcache = state.fCache; 569 void* auxData; 570 SkGLTextCache* textCache = NULL; 571 572 if (gcache->getAuxProcData(SkGLDevice::GlyphCacheAuxProc, &auxData)) { 573 textCache = (SkGLTextCache*)auxData; 574 } 575 if (NULL == textCache) { 576 // need to create one 577 textCache = SkNEW(SkGLTextCache); 578 gcache->setAuxProc(SkGLDevice::GlyphCacheAuxProc, textCache); 579 } 580 581 int offset; 582 SkGLTextCache::Strike* strike = textCache->findGlyph(glyph, &offset); 583 if (NULL == strike) { 584 // make sure the glyph has an image 585 uint8_t* aa = (uint8_t*)glyph.fImage; 586 if (NULL == aa) { 587 aa = (uint8_t*)gcache->findImage(glyph); 588 if (NULL == aa) { 589 return; // can't rasterize glyph 590 } 591 } 592 strike = textCache->addGlyphAndBind(glyph, aa, &offset); 593 if (NULL == strike) { 594 // too big to cache, need to draw as is... 595 return; 596 } 597 } 598 599 const int shiftW = strike->widthShift(); 600 const int shiftH = strike->heightShift(); 601 602 SkFixed left = offset << (16 - shiftW); 603 SkFixed right = (offset + glyph.fWidth) << (16 - shiftW); 604 SkFixed bottom = glyph.fHeight << (16 - shiftH); 605 606 procs->addQuad(strike->texture(), x, y, glyph, left, right, bottom); 607} 608 609#if 1 610// matches the orientation used in SkGL::setRectFan. Too bad we can't rely on 611// QUADS in android's GL 612static const uint8_t gQuadIndices[] = { 613 0, 1, 2, 0, 2, 3, 614 4, 5, 6, 4, 6, 7, 615 8, 9, 10, 8, 10, 11, 616 12, 13, 14, 12, 14, 15, 617 16, 17, 18, 16, 18, 19, 618 20, 21, 22, 20, 22, 23, 619 24, 25, 26, 24, 26, 27, 620 28, 29, 30, 28, 30, 31, 621 32, 33, 34, 32, 34, 35, 622 36, 37, 38, 36, 38, 39, 623 40, 41, 42, 40, 42, 43, 624 44, 45, 46, 44, 46, 47, 625 48, 49, 50, 48, 50, 51, 626 52, 53, 54, 52, 54, 55, 627 56, 57, 58, 56, 58, 59, 628 60, 61, 62, 60, 62, 63, 629 64, 65, 66, 64, 66, 67, 630 68, 69, 70, 68, 70, 71, 631 72, 73, 74, 72, 74, 75, 632 76, 77, 78, 76, 78, 79, 633 80, 81, 82, 80, 82, 83, 634 84, 85, 86, 84, 86, 87, 635 88, 89, 90, 88, 90, 91, 636 92, 93, 94, 92, 94, 95, 637 96, 97, 98, 96, 98, 99, 638 100, 101, 102, 100, 102, 103, 639 104, 105, 106, 104, 106, 107, 640 108, 109, 110, 108, 110, 111, 641 112, 113, 114, 112, 114, 115, 642 116, 117, 118, 116, 118, 119, 643 120, 121, 122, 120, 122, 123, 644 124, 125, 126, 124, 126, 127 645}; 646#else 647static void generateQuadIndices(int n) { 648 int index = 0; 649 for (int i = 0; i < n; i++) { 650 SkDebugf(" %3d, %3d, %3d, %3d, %3d, %3d,\n", 651 index, index + 1, index + 2, index, index + 2, index + 3); 652 index += 4; 653 } 654} 655#endif 656 657void SkGLDrawProcs::drawQuads() { 658 SkASSERT(SK_ARRAY_COUNT(gQuadIndices) == MAX_QUADS * 6); 659 660 glBindTexture(GL_TEXTURE_2D, fCurrTexture); 661 662#if 0 663 static bool gOnce; 664 if (!gOnce) { 665 generateQuadIndices(MAX_QUADS); 666 gOnce = true; 667 } 668#endif 669 670 // convert from quad vertex count to triangle vertex count 671 // 6/4 * n == n + (n >> 1) since n is always a multiple of 4 672 SkASSERT((fCurrQuad & 3) == 0); 673 int count = fCurrQuad + (fCurrQuad >> 1); 674 675 if (fClip->isComplex()) { 676 SkGLClipIter iter(fViewportHeight); 677 iter.reset(*fClip); 678 while (!iter.done()) { 679 iter.scissor(); 680 glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_BYTE, gQuadIndices); 681 iter.next(); 682 } 683 } else { 684 glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_BYTE, gQuadIndices); 685 } 686} 687 688void SkGLDevice::setupForText(SkDraw* draw, const SkPaint& paint) { 689 // we handle complex clips in the SkDraw common code, so we don't check 690 // for it here 691 this->updateMatrixClip(); 692 693 SkGL::SetPaint(paint, false); 694 695 glMatrixMode(GL_TEXTURE); 696 glLoadIdentity(); 697 698 glMatrixMode(GL_MODELVIEW); 699 glPushMatrix(); 700 glLoadIdentity(); 701 702 // deferred allocation 703 if (NULL == fDrawProcs) { 704 fDrawProcs = SkNEW(SkGLDrawProcs); 705 fDrawProcs->fD1GProc = SkGL_Draw1Glyph; 706 } 707 708 // init our (and GL's) state 709 fDrawProcs->init(draw->fClip, this->height()); 710 // assign to the caller's SkDraw 711 draw->fProcs = fDrawProcs; 712 713 glEnable(GL_TEXTURE_2D); 714 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 715 glShadeModel(GL_FLAT); 716} 717 718void SkGLDevice::drawText(const SkDraw& draw, const void* text, 719 size_t byteLength, SkScalar x, SkScalar y, 720 const SkPaint& paint) { 721 /* Currently, perspective text is draw via paths, invoked directly by 722 SkDraw. This can't work for us, since the bitmap that our draw points 723 to has no pixels, so we just abort if we're in perspective. 724 725 Better fix would be to... 726 - have a callback inside draw to handle path drawing 727 - option to have draw call the font cache, which we could patch (?) 728 */ 729 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) { 730 return; 731 } 732 733 SkDraw myDraw(draw); 734 this->setupForText(&myDraw, paint); 735 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint); 736 fDrawProcs->flush(); 737 glPopMatrix(); // GL_MODELVIEW 738} 739 740void SkGLDevice::drawPosText(const SkDraw& draw, const void* text, 741 size_t byteLength, const SkScalar pos[], 742 SkScalar constY, int scalarsPerPos, 743 const SkPaint& paint) { 744 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) { 745 return; 746 } 747 748 SkDraw myDraw(draw); 749 this->setupForText(&myDraw, paint); 750 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY, 751 scalarsPerPos, paint); 752 fDrawProcs->flush(); 753 glPopMatrix(); // GL_MODELVIEW 754} 755 756void SkGLDevice::drawTextOnPath(const SkDraw& draw, const void* text, 757 size_t byteLength, const SkPath& path, 758 const SkMatrix* m, const SkPaint& paint) { 759 // not supported yet 760} 761 762