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