blob: d5fa1ccc65afae99fe497ec07ee07ea1060b1340 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
2 Copyright 2010 Google Inc.
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
18#include "GrAtlas.h"
19#include "GrClipIterator.h"
20#include "GrContext.h"
21#include "GrTextContext.h"
22#include "GrTextStrike.h"
23#include "GrTextStrike_impl.h"
24#include "GrFontScaler.h"
25
26static const GrVertexLayout VLAYOUT = GrDrawTarget::kTextFormat_VertexLayoutBit;
27
28void GrTextContext::flushGlyphs() {
29 if (fCurrVertex > 0) {
30 GrDrawTarget::AutoStateRestore asr(fDrawTarget);
31
32 // setup our sampler state for our text texture/atlas
33
34 GrSamplerState sampler(GrSamplerState::kRepeat_WrapMode,
35 GrSamplerState::kRepeat_WrapMode,
36 GrSamplerState::kAlphaMod_SampleMode,
37 !fExtMatrix.isIdentity());
38 fDrawTarget->setSamplerState(sampler);
39
40 GrAssert(GrIsALIGN4(fCurrVertex));
41 int nIndices = fCurrVertex + (fCurrVertex >> 1);
42 GrAssert(fCurrTexture);
43 fDrawTarget->setTexture(fCurrTexture);
44 fDrawTarget->setTextureMatrix(GrMatrix::I());
45 fDrawTarget->setIndexSourceToBuffer(fContext->quadIndexBuffer());
46
47 fDrawTarget->drawIndexed(GrDrawTarget::kTriangles_PrimitiveType,
48 0, 0, fCurrVertex, nIndices);
49
50 fDrawTarget->releaseReservedGeometry();
51 fVertices = NULL;
52 fMaxVertices = 0;
53 fCurrVertex = 0;
54 fCurrTexture->unref();
55 fCurrTexture = NULL;
56 }
57}
58
59GrTextContext::GrTextContext(GrContext* context, const GrMatrix* extMatrix) {
60 fContext = context;
61 fStrike = NULL;
62
63 fCurrTexture = NULL;
64 fCurrVertex = 0;
65 fClipRect = context->getClip().getBounds();
66
67 if (NULL != extMatrix) {
68 fExtMatrix = *extMatrix;
69 } else {
70 fExtMatrix = GrMatrix::I();
71 }
72 if (!fExtMatrix.isIdentity()) {
73 GrMatrix inverse;
74 GrRect r;
75 r.set(fClipRect);
76 if (fExtMatrix.invert(&inverse)) {
77 inverse.mapRect(&r);
78 r.roundOut(&fClipRect);
79 }
80 }
81
82 fContext->getViewMatrix(&fOrigViewMatrix);
83 fContext->setViewMatrix(fExtMatrix);
84
85 fVertices = NULL;
86 fMaxVertices = 0;
87 fDrawTarget = fContext->getTextTarget();
88}
89
90GrTextContext::~GrTextContext() {
91 this->flushGlyphs();
92 fContext->setViewMatrix(fOrigViewMatrix);
93}
94
95void GrTextContext::flush() {
96 this->flushGlyphs();
97}
98
99static inline void setRectFan(GrGpuTextVertex v[4], int l, int t, int r, int b,
100 int stride) {
101 v[0 * stride].setI(l, t);
102 v[1 * stride].setI(l, b);
103 v[2 * stride].setI(r, b);
104 v[3 * stride].setI(r, t);
105}
106
107void GrTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
108 GrFixed vx, GrFixed vy,
109 GrFontScaler* scaler) {
110 if (NULL == fStrike) {
111 fStrike = fContext->getFontCache()->getStrike(scaler);
112 }
113
114 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
115 if (NULL == glyph || glyph->fBounds.isEmpty()) {
116 return;
117 }
118
119 vx += GrIntToFixed(glyph->fBounds.fLeft);
120 vy += GrIntToFixed(glyph->fBounds.fTop);
121
122 // keep them as ints until we've done the clip-test
123 GrFixed width = glyph->fBounds.width();
124 GrFixed height = glyph->fBounds.height();
125
126 // check if we clipped out
127 if (true || NULL == glyph->fAtlas) {
128 int x = vx >> 16;
129 int y = vy >> 16;
130 if (fClipRect.quickReject(x, y, x + width, y + height)) {
131// Gr_clz(3); // so we can set a break-point in the debugger
132 return;
133 }
134 }
135
136 if (NULL == glyph->fAtlas) {
137 if (fStrike->getGlyphAtlas(glyph, scaler)) {
138 goto HAS_ATLAS;
139 }
140 // try to purge
141 fContext->getFontCache()->purgeExceptFor(fStrike);
142 if (fStrike->getGlyphAtlas(glyph, scaler)) {
143 goto HAS_ATLAS;
144 }
145
146 // Draw as a path, so we flush any accumulated glyphs first
147 this->flushGlyphs();
148
149 if (NULL == glyph->fPath) {
150
151 GrPath* path = new GrPath;
152 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
153 // flag the glyph as being dead?
154 delete path;
155 return;
156 }
157 glyph->fPath = path;
158 }
159 GrPath::Iter iter(*glyph->fPath);
160 bool useTexture = false;
161 GrPoint translate;
162 translate.set(GrFixedToScalar(vx - GrIntToFixed(glyph->fBounds.fLeft)),
163 GrFixedToScalar(vy - GrIntToFixed(glyph->fBounds.fTop)));
164 fContext->drawPath(&iter, GrContext::kWinding_PathFill,
165 useTexture, &translate);
166 return;
167 }
168
169HAS_ATLAS:
170 GrAssert(glyph->fAtlas);
171
172 // now promote them to fixed
173 width = GrIntToFixed(width);
174 height = GrIntToFixed(height);
175
176 GrTexture* texture = glyph->fAtlas->texture();
177 GrAssert(texture);
178
179 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
180 this->flushGlyphs();
181 fCurrTexture = texture;
182 fCurrTexture->ref();
183 }
184
185 if (NULL == fVertices) {
186 // If we need to reserve vertices allow the draw target to suggest
187 // a number of verts to reserve and whether to perform a flush.
188 fMaxVertices = kMinRequestedVerts;
189 bool flush = fDrawTarget->geometryHints(VLAYOUT,
190 &fMaxVertices,
191 NULL);
192 if (flush) {
193 this->flushGlyphs();
194 fContext->flushText();
195 fDrawTarget = fContext->getTextTarget();
196 fMaxVertices = kDefaultRequestedVerts;
197 // ignore return, no point in flushing again.
198 fDrawTarget->geometryHints(VLAYOUT,
199 &fMaxVertices,
200 NULL);
201 }
202
203 if (fMaxVertices < kMinRequestedVerts) {
204 fMaxVertices = kDefaultRequestedVerts;
205 } else if (fMaxVertices > (fContext->maxQuadsInIndexBuffer() * 4)) {
206 // don't exceed the limit of the index buffer
207 fMaxVertices = (fContext->maxQuadsInIndexBuffer() * 4);
208 }
209 bool success = fDrawTarget->reserveAndLockGeometry(VLAYOUT,
210 fMaxVertices, 0,
211 (void**)&fVertices,
212 NULL);
213 GrAlwaysAssert(success);
214 }
215
216 GrFixed tx = GrIntToFixed(glyph->fAtlasLocation.fX);
217 GrFixed ty = GrIntToFixed(glyph->fAtlasLocation.fY);
218
219#if GR_GL_TEXT_TEXTURE_NORMALIZED
220 int x = vx >> 16;
221 int y = vy >> 16;
222 int w = width >> 16;
223 int h = height >> 16;
224
225 setRectFan(&fVertices[2*fCurrVertex], x, y, x + w, y + h, 2);
226 setRectFan(&fVertices[2*fCurrVertex+1],
227 texture->normalizeFixedX(tx),
228 texture->normalizeFixedY(ty),
229 texture->normalizeFixedX(tx + width),
230 texture->normalizeFixedY(ty + height),
231 2);
232#else
233 fVertices[2*fCurrVertex].setXRectFan(vx, vy, vx + width, vy + height,
234 2 * sizeof(GrGpuTextVertex));
235 fVertices[2*fCurrVertex+1].setXRectFan(texture->normalizeFixedX(tx),
236 texture->normalizeFixedY(ty),
237 texture->normalizeFixedX(tx + width),
238 texture->normalizeFixedY(ty + height),
239 2 * sizeof(GrGpuTextVertex));
240#endif
241 fCurrVertex += 4;
242}
243
244