OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2006, 2007, 2008, 2009 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 AN
Y | |
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 AN
Y | |
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 O
N | |
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 #include "config.h" | |
26 #include "platform/fonts/Font.h" | |
27 | |
28 #include "platform/fonts/Character.h" | |
29 #include "platform/fonts/FontFallbackList.h" | |
30 #include "platform/fonts/GlyphBuffer.h" | |
31 #include "platform/fonts/SimpleFontData.h" | |
32 #include "platform/fonts/harfbuzz/HarfBuzzShaper.h" | |
33 #include "platform/fonts/mac/ComplexTextController.h" | |
34 #include "platform/geometry/IntRect.h" | |
35 #include "platform/graphics/GraphicsContext.h" | |
36 #include "platform/text/TextRun.h" | |
37 #include "wtf/MathExtras.h" | |
38 | |
39 namespace blink { | |
40 | |
41 static bool preferHarfBuzz(const Font* font) | |
42 { | |
43 const FontDescription& description = font->fontDescription(); | |
44 return description.featureSettings() && description.featureSettings()->size(
) > 0; | |
45 } | |
46 | |
47 FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint
& point, int h, | |
48 int from, int to) const | |
49 { | |
50 if (preferHarfBuzz(this)) { | |
51 HarfBuzzShaper shaper(this, run); | |
52 if (shaper.shape()) | |
53 return shaper.selectionRect(point, h, from, to); | |
54 } | |
55 ComplexTextController controller(this, run); | |
56 controller.advance(from); | |
57 float beforeWidth = controller.runWidthSoFar(); | |
58 controller.advance(to); | |
59 float afterWidth = controller.runWidthSoFar(); | |
60 | |
61 // Using roundf() rather than ceilf() for the right edge as a compromise to
ensure correct caret positioning | |
62 if (run.rtl()) { | |
63 float totalWidth = controller.totalWidth(); | |
64 return FloatRect(floorf(point.x() + totalWidth - afterWidth), point.y(),
roundf(point.x() + totalWidth - beforeWidth) - floorf(point.x() + totalWidth -
afterWidth), h); | |
65 } | |
66 | |
67 return FloatRect(floorf(point.x() + beforeWidth), point.y(), roundf(point.x(
) + afterWidth) - floorf(point.x() + beforeWidth), h); | |
68 } | |
69 | |
70 float Font::getGlyphsAndAdvancesForComplexText(const TextRunPaintInfo& runInfo,
GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const | |
71 { | |
72 float initialAdvance; | |
73 | |
74 ComplexTextController controller(this, runInfo.run, false, 0, forTextEmphasi
s); | |
75 controller.advance(runInfo.from); | |
76 float beforeWidth = controller.runWidthSoFar(); | |
77 controller.advance(runInfo.to, &glyphBuffer); | |
78 | |
79 if (glyphBuffer.isEmpty()) | |
80 return 0; | |
81 | |
82 float afterWidth = controller.runWidthSoFar(); | |
83 | |
84 if (runInfo.run.rtl()) { | |
85 initialAdvance = controller.totalWidth() - afterWidth; | |
86 glyphBuffer.reverse(); | |
87 } else | |
88 initialAdvance = beforeWidth; | |
89 | |
90 return initialAdvance; | |
91 } | |
92 | |
93 float Font::drawComplexText(GraphicsContext* context, const TextRunPaintInfo& ru
nInfo, const FloatPoint& point) const | |
94 { | |
95 if (preferHarfBuzz(this)) { | |
96 GlyphBuffer glyphBuffer; | |
97 HarfBuzzShaper shaper(this, runInfo.run); | |
98 shaper.setDrawRange(runInfo.from, runInfo.to); | |
99 if (shaper.shape(&glyphBuffer)) { | |
100 return drawGlyphBuffer(context, runInfo, glyphBuffer, point); | |
101 } | |
102 } | |
103 // This glyph buffer holds our glyphs + advances + font data for each glyph. | |
104 GlyphBuffer glyphBuffer; | |
105 | |
106 float startX = point.x() + getGlyphsAndAdvancesForComplexText(runInfo, glyph
Buffer); | |
107 | |
108 // We couldn't generate any glyphs for the run. Give up. | |
109 if (glyphBuffer.isEmpty()) | |
110 return 0; | |
111 | |
112 // Draw the glyph buffer now at the starting point returned in startX. | |
113 FloatPoint startPoint(startX, point.y()); | |
114 return drawGlyphBuffer(context, runInfo, glyphBuffer, startPoint); | |
115 } | |
116 | |
117 void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextR
unPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const | |
118 { | |
119 GlyphBuffer glyphBuffer; | |
120 float initialAdvance = getGlyphsAndAdvancesForComplexText(runInfo, glyphBuff
er, ForTextEmphasis); | |
121 | |
122 if (glyphBuffer.isEmpty()) | |
123 return; | |
124 | |
125 drawEmphasisMarks(context, runInfo, glyphBuffer, mark, FloatPoint(point.x()
+ initialAdvance, point.y())); | |
126 } | |
127 | |
128 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon
tData*>* fallbackFonts, IntRectExtent* glyphBounds) const | |
129 { | |
130 if (preferHarfBuzz(this)) { | |
131 HarfBuzzShaper shaper(this, run); | |
132 if (shaper.shape()) | |
133 return shaper.totalWidth(); | |
134 } | |
135 ComplexTextController controller(this, run, true, fallbackFonts); | |
136 glyphBounds->setTop(floorf(-controller.minGlyphBoundingBoxY())); | |
137 glyphBounds->setBottom(ceilf(controller.maxGlyphBoundingBoxY())); | |
138 glyphBounds->setLeft(std::max<int>(0, floorf(-controller.minGlyphBoundingBox
X()))); | |
139 glyphBounds->setRight(std::max<int>(0, ceilf(controller.maxGlyphBoundingBoxX
() - controller.totalWidth()))); | |
140 | |
141 return controller.totalWidth(); | |
142 } | |
143 | |
144 int Font::offsetForPositionForComplexText(const TextRun& run, float x, bool incl
udePartialGlyphs) const | |
145 { | |
146 if (preferHarfBuzz(this)) { | |
147 HarfBuzzShaper shaper(this, run); | |
148 if (shaper.shape()) | |
149 return shaper.offsetForPosition(x); | |
150 } | |
151 ComplexTextController controller(this, run); | |
152 return controller.offsetForPosition(x, includePartialGlyphs); | |
153 } | |
154 | |
155 const SimpleFontData* Font::fontDataForCombiningCharacterSequence(const UChar* c
haracters, size_t length, FontDataVariant variant) const | |
156 { | |
157 UChar32 baseCharacter; | |
158 size_t baseCharacterLength = 0; | |
159 U16_NEXT(characters, baseCharacterLength, length, baseCharacter); | |
160 | |
161 GlyphData baseCharacterGlyphData = glyphDataForCharacter(baseCharacter, fals
e, false, variant); | |
162 | |
163 if (!baseCharacterGlyphData.glyph) | |
164 return 0; | |
165 | |
166 if (length == baseCharacterLength) | |
167 return baseCharacterGlyphData.fontData; | |
168 | |
169 bool triedBaseCharacterFontData = false; | |
170 | |
171 unsigned i = 0; | |
172 for (const FontData* fontData = fontDataAt(0); fontData; fontData = fontData
At(++i)) { | |
173 const SimpleFontData* simpleFontData = fontData->fontDataForCharacter(ba
seCharacter); | |
174 if (variant == NormalVariant) { | |
175 if (simpleFontData->platformData().orientation() == Vertical) { | |
176 if (Character::isCJKIdeographOrSymbol(baseCharacter) && !simpleF
ontData->hasVerticalGlyphs()) { | |
177 variant = BrokenIdeographVariant; | |
178 simpleFontData = simpleFontData->brokenIdeographFontData().g
et(); | |
179 } else if (m_fontDescription.nonCJKGlyphOrientation() == NonCJKG
lyphOrientationVerticalRight) { | |
180 SimpleFontData* verticalRightFontData = simpleFontData->vert
icalRightOrientationFontData().get(); | |
181 Glyph verticalRightGlyph = verticalRightFontData->glyphForCh
aracter(baseCharacter); | |
182 if (verticalRightGlyph == baseCharacterGlyphData.glyph) | |
183 simpleFontData = verticalRightFontData; | |
184 } else { | |
185 SimpleFontData* uprightFontData = simpleFontData->uprightOri
entationFontData().get(); | |
186 Glyph uprightGlyph = uprightFontData->glyphForCharacter(base
Character); | |
187 if (uprightGlyph != baseCharacterGlyphData.glyph) | |
188 simpleFontData = uprightFontData; | |
189 } | |
190 } | |
191 } else { | |
192 if (const SimpleFontData* variantFontData = simpleFontData->variantF
ontData(m_fontDescription, variant).get()) | |
193 simpleFontData = variantFontData; | |
194 } | |
195 | |
196 if (simpleFontData == baseCharacterGlyphData.fontData) | |
197 triedBaseCharacterFontData = true; | |
198 | |
199 if (simpleFontData->canRenderCombiningCharacterSequence(characters, leng
th)) | |
200 return simpleFontData; | |
201 } | |
202 | |
203 if (!triedBaseCharacterFontData && baseCharacterGlyphData.fontData && baseCh
aracterGlyphData.fontData->canRenderCombiningCharacterSequence(characters, lengt
h)) | |
204 return baseCharacterGlyphData.fontData; | |
205 | |
206 return SimpleFontData::systemFallback(); | |
207 } | |
208 | |
209 } // namespace blink | |
OLD | NEW |