Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(110)

Unified Diff: src/core/SkDraw.cpp

Issue 1420973005: Refactor glyph selection and positioning (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: clean up Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/core/SkDraw.cpp
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index d8d6fcf57fe123b7926eae12b668114c600e94dc..f884d3bf3e5c4e8df8cd730f8ca3ce6444201b56 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -14,6 +14,7 @@
#include "SkDeviceLooper.h"
#include "SkFixed.h"
#include "SkMaskFilter.h"
+#include "SkMatrix.h"
#include "SkPaint.h"
#include "SkPathEffect.h"
#include "SkRasterClip.h"
@@ -25,8 +26,10 @@
#include "SkString.h"
#include "SkStroke.h"
#include "SkStrokeRec.h"
+#include "SkTemplates.h"
#include "SkTextMapStateProc.h"
#include "SkTLazy.h"
+#include "SkUtility.h"
#include "SkUtils.h"
#include "SkVertState.h"
@@ -1439,7 +1442,7 @@ void SkDraw::drawText_asPaths(const char text[], size_t byteLength,
#pragma warning ( disable : 4701 )
#endif
-//////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////
static void D1G_RectClip(const SkDraw1Glyph& state, Sk48Dot16 fx, Sk48Dot16 fy, const SkGlyph& glyph) {
// Prevent glyphs from being drawn outside of or straddling the edge of device space.
@@ -1726,6 +1729,491 @@ void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength,
}
}
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Calculate a type with the same size as the max of all the Ts.
+template <typename... Ts> struct MaxSizeOf;
+
+template <> struct MaxSizeOf<> { static const size_t value = 0; };
+
+template <typename H, typename... Ts> struct MaxSizeOf<H, Ts...> {
+ static const size_t value =
+ sizeof(H) >= MaxSizeOf<Ts...>::value ? sizeof(H) : MaxSizeOf<Ts...>::value;
+};
+
+// UntaggedVariant is a pile of memory that can hold one of the Ts. It provides a way
+// to initialize that memory in a typesafe way.
+template <typename... Ts>
+class UntaggedVariant {
+public:
+ UntaggedVariant() {}
+ ~UntaggedVariant() {}
+ UntaggedVariant(const UntaggedVariant&) = delete;
+ UntaggedVariant& operator=(const UntaggedVariant&) = delete;
+ UntaggedVariant(UntaggedVariant&&) = delete;
+ UntaggedVariant& operator=(UntaggedVariant&&) = delete;
+
+ template <typename Variant, typename... Args>
+ void initialize(Args &&... args) {
+ SkASSERT(sizeof(Variant) <= sizeof(fSpace));
+ #if defined(_MSC_VER) && _MSC_VER < 1900
+ #define alignof __alignof
+ #endif
+ SkASSERT(alignof(Variant) <= alignof(Space));
+ new (&fSpace) Variant(skstd::forward<Args>(args)...);
+ }
+
+private:
+ typedef SkAlignedSStorage<MaxSizeOf<Ts...>::value> Space;
+ Space fSpace;
+};
+
+// PolymorphicVariant holds subclasses of Base without slicing. Ts must be subclasses of Base.
+template <typename Base, typename... Ts>
+class PolymorphicVariant {
+public:
+ typedef UntaggedVariant<Ts...> Variants;
+ template <typename Initializer>
+ PolymorphicVariant(Initializer&& initializer) {
+ initializer(&fVariants);
+ }
+ ~PolymorphicVariant() { get()->~Base(); }
+ Base* get() const { return reinterpret_cast<Base*>(&fVariants); }
+ Base* operator->() const { return get(); }
+ Base& operator*() const { return *get(); }
+
+private:
+ mutable Variants fVariants;
+};
+
+// PositionReaderInterface reads a point from the pos vector.
+// * HorizontalPositions - assumes a common Y for many X values.
+// * ArbitraryPositions - a list of (X,Y) pairs.
+class PositionReaderInterface : SkNoncopyable {
+public:
+ virtual ~PositionReaderInterface() { }
+ virtual SkPoint nextPoint() = 0;
+};
+
+class HorizontalPositions final : public PositionReaderInterface {
+public:
+ HorizontalPositions(const SkScalar* positions)
+ : fPositions(positions) { }
+
+ SkPoint nextPoint() override {
+ SkScalar x = *fPositions++;
+ return {x, 0};
+ }
+private:
+ const SkScalar* fPositions;
+};
+
+class ArbitraryPositions final : public PositionReaderInterface {
+public:
+ ArbitraryPositions(const SkScalar* positions)
+ : fPositions(positions) { }
+ SkPoint nextPoint() override {
+ SkPoint to_return {fPositions[0], fPositions[1]};
+ fPositions += 2;
+ return to_return;
+ }
+
+private:
+ const SkScalar* fPositions;
+};
+
+typedef PolymorphicVariant<PositionReaderInterface, HorizontalPositions, ArbitraryPositions>
+ PositionReader;
+
+// MapperInterface given a point map it through the matrix. There are several shortcut variants.
+// * TranslationMapper - assumes a translation only matrix.
+// * XScaleMapper - assumes an X scaling and a translation.
+// * GeneralMapper - Does all other matricies.
+class MapperInterface : SkNoncopyable {
+public:
+ virtual ~MapperInterface() {}
+ virtual SkPoint map(SkPoint position) const = 0;
+};
+
+class TranslationMapper final : public MapperInterface {
+public:
+ TranslationMapper(const SkMatrix& matrix, const SkPoint origin)
+ : fTranslate(matrix.mapXY(origin.fX, origin.fY)) { }
+ SkPoint map(SkPoint position) const override {
+ return position + fTranslate;
+ }
+
+private:
+ const SkPoint fTranslate;
+};
+
+class XScaleMapper final : public MapperInterface {
+public:
+ XScaleMapper(const SkMatrix& matrix, const SkPoint origin)
+ : fTranslate(matrix.mapXY(origin.fX, origin.fY))
+ , fXScale(matrix.getScaleX()) { }
+ SkPoint map(SkPoint position) const override {
+ return {fXScale * position.fX + fTranslate.fX, fTranslate.fY};
+ }
+
+private:
+ const SkPoint fTranslate;
+ const SkScalar fXScale;
+};
+
+// The caller must keep matrix alive while this class is used.
+class GeneralMapper final : public MapperInterface {
+public:
+ GeneralMapper(const SkMatrix& matrix, const SkPoint origin)
+ : fOrigin(origin)
+ , fMatrix(matrix)
+ , fMapProc(matrix.getMapXYProc()) { }
+ SkPoint map(SkPoint position) const override {
+ SkPoint result;
+ fMapProc(fMatrix, position.fX + fOrigin.fX, position.fY + fOrigin.fY, &result);
+ return result;
+ }
+
+private:
+ const SkPoint fOrigin;
+ const SkMatrix& fMatrix;
+ const SkMatrix::MapXYProc fMapProc;
+};
+
+typedef PolymorphicVariant<MapperInterface, TranslationMapper, XScaleMapper, GeneralMapper> Mapper;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Text alignment handles shifting the glyph based on its width.
+static SkPoint text_alignment_adjustment(SkPaint::Align textAlignment, const SkGlyph& glyph) {
+ switch (textAlignment) {
+ case SkPaint::kLeft_Align:
+ return {0.0f, 0.0f};
+ break;
+ case SkPaint::kCenter_Align:
+ return {SkFixedToScalar(glyph.fAdvanceX >> 1),
+ SkFixedToScalar(glyph.fAdvanceY >> 1)};
+ break;
+ case SkPaint::kRight_Align:
+ return {SkFixedToScalar(glyph.fAdvanceX),
+ SkFixedToScalar(glyph.fAdvanceY)};
+ break;
+ }
+ // Even though the entire enum is covered above, MVSC doesn't think so. Make it happy.
+ SkFAIL("Should never get here.");
+ return {0.0f, 0.0f};
+}
+
+// The "call" to SkFixedToScalar is actually a macro. It's macros all the way down.
+static const SkScalar kSubpixelRounding = SkFixedToScalar(SkGlyph::kSubpixelRound);
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Functions for handling sub-pixel aligned positions.
+// The subpixel_position_rounding function returns a point suitable for rounding a sub-pixel
+// positioned glyph.
+static SkPoint subpixel_position_rounding(SkAxisAlignment axisAlignment) {
+ switch (axisAlignment) {
+ case kX_SkAxisAlignment:
+ return {SkFixedToScalar(SkGlyph::kSubpixelRound), SK_ScalarHalf};
+ case kY_SkAxisAlignment:
+ return {SK_ScalarHalf, kSubpixelRounding};
+ case kNone_SkAxisAlignment:
+ return {kSubpixelRounding, kSubpixelRounding};
+ }
+ SkFAIL("Should not get here.");
+ return {0.0f, 0.0f};
+}
+
+// The subpixel_position_alignment function produces a suitable position for the glyph cache to
+// produce the correct sub-pixel alignment. If a position is aligned with an axis a shortcut of 0
+// is used for the sub-pixel position.
+static SkIPoint subpixel_position_alignment(SkAxisAlignment axisAlignment, SkPoint position) {
+ switch (axisAlignment) {
+ case kX_SkAxisAlignment:
+ return {SkScalarToFixed(position.fX + kSubpixelRounding), 0};
+ case kY_SkAxisAlignment:
+ return {0, SkScalarToFixed(position.fY + kSubpixelRounding)};
+ case kNone_SkAxisAlignment:
+ return {SkScalarToFixed(position.fX + kSubpixelRounding),
+ SkScalarToFixed(position.fY + kSubpixelRounding)};
+ }
+ SkFAIL("Should not get here.");
+ return {0, 0};
+}
+
+// GlyphFindAndPlaceInterface given the text and position finds the correct glyph and does glyph
+// specific position adjustment. The findAndPositionGlyph method takes text and position and calls
+// processOneGlyph with the correct glyph, final position and rounding terms. The final position
+// is not rounded yet and is the responsibility of processOneGlyph.
+template <typename ProcessOneGlyph>
+class GlyphFindAndPlaceInterface : SkNoncopyable {
+public:
+ struct Result {
+ const SkGlyph* fGlyph;
+ Sk48Dot16 fX;
+ Sk48Dot16 fY;
+ };
+ virtual ~GlyphFindAndPlaceInterface() { };
+ // This should be a pure virtual, but some versions of GCC <= 4.8 have a bug that causes a
+ // compile error.
+ // See GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60277
+ virtual void findAndPositionGlyph(const char** text, SkPoint position,
+ ProcessOneGlyph&& processOneGlyph) {};
+};
+
+// GlyphFindAndPlaceForSubpixel handles finding and placing glyphs when sub-pixel positioning is
+// requested. After it has found and placed the glyph it calls the templated function
+// ProcessOneGlyph in order to actually perform an action.
+template <typename ProcessOneGlyph, SkPaint::Align kTextAlignment, SkAxisAlignment kAxisAlignment>
+class GlyphFindAndPlaceForSubpixel final : public GlyphFindAndPlaceInterface<ProcessOneGlyph> {
+public:
+ GlyphFindAndPlaceForSubpixel(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc)
+ : fCache(cache)
+ , fGlyphCacheProc(glyphCacheProc) {
+ }
+ void findAndPositionGlyph(const char** text, SkPoint position,
+ ProcessOneGlyph&& processOneGlyph) override {
+ SkPoint finalPosition = position;
+ if (kTextAlignment != SkPaint::kLeft_Align) {
+ // Get the width of an un-sub-pixel positioned glyph for calculating the alignment.
+ // This is not needed for kLeftAlign because its adjustment is always {0, 0}.
+ const char* tempText = *text;
+ const SkGlyph& metricGlyph = fGlyphCacheProc(fCache, &tempText, 0, 0);
+
+ if (metricGlyph.fWidth <= 0) {
+ return;
+ }
+
+ // Adjust the final position by the alignment adjustment.
+ finalPosition -= text_alignment_adjustment(kTextAlignment, metricGlyph);
+ }
+
+ // Find the glyph.
+ SkIPoint lookupPosition = subpixel_position_alignment(kAxisAlignment, finalPosition);
+ const SkGlyph& renderGlyph = fGlyphCacheProc(
+ fCache, text, lookupPosition.fX, lookupPosition.fY);
+
+ // If the glyph has no width (no pixels) then don't bother processing it.
+ if (renderGlyph.fWidth > 0) {
+ processOneGlyph(renderGlyph, finalPosition, subpixel_position_rounding(kAxisAlignment));
+ }
+ }
+
+private:
+ SkGlyphCache* const fCache;
+ SkDrawCacheProc fGlyphCacheProc;
+};
+
+// GlyphFindAndPlaceForFullPixel handles finding and placing glyphs when no sub-pixel positioning
+// is requested.
+template <typename ProcessOneGlyph, SkPaint::Align kTextAlignment>
+class GlyphFindAndPlaceForFullPixel final : public GlyphFindAndPlaceInterface<ProcessOneGlyph> {
+public:
+ GlyphFindAndPlaceForFullPixel(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc)
+ : fCache(cache)
+ , fGlyphCacheProc(glyphCacheProc) { }
+ void findAndPositionGlyph(const char** text, SkPoint position,
+ ProcessOneGlyph&& processOneGlyph) override {
+ SkPoint finalPosition = position;
+ const SkGlyph& glyph = fGlyphCacheProc(fCache, text, 0, 0);
+ if (glyph.fWidth <= 0) {
+ return;
+ }
+ finalPosition -= text_alignment_adjustment(kTextAlignment, glyph);
+ processOneGlyph(glyph, finalPosition, {SK_ScalarHalf, SK_ScalarHalf});
+ }
+
+private:
+ SkGlyphCache* const fCache;
+ SkDrawCacheProc fGlyphCacheProc;
+};
+
+// GlyphFindAndPlace is a large variant that encapsulates the multiple types of finding and
+// placing a glyph. There are three factors that go into the different factors.
+// * Is sub-pixel positioned - a boolean that says whether to use sub-pixel positioning.
+// * Text alignment - indicates if the glyph should be placed to the right, centered or left of a
+// given position.
+// * Axis alignment - indicates if the glyphs final sub-pixel position should be rounded to a
+// whole pixel if the glyph is aligned with an axis. This is only used for sub-pixel positioning
+// and allows the baseline to look crisp.
+template <typename ProcessOneGlyph>
+using GlyphFindAndPlace =
+ PolymorphicVariant<
+ GlyphFindAndPlaceInterface<ProcessOneGlyph>,
+ // Subpixel
+ GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align, kNone_SkAxisAlignment>,
+ GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align, kX_SkAxisAlignment >,
+ GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align, kY_SkAxisAlignment >,
+ GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align, kNone_SkAxisAlignment>,
+ GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align, kX_SkAxisAlignment >,
+ GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kCenter_Align, kY_SkAxisAlignment >,
+ GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kRight_Align, kNone_SkAxisAlignment>,
+ GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kRight_Align, kX_SkAxisAlignment >,
+ GlyphFindAndPlaceForSubpixel<ProcessOneGlyph, SkPaint::kRight_Align, kY_SkAxisAlignment >,
+ // Full pixel
+ GlyphFindAndPlaceForFullPixel<ProcessOneGlyph, SkPaint::kLeft_Align >,
+ GlyphFindAndPlaceForFullPixel<ProcessOneGlyph, SkPaint::kCenter_Align>,
+ GlyphFindAndPlaceForFullPixel<ProcessOneGlyph, SkPaint::kRight_Align >
+ >;
+
+// init_subpixel is a helper function for initializing all the variants of
+// GlyphFindAndPlaceForSubpixel.
+template <typename ProcessOneGlyph, SkPaint::Align kTextAlignment>
+static void init_subpixel(
+ typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init,
+ SkAxisAlignment axisAlignment,
+ SkGlyphCache* cache,
+ SkDrawCacheProc glyphCacheProc) {
+ switch (axisAlignment) {
+ case kX_SkAxisAlignment:
+ to_init->template initialize<GlyphFindAndPlaceForSubpixel<
+ ProcessOneGlyph, kTextAlignment, kX_SkAxisAlignment>>(
+ cache, glyphCacheProc);
+ break;
+ case kNone_SkAxisAlignment:
+ to_init->template initialize<GlyphFindAndPlaceForSubpixel<
+ ProcessOneGlyph, kTextAlignment, kNone_SkAxisAlignment>>(
+ cache, glyphCacheProc);
+ break;
+ case kY_SkAxisAlignment:
+ to_init->template initialize<GlyphFindAndPlaceForSubpixel<
+ ProcessOneGlyph, kTextAlignment, kY_SkAxisAlignment>>(
+ cache, glyphCacheProc);
+ break;
+ }
+}
+
+// specialized_process_pos_text is a version of ProcessPosText that de-virtualizes the different
+// components used. It returns true if it can handle the situation, otherwise it returns false.
+// This allows greater inlining freedom to the compiler. Currently, there is only one specialized
+// variant: sub-pixel position, left-aligned, x-axis-aligned, translation, and one scalar per
+// position entry.
+// * This is by far the most common type of text Blink draws.
+template <typename ProcessOneGlyph>
+static bool specialized_process_pos_text(const char* const text, size_t byteLength,
+ const SkPoint& offset, const SkMatrix& matrix,
+ const SkScalar pos[], int scalarsPerPosition,
+ SkPaint::Align textAlignment,
+ SkDrawCacheProc& glyphCacheProc,
+ SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph) {
+ SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(matrix);
+ uint32_t mtype = matrix.getType();
+ if (scalarsPerPosition == 1
+ && textAlignment == SkPaint::kLeft_Align
+ && axisAlignment == kX_SkAxisAlignment
+ && cache->isSubpixel()
+ && mtype <= SkMatrix::kTranslate_Mask) {
+ typedef GlyphFindAndPlaceForSubpixel<
+ ProcessOneGlyph, SkPaint::kLeft_Align, kX_SkAxisAlignment> Positioner;
+ HorizontalPositions positions{pos};
+ TranslationMapper mapper{matrix, offset};
+ Positioner positioner(cache, glyphCacheProc);
+ const char *cursor = text;
+ const char *stop = text + byteLength;
+ while (cursor < stop) {
+ SkPoint mappedPoint = mapper.TranslationMapper::map(
+ positions.HorizontalPositions::nextPoint());
+ positioner.Positioner::findAndPositionGlyph(
+ &cursor, mappedPoint, skstd::forward<ProcessOneGlyph>(processOneGlyph));
+ }
+ return true;
+ }
+ return false;
+}
+
+// ProcessPosText handles all cases for finding and positioning glyphs. It has a very large
+// multiplicity. It figures out the glyph, position and rounding and pass those parameters to
+// processOneGlyph.
+//
+// The routine processOneGlyph passed in by the client has the following signature:
+// void f(const SkGlyph& glyph, SkPoint position, SkPoint rounding);
+//
+// * Sub-pixel positioning (2) - use sub-pixel positioning.
+// * Text alignment (3) - text alignment with respect to the glyph's width.
+// * Matrix type (3) - special cases for translation and X-coordinate scaling.
+// * Components per position (2) - the positions vector can have a common Y with different Xs, or
+// XY-pairs.
+// * Axis Alignment (for sub-pixel positioning) (3) - when using sub-pixel positioning, round to
+// a whole coordinate instead of using sub-pixel positioning.
+// The number of variations is 108 for sub-pixel and 36 for full-pixel.
+// This routine handles all of them using inline polymorphic variable (no heap allocation).
+template <typename ProcessOneGlyph>
+static void process_pos_text(const char text[], size_t byteLength,
+ const SkPoint& offset, const SkMatrix& matrix,
+ const SkScalar pos[], int scalarsPerPosition,
+ SkPaint::Align textAlignment, SkDrawCacheProc& glyphCacheProc,
+ SkGlyphCache* cache, ProcessOneGlyph&& processOneGlyph) {
+
+ PositionReader positionReader {
+ [&](PositionReader::Variants* to_init) {
+ if (2 == scalarsPerPosition) {
+ to_init->initialize<ArbitraryPositions>(pos);
+ } else {
+ to_init->initialize<HorizontalPositions>(pos);
+ }
+ }
+ };
+
+ Mapper mapper {
+ [&] (Mapper::Variants* to_init) {
+ uint32_t mtype = matrix.getType();
+ if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)
+ || scalarsPerPosition == 2) {
+ to_init->initialize<GeneralMapper>(matrix, offset);
+ } else if (mtype & SkMatrix::kScale_Mask) {
+ to_init->initialize<XScaleMapper>(matrix, offset);
+ } else {
+ to_init->initialize<TranslationMapper>(matrix, offset);
+ }
+ }
+ };
+
+ GlyphFindAndPlace<ProcessOneGlyph> findAndPosition{
+ [&](typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init) {
+ if (cache->isSubpixel()) {
+ SkAxisAlignment axisAlignment = SkComputeAxisAlignmentForHText(matrix);
+ switch (textAlignment) {
+ case SkPaint::kLeft_Align:
+ init_subpixel<ProcessOneGlyph, SkPaint::kLeft_Align>(
+ to_init, axisAlignment, cache, glyphCacheProc);
+ break;
+ case SkPaint::kCenter_Align:
+ init_subpixel<ProcessOneGlyph, SkPaint::kCenter_Align>(
+ to_init, axisAlignment, cache, glyphCacheProc);
+ break;
+ case SkPaint::kRight_Align:
+ init_subpixel<ProcessOneGlyph, SkPaint::kRight_Align>(
+ to_init, axisAlignment, cache, glyphCacheProc);
+ break;
+ }
+ } else {
+ switch (textAlignment) {
+ case SkPaint::kLeft_Align:
+ to_init->template initialize<GlyphFindAndPlaceForFullPixel<ProcessOneGlyph,
+ SkPaint::kLeft_Align>>(
+ cache, glyphCacheProc);
+ break;
+ case SkPaint::kCenter_Align:
+ to_init->template initialize<GlyphFindAndPlaceForFullPixel<ProcessOneGlyph,
+ SkPaint::kCenter_Align>>(
+ cache, glyphCacheProc);
+ break;
+ case SkPaint::kRight_Align:
+ to_init->template initialize<GlyphFindAndPlaceForFullPixel<ProcessOneGlyph,
+ SkPaint::kRight_Align>>(
+ cache, glyphCacheProc);
+ break;
+ }
+ }
+ }
+ };
+
+ const char* stop = text + byteLength;
+ while (text < stop) {
+ SkPoint mappedPoint = mapper->map(positionReader->nextPoint());
+ findAndPosition->findAndPositionGlyph(
+ &text, mappedPoint, skstd::forward<ProcessOneGlyph>(processOneGlyph));
+ }
+}
+
void SkDraw::drawPosText(const char text[], size_t byteLength,
const SkScalar pos[], int scalarsPerPosition,
const SkPoint& offset, const SkPaint& paint) const {
@@ -1760,108 +2248,20 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
}
}
- const char* stop = text + byteLength;
- SkTextAlignProc alignProc(paint.getTextAlign());
SkDraw1Glyph d1g;
SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint);
- SkTextMapStateProc tmsProc(*fMatrix, offset, scalarsPerPosition);
-
- if (cache->isSubpixel()) {
- // maybe we should skip the rounding if linearText is set
- SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix);
-
- SkFixed fxMask = ~0;
- SkFixed fyMask = ~0;
- if (kX_SkAxisAlignment == baseline) {
- fyMask = 0;
- d1g.fHalfSampleY = SK_ScalarHalf;
- } else if (kY_SkAxisAlignment == baseline) {
- fxMask = 0;
- d1g.fHalfSampleX = SK_ScalarHalf;
- }
- if (SkPaint::kLeft_Align == paint.getTextAlign()) {
- while (text < stop) {
- SkPoint tmsLoc;
- tmsProc(pos, &tmsLoc);
-
- Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + d1g.fHalfSampleX);
- Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + d1g.fHalfSampleY);
-
- const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
-
- if (glyph.fWidth) {
- proc(d1g, fx, fy, glyph);
- }
- pos += scalarsPerPosition;
- }
- } else {
- while (text < stop) {
- const char* currentText = text;
- const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
-
- if (metricGlyph.fWidth) {
- SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
- SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
- SkPoint tmsLoc;
- tmsProc(pos, &tmsLoc);
-
- SkPoint alignLoc;
- alignProc(tmsLoc, metricGlyph, &alignLoc);
-
- Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + d1g.fHalfSampleX);
- Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + d1g.fHalfSampleY);
-
- // have to call again, now that we've been "aligned"
- const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
- fx & fxMask, fy & fyMask);
- // the assumption is that the metrics haven't changed
- SkASSERT(prevAdvX == glyph.fAdvanceX);
- SkASSERT(prevAdvY == glyph.fAdvanceY);
- SkASSERT(glyph.fWidth);
-
- proc(d1g, fx, fy, glyph);
- }
- pos += scalarsPerPosition;
- }
- }
- } else { // not subpixel
- if (SkPaint::kLeft_Align == paint.getTextAlign()) {
- while (text < stop) {
- // the last 2 parameters are ignored
- const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
-
- if (glyph.fWidth) {
- SkPoint tmsLoc;
- tmsProc(pos, &tmsLoc);
-
- proc(d1g,
- SkScalarTo48Dot16(tmsLoc.fX + SK_ScalarHalf), //d1g.fHalfSampleX,
- SkScalarTo48Dot16(tmsLoc.fY + SK_ScalarHalf), //d1g.fHalfSampleY,
- glyph);
- }
- pos += scalarsPerPosition;
- }
- } else {
- while (text < stop) {
- // the last 2 parameters are ignored
- const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
-
- if (glyph.fWidth) {
- SkPoint tmsLoc;
- tmsProc(pos, &tmsLoc);
-
- SkPoint alignLoc;
- alignProc(tmsLoc, glyph, &alignLoc);
-
- proc(d1g,
- SkScalarTo48Dot16(alignLoc.fX + SK_ScalarHalf), //d1g.fHalfSampleX,
- SkScalarTo48Dot16(alignLoc.fY + SK_ScalarHalf), //d1g.fHalfSampleY,
- glyph);
- }
- pos += scalarsPerPosition;
- }
- }
+ auto processOneGlyph =
+ [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
+ position += rounding;
+ proc(d1g, SkScalarToFixed(position.fX), SkScalarToFixed(position.fY), glyph);
+ };
+
+ SkPaint::Align textAlignment = paint.getTextAlign();
+ if (!specialized_process_pos_text(text, byteLength, offset, *fMatrix, pos, scalarsPerPosition,
+ textAlignment, glyphCacheProc, cache, processOneGlyph)) {
+ process_pos_text(text, byteLength, offset, *fMatrix, pos, scalarsPerPosition,
+ textAlignment, glyphCacheProc, cache, processOneGlyph);
}
}
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698