1/*
2 * Copyright (C) 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#pragma once
26
27#include "FloatPoint.h"
28#include "GlyphBuffer.h"
29#include <wtf/HashSet.h>
30#include <wtf/RefCounted.h>
31#include <wtf/RetainPtr.h>
32#include <wtf/Vector.h>
33#include <wtf/text/WTFString.h>
34
35typedef unsigned short CGGlyph;
36
37typedef const struct __CTRun * CTRunRef;
38typedef const struct __CTLine * CTLineRef;
39
40typedef struct hb_buffer_t hb_buffer_t;
41
42namespace WebCore {
43
44class FontCascade;
45class Font;
46class TextRun;
47
48enum GlyphIterationStyle { IncludePartialGlyphs, ByWholeGlyphs };
49
50// See https://trac.webkit.org/wiki/ComplexTextController for more information about ComplexTextController.
51class ComplexTextController {
52 WTF_MAKE_FAST_ALLOCATED;
53public:
54 ComplexTextController(const FontCascade&, const TextRun&, bool mayUseNaturalWritingDirection = false, HashSet<const Font*>* fallbackFonts = 0, bool forTextEmphasis = false);
55
56 class ComplexTextRun;
57 WEBCORE_EXPORT ComplexTextController(const FontCascade&, const TextRun&, Vector<Ref<ComplexTextRun>>&);
58
59 // Advance and emit glyphs up to the specified character.
60 WEBCORE_EXPORT void advance(unsigned to, GlyphBuffer* = nullptr, GlyphIterationStyle = IncludePartialGlyphs, HashSet<const Font*>* fallbackFonts = nullptr);
61
62 // Compute the character offset for a given x coordinate.
63 unsigned offsetForPosition(float x, bool includePartialGlyphs);
64
65 // Returns the width of everything we've consumed so far.
66 float runWidthSoFar() const { return m_runWidthSoFar; }
67
68 float totalWidth() const { return m_totalWidth; }
69
70 float minGlyphBoundingBoxX() const { return m_minGlyphBoundingBoxX; }
71 float maxGlyphBoundingBoxX() const { return m_maxGlyphBoundingBoxX; }
72 float minGlyphBoundingBoxY() const { return m_minGlyphBoundingBoxY; }
73 float maxGlyphBoundingBoxY() const { return m_maxGlyphBoundingBoxY; }
74
75 class ComplexTextRun : public RefCounted<ComplexTextRun> {
76 public:
77 static Ref<ComplexTextRun> create(CTRunRef ctRun, const Font& font, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd)
78 {
79 return adoptRef(*new ComplexTextRun(ctRun, font, characters, stringLocation, stringLength, indexBegin, indexEnd));
80 }
81
82 static Ref<ComplexTextRun> create(hb_buffer_t* buffer, const Font& font, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd)
83 {
84 return adoptRef(*new ComplexTextRun(buffer, font, characters, stringLocation, stringLength, indexBegin, indexEnd));
85 }
86
87 static Ref<ComplexTextRun> create(const Font& font, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd, bool ltr)
88 {
89 return adoptRef(*new ComplexTextRun(font, characters, stringLocation, stringLength, indexBegin, indexEnd, ltr));
90 }
91
92 static Ref<ComplexTextRun> create(const Vector<FloatSize>& advances, const Vector<FloatPoint>& origins, const Vector<Glyph>& glyphs, const Vector<unsigned>& stringIndices, FloatSize initialAdvance, const Font& font, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd, bool ltr)
93 {
94 return adoptRef(*new ComplexTextRun(advances, origins, glyphs, stringIndices, initialAdvance, font, characters, stringLocation, stringLength, indexBegin, indexEnd, ltr));
95 }
96
97 unsigned glyphCount() const { return m_glyphCount; }
98 const Font& font() const { return m_font; }
99 const UChar* characters() const { return m_characters; }
100 unsigned stringLocation() const { return m_stringLocation; }
101 unsigned stringLength() const { return m_stringLength; }
102 ALWAYS_INLINE unsigned indexAt(unsigned) const;
103 unsigned indexBegin() const { return m_indexBegin; }
104 unsigned indexEnd() const { return m_indexEnd; }
105 unsigned endOffsetAt(unsigned i) const { ASSERT(!m_isMonotonic); return m_glyphEndOffsets[i]; }
106 const CGGlyph* glyphs() const { return m_glyphs.data(); }
107
108 /*
109 * This is the format of the information CoreText gives us about each run:
110 *
111 * ----->X (Paint glyph position) X (Paint glyph position) X (Paint glyph position)
112 * / 7 7 7
113 * / / / /
114 * (Initial advance) / / (Glyph origin) / (Glyph origin) / (Glyph origin)
115 * ------------------- / / /
116 * / / / /
117 * X X--------------------------X--------------------------X--------------------------X
118 * (text position ^) (base advance) (base advance) (base advance)
119 *
120 *
121 *
122 *
123 *
124 * And here is the output we transform this into (for each run):
125 *
126 * ----->X------------------------->X------------------------->X
127 * / (Paint advance) (Paint advance) \
128 * / \
129 * (Initial advance) / \ (Paint advance)
130 * ------------------- ----------------
131 * / \
132 * X--------------------------------------------------X--------------------------X--------------------------X
133 * (text position ^) (layout advance) (layout advance) (layout advance)
134 */
135 void growInitialAdvanceHorizontally(float delta) { m_initialAdvance.expand(delta, 0); }
136 FloatSize initialAdvance() const { return m_initialAdvance; }
137 const FloatSize* baseAdvances() const { return m_baseAdvances.data(); }
138 const FloatPoint* glyphOrigins() const { return m_glyphOrigins.size() == glyphCount() ? m_glyphOrigins.data() : nullptr; }
139 bool isLTR() const { return m_isLTR; }
140 bool isMonotonic() const { return m_isMonotonic; }
141 void setIsNonMonotonic();
142
143 private:
144 ComplexTextRun(CTRunRef, const Font&, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd);
145 ComplexTextRun(hb_buffer_t*, const Font&, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd);
146 ComplexTextRun(const Font&, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd, bool ltr);
147 WEBCORE_EXPORT ComplexTextRun(const Vector<FloatSize>& advances, const Vector<FloatPoint>& origins, const Vector<Glyph>& glyphs, const Vector<unsigned>& stringIndices, FloatSize initialAdvance, const Font&, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd, bool ltr);
148
149 Vector<FloatSize, 64> m_baseAdvances;
150 Vector<FloatPoint, 64> m_glyphOrigins;
151 Vector<CGGlyph, 64> m_glyphs;
152 Vector<unsigned, 64> m_glyphEndOffsets;
153 Vector<unsigned, 64> m_coreTextIndices;
154 FloatSize m_initialAdvance;
155 const Font& m_font;
156 const UChar* m_characters;
157 unsigned m_stringLength;
158 unsigned m_indexBegin;
159 unsigned m_indexEnd;
160 unsigned m_glyphCount;
161 unsigned m_stringLocation;
162 bool m_isLTR;
163 bool m_isMonotonic { true };
164 };
165private:
166 void computeExpansionOpportunity();
167 void finishConstruction();
168
169 static unsigned stringBegin(const ComplexTextRun& run) { return run.stringLocation() + run.indexBegin(); }
170 static unsigned stringEnd(const ComplexTextRun& run) { return run.stringLocation() + run.indexEnd(); }
171
172 void collectComplexTextRuns();
173
174 void collectComplexTextRunsForCharacters(const UChar*, unsigned length, unsigned stringLocation, const Font*);
175 void adjustGlyphsAndAdvances();
176
177 unsigned indexOfCurrentRun(unsigned& leftmostGlyph);
178 unsigned incrementCurrentRun(unsigned& leftmostGlyph);
179
180 float runWidthSoFarFraction(unsigned glyphStartOffset, unsigned glyphEndOffset, unsigned oldCharacterInCurrentGlyph, GlyphIterationStyle) const;
181
182 FloatPoint glyphOrigin(unsigned index) const { return index < m_glyphOrigins.size() ? m_glyphOrigins[index] : FloatPoint(); }
183
184 Vector<FloatSize, 256> m_adjustedBaseAdvances;
185 Vector<FloatPoint, 256> m_glyphOrigins;
186 Vector<CGGlyph, 256> m_adjustedGlyphs;
187
188 Vector<UChar, 256> m_smallCapsBuffer;
189
190 // There is a 3-level hierarchy here. At the top, we are interested in m_run.string(). We partition that string
191 // into Lines, each of which is a sequence of characters which should use the same Font. Core Text then partitions
192 // the Line into ComplexTextRuns.
193 // ComplexTextRun::stringLocation() and ComplexTextRun::stringLength() refer to the offset and length of the Line
194 // relative to m_run.string(). ComplexTextRun::indexAt() returns to the offset of a codepoint relative to
195 // its Line. ComplexTextRun::glyphs() and ComplexTextRun::advances() refer to glyphs relative to the ComplexTextRun.
196 // The length of the entire TextRun is m_run.length()
197 Vector<RefPtr<ComplexTextRun>, 16> m_complexTextRuns;
198
199 // The initial capacity of these vectors was selected as being the smallest power of two greater than
200 // the average (3.5) plus one standard deviation (7.5) of nonzero sizes used on Arabic Wikipedia.
201 Vector<unsigned, 16> m_runIndices;
202 Vector<unsigned, 16> m_glyphCountFromStartToIndex;
203
204#if PLATFORM(COCOA)
205 Vector<RetainPtr<CTLineRef>> m_coreTextLines;
206#endif
207
208 Vector<String> m_stringsFor8BitRuns;
209
210 HashSet<const Font*>* m_fallbackFonts { nullptr };
211
212 const FontCascade& m_font;
213 const TextRun& m_run;
214
215 unsigned m_currentCharacter { 0 };
216 unsigned m_end { 0 };
217
218 float m_totalWidth { 0 };
219 float m_runWidthSoFar { 0 };
220 unsigned m_numGlyphsSoFar { 0 };
221 unsigned m_currentRun { 0 };
222 unsigned m_glyphInCurrentRun { 0 };
223 unsigned m_characterInCurrentGlyph { 0 };
224 float m_expansion { 0 };
225 float m_expansionPerOpportunity { 0 };
226
227 float m_minGlyphBoundingBoxX { std::numeric_limits<float>::max() };
228 float m_maxGlyphBoundingBoxX { std::numeric_limits<float>::min() };
229 float m_minGlyphBoundingBoxY { std::numeric_limits<float>::max() };
230 float m_maxGlyphBoundingBoxY { std::numeric_limits<float>::min() };
231
232 bool m_isLTROnly { true };
233 bool m_mayUseNaturalWritingDirection { false };
234 bool m_forTextEmphasis { false };
235};
236
237} // namespace WebCore
238