skia2/modules/skparagraph/include/TextStyle.h

327 lines
11 KiB
C
Raw Normal View History

// Copyright 2019 Google LLC.
#ifndef TextStyle_DEFINED
#define TextStyle_DEFINED
#include <vector>
#include "include/core/SkColor.h"
#include "include/core/SkFont.h"
#include "include/core/SkFontMetrics.h"
#include "include/core/SkFontStyle.h"
#include "include/core/SkPaint.h"
#include "include/core/SkScalar.h"
#include "modules/skparagraph/include/DartTypes.h"
#include "modules/skparagraph/include/TextShadow.h"
// TODO: Make it external so the other platforms (Android) could use it
#define DEFAULT_FONT_FAMILY "sans-serif"
namespace skia {
namespace textlayout {
static inline bool nearlyZero(SkScalar x, SkScalar tolerance = SK_ScalarNearlyZero) {
if (SkScalarIsFinite(x)) {
return SkScalarNearlyZero(x, tolerance);
}
return false;
}
static inline bool nearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance = SK_ScalarNearlyZero) {
if (SkScalarIsFinite(x) && SkScalarIsFinite(x)) {
return SkScalarNearlyEqual(x, y, tolerance);
}
// Inf == Inf, anything else is false
return x == y;
}
// Multiple decorations can be applied at once. Ex: Underline and overline is
// (0x1 | 0x2)
enum TextDecoration {
kNoDecoration = 0x0,
kUnderline = 0x1,
kOverline = 0x2,
kLineThrough = 0x4,
};
constexpr TextDecoration AllTextDecorations[] = {
kNoDecoration,
kUnderline,
kOverline,
kLineThrough,
};
enum TextDecorationStyle { kSolid, kDouble, kDotted, kDashed, kWavy };
enum TextDecorationMode { kGaps, kThrough };
enum StyleType {
kNone,
kAllAttributes,
kFont,
kForeground,
kBackground,
kShadow,
kDecorations,
kLetterSpacing,
kWordSpacing
};
struct Decoration {
TextDecoration fType;
TextDecorationMode fMode;
SkColor fColor;
TextDecorationStyle fStyle;
SkScalar fThicknessMultiplier;
bool operator==(const Decoration& other) const {
return this->fType == other.fType &&
this->fMode == other.fMode &&
this->fColor == other.fColor &&
this->fStyle == other.fStyle &&
this->fThicknessMultiplier == other.fThicknessMultiplier;
}
};
/// Where to vertically align the placeholder relative to the surrounding text.
enum class PlaceholderAlignment {
/// Match the baseline of the placeholder with the baseline.
kBaseline,
/// Align the bottom edge of the placeholder with the baseline such that the
/// placeholder sits on top of the baseline.
kAboveBaseline,
/// Align the top edge of the placeholder with the baseline specified in
/// such that the placeholder hangs below the baseline.
kBelowBaseline,
/// Align the top edge of the placeholder with the top edge of the font.
/// When the placeholder is very tall, the extra space will hang from
/// the top and extend through the bottom of the line.
kTop,
/// Align the bottom edge of the placeholder with the top edge of the font.
/// When the placeholder is very tall, the extra space will rise from
/// the bottom and extend through the top of the line.
kBottom,
/// Align the middle of the placeholder with the middle of the text. When the
/// placeholder is very tall, the extra space will grow equally from
/// the top and bottom of the line.
kMiddle,
};
struct FontFeature {
FontFeature(const SkString name, int value) : fName(name), fValue(value) {}
Add back deprecated warnings. Unfortunately in clang 'deprecated' is both a set of warnings (at least one of which we don't want) and a group of warnings (most of which we do want). Leave the top level disabled, but re-enable all the warnings in the group. Most of the code changes are for the deprecated-copy diagnostic. In C++11 implementing a copy constructor xor copy assignment operator the default implementation of the other is still required to be the default but is deprecated (the compiler can warn against doing this). The idea is that if there was a need for a non-default copy constructor or copy assignment operator then both should be implemented explicitly, since it is unlikely that the default will do what is expected. Note that the deprecated-copy-dtor has not yet been enabled as there will need to be a lot more work to enable this diagnostic. Similar to deprecated-copy, in C++11 when implementing a destructor the copy constructor and copy assignment operator are still defaulted if not declared, but this is also deprecated. The idea here is that if some special handling is needed to destroy the object there is probably some need to do something non-trivial when copying the object (or copying should be disallowed). Also, there are still some deprecated-declarations to clean up on Android and Mac. Change-Id: I5fc4b62713220e6f7d3724fd7342b4c8c74a3c67 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/278916 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Ben Wagner <bungeman@google.com>
2020-03-23 21:22:24 +00:00
bool operator==(const FontFeature& that) const {
return fName == that.fName && fValue == that.fValue;
}
SkString fName;
int fValue;
};
struct PlaceholderStyle {
PlaceholderStyle() = default;
PlaceholderStyle(SkScalar width, SkScalar height, PlaceholderAlignment alignment,
TextBaseline baseline, SkScalar offset)
: fWidth(width)
, fHeight(height)
, fAlignment(alignment)
, fBaseline(baseline)
, fBaselineOffset(offset) {}
Add back deprecated warnings. Unfortunately in clang 'deprecated' is both a set of warnings (at least one of which we don't want) and a group of warnings (most of which we do want). Leave the top level disabled, but re-enable all the warnings in the group. Most of the code changes are for the deprecated-copy diagnostic. In C++11 implementing a copy constructor xor copy assignment operator the default implementation of the other is still required to be the default but is deprecated (the compiler can warn against doing this). The idea is that if there was a need for a non-default copy constructor or copy assignment operator then both should be implemented explicitly, since it is unlikely that the default will do what is expected. Note that the deprecated-copy-dtor has not yet been enabled as there will need to be a lot more work to enable this diagnostic. Similar to deprecated-copy, in C++11 when implementing a destructor the copy constructor and copy assignment operator are still defaulted if not declared, but this is also deprecated. The idea here is that if some special handling is needed to destroy the object there is probably some need to do something non-trivial when copying the object (or copying should be disallowed). Also, there are still some deprecated-declarations to clean up on Android and Mac. Change-Id: I5fc4b62713220e6f7d3724fd7342b4c8c74a3c67 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/278916 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Ben Wagner <bungeman@google.com>
2020-03-23 21:22:24 +00:00
bool equals(const PlaceholderStyle&) const;
SkScalar fWidth = 0;
SkScalar fHeight = 0;
PlaceholderAlignment fAlignment = PlaceholderAlignment::kBaseline;
TextBaseline fBaseline = TextBaseline::kAlphabetic;
// Distance from the top edge of the rect to the baseline position. This
// baseline will be aligned against the alphabetic baseline of the surrounding
// text.
//
// Positive values drop the baseline lower (positions the rect higher) and
// small or negative values will cause the rect to be positioned underneath
// the line. When baseline == height, the bottom edge of the rect will rest on
// the alphabetic baseline.
SkScalar fBaselineOffset = 0;
};
class TextStyle {
public:
TextStyle() = default;
TextStyle(const TextStyle& other, bool placeholder);
bool equals(const TextStyle& other) const;
bool equalsByFonts(const TextStyle& that) const;
bool matchOneAttribute(StyleType styleType, const TextStyle& other) const;
bool operator==(const TextStyle& rhs) const { return this->equals(rhs); }
// Colors
SkColor getColor() const { return fColor; }
void setColor(SkColor color) { fColor = color; }
bool hasForeground() const { return fHasForeground; }
SkPaint getForeground() const { return fForeground; }
void setForegroundColor(SkPaint paint) {
fHasForeground = true;
fForeground = std::move(paint);
}
void clearForegroundColor() { fHasForeground = false; }
bool hasBackground() const { return fHasBackground; }
SkPaint getBackground() const { return fBackground; }
void setBackgroundColor(SkPaint paint) {
fHasBackground = true;
fBackground = std::move(paint);
}
void clearBackgroundColor() { fHasBackground = false; }
// Decorations
Decoration getDecoration() const { return fDecoration; }
TextDecoration getDecorationType() const { return fDecoration.fType; }
TextDecorationMode getDecorationMode() const { return fDecoration.fMode; }
SkColor getDecorationColor() const { return fDecoration.fColor; }
TextDecorationStyle getDecorationStyle() const { return fDecoration.fStyle; }
SkScalar getDecorationThicknessMultiplier() const {
return fDecoration.fThicknessMultiplier;
}
void setDecoration(TextDecoration decoration) { fDecoration.fType = decoration; }
void setDecorationMode(TextDecorationMode mode) { fDecoration.fMode = mode; }
void setDecorationStyle(TextDecorationStyle style) { fDecoration.fStyle = style; }
void setDecorationColor(SkColor color) { fDecoration.fColor = color; }
void setDecorationThicknessMultiplier(SkScalar m) { fDecoration.fThicknessMultiplier = m; }
// Weight/Width/Slant
SkFontStyle getFontStyle() const { return fFontStyle; }
void setFontStyle(SkFontStyle fontStyle) { fFontStyle = fontStyle; }
// Shadows
size_t getShadowNumber() const { return fTextShadows.size(); }
std::vector<TextShadow> getShadows() const { return fTextShadows; }
void addShadow(TextShadow shadow) { fTextShadows.emplace_back(shadow); }
void resetShadows() { fTextShadows.clear(); }
// Font features
size_t getFontFeatureNumber() const { return fFontFeatures.size(); }
std::vector<FontFeature> getFontFeatures() const { return fFontFeatures; }
void addFontFeature(const SkString& fontFeature, int value)
{ fFontFeatures.emplace_back(fontFeature, value); }
void resetFontFeatures() { fFontFeatures.clear(); }
SkScalar getFontSize() const { return fFontSize; }
void setFontSize(SkScalar size) { fFontSize = size; }
const std::vector<SkString>& getFontFamilies() const { return fFontFamilies; }
void setFontFamilies(std::vector<SkString> families) {
fFontFamilies = std::move(families);
}
void setHeight(SkScalar height) { fHeight = height; }
SkScalar getHeight() const { return fHeightOverride ? fHeight : 0; }
void setHeightOverride(bool heightOverride) { fHeightOverride = heightOverride; }
bool getHeightOverride() const { return fHeightOverride; }
void setLetterSpacing(SkScalar letterSpacing) { fLetterSpacing = letterSpacing; }
SkScalar getLetterSpacing() const { return fLetterSpacing; }
void setWordSpacing(SkScalar wordSpacing) { fWordSpacing = wordSpacing; }
SkScalar getWordSpacing() const { return fWordSpacing; }
SkTypeface* getTypeface() const { return fTypeface.get(); }
sk_sp<SkTypeface> refTypeface() const { return fTypeface; }
void setTypeface(sk_sp<SkTypeface> typeface) { fTypeface = std::move(typeface); }
SkString getLocale() const { return fLocale; }
void setLocale(const SkString& locale) { fLocale = locale; }
TextBaseline getTextBaseline() const { return fTextBaseline; }
void setTextBaseline(TextBaseline baseline) { fTextBaseline = baseline; }
void getFontMetrics(SkFontMetrics* metrics) const;
bool isPlaceholder() const { return fIsPlaceholder; }
void setPlaceholder() { fIsPlaceholder = true; }
private:
Decoration fDecoration = {
TextDecoration::kNoDecoration,
// TODO: switch back to kGaps when (if) switching flutter to skparagraph
TextDecorationMode::kThrough,
// It does not make sense to draw a transparent object, so we use this as a default
// value to indicate no decoration color was set.
SK_ColorTRANSPARENT, TextDecorationStyle::kSolid,
// Thickness is applied as a multiplier to the default thickness of the font.
1.0f};
SkFontStyle fFontStyle;
std::vector<SkString> fFontFamilies = { SkString(DEFAULT_FONT_FAMILY) };
SkScalar fFontSize = 14.0;
SkScalar fHeight = 1.0;
bool fHeightOverride = false;
SkString fLocale = {};
SkScalar fLetterSpacing = 0.0;
SkScalar fWordSpacing = 0.0;
TextBaseline fTextBaseline = TextBaseline::kAlphabetic;
SkColor fColor = SK_ColorWHITE;
bool fHasBackground = false;
SkPaint fBackground;
bool fHasForeground = false;
SkPaint fForeground;
std::vector<TextShadow> fTextShadows;
sk_sp<SkTypeface> fTypeface;
bool fIsPlaceholder = false;
std::vector<FontFeature> fFontFeatures;
};
typedef size_t TextIndex;
typedef SkRange<size_t> TextRange;
const SkRange<size_t> EMPTY_TEXT = EMPTY_RANGE;
struct Block {
Block() = default;
Block(size_t start, size_t end, const TextStyle& style) : fRange(start, end), fStyle(style) {}
Block(TextRange textRange, const TextStyle& style) : fRange(textRange), fStyle(style) {}
void add(TextRange tail) {
SkASSERT(fRange.end == tail.start);
fRange = TextRange(fRange.start, fRange.start + fRange.width() + tail.width());
}
TextRange fRange = EMPTY_RANGE;
TextStyle fStyle;
};
typedef size_t BlockIndex;
typedef SkRange<size_t> BlockRange;
const size_t EMPTY_BLOCK = EMPTY_INDEX;
const SkRange<size_t> EMPTY_BLOCKS = EMPTY_RANGE;
struct Placeholder {
Placeholder() = default;
Placeholder(size_t start, size_t end, const PlaceholderStyle& style, const TextStyle& textStyle,
BlockRange blocksBefore, TextRange textBefore)
: fRange(start, end)
, fStyle(style)
, fTextStyle(textStyle)
, fBlocksBefore(blocksBefore)
, fTextBefore(textBefore) {}
TextRange fRange = EMPTY_RANGE;
PlaceholderStyle fStyle;
TextStyle fTextStyle;
BlockRange fBlocksBefore;
TextRange fTextBefore;
};
} // namespace textlayout
} // namespace skia
#endif // TextStyle_DEFINED