Home | History | Annotate | Download | only in atlastext
      1 /*
      2  * Copyright 2017 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkAtlasTextTarget.h"
      9 
     10 #include "GrClip.h"
     11 #include "GrContextPriv.h"
     12 #include "GrDrawingManager.h"
     13 #include "GrMemoryPool.h"
     14 #include "SkAtlasTextContext.h"
     15 #include "SkAtlasTextFont.h"
     16 #include "SkAtlasTextRenderer.h"
     17 #include "SkGlyphRunPainter.h"
     18 #include "SkGr.h"
     19 #include "SkInternalAtlasTextContext.h"
     20 #include "ops/GrAtlasTextOp.h"
     21 #include "text/GrTextContext.h"
     22 
     23 static constexpr int kMaxBatchLookBack = 10;
     24 
     25 SkAtlasTextTarget::SkAtlasTextTarget(sk_sp<SkAtlasTextContext> context, int width, int height,
     26                                      void* handle)
     27         : fHandle(handle)
     28         , fContext(std::move(context))
     29         , fWidth(width)
     30         , fHeight(height)
     31         , fMatrixStack(sizeof(SkMatrix), 4)
     32         , fSaveCnt(0) {
     33     fMatrixStack.push_back();
     34     this->accessCTM()->reset();
     35 }
     36 
     37 SkAtlasTextTarget::~SkAtlasTextTarget() { fContext->renderer()->targetDeleted(fHandle); }
     38 
     39 int SkAtlasTextTarget::save() {
     40     const auto& currCTM = this->ctm();
     41     *static_cast<SkMatrix*>(fMatrixStack.push_back()) = currCTM;
     42     return fSaveCnt++;
     43 }
     44 
     45 void SkAtlasTextTarget::restore() {
     46     if (fSaveCnt) {
     47         fMatrixStack.pop_back();
     48         fSaveCnt--;
     49     }
     50 }
     51 
     52 void SkAtlasTextTarget::restoreToCount(int count) {
     53     while (fSaveCnt > count) {
     54         this->restore();
     55     }
     56 }
     57 
     58 void SkAtlasTextTarget::translate(SkScalar dx, SkScalar dy) {
     59     this->accessCTM()->preTranslate(dx, dy);
     60 }
     61 
     62 void SkAtlasTextTarget::scale(SkScalar sx, SkScalar sy) { this->accessCTM()->preScale(sx, sy); }
     63 
     64 void SkAtlasTextTarget::rotate(SkScalar degrees) { this->accessCTM()->preRotate(degrees); }
     65 
     66 void SkAtlasTextTarget::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
     67     this->accessCTM()->preRotate(degrees, px, py);
     68 }
     69 
     70 void SkAtlasTextTarget::skew(SkScalar sx, SkScalar sy) { this->accessCTM()->preSkew(sx, sy); }
     71 
     72 void SkAtlasTextTarget::concat(const SkMatrix& matrix) { this->accessCTM()->preConcat(matrix); }
     73 
     74 //////////////////////////////////////////////////////////////////////////////
     75 
     76 static const GrColorSpaceInfo kColorSpaceInfo(nullptr, kRGBA_8888_GrPixelConfig);
     77 static const SkSurfaceProps kProps(
     78         SkSurfaceProps::kUseDistanceFieldFonts_Flag, kUnknown_SkPixelGeometry);
     79 
     80 //////////////////////////////////////////////////////////////////////////////
     81 
     82 class SkInternalAtlasTextTarget : public GrTextTarget, public SkAtlasTextTarget {
     83 public:
     84     SkInternalAtlasTextTarget(sk_sp<SkAtlasTextContext> context,
     85                               int width, int height,
     86                               void* handle)
     87             : GrTextTarget(width, height, kColorSpaceInfo)
     88             , SkAtlasTextTarget(std::move(context), width, height, handle)
     89             , fGlyphPainter(kProps, kColorSpaceInfo) {
     90         fOpMemoryPool = fContext->internal().grContext()->priv().refOpMemoryPool();
     91     }
     92 
     93     ~SkInternalAtlasTextTarget() override {
     94         this->deleteOps();
     95     }
     96 
     97     /** GrTextTarget overrides */
     98 
     99     void addDrawOp(const GrClip&, std::unique_ptr<GrAtlasTextOp> op) override;
    100 
    101     void drawShape(const GrClip&, const SkPaint&, const SkMatrix& viewMatrix,
    102                    const GrShape&) override {
    103         SkDebugf("Path glyph??");
    104     }
    105 
    106     void makeGrPaint(GrMaskFormat, const SkPaint& skPaint, const SkMatrix&,
    107                      GrPaint* grPaint) override {
    108         grPaint->setColor4f(skPaint.getColor4f().premul());
    109     }
    110 
    111     GrContext* getContext() override {
    112         return this->context()->internal().grContext();
    113     }
    114 
    115     SkGlyphRunListPainter* glyphPainter() override {
    116         return &fGlyphPainter;
    117     }
    118 
    119     /** SkAtlasTextTarget overrides */
    120 
    121     void drawText(const SkGlyphID[], const SkPoint[], int glyphCnt, uint32_t color,
    122                   const SkAtlasTextFont&) override;
    123     void flush() override;
    124 
    125 private:
    126     void deleteOps();
    127 
    128     uint32_t fColor;
    129     using SkAtlasTextTarget::fWidth;
    130     using SkAtlasTextTarget::fHeight;
    131     SkTArray<std::unique_ptr<GrAtlasTextOp>, true> fOps;
    132     sk_sp<GrOpMemoryPool> fOpMemoryPool;
    133     SkGlyphRunListPainter fGlyphPainter;
    134 };
    135 
    136 //////////////////////////////////////////////////////////////////////////////
    137 
    138 std::unique_ptr<SkAtlasTextTarget> SkAtlasTextTarget::Make(sk_sp<SkAtlasTextContext> context,
    139                                                            int width, int height, void* handle) {
    140     return std::unique_ptr<SkAtlasTextTarget>(
    141             new SkInternalAtlasTextTarget(std::move(context), width, height, handle));
    142 }
    143 
    144 //////////////////////////////////////////////////////////////////////////////
    145 
    146 void SkInternalAtlasTextTarget::drawText(const SkGlyphID glyphs[], const SkPoint positions[],
    147                                          int glyphCnt, uint32_t color,
    148                                          const SkAtlasTextFont& font) {
    149     SkPaint paint;
    150     paint.setAntiAlias(true);
    151 
    152     // The atlas text context does munging of the paint color. We store the client's color here
    153     // and then overwrite the generated op's color when addDrawOp() is called.
    154     fColor = color;
    155 
    156     SkSurfaceProps props(SkSurfaceProps::kUseDistanceFieldFonts_Flag, kUnknown_SkPixelGeometry);
    157     auto grContext = this->context()->internal().grContext();
    158     auto atlasTextContext = grContext->priv().drawingManager()->getTextContext();
    159     SkGlyphRunBuilder builder;
    160     builder.drawGlyphsWithPositions(paint, font.makeFont(),
    161                                     SkSpan<const SkGlyphID>{glyphs, SkTo<size_t>(glyphCnt)},
    162                                     positions);
    163     auto glyphRunList = builder.useGlyphRunList();
    164     if (!glyphRunList.empty()) {
    165         atlasTextContext->drawGlyphRunList(grContext, this, GrNoClip(), this->ctm(), props,
    166                                            glyphRunList);
    167     }
    168 }
    169 
    170 void SkInternalAtlasTextTarget::addDrawOp(const GrClip& clip, std::unique_ptr<GrAtlasTextOp> op) {
    171     SkASSERT(clip.quickContains(SkRect::MakeIWH(fWidth, fHeight)));
    172     // The SkAtlasTextRenderer currently only handles grayscale SDF glyphs.
    173     if (op->maskType() != GrAtlasTextOp::kGrayscaleDistanceField_MaskType) {
    174         return;
    175     }
    176     const GrCaps& caps = *this->context()->internal().grContext()->priv().caps();
    177     op->finalizeForTextTarget(fColor, caps);
    178     int n = SkTMin(kMaxBatchLookBack, fOps.count());
    179     for (int i = 0; i < n; ++i) {
    180         GrAtlasTextOp* other = fOps.fromBack(i).get();
    181         if (other->combineIfPossible(op.get(), caps) == GrOp::CombineResult::kMerged) {
    182             fOpMemoryPool->release(std::move(op));
    183             return;
    184         }
    185         if (GrRectsOverlap(op->bounds(), other->bounds())) {
    186             break;
    187         }
    188     }
    189     fOps.emplace_back(std::move(op));
    190 }
    191 
    192 void SkInternalAtlasTextTarget::deleteOps() {
    193     for (int i = 0; i < fOps.count(); ++i) {
    194         if (fOps[i]) {
    195             fOpMemoryPool->release(std::move(fOps[i]));
    196         }
    197     }
    198     fOps.reset();
    199 }
    200 
    201 void SkInternalAtlasTextTarget::flush() {
    202     for (int i = 0; i < fOps.count(); ++i) {
    203         fOps[i]->executeForTextTarget(this);
    204     }
    205     this->context()->internal().flush();
    206     this->deleteOps();
    207 }
    208 
    209 void GrAtlasTextOp::finalizeForTextTarget(uint32_t color, const GrCaps& caps) {
    210     // TODO4F: Odd handling of client colors among AtlasTextTarget and AtlasTextRenderer
    211     SkPMColor4f color4f = SkPMColor4f::FromBytes_RGBA(color);
    212     for (int i = 0; i < fGeoCount; ++i) {
    213         fGeoData[i].fColor = color4f;
    214     }
    215     // Atlas text doesn't use MSAA, so no need to handle a GrFSAAType.
    216     // Also, no need to support normalized F16 with manual clamp?
    217     this->finalize(caps, nullptr /* applied clip */, GrFSAAType::kNone, GrClampType::kAuto);
    218 }
    219 
    220 void GrAtlasTextOp::executeForTextTarget(SkAtlasTextTarget* target) {
    221     FlushInfo flushInfo;
    222     SkExclusiveStrikePtr autoGlyphCache;
    223     auto& context = target->context()->internal();
    224     auto glyphCache = context.grContext()->priv().getGrStrikeCache();
    225     auto atlasManager = context.grContext()->priv().getAtlasManager();
    226     auto resourceProvider = context.grContext()->priv().resourceProvider();
    227 
    228     unsigned int numProxies;
    229     if (!atlasManager->getProxies(kA8_GrMaskFormat, &numProxies)) {
    230         return;
    231     }
    232 
    233     for (int i = 0; i < fGeoCount; ++i) {
    234         // TODO4F: Preserve float colors
    235         GrTextBlob::VertexRegenerator regenerator(
    236                 resourceProvider, fGeoData[i].fBlob, fGeoData[i].fRun, fGeoData[i].fSubRun,
    237                 fGeoData[i].fViewMatrix, fGeoData[i].fX, fGeoData[i].fY,
    238                 fGeoData[i].fColor.toBytes_RGBA(), &context, glyphCache, atlasManager,
    239                 &autoGlyphCache);
    240         bool done = false;
    241         while (!done) {
    242             GrTextBlob::VertexRegenerator::Result result;
    243             if (!regenerator.regenerate(&result)) {
    244                 break;
    245             }
    246             done = result.fFinished;
    247 
    248             context.recordDraw(result.fFirstVertex, result.fGlyphsRegenerated,
    249                                fGeoData[i].fViewMatrix, target->handle());
    250             if (!result.fFinished) {
    251                 // Make space in the atlas so we can continue generating vertices.
    252                 context.flush();
    253             }
    254         }
    255     }
    256 }
    257