Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 #include "GrAtlasTextContext.h" | 7 #include "GrAtlasTextContext.h" |
| 8 | 8 |
| 9 #include "GrAtlas.h" | 9 #include "GrAtlas.h" |
| 10 #include "GrBatch.h" | 10 #include "GrBatch.h" |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 83 return SkNEW_ARGS(GrAtlasTextContext, (context, gpuDevice, props)); | 83 return SkNEW_ARGS(GrAtlasTextContext, (context, gpuDevice, props)); |
| 84 } | 84 } |
| 85 | 85 |
| 86 bool GrAtlasTextContext::canDraw(const GrRenderTarget*, | 86 bool GrAtlasTextContext::canDraw(const GrRenderTarget*, |
| 87 const GrClip&, | 87 const GrClip&, |
| 88 const GrPaint&, | 88 const GrPaint&, |
| 89 const SkPaint& skPaint, | 89 const SkPaint& skPaint, |
| 90 const SkMatrix& viewMatrix) { | 90 const SkMatrix& viewMatrix) { |
| 91 return !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); | 91 return !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); |
| 92 } | 92 } |
| 93 | 93 |
|
robertphillips
2015/04/09 13:15:32
kMinDiscernableTranslation ?
Can this be moved int
joshualitt
2015/04/09 14:59:00
Acknowledged.
| |
| 94 bool GrAtlasTextContext::MustRegenerateBlob(const BitmapTextBlob& blob, const Sk Paint& paint, | 94 static const SkScalar kThreshold = 0.0625; |
| 95 | |
| 96 bool GrAtlasTextContext::MustRegenerateBlob(SkScalar* transX, SkScalar* transY, | |
| 97 const BitmapTextBlob& blob, const Sk Paint& paint, | |
| 95 const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { | 98 const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { |
| 96 // We always regenerate blobs with patheffects or mask filters we could cach e these | 99 // Color can affect the mask |
| 97 // TODO find some way to cache the maskfilter / patheffects on the textblob | 100 // TODO we can adjust the color within specific gamma slots |
| 98 return !blob.fViewMatrix.cheapEqualTo(viewMatrix) || blob.fX != x || blob.fY != y || | 101 if (blob.fColor != paint.getColor()) { |
| 99 paint.getMaskFilter() || paint.getPathEffect() || paint.getStyle() ! = blob.fStyle; | 102 return true; |
| 103 } | |
| 104 | |
| 105 if (blob.fViewMatrix.hasPerspective() != viewMatrix.hasPerspective()) { | |
| 106 return true; | |
| 107 } | |
| 108 | |
| 109 if (blob.fViewMatrix.hasPerspective() && !blob.fViewMatrix.cheapEqualTo(view Matrix)) { | |
| 110 return true; | |
| 111 } | |
| 112 | |
| 113 if (blob.fViewMatrix.getScaleX() != viewMatrix.getScaleX() || | |
| 114 blob.fViewMatrix.getScaleY() != viewMatrix.getScaleY() || | |
| 115 blob.fViewMatrix.getSkewX() != viewMatrix.getSkewX() || | |
| 116 blob.fViewMatrix.getSkewY() != viewMatrix.getSkewY()) { | |
| 117 return true; | |
| 118 } | |
| 119 | |
| 120 // We can update the positions in the cachedtextblobs without regenerating t he whole blob, but | |
| 121 // only for integer translations. | |
|
robertphillips
2015/04/09 13:15:32
That's an ominous todo
Shouldn't this be something
joshualitt
2015/04/09 14:59:00
I took another stab at it. I *think* I can allow
| |
| 122 // TODO I think this is wrong | |
| 123 if (SkScalarFraction(blob.fViewMatrix.getTranslateX() - | |
| 124 viewMatrix.getTranslateX()) > kThreshold || | |
| 125 SkScalarFraction(x - blob.fX) > kThreshold || | |
| 126 SkScalarFraction(blob.fViewMatrix.getTranslateX() - | |
| 127 viewMatrix.getTranslateX()) > kThreshold || | |
| 128 SkScalarFraction(y - blob.fY) > kThreshold) { | |
| 129 return true; | |
| 130 } | |
| 131 | |
|
robertphillips
2015/04/09 13:15:32
// This cool math does the following ...
?
joshualitt
2015/04/09 14:59:00
Acknowledged.
| |
| 132 (*transX) = viewMatrix.getTranslateX() + | |
| 133 viewMatrix.getScaleX() * (x - blob.fX) + | |
| 134 viewMatrix.getSkewX() * (y - blob.fY) - | |
| 135 blob.fViewMatrix.getTranslateX(); | |
| 136 | |
| 137 (*transY) = viewMatrix.getTranslateY() + | |
| 138 viewMatrix.getSkewY() * (x - blob.fX) + | |
| 139 viewMatrix.getScaleY() * (y - blob.fY) - | |
| 140 blob.fViewMatrix.getTranslateY(); | |
| 141 return false; | |
| 100 } | 142 } |
| 101 | 143 |
| 102 | 144 |
| 103 inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run, | 145 inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run, |
| 104 const SkPaint& skPaint, | 146 const SkPaint& skPaint, |
| 105 const SkMatrix& viewMatrix) { | 147 const SkMatrix& viewMatrix) { |
| 106 skPaint.getScalerContextDescriptor(&run->fDescriptor, &fDeviceProperties, &v iewMatrix, false); | 148 skPaint.getScalerContextDescriptor(&run->fDescriptor, &fDeviceProperties, &v iewMatrix, false); |
| 107 run->fTypeface.reset(SkSafeRef(skPaint.getTypeface())); | 149 run->fTypeface.reset(SkSafeRef(skPaint.getTypeface())); |
| 108 return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc()) ; | 150 return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc()) ; |
| 109 } | 151 } |
| 110 | 152 |
| 111 void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, | 153 void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, |
| 112 const SkPaint& skPaint, const SkMatrix& vi ewMatrix, | 154 const SkPaint& skPaint, const SkMatrix& vi ewMatrix, |
| 113 const SkTextBlob* blob, SkScalar x, SkScal ar y, | 155 const SkTextBlob* blob, SkScalar x, SkScal ar y, |
| 114 SkDrawFilter* drawFilter, const SkIRect& c lipBounds) { | 156 SkDrawFilter* drawFilter, const SkIRect& c lipBounds) { |
| 115 uint32_t uniqueID = blob->uniqueID(); | 157 uint32_t uniqueID = blob->uniqueID(); |
| 116 BitmapTextBlob* cacheBlob = fCache->find(uniqueID); | 158 SkAutoTUnref<BitmapTextBlob> cacheBlob; |
| 159 // TODO start caching these, mix bits into the key | |
|
robertphillips
2015/04/09 13:15:32
Would this be more natural as "canCache" ?
joshualitt
2015/04/09 14:59:00
Acknowledged.
| |
| 160 bool mustNotCache = skPaint.getPathEffect() || | |
| 161 skPaint.getMaskFilter() || | |
| 162 skPaint.getColorFilter() || | |
| 163 skPaint.getStyle() != SkPaint::kFill_Style || | |
| 164 drawFilter; | |
| 165 | |
| 166 if (!mustNotCache) { | |
| 167 cacheBlob.reset(SkSafeRef(fCache->find(uniqueID))); | |
| 168 } | |
| 169 | |
| 117 SkIRect clipRect; | 170 SkIRect clipRect; |
| 118 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); | 171 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); |
| 119 | 172 |
| 173 SkScalar transX = 0.f; | |
| 174 SkScalar transY = 0.f; | |
| 175 | |
| 120 if (cacheBlob) { | 176 if (cacheBlob) { |
| 121 if (MustRegenerateBlob(*cacheBlob, skPaint, viewMatrix, x, y)) { | 177 if (MustRegenerateBlob(&transX, &transY, *cacheBlob, skPaint, viewMatrix , x, y)) { |
| 122 // We have to remake the blob because changes may invalidate our mas ks. | 178 // We have to remake the blob because changes may invalidate our mas ks. |
| 123 // TODO we could probably get away reuse most of the time if the poi nter is unique, | 179 // TODO we could probably get away reuse most of the time if the poi nter is unique, |
| 124 // but we'd have to clear the subrun information | 180 // but we'd have to clear the subrun information |
| 125 fCache->remove(cacheBlob); | 181 fCache->remove(cacheBlob); |
| 126 cacheBlob = fCache->createCachedBlob(blob, kGrayTextVASize); | 182 cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, kGrayTextVASize ))); |
| 127 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, drawFilter, | 183 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, drawFilter, |
| 128 clipRect); | 184 clipRect); |
| 129 } else { | 185 } else { |
| 186 // If we can reuse the blob, then make sure we update the blob's vie wmatrix and x/y | |
| 187 // offsets to reflect the results of any translations we may apply i n generateGeometry | |
| 188 cacheBlob->fViewMatrix = viewMatrix; | |
| 189 cacheBlob->fX = x; | |
| 190 cacheBlob->fY = y; | |
| 130 fCache->makeMRU(cacheBlob); | 191 fCache->makeMRU(cacheBlob); |
| 131 } | 192 } |
| 132 } else { | 193 } else { |
| 133 cacheBlob = fCache->createCachedBlob(blob, kGrayTextVASize); | 194 if (mustNotCache) { |
| 195 cacheBlob.reset(fCache->createBlob(blob, kGrayTextVASize)); | |
| 196 } else { | |
| 197 cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, kGrayTextVASize ))); | |
| 198 } | |
| 134 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, dra wFilter, clipRect); | 199 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, dra wFilter, clipRect); |
| 135 } | 200 } |
| 136 | 201 |
| 137 // Though for the time being runs in the textblob can override the paint, th ey only touch font | 202 // Though for the time being runs in the textblob can override the paint, th ey only touch font |
| 138 // info. | 203 // info. |
| 139 GrPaint grPaint; | 204 GrPaint grPaint; |
| 140 SkPaint2GrPaintShader(fContext, rt, skPaint, viewMatrix, true, &grPaint); | 205 SkPaint2GrPaintShader(fContext, rt, skPaint, viewMatrix, true, &grPaint); |
| 141 | 206 |
| 142 this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint , drawFilter, | 207 this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint , drawFilter, |
| 143 clip, viewMatrix, clipBounds, x, y); | 208 clip, viewMatrix, clipBounds, x, y, transX, transY); |
| 144 } | 209 } |
| 145 | 210 |
| 146 void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, | 211 void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, |
| 147 const SkPaint& skPaint, const SkMatr ix& viewMatrix, | 212 const SkPaint& skPaint, const SkMatr ix& viewMatrix, |
| 148 const SkTextBlob* blob, SkScalar x, SkScalar y, | 213 const SkTextBlob* blob, SkScalar x, SkScalar y, |
| 149 SkDrawFilter* drawFilter, const SkIR ect& clipRect) { | 214 SkDrawFilter* drawFilter, const SkIR ect& clipRect) { |
| 150 cacheBlob->fViewMatrix = viewMatrix; | 215 cacheBlob->fViewMatrix = viewMatrix; |
| 151 cacheBlob->fX = x; | 216 cacheBlob->fX = x; |
| 152 cacheBlob->fY = y; | 217 cacheBlob->fY = y; |
| 218 cacheBlob->fColor = skPaint.getColor(); | |
| 153 cacheBlob->fStyle = skPaint.getStyle(); | 219 cacheBlob->fStyle = skPaint.getStyle(); |
| 154 | 220 |
| 155 // Regenerate textblob | 221 // Regenerate textblob |
| 156 SkPaint runPaint = skPaint; | 222 SkPaint runPaint = skPaint; |
| 157 SkTextBlob::RunIterator it(blob); | 223 SkTextBlob::RunIterator it(blob); |
| 158 for (int run = 0; !it.done(); it.next(), run++) { | 224 for (int run = 0; !it.done(); it.next(), run++) { |
| 159 int glyphCount = it.glyphCount(); | 225 int glyphCount = it.glyphCount(); |
| 160 size_t textLen = glyphCount * sizeof(uint16_t); | 226 size_t textLen = glyphCount * sizeof(uint16_t); |
| 161 const SkPoint& offset = it.offset(); | 227 const SkPoint& offset = it.offset(); |
| 162 // applyFontToPaint() always overwrites the exact same attributes, | 228 // applyFontToPaint() always overwrites the exact same attributes, |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 178 PerSubRunInfo& newRun = cacheBlob->fRuns[run].fSubRunInfo.back(); | 244 PerSubRunInfo& newRun = cacheBlob->fRuns[run].fSubRunInfo.back(); |
| 179 PerSubRunInfo& lastRun = cacheBlob->fRuns[run - 1].fSubRunInfo.back( ); | 245 PerSubRunInfo& lastRun = cacheBlob->fRuns[run - 1].fSubRunInfo.back( ); |
| 180 | 246 |
| 181 newRun.fVertexStartIndex = lastRun.fVertexEndIndex; | 247 newRun.fVertexStartIndex = lastRun.fVertexEndIndex; |
| 182 newRun.fVertexEndIndex = lastRun.fVertexEndIndex; | 248 newRun.fVertexEndIndex = lastRun.fVertexEndIndex; |
| 183 | 249 |
| 184 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex; | 250 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex; |
| 185 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex; | 251 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex; |
| 186 } | 252 } |
| 187 | 253 |
| 188 if (SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix)) { | 254 if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) { |
| 189 cacheBlob->fRuns[run].fDrawAsPaths = true; | 255 cacheBlob->fRuns[run].fDrawAsPaths = true; |
| 190 continue; | 256 continue; |
| 191 } | 257 } |
| 192 cacheBlob->fRuns[run].fDrawAsPaths = false; | 258 cacheBlob->fRuns[run].fDrawAsPaths = false; |
| 193 | 259 |
| 194 switch (it.positioning()) { | 260 switch (it.positioning()) { |
| 195 case SkTextBlob::kDefault_Positioning: | 261 case SkTextBlob::kDefault_Positioning: |
| 196 this->internalDrawText(cacheBlob, run, cache, runPaint, viewMatr ix, | 262 this->internalDrawText(cacheBlob, run, cache, runPaint, viewMatr ix, |
| 197 (const char *)it.glyphs(), textLen, | 263 (const char *)it.glyphs(), textLen, |
| 198 x + offset.x(), y + offset.y(), clipRect) ; | 264 x + offset.x(), y + offset.y(), clipRect) ; |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 529 return; | 595 return; |
| 530 } | 596 } |
| 531 | 597 |
| 532 int x = vx + glyph->fBounds.fLeft; | 598 int x = vx + glyph->fBounds.fLeft; |
| 533 int y = vy + glyph->fBounds.fTop; | 599 int y = vy + glyph->fBounds.fTop; |
| 534 | 600 |
| 535 // keep them as ints until we've done the clip-test | 601 // keep them as ints until we've done the clip-test |
| 536 int width = glyph->fBounds.width(); | 602 int width = glyph->fBounds.width(); |
| 537 int height = glyph->fBounds.height(); | 603 int height = glyph->fBounds.height(); |
| 538 | 604 |
| 539 // check if we clipped out | |
| 540 if (clipRect.quickReject(x, y, x + width, y + height)) { | |
| 541 return; | |
| 542 } | |
| 543 | |
| 544 // If the glyph is too large we fall back to paths | 605 // If the glyph is too large we fall back to paths |
| 545 if (fCurrStrike->glyphTooLargeForAtlas(glyph)) { | 606 if (fCurrStrike->glyphTooLargeForAtlas(glyph)) { |
| 546 if (NULL == glyph->fPath) { | 607 if (NULL == glyph->fPath) { |
| 547 SkPath* path = SkNEW(SkPath); | 608 SkPath* path = SkNEW(SkPath); |
| 548 if (!scaler->getGlyphPath(glyph->glyphID(), path)) { | 609 if (!scaler->getGlyphPath(glyph->glyphID(), path)) { |
| 549 // flag the glyph as being dead? | 610 // flag the glyph as being dead? |
| 550 SkDELETE(path); | 611 SkDELETE(path); |
| 551 return; | 612 return; |
| 552 } | 613 } |
| 553 glyph->fPath = path; | 614 glyph->fPath = path; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 591 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVert exEndIndex); | 652 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVert exEndIndex); |
| 592 | 653 |
| 593 // V0 | 654 // V0 |
| 594 SkPoint* position = reinterpret_cast<SkPoint*>(vertex); | 655 SkPoint* position = reinterpret_cast<SkPoint*>(vertex); |
| 595 position->set(r.fLeft, r.fTop); | 656 position->set(r.fLeft, r.fTop); |
| 596 if (kA8_GrMaskFormat == format) { | 657 if (kA8_GrMaskFormat == format) { |
| 597 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; | 658 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; |
| 598 *colorPtr = color; | 659 *colorPtr = color; |
| 599 } | 660 } |
| 600 vertex += vertexStride; | 661 vertex += vertexStride; |
| 601 | |
| 602 // V1 | 662 // V1 |
| 603 position = reinterpret_cast<SkPoint*>(vertex); | 663 position = reinterpret_cast<SkPoint*>(vertex); |
| 604 position->set(r.fLeft, r.fBottom); | 664 position->set(r.fLeft, r.fBottom); |
| 605 if (kA8_GrMaskFormat == format) { | 665 if (kA8_GrMaskFormat == format) { |
| 606 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; | 666 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; |
| 607 *colorPtr = color; | 667 *colorPtr = color; |
| 608 } | 668 } |
| 609 vertex += vertexStride; | 669 vertex += vertexStride; |
| 610 | 670 |
| 611 // V2 | 671 // V2 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 633 public: | 693 public: |
| 634 typedef GrAtlasTextContext::BitmapTextBlob Blob; | 694 typedef GrAtlasTextContext::BitmapTextBlob Blob; |
| 635 typedef Blob::Run Run; | 695 typedef Blob::Run Run; |
| 636 typedef Run::SubRunInfo TextInfo; | 696 typedef Run::SubRunInfo TextInfo; |
| 637 struct Geometry { | 697 struct Geometry { |
| 638 Geometry() {} | 698 Geometry() {} |
| 639 Geometry(const Geometry& geometry) | 699 Geometry(const Geometry& geometry) |
| 640 : fBlob(SkRef(geometry.fBlob.get())) | 700 : fBlob(SkRef(geometry.fBlob.get())) |
| 641 , fRun(geometry.fRun) | 701 , fRun(geometry.fRun) |
| 642 , fSubRun(geometry.fSubRun) | 702 , fSubRun(geometry.fSubRun) |
| 643 , fColor(geometry.fColor) {} | 703 , fColor(geometry.fColor) |
| 704 , fTransX(geometry.fTransX) | |
| 705 , fTransY(geometry.fTransY) {} | |
| 644 SkAutoTUnref<Blob> fBlob; | 706 SkAutoTUnref<Blob> fBlob; |
| 645 int fRun; | 707 int fRun; |
| 646 int fSubRun; | 708 int fSubRun; |
| 647 GrColor fColor; | 709 GrColor fColor; |
| 710 SkScalar fTransX; | |
| 711 SkScalar fTransY; | |
| 648 }; | 712 }; |
| 649 | 713 |
| 650 static GrBatch* Create(const Geometry& geometry, GrMaskFormat maskFormat, | 714 static GrBatch* Create(const Geometry& geometry, GrMaskFormat maskFormat, |
| 651 int glyphCount, GrBatchFontCache* fontCache) { | 715 int glyphCount, GrBatchFontCache* fontCache) { |
| 652 return SkNEW_ARGS(BitmapTextBatch, (geometry, maskFormat, glyphCount, fo ntCache)); | 716 return SkNEW_ARGS(BitmapTextBatch, (geometry, maskFormat, glyphCount, fo ntCache)); |
| 653 } | 717 } |
| 654 | 718 |
| 655 const char* name() const override { return "BitmapTextBatch"; } | 719 const char* name() const override { return "BitmapTextBatch"; } |
| 656 | 720 |
| 657 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { | 721 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 751 int instancesToFlush = 0; | 815 int instancesToFlush = 0; |
| 752 for (int i = 0; i < instanceCount; i++) { | 816 for (int i = 0; i < instanceCount; i++) { |
| 753 Geometry& args = fGeoData[i]; | 817 Geometry& args = fGeoData[i]; |
| 754 Blob* blob = args.fBlob; | 818 Blob* blob = args.fBlob; |
| 755 Run& run = blob->fRuns[args.fRun]; | 819 Run& run = blob->fRuns[args.fRun]; |
| 756 TextInfo& info = run.fSubRunInfo[args.fSubRun]; | 820 TextInfo& info = run.fSubRunInfo[args.fSubRun]; |
| 757 | 821 |
| 758 uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat); | 822 uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat); |
| 759 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlas Gen; | 823 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlas Gen; |
| 760 bool regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColo r != args.fColor; | 824 bool regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColo r != args.fColor; |
| 825 bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0. f; | |
| 761 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; | 826 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; |
| 762 | 827 |
| 763 // We regenerate both texture coords and colors in the blob itself, and update the | 828 // We regenerate both texture coords and colors in the blob itself, and update the |
| 764 // atlas generation. If we don't end up purging any unused plots, w e can avoid | 829 // atlas generation. If we don't end up purging any unused plots, w e can avoid |
| 765 // regenerating the coords. We could take a finer grained approach to updating texture | 830 // regenerating the coords. We could take a finer grained approach to updating texture |
| 766 // coords but its not clear if the extra bookkeeping would offset an y gains. | 831 // coords but its not clear if the extra bookkeeping would offset an y gains. |
| 767 // To avoid looping over the glyphs twice, we do one loop and condit ionally update color | 832 // To avoid looping over the glyphs twice, we do one loop and condit ionally update color |
| 768 // or coords as needed. One final note, if we have to break a run f or an atlas eviction | 833 // or coords as needed. One final note, if we have to break a run f or an atlas eviction |
| 769 // then we can't really trust the atlas has all of the correct data. Atlas evictions | 834 // then we can't really trust the atlas has all of the correct data. Atlas evictions |
| 770 // should be pretty rare, so we just always regenerate in those case s | 835 // should be pretty rare, so we just always regenerate in those case s |
| 771 if (regenerateTextureCoords || regenerateColors) { | 836 if (regenerateTextureCoords || regenerateColors || regeneratePositio ns) { |
| 772 // first regenerate texture coordinates / colors if need be | 837 // first regenerate texture coordinates / colors if need be |
| 773 const SkDescriptor* desc = NULL; | 838 const SkDescriptor* desc = NULL; |
| 774 SkGlyphCache* cache = NULL; | 839 SkGlyphCache* cache = NULL; |
| 775 GrFontScaler* scaler = NULL; | 840 GrFontScaler* scaler = NULL; |
| 776 GrBatchTextStrike* strike = NULL; | 841 GrBatchTextStrike* strike = NULL; |
| 777 bool brokenRun = false; | 842 bool brokenRun = false; |
| 778 if (regenerateTextureCoords) { | 843 if (regenerateTextureCoords) { |
| 779 info.fBulkUseToken.reset(); | 844 info.fBulkUseToken.reset(); |
| 780 desc = run.fDescriptor.getDesc(); | 845 desc = run.fDescriptor.getDesc(); |
| 781 cache = SkGlyphCache::DetachCache(run.fTypeface, desc); | 846 cache = SkGlyphCache::DetachCache(run.fTypeface, desc); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 815 this->regenerateTextureCoords(glyph, vertex, vertexStrid e); | 880 this->regenerateTextureCoords(glyph, vertex, vertexStrid e); |
| 816 } | 881 } |
| 817 | 882 |
| 818 if (regenerateColors) { | 883 if (regenerateColors) { |
| 819 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVert ices); | 884 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVert ices); |
| 820 vertex += info.fVertexStartIndex; | 885 vertex += info.fVertexStartIndex; |
| 821 vertex += vertexStride * glyphIdx * kVerticesPerGlyph + sizeof(SkPoint); | 886 vertex += vertexStride * glyphIdx * kVerticesPerGlyph + sizeof(SkPoint); |
| 822 this->regenerateColors(vertex, vertexStride, args.fColor ); | 887 this->regenerateColors(vertex, vertexStride, args.fColor ); |
| 823 } | 888 } |
| 824 | 889 |
| 890 if (regeneratePositions) { | |
| 891 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVert ices); | |
| 892 vertex += info.fVertexStartIndex; | |
| 893 vertex += vertexStride * glyphIdx * kVerticesPerGlyph; | |
| 894 SkScalar transX = args.fTransX; | |
| 895 SkScalar transY = args.fTransY; | |
| 896 this->regeneratePositions(vertex, vertexStride, transX, transY); | |
| 897 } | |
| 825 instancesToFlush++; | 898 instancesToFlush++; |
| 826 } | 899 } |
| 827 | 900 |
| 901 // We my have changed the color so update it here | |
| 902 run.fColor = args.fColor; | |
| 828 if (regenerateTextureCoords) { | 903 if (regenerateTextureCoords) { |
| 829 SkGlyphCache::AttachCache(cache); | 904 SkGlyphCache::AttachCache(cache); |
| 830 info.fAtlasGeneration = brokenRun ? GrBatchAtlas::kInvalidAt lasGeneration : | 905 info.fAtlasGeneration = brokenRun ? GrBatchAtlas::kInvalidAt lasGeneration : |
| 831 fFontCache->atlasGenerat ion(fMaskFormat); | 906 fFontCache->atlasGenerat ion(fMaskFormat); |
| 832 } | 907 } |
| 833 } else { | 908 } else { |
| 834 instancesToFlush += glyphCount; | 909 instancesToFlush += glyphCount; |
| 835 | 910 |
| 836 // set use tokens for all of the glyphs in our subrun. This is only valid if we | 911 // set use tokens for all of the glyphs in our subrun. This is only valid if we |
| 837 // have a valid atlas generation | 912 // have a valid atlas generation |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 897 } | 972 } |
| 898 | 973 |
| 899 void regenerateColors(intptr_t vertex, size_t vertexStride, GrColor color) { | 974 void regenerateColors(intptr_t vertex, size_t vertexStride, GrColor color) { |
| 900 for (int i = 0; i < kVerticesPerGlyph; i++) { | 975 for (int i = 0; i < kVerticesPerGlyph; i++) { |
| 901 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex); | 976 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex); |
| 902 *vcolor = color; | 977 *vcolor = color; |
| 903 vertex += vertexStride; | 978 vertex += vertexStride; |
| 904 } | 979 } |
| 905 } | 980 } |
| 906 | 981 |
| 982 void regeneratePositions(intptr_t vertex, size_t vertexStride, SkScalar tran sX, | |
| 983 SkScalar transY) { | |
| 984 for (int i = 0; i < kVerticesPerGlyph; i++) { | |
| 985 SkPoint* point = reinterpret_cast<SkPoint*>(vertex); | |
| 986 point->fX += transX; | |
| 987 point->fY += transY; | |
| 988 vertex += vertexStride; | |
| 989 } | |
| 990 } | |
| 991 | |
| 907 void initDraw(GrBatchTarget* batchTarget, | 992 void initDraw(GrBatchTarget* batchTarget, |
| 908 const GrGeometryProcessor* gp, | 993 const GrGeometryProcessor* gp, |
| 909 const GrPipeline* pipeline) { | 994 const GrPipeline* pipeline) { |
| 910 batchTarget->initDraw(gp, pipeline); | 995 batchTarget->initDraw(gp, pipeline); |
| 911 | 996 |
| 912 // TODO remove this when batch is everywhere | 997 // TODO remove this when batch is everywhere |
| 913 GrPipelineInfo init; | 998 GrPipelineInfo init; |
| 914 init.fColorIgnored = fBatch.fColorIgnored; | 999 init.fColorIgnored = fBatch.fColorIgnored; |
| 915 init.fOverrideColor = GrColor_ILLEGAL; | 1000 init.fOverrideColor = GrColor_ILLEGAL; |
| 916 init.fCoverageIgnored = fBatch.fCoverageIgnored; | 1001 init.fCoverageIgnored = fBatch.fCoverageIgnored; |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1003 break; | 1088 break; |
| 1004 case SkTextBlob::kFull_Positioning: | 1089 case SkTextBlob::kFull_Positioning: |
| 1005 this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs (), | 1090 this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs (), |
| 1006 textLen, it.pos(), 2, SkPoint::Make(x, y), c lipBounds); | 1091 textLen, it.pos(), 2, SkPoint::Make(x, y), c lipBounds); |
| 1007 break; | 1092 break; |
| 1008 } | 1093 } |
| 1009 } | 1094 } |
| 1010 | 1095 |
| 1011 inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder * pipelineBuilder, | 1096 inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder * pipelineBuilder, |
| 1012 BitmapTextBlob* cacheBlob, int run, GrC olor color, | 1097 BitmapTextBlob* cacheBlob, int run, GrC olor color, |
| 1013 uint8_t paintAlpha) { | 1098 uint8_t paintAlpha, SkScalar transX, Sk Scalar transY) { |
| 1014 for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); sub Run++) { | 1099 for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); sub Run++) { |
| 1015 const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun]; | 1100 const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun]; |
| 1016 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; | 1101 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; |
| 1017 if (0 == glyphCount) { | 1102 if (0 == glyphCount) { |
| 1018 continue; | 1103 continue; |
| 1019 } | 1104 } |
| 1020 | 1105 |
| 1021 GrMaskFormat format = info.fMaskFormat; | 1106 GrMaskFormat format = info.fMaskFormat; |
| 1022 GrColor subRunColor = kARGB_GrMaskFormat == format ? | 1107 GrColor subRunColor = kARGB_GrMaskFormat == format ? |
| 1023 SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha) : | 1108 SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha) : |
| 1024 color; | 1109 color; |
| 1025 | 1110 |
| 1026 BitmapTextBatch::Geometry geometry; | 1111 BitmapTextBatch::Geometry geometry; |
| 1027 geometry.fBlob.reset(SkRef(cacheBlob)); | 1112 geometry.fBlob.reset(SkRef(cacheBlob)); |
| 1028 geometry.fRun = run; | 1113 geometry.fRun = run; |
| 1029 geometry.fSubRun = subRun; | 1114 geometry.fSubRun = subRun; |
| 1030 geometry.fColor = subRunColor; | 1115 geometry.fColor = subRunColor; |
| 1116 geometry.fTransX = transX; | |
| 1117 geometry.fTransY = transY; | |
| 1031 SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, format, gl yphCount, | 1118 SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, format, gl yphCount, |
| 1032 fContext->getBatchFo ntCache())); | 1119 fContext->getBatchFo ntCache())); |
| 1033 | 1120 |
| 1034 target->drawBatch(pipelineBuilder, batch, &cacheBlob->fRuns[run].fVertex Bounds); | 1121 target->drawBatch(pipelineBuilder, batch, &cacheBlob->fRuns[run].fVertex Bounds); |
| 1035 } | 1122 } |
| 1036 } | 1123 } |
| 1037 | 1124 |
| 1038 inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRend erTarget* rt, | 1125 inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRend erTarget* rt, |
| 1039 const GrPaint& grPaint, const GrC lip& clip) { | 1126 const GrPaint& grPaint, const GrC lip& clip, |
| 1127 SkScalar transX, SkScalar transY) { | |
| 1040 for (int i = 0; i < cacheBlob->fBigGlyphs.count(); i++) { | 1128 for (int i = 0; i < cacheBlob->fBigGlyphs.count(); i++) { |
| 1041 const BitmapTextBlob::BigGlyph& bigGlyph = cacheBlob->fBigGlyphs[i]; | 1129 BitmapTextBlob::BigGlyph& bigGlyph = cacheBlob->fBigGlyphs[i]; |
| 1130 bigGlyph.fVx += transX; | |
| 1131 bigGlyph.fVy += transY; | |
| 1042 SkMatrix translate; | 1132 SkMatrix translate; |
| 1043 translate.setTranslate(SkIntToScalar(bigGlyph.fVx), SkIntToScalar(bigGly ph.fVy)); | 1133 translate.setTranslate(SkIntToScalar(bigGlyph.fVx), |
| 1134 SkIntToScalar(bigGlyph.fVy)); | |
| 1044 SkPath tmpPath(bigGlyph.fPath); | 1135 SkPath tmpPath(bigGlyph.fPath); |
| 1045 tmpPath.transform(translate); | 1136 tmpPath.transform(translate); |
| 1046 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle); | 1137 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle); |
| 1047 fContext->drawPath(rt, clip, grPaint, SkMatrix::I(), tmpPath, strokeInfo ); | 1138 fContext->drawPath(rt, clip, grPaint, SkMatrix::I(), tmpPath, strokeInfo ); |
| 1048 } | 1139 } |
| 1049 } | 1140 } |
| 1050 | 1141 |
| 1051 void GrAtlasTextContext::flush(GrDrawTarget* target, | 1142 void GrAtlasTextContext::flush(GrDrawTarget* target, |
| 1052 const SkTextBlob* blob, | 1143 const SkTextBlob* blob, |
| 1053 BitmapTextBlob* cacheBlob, | 1144 BitmapTextBlob* cacheBlob, |
| 1054 GrRenderTarget* rt, | 1145 GrRenderTarget* rt, |
| 1055 const SkPaint& skPaint, | 1146 const SkPaint& skPaint, |
| 1056 const GrPaint& grPaint, | 1147 const GrPaint& grPaint, |
| 1057 SkDrawFilter* drawFilter, | 1148 SkDrawFilter* drawFilter, |
| 1058 const GrClip& clip, | 1149 const GrClip& clip, |
| 1059 const SkMatrix& viewMatrix, | 1150 const SkMatrix& viewMatrix, |
| 1060 const SkIRect& clipBounds, | 1151 const SkIRect& clipBounds, |
| 1061 SkScalar x, | 1152 SkScalar x, SkScalar y, |
| 1062 SkScalar y) { | 1153 SkScalar transX, SkScalar transY) { |
| 1063 // We loop through the runs of the blob, flushing each. If any run is too l arge, then we flush | 1154 // We loop through the runs of the blob, flushing each. If any run is too l arge, then we flush |
| 1064 // it as paths | 1155 // it as paths |
| 1065 GrPipelineBuilder pipelineBuilder; | 1156 GrPipelineBuilder pipelineBuilder; |
| 1066 pipelineBuilder.setFromPaint(grPaint, rt, clip); | 1157 pipelineBuilder.setFromPaint(grPaint, rt, clip); |
| 1067 | 1158 |
| 1068 GrColor color = grPaint.getColor(); | 1159 GrColor color = grPaint.getColor(); |
| 1069 uint8_t paintAlpha = skPaint.getAlpha(); | 1160 uint8_t paintAlpha = skPaint.getAlpha(); |
| 1070 | 1161 |
| 1071 SkTextBlob::RunIterator it(blob); | 1162 SkTextBlob::RunIterator it(blob); |
| 1072 for (int run = 0; !it.done(); it.next(), run++) { | 1163 for (int run = 0; !it.done(); it.next(), run++) { |
| 1073 if (cacheBlob->fRuns[run].fDrawAsPaths) { | 1164 if (cacheBlob->fRuns[run].fDrawAsPaths) { |
| 1074 this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBound s, x, y); | 1165 this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBound s, x, y); |
| 1075 continue; | 1166 continue; |
| 1076 } | 1167 } |
| 1077 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp ha); | 1168 cacheBlob->fRuns[run].fVertexBounds.offset(transX, transY); |
| 1169 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp ha, transX, transY); | |
| 1078 } | 1170 } |
| 1079 | 1171 |
| 1080 // Now flush big glyphs | 1172 // Now flush big glyphs |
| 1081 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip); | 1173 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, transX, transY); |
| 1082 } | 1174 } |
| 1083 | 1175 |
| 1084 void GrAtlasTextContext::flush(GrDrawTarget* target, | 1176 void GrAtlasTextContext::flush(GrDrawTarget* target, |
| 1085 BitmapTextBlob* cacheBlob, | 1177 BitmapTextBlob* cacheBlob, |
| 1086 GrRenderTarget* rt, | 1178 GrRenderTarget* rt, |
| 1087 const SkPaint& skPaint, | 1179 const SkPaint& skPaint, |
| 1088 const GrPaint& grPaint, | 1180 const GrPaint& grPaint, |
| 1089 const GrClip& clip, | 1181 const GrClip& clip, |
| 1090 const SkMatrix& viewMatrix) { | 1182 const SkMatrix& viewMatrix) { |
| 1091 GrPipelineBuilder pipelineBuilder; | 1183 GrPipelineBuilder pipelineBuilder; |
| 1092 pipelineBuilder.setFromPaint(grPaint, rt, clip); | 1184 pipelineBuilder.setFromPaint(grPaint, rt, clip); |
| 1093 | 1185 |
| 1094 GrColor color = grPaint.getColor(); | 1186 GrColor color = grPaint.getColor(); |
| 1095 uint8_t paintAlpha = skPaint.getAlpha(); | 1187 uint8_t paintAlpha = skPaint.getAlpha(); |
| 1096 for (int run = 0; run < cacheBlob->fRunCount; run++) { | 1188 for (int run = 0; run < cacheBlob->fRunCount; run++) { |
| 1097 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp ha); | 1189 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp ha, 0, 0); |
| 1098 } | 1190 } |
| 1099 | 1191 |
| 1100 // Now flush big glyphs | 1192 // Now flush big glyphs |
| 1101 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip); | 1193 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0); |
| 1102 } | 1194 } |
| OLD | NEW |