1/*
2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
3 * (C) 2000 Antti Koivisto (koivisto@kde.org)
4 * (C) 2000 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2003-2017 Apple Inc. All rights reserved.
6 * Copyright (C) 2008 Holger Hans Peter Freyther
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25#pragma once
26
27#include "DashArray.h"
28#include "Font.h"
29#include "FontCascadeDescription.h"
30#include "FontCascadeFonts.h"
31#include "Path.h"
32#include <wtf/HashSet.h>
33#include <wtf/Optional.h>
34#include <wtf/WeakPtr.h>
35#include <wtf/unicode/CharacterNames.h>
36
37// "X11/X.h" defines Complex to 0 and conflicts
38// with Complex value in CodePath enum.
39#ifdef Complex
40#undef Complex
41#endif
42
43namespace WebCore {
44
45class GraphicsContext;
46class LayoutRect;
47class RenderText;
48class TextLayout;
49class TextRun;
50
51namespace DisplayList {
52class DisplayList;
53}
54
55struct GlyphData;
56
57struct GlyphOverflow {
58 bool isEmpty() const
59 {
60 return !left && !right && !top && !bottom;
61 }
62
63 void extendTo(const GlyphOverflow& other)
64 {
65 left = std::max(left, other.left);
66 right = std::max(right, other.right);
67 top = std::max(top, other.top);
68 bottom = std::max(bottom, other.bottom);
69 }
70
71 bool operator!=(const GlyphOverflow& other)
72 {
73 // FIXME: Probably should name this rather than making it the != operator since it ignores the value of computeBounds.
74 return left != other.left || right != other.right || top != other.top || bottom != other.bottom;
75 }
76
77 int left { 0 };
78 int right { 0 };
79 int top { 0 };
80 int bottom { 0 };
81 bool computeBounds { false };
82};
83
84class TextLayoutDeleter {
85public:
86 void operator()(TextLayout*) const;
87};
88
89class FontCascade : public CanMakeWeakPtr<FontCascade> {
90public:
91 WEBCORE_EXPORT FontCascade();
92 WEBCORE_EXPORT FontCascade(FontCascadeDescription&&, float letterSpacing = 0, float wordSpacing = 0);
93 // This constructor is only used if the platform wants to start with a native font.
94 WEBCORE_EXPORT FontCascade(const FontPlatformData&, FontSmoothingMode = FontSmoothingMode::AutoSmoothing);
95
96 FontCascade(const FontCascade&);
97 WEBCORE_EXPORT FontCascade& operator=(const FontCascade&);
98
99 WEBCORE_EXPORT bool operator==(const FontCascade& other) const;
100 bool operator!=(const FontCascade& other) const { return !(*this == other); }
101
102 const FontCascadeDescription& fontDescription() const { return m_fontDescription; }
103
104 int pixelSize() const { return fontDescription().computedPixelSize(); }
105 float size() const { return fontDescription().computedSize(); }
106
107 WEBCORE_EXPORT void update(RefPtr<FontSelector>&& = nullptr) const;
108
109 enum CustomFontNotReadyAction { DoNotPaintIfFontNotReady, UseFallbackIfFontNotReady };
110 WEBCORE_EXPORT float drawText(GraphicsContext&, const TextRun&, const FloatPoint&, unsigned from = 0, Optional<unsigned> to = WTF::nullopt, CustomFontNotReadyAction = DoNotPaintIfFontNotReady) const;
111 static void drawGlyphs(GraphicsContext&, const Font&, const GlyphBuffer&, unsigned from, unsigned numGlyphs, const FloatPoint&, FontSmoothingMode);
112 void drawEmphasisMarks(GraphicsContext&, const TextRun&, const AtomString& mark, const FloatPoint&, unsigned from = 0, Optional<unsigned> to = WTF::nullopt) const;
113
114 DashArray dashesForIntersectionsWithRect(const TextRun&, const FloatPoint& textOrigin, const FloatRect& lineExtents) const;
115
116 float widthOfTextRange(const TextRun&, unsigned from, unsigned to, HashSet<const Font*>* fallbackFonts = 0, float* outWidthBeforeRange = nullptr, float* outWidthAfterRange = nullptr) const;
117 WEBCORE_EXPORT float width(const TextRun&, HashSet<const Font*>* fallbackFonts = 0, GlyphOverflow* = 0) const;
118 float widthForSimpleText(StringView text) const;
119
120 std::unique_ptr<TextLayout, TextLayoutDeleter> createLayout(RenderText&, float xPos, bool collapseWhiteSpace) const;
121 static float width(TextLayout&, unsigned from, unsigned len, HashSet<const Font*>* fallbackFonts = 0);
122
123 int offsetForPosition(const TextRun&, float position, bool includePartialGlyphs) const;
124 void adjustSelectionRectForText(const TextRun&, LayoutRect& selectionRect, unsigned from = 0, Optional<unsigned> to = WTF::nullopt) const;
125
126 bool isSmallCaps() const { return m_fontDescription.variantCaps() == FontVariantCaps::Small; }
127
128 float wordSpacing() const { return m_wordSpacing; }
129 float letterSpacing() const { return m_letterSpacing; }
130 void setWordSpacing(float s) { m_wordSpacing = s; }
131 void setLetterSpacing(float s) { m_letterSpacing = s; }
132 bool isFixedPitch() const;
133
134 FontRenderingMode renderingMode() const { return m_fontDescription.renderingMode(); }
135
136 bool enableKerning() const { return m_enableKerning; }
137 bool requiresShaping() const { return m_requiresShaping; }
138
139 const AtomString& firstFamily() const { return m_fontDescription.firstFamily(); }
140 unsigned familyCount() const { return m_fontDescription.familyCount(); }
141 const AtomString& familyAt(unsigned i) const { return m_fontDescription.familyAt(i); }
142
143 // A WTF::nullopt return value indicates "font-style: normal".
144 Optional<FontSelectionValue> italic() const { return m_fontDescription.italic(); }
145 FontSelectionValue weight() const { return m_fontDescription.weight(); }
146 FontWidthVariant widthVariant() const { return m_fontDescription.widthVariant(); }
147
148 bool isPlatformFont() const { return m_fonts->isForPlatformFont(); }
149
150 const FontMetrics& fontMetrics() const { return primaryFont().fontMetrics(); }
151 float spaceWidth() const { return primaryFont().spaceWidth() + m_letterSpacing; }
152 float tabWidth(const Font&, const TabSize&, float) const;
153 float tabWidth(const TabSize& tabSize, float position) const { return tabWidth(primaryFont(), tabSize, position); }
154 bool hasValidAverageCharWidth() const;
155 bool fastAverageCharWidthIfAvailable(float &width) const; // returns true on success
156
157 int emphasisMarkAscent(const AtomString&) const;
158 int emphasisMarkDescent(const AtomString&) const;
159 int emphasisMarkHeight(const AtomString&) const;
160
161 const Font& primaryFont() const;
162 const FontRanges& fallbackRangesAt(unsigned) const;
163 GlyphData glyphDataForCharacter(UChar32, bool mirror, FontVariant = AutoVariant) const;
164
165 const Font* fontForCombiningCharacterSequence(const UChar*, size_t length) const;
166
167 static bool isCJKIdeograph(UChar32);
168 static bool isCJKIdeographOrSymbol(UChar32);
169
170 // Returns (the number of opportunities, whether the last expansion is a trailing expansion)
171 // If there are no opportunities, the bool will be true iff we are forbidding leading expansions.
172 static std::pair<unsigned, bool> expansionOpportunityCount(const StringView&, TextDirection, ExpansionBehavior);
173
174 // Whether or not there is an expansion opportunity just before the first character
175 // Note that this does not take a isAfterExpansion flag; this assumes that isAfterExpansion is false
176 // Here, "Leading" and "Trailing" are relevant after the line has been rearranged for bidi.
177 // ("Leading" means "left" and "Trailing" means "right.")
178 static bool leadingExpansionOpportunity(const StringView&, TextDirection);
179 static bool trailingExpansionOpportunity(const StringView&, TextDirection);
180
181 WEBCORE_EXPORT static void setShouldUseSmoothing(bool);
182 WEBCORE_EXPORT static bool shouldUseSmoothing();
183
184 static bool isSubpixelAntialiasingAvailable();
185
186 enum CodePath { Auto, Simple, Complex, SimpleWithGlyphOverflow };
187 CodePath codePath(const TextRun&, Optional<unsigned> from = WTF::nullopt, Optional<unsigned> to = WTF::nullopt) const;
188 static CodePath characterRangeCodePath(const LChar*, unsigned) { return Simple; }
189 static CodePath characterRangeCodePath(const UChar*, unsigned len);
190
191 bool primaryFontIsSystemFont() const;
192
193 std::unique_ptr<DisplayList::DisplayList> displayListForTextRun(GraphicsContext&, const TextRun&, unsigned from = 0, Optional<unsigned> to = { }, CustomFontNotReadyAction = CustomFontNotReadyAction::DoNotPaintIfFontNotReady) const;
194
195#if PLATFORM(WIN) && USE(CG)
196 static void setFontSmoothingLevel(int);
197 static uint32_t setFontSmoothingStyle(CGContextRef, bool fontAllowsSmoothing);
198 static void setFontSmoothingContrast(CGFloat);
199 static void systemFontSmoothingChanged();
200 static void setCGContextFontRenderingStyle(CGContextRef, bool isSystemFont, bool isPrinterFont, bool usePlatformNativeGlyphs);
201 static void getPlatformGlyphAdvances(CGFontRef, const CGAffineTransform&, bool isSystemFont, bool isPrinterFont, CGGlyph, CGSize& advance);
202#endif
203private:
204 enum ForTextEmphasisOrNot { NotForTextEmphasis, ForTextEmphasis };
205
206 float glyphBufferForTextRun(CodePath, const TextRun&, unsigned from, unsigned to, GlyphBuffer&) const;
207 // Returns the initial in-stream advance.
208 float getGlyphsAndAdvancesForSimpleText(const TextRun&, unsigned from, unsigned to, GlyphBuffer&, ForTextEmphasisOrNot = NotForTextEmphasis) const;
209 void drawEmphasisMarksForSimpleText(GraphicsContext&, const TextRun&, const AtomString& mark, const FloatPoint&, unsigned from, unsigned to) const;
210 void drawGlyphBuffer(GraphicsContext&, const GlyphBuffer&, FloatPoint&, CustomFontNotReadyAction) const;
211 void drawEmphasisMarks(GraphicsContext&, const GlyphBuffer&, const AtomString&, const FloatPoint&) const;
212 float floatWidthForSimpleText(const TextRun&, HashSet<const Font*>* fallbackFonts = 0, GlyphOverflow* = 0) const;
213 int offsetForPositionForSimpleText(const TextRun&, float position, bool includePartialGlyphs) const;
214 void adjustSelectionRectForSimpleText(const TextRun&, LayoutRect& selectionRect, unsigned from, unsigned to) const;
215
216 Optional<GlyphData> getEmphasisMarkGlyphData(const AtomString&) const;
217
218 static bool canReturnFallbackFontsForComplexText();
219 static bool canExpandAroundIdeographsInComplexText();
220
221 // Returns the initial in-stream advance.
222 float getGlyphsAndAdvancesForComplexText(const TextRun&, unsigned from, unsigned to, GlyphBuffer&, ForTextEmphasisOrNot = NotForTextEmphasis) const;
223 void drawEmphasisMarksForComplexText(GraphicsContext&, const TextRun&, const AtomString& mark, const FloatPoint&, unsigned from, unsigned to) const;
224 float floatWidthForComplexText(const TextRun&, HashSet<const Font*>* fallbackFonts = 0, GlyphOverflow* = 0) const;
225 int offsetForPositionForComplexText(const TextRun&, float position, bool includePartialGlyphs) const;
226 void adjustSelectionRectForComplexText(const TextRun&, LayoutRect& selectionRect, unsigned from, unsigned to) const;
227
228 static std::pair<unsigned, bool> expansionOpportunityCountInternal(const LChar*, unsigned length, TextDirection, ExpansionBehavior);
229 static std::pair<unsigned, bool> expansionOpportunityCountInternal(const UChar*, unsigned length, TextDirection, ExpansionBehavior);
230
231 friend struct WidthIterator;
232
233public:
234#if ENABLE(TEXT_AUTOSIZING)
235 bool equalForTextAutoSizing(const FontCascade& other) const
236 {
237 return m_fontDescription.equalForTextAutoSizing(other.m_fontDescription)
238 && m_letterSpacing == other.m_letterSpacing
239 && m_wordSpacing == other.m_wordSpacing;
240 }
241#endif
242
243 // Useful for debugging the different font rendering code paths.
244 WEBCORE_EXPORT static void setCodePath(CodePath);
245 static CodePath codePath();
246 static CodePath s_codePath;
247
248 FontSelector* fontSelector() const;
249 static bool treatAsSpace(UChar c) { return c == ' ' || c == '\t' || c == '\n' || c == noBreakSpace; }
250 static bool treatAsZeroWidthSpace(UChar c) { return treatAsZeroWidthSpaceInComplexScript(c) || c == 0x200c || c == 0x200d; }
251 static bool treatAsZeroWidthSpaceInComplexScript(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == softHyphen || c == zeroWidthSpace || (c >= 0x200e && c <= 0x200f) || (c >= 0x202a && c <= 0x202e) || c == zeroWidthNoBreakSpace || c == objectReplacementCharacter; }
252 static bool canReceiveTextEmphasis(UChar32);
253
254 static inline UChar normalizeSpaces(UChar character)
255 {
256 if (treatAsSpace(character))
257 return space;
258
259 if (treatAsZeroWidthSpace(character))
260 return zeroWidthSpace;
261
262 return character;
263 }
264
265 static String normalizeSpaces(const LChar*, unsigned length);
266 static String normalizeSpaces(const UChar*, unsigned length);
267
268 bool useBackslashAsYenSymbol() const { return m_useBackslashAsYenSymbol; }
269 FontCascadeFonts* fonts() const { return m_fonts.get(); }
270 bool isLoadingCustomFonts() const;
271
272private:
273
274 bool advancedTextRenderingMode() const
275 {
276 auto textRenderingMode = m_fontDescription.textRenderingMode();
277 if (textRenderingMode == TextRenderingMode::GeometricPrecision || textRenderingMode == TextRenderingMode::OptimizeLegibility)
278 return true;
279 if (textRenderingMode == TextRenderingMode::OptimizeSpeed)
280 return false;
281#if PLATFORM(COCOA) || USE(FREETYPE)
282 return true;
283#else
284 return false;
285#endif
286 }
287
288 bool computeEnableKerning() const
289 {
290 auto kerning = m_fontDescription.kerning();
291 if (kerning == Kerning::Normal)
292 return true;
293 if (kerning == Kerning::NoShift)
294 return false;
295 return advancedTextRenderingMode();
296 }
297
298 bool computeRequiresShaping() const
299 {
300#if PLATFORM(COCOA) || USE(FREETYPE)
301 if (!m_fontDescription.variantSettings().isAllNormal())
302 return true;
303 if (m_fontDescription.featureSettings().size())
304 return true;
305#endif
306 return advancedTextRenderingMode();
307 }
308
309 static int syntheticObliqueAngle() { return 14; }
310
311#if PLATFORM(WIN) && USE(CG)
312 static double s_fontSmoothingContrast;
313 static uint32_t s_fontSmoothingType;
314 static int s_fontSmoothingLevel;
315 static uint32_t s_systemFontSmoothingType;
316 static bool s_systemFontSmoothingSet;
317 static bool s_systemFontSmoothingEnabled;
318#endif
319
320 FontCascadeDescription m_fontDescription;
321 mutable RefPtr<FontCascadeFonts> m_fonts;
322 float m_letterSpacing { 0 };
323 float m_wordSpacing { 0 };
324 mutable bool m_useBackslashAsYenSymbol { false };
325 mutable bool m_enableKerning { false }; // Computed from m_fontDescription.
326 mutable bool m_requiresShaping { false }; // Computed from m_fontDescription.
327};
328
329void invalidateFontCascadeCache();
330void pruneUnreferencedEntriesFromFontCascadeCache();
331void pruneSystemFallbackFonts();
332void clearWidthCaches();
333
334inline const Font& FontCascade::primaryFont() const
335{
336 ASSERT(m_fonts);
337 return m_fonts->primaryFont(m_fontDescription);
338}
339
340inline const FontRanges& FontCascade::fallbackRangesAt(unsigned index) const
341{
342 ASSERT(m_fonts);
343 return m_fonts->realizeFallbackRangesAt(m_fontDescription, index);
344}
345
346inline bool FontCascade::isFixedPitch() const
347{
348 ASSERT(m_fonts);
349 return m_fonts->isFixedPitch(m_fontDescription);
350}
351
352inline FontSelector* FontCascade::fontSelector() const
353{
354 return m_fonts ? m_fonts->fontSelector() : nullptr;
355}
356
357inline float FontCascade::tabWidth(const Font& font, const TabSize& tabSize, float position) const
358{
359 float baseTabWidth = tabSize.widthInPixels(font.spaceWidth());
360 if (!baseTabWidth)
361 return letterSpacing();
362 float tabDeltaWidth = baseTabWidth - fmodf(position, baseTabWidth);
363 return (tabDeltaWidth < font.spaceWidth() / 2) ? baseTabWidth : tabDeltaWidth;
364}
365
366}
367