add gpu backend (not hooked up yet)
git-svn-id: http://skia.googlecode.com/svn/trunk@649 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrTextContext.cpp b/gpu/src/GrTextContext.cpp
new file mode 100644
index 0000000..d5fa1cc
--- /dev/null
+++ b/gpu/src/GrTextContext.cpp
@@ -0,0 +1,244 @@
+/*
+ Copyright 2010 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+
+#include "GrAtlas.h"
+#include "GrClipIterator.h"
+#include "GrContext.h"
+#include "GrTextContext.h"
+#include "GrTextStrike.h"
+#include "GrTextStrike_impl.h"
+#include "GrFontScaler.h"
+
+static const GrVertexLayout VLAYOUT = GrDrawTarget::kTextFormat_VertexLayoutBit;
+
+void GrTextContext::flushGlyphs() {
+ if (fCurrVertex > 0) {
+ GrDrawTarget::AutoStateRestore asr(fDrawTarget);
+
+ // setup our sampler state for our text texture/atlas
+
+ GrSamplerState sampler(GrSamplerState::kRepeat_WrapMode,
+ GrSamplerState::kRepeat_WrapMode,
+ GrSamplerState::kAlphaMod_SampleMode,
+ !fExtMatrix.isIdentity());
+ fDrawTarget->setSamplerState(sampler);
+
+ GrAssert(GrIsALIGN4(fCurrVertex));
+ int nIndices = fCurrVertex + (fCurrVertex >> 1);
+ GrAssert(fCurrTexture);
+ fDrawTarget->setTexture(fCurrTexture);
+ fDrawTarget->setTextureMatrix(GrMatrix::I());
+ fDrawTarget->setIndexSourceToBuffer(fContext->quadIndexBuffer());
+
+ fDrawTarget->drawIndexed(GrDrawTarget::kTriangles_PrimitiveType,
+ 0, 0, fCurrVertex, nIndices);
+
+ fDrawTarget->releaseReservedGeometry();
+ fVertices = NULL;
+ fMaxVertices = 0;
+ fCurrVertex = 0;
+ fCurrTexture->unref();
+ fCurrTexture = NULL;
+ }
+}
+
+GrTextContext::GrTextContext(GrContext* context, const GrMatrix* extMatrix) {
+ fContext = context;
+ fStrike = NULL;
+
+ fCurrTexture = NULL;
+ fCurrVertex = 0;
+ fClipRect = context->getClip().getBounds();
+
+ if (NULL != extMatrix) {
+ fExtMatrix = *extMatrix;
+ } else {
+ fExtMatrix = GrMatrix::I();
+ }
+ if (!fExtMatrix.isIdentity()) {
+ GrMatrix inverse;
+ GrRect r;
+ r.set(fClipRect);
+ if (fExtMatrix.invert(&inverse)) {
+ inverse.mapRect(&r);
+ r.roundOut(&fClipRect);
+ }
+ }
+
+ fContext->getViewMatrix(&fOrigViewMatrix);
+ fContext->setViewMatrix(fExtMatrix);
+
+ fVertices = NULL;
+ fMaxVertices = 0;
+ fDrawTarget = fContext->getTextTarget();
+}
+
+GrTextContext::~GrTextContext() {
+ this->flushGlyphs();
+ fContext->setViewMatrix(fOrigViewMatrix);
+}
+
+void GrTextContext::flush() {
+ this->flushGlyphs();
+}
+
+static inline void setRectFan(GrGpuTextVertex v[4], int l, int t, int r, int b,
+ int stride) {
+ v[0 * stride].setI(l, t);
+ v[1 * stride].setI(l, b);
+ v[2 * stride].setI(r, b);
+ v[3 * stride].setI(r, t);
+}
+
+void GrTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
+ GrFixed vx, GrFixed vy,
+ GrFontScaler* scaler) {
+ if (NULL == fStrike) {
+ fStrike = fContext->getFontCache()->getStrike(scaler);
+ }
+
+ GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
+ if (NULL == glyph || glyph->fBounds.isEmpty()) {
+ return;
+ }
+
+ vx += GrIntToFixed(glyph->fBounds.fLeft);
+ vy += GrIntToFixed(glyph->fBounds.fTop);
+
+ // keep them as ints until we've done the clip-test
+ GrFixed width = glyph->fBounds.width();
+ GrFixed height = glyph->fBounds.height();
+
+ // check if we clipped out
+ if (true || NULL == glyph->fAtlas) {
+ int x = vx >> 16;
+ int y = vy >> 16;
+ if (fClipRect.quickReject(x, y, x + width, y + height)) {
+// Gr_clz(3); // so we can set a break-point in the debugger
+ return;
+ }
+ }
+
+ if (NULL == glyph->fAtlas) {
+ if (fStrike->getGlyphAtlas(glyph, scaler)) {
+ goto HAS_ATLAS;
+ }
+ // try to purge
+ fContext->getFontCache()->purgeExceptFor(fStrike);
+ if (fStrike->getGlyphAtlas(glyph, scaler)) {
+ goto HAS_ATLAS;
+ }
+
+ // Draw as a path, so we flush any accumulated glyphs first
+ this->flushGlyphs();
+
+ if (NULL == glyph->fPath) {
+
+ GrPath* path = new GrPath;
+ if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
+ // flag the glyph as being dead?
+ delete path;
+ return;
+ }
+ glyph->fPath = path;
+ }
+ GrPath::Iter iter(*glyph->fPath);
+ bool useTexture = false;
+ GrPoint translate;
+ translate.set(GrFixedToScalar(vx - GrIntToFixed(glyph->fBounds.fLeft)),
+ GrFixedToScalar(vy - GrIntToFixed(glyph->fBounds.fTop)));
+ fContext->drawPath(&iter, GrContext::kWinding_PathFill,
+ useTexture, &translate);
+ return;
+ }
+
+HAS_ATLAS:
+ GrAssert(glyph->fAtlas);
+
+ // now promote them to fixed
+ width = GrIntToFixed(width);
+ height = GrIntToFixed(height);
+
+ GrTexture* texture = glyph->fAtlas->texture();
+ GrAssert(texture);
+
+ if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
+ this->flushGlyphs();
+ fCurrTexture = texture;
+ fCurrTexture->ref();
+ }
+
+ if (NULL == fVertices) {
+ // If we need to reserve vertices allow the draw target to suggest
+ // a number of verts to reserve and whether to perform a flush.
+ fMaxVertices = kMinRequestedVerts;
+ bool flush = fDrawTarget->geometryHints(VLAYOUT,
+ &fMaxVertices,
+ NULL);
+ if (flush) {
+ this->flushGlyphs();
+ fContext->flushText();
+ fDrawTarget = fContext->getTextTarget();
+ fMaxVertices = kDefaultRequestedVerts;
+ // ignore return, no point in flushing again.
+ fDrawTarget->geometryHints(VLAYOUT,
+ &fMaxVertices,
+ NULL);
+ }
+
+ if (fMaxVertices < kMinRequestedVerts) {
+ fMaxVertices = kDefaultRequestedVerts;
+ } else if (fMaxVertices > (fContext->maxQuadsInIndexBuffer() * 4)) {
+ // don't exceed the limit of the index buffer
+ fMaxVertices = (fContext->maxQuadsInIndexBuffer() * 4);
+ }
+ bool success = fDrawTarget->reserveAndLockGeometry(VLAYOUT,
+ fMaxVertices, 0,
+ (void**)&fVertices,
+ NULL);
+ GrAlwaysAssert(success);
+ }
+
+ GrFixed tx = GrIntToFixed(glyph->fAtlasLocation.fX);
+ GrFixed ty = GrIntToFixed(glyph->fAtlasLocation.fY);
+
+#if GR_GL_TEXT_TEXTURE_NORMALIZED
+ int x = vx >> 16;
+ int y = vy >> 16;
+ int w = width >> 16;
+ int h = height >> 16;
+
+ setRectFan(&fVertices[2*fCurrVertex], x, y, x + w, y + h, 2);
+ setRectFan(&fVertices[2*fCurrVertex+1],
+ texture->normalizeFixedX(tx),
+ texture->normalizeFixedY(ty),
+ texture->normalizeFixedX(tx + width),
+ texture->normalizeFixedY(ty + height),
+ 2);
+#else
+ fVertices[2*fCurrVertex].setXRectFan(vx, vy, vx + width, vy + height,
+ 2 * sizeof(GrGpuTextVertex));
+ fVertices[2*fCurrVertex+1].setXRectFan(texture->normalizeFixedX(tx),
+ texture->normalizeFixedY(ty),
+ texture->normalizeFixedX(tx + width),
+ texture->normalizeFixedY(ty + height),
+ 2 * sizeof(GrGpuTextVertex));
+#endif
+ fCurrVertex += 4;
+}
+
+