• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2003, 2006 Apple Computer, Inc.
3  * Copyright (C) 2008 Holger Hans Peter Freyther
4  * Copyright (C) 2009 Torch Mobile, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "config.h"
24 #include "Font.h"
25 
26 #include "CharacterNames.h"
27 #include "FontCache.h"
28 #include "FontFallbackList.h"
29 #include "FloatRect.h"
30 #include "GlyphBuffer.h"
31 #include "GlyphPageTreeNode.h"
32 #include "IntPoint.h"
33 #include "SimpleFontData.h"
34 #include "WidthIterator.h"
35 
36 #include <wtf/unicode/Unicode.h>
37 #include <wtf/MathExtras.h>
38 
39 using namespace WTF;
40 using namespace Unicode;
41 
42 namespace WebCore {
43 
glyphDataForCharacter(UChar32 c,bool mirror,bool forceSmallCaps) const44 GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCaps) const
45 {
46     ASSERT(isMainThread());
47 
48     bool useSmallCapsFont = forceSmallCaps;
49     if (m_fontDescription.smallCaps()) {
50         UChar32 upperC = toUpper(c);
51         if (upperC != c) {
52             c = upperC;
53             useSmallCapsFont = true;
54         }
55     }
56 
57     if (mirror)
58         c = mirroredChar(c);
59 
60     unsigned pageNumber = (c / GlyphPage::size);
61 
62     GlyphPageTreeNode* node = pageNumber ? m_fontList->m_pages.get(pageNumber) : m_fontList->m_pageZero;
63     if (!node) {
64         node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber);
65         if (pageNumber)
66             m_fontList->m_pages.set(pageNumber, node);
67         else
68             m_fontList->m_pageZero = node;
69     }
70 
71     GlyphPage* page;
72     if (!useSmallCapsFont) {
73         // Fastest loop, for the common case (not small caps).
74         while (true) {
75             page = node->page();
76             if (page) {
77                 GlyphData data = page->glyphDataForCharacter(c);
78                 if (data.fontData)
79                     return data;
80                 if (node->isSystemFallback())
81                     break;
82             }
83 
84             // Proceed with the fallback list.
85             node = node->getChild(fontDataAt(node->level()), pageNumber);
86             if (pageNumber)
87                 m_fontList->m_pages.set(pageNumber, node);
88             else
89                 m_fontList->m_pageZero = node;
90         }
91     } else {
92         while (true) {
93             page = node->page();
94             if (page) {
95                 GlyphData data = page->glyphDataForCharacter(c);
96                 if (data.fontData) {
97                     // The smallCapsFontData function should not normally return 0.
98                     // But if it does, we will just render the capital letter big.
99                     const SimpleFontData* smallCapsFontData = data.fontData->smallCapsFontData(m_fontDescription);
100                     if (!smallCapsFontData)
101                         return data;
102 
103                     GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRootChild(smallCapsFontData, pageNumber);
104                     const GlyphPage* smallCapsPage = smallCapsNode->page();
105                     if (smallCapsPage) {
106                         GlyphData data = smallCapsPage->glyphDataForCharacter(c);
107                         if (data.fontData)
108                             return data;
109                     }
110 
111                     // Do not attempt system fallback off the smallCapsFontData. This is the very unlikely case that
112                     // a font has the lowercase character but the small caps font does not have its uppercase version.
113                     return smallCapsFontData->missingGlyphData();
114                 }
115 
116                 if (node->isSystemFallback())
117                     break;
118             }
119 
120             // Proceed with the fallback list.
121             node = node->getChild(fontDataAt(node->level()), pageNumber);
122             if (pageNumber)
123                 m_fontList->m_pages.set(pageNumber, node);
124             else
125                 m_fontList->m_pageZero = node;
126         }
127     }
128 
129     ASSERT(page);
130     ASSERT(node->isSystemFallback());
131 
132     // System fallback is character-dependent. When we get here, we
133     // know that the character in question isn't in the system fallback
134     // font's glyph page. Try to lazily create it here.
135     UChar codeUnits[2];
136     int codeUnitsLength;
137     if (c <= 0xFFFF) {
138         codeUnits[0] = Font::normalizeSpaces(c);
139         codeUnitsLength = 1;
140     } else {
141         codeUnits[0] = U16_LEAD(c);
142         codeUnits[1] = U16_TRAIL(c);
143         codeUnitsLength = 2;
144     }
145     const SimpleFontData* characterFontData = fontCache()->getFontDataForCharacters(*this, codeUnits, codeUnitsLength);
146     if (useSmallCapsFont && characterFontData)
147         characterFontData = characterFontData->smallCapsFontData(m_fontDescription);
148     if (characterFontData) {
149         // Got the fallback glyph and font.
150         GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page();
151         GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
152         // Cache it so we don't have to do system fallback again next time.
153         if (!useSmallCapsFont) {
154 #if OS(WINCE)
155             // missingGlyphData returns a null character, which is not suitable for GDI to display.
156             // Also, sometimes we cannot map a font for the character on WINCE, but GDI can still
157             // display the character, probably because the font package is not installed correctly.
158             // So we just always set the glyph to be same as the character, and let GDI solve it.
159             page->setGlyphDataForCharacter(c, c, characterFontData);
160             return page->glyphDataForCharacter(c);
161 #else
162             page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
163 #endif
164         }
165         return data;
166     }
167 
168     // Even system fallback can fail; use the missing glyph in that case.
169     // FIXME: It would be nicer to use the missing glyph from the last resort font instead.
170     GlyphData data = primaryFont()->missingGlyphData();
171     if (!useSmallCapsFont) {
172 #if OS(WINCE)
173         // See comment about WINCE GDI handling near setGlyphDataForCharacter above.
174         page->setGlyphDataForCharacter(c, c, data.fontData);
175         return page->glyphDataForCharacter(c);
176 #else
177         page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
178 #endif
179     }
180     return data;
181 }
182 
setCodePath(CodePath p)183 void Font::setCodePath(CodePath p)
184 {
185     s_codePath = p;
186 }
187 
codePath()188 Font::CodePath Font::codePath()
189 {
190     return s_codePath;
191 }
192 
canUseGlyphCache(const TextRun & run) const193 bool Font::canUseGlyphCache(const TextRun& run) const
194 {
195     switch (s_codePath) {
196         case Auto:
197             break;
198         case Simple:
199             return true;
200         case Complex:
201             return false;
202     }
203 
204     // Start from 0 since drawing and highlighting also measure the characters before run->from
205     for (int i = 0; i < run.length(); i++) {
206         const UChar c = run[i];
207         if (c < 0x300)      // U+0300 through U+036F Combining diacritical marks
208             continue;
209         if (c <= 0x36F)
210             return false;
211 
212         if (c < 0x0591 || c == 0x05BE)     // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
213             continue;
214         if (c <= 0x05CF)
215             return false;
216 
217         if (c < 0x0600)     // U+0600 through U+1059 Arabic, Syriac, Thaana, Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
218             continue;
219         if (c <= 0x1059)
220             return false;
221 
222         if (c < 0x1100)     // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose; Modern Korean will be precomposed as a result of step A)
223             continue;
224         if (c <= 0x11FF)
225             return false;
226 
227         if (c < 0x1780)     // U+1780 through U+18AF Khmer, Mongolian
228             continue;
229         if (c <= 0x18AF)
230             return false;
231 
232         if (c < 0x1900)     // U+1900 through U+194F Limbu (Unicode 4.0)
233             continue;
234         if (c <= 0x194F)
235             return false;
236 
237         if (c < 0x20D0)     // U+20D0 through U+20FF Combining marks for symbols
238             continue;
239         if (c <= 0x20FF)
240             return false;
241 
242         if (c < 0xFE20)     // U+FE20 through U+FE2F Combining half marks
243             continue;
244         if (c <= 0xFE2F)
245             return false;
246     }
247 
248     if (typesettingFeatures())
249         return false;
250 
251     return true;
252 
253 }
254 
drawSimpleText(GraphicsContext * context,const TextRun & run,const FloatPoint & point,int from,int to) const255 void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
256 {
257     // This glyph buffer holds our glyphs+advances+font data for each glyph.
258     GlyphBuffer glyphBuffer;
259 
260     float startX = point.x();
261     WidthIterator it(this, run);
262     it.advance(from);
263     float beforeWidth = it.m_runWidthSoFar;
264     it.advance(to, &glyphBuffer);
265 
266     // We couldn't generate any glyphs for the run.  Give up.
267     if (glyphBuffer.isEmpty())
268         return;
269 
270     float afterWidth = it.m_runWidthSoFar;
271 
272     if (run.rtl()) {
273         float finalRoundingWidth = it.m_finalRoundingWidth;
274         it.advance(run.length());
275         startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
276     } else
277         startX += beforeWidth;
278 
279     // Swap the order of the glyphs if right-to-left.
280     if (run.rtl())
281         for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
282             glyphBuffer.swap(i, end);
283 
284     // Calculate the starting point of the glyphs to be displayed by adding
285     // all the advances up to the first glyph.
286     FloatPoint startPoint(startX, point.y());
287     drawGlyphBuffer(context, glyphBuffer, run, startPoint);
288 }
289 
drawGlyphBuffer(GraphicsContext * context,const GlyphBuffer & glyphBuffer,const TextRun &,const FloatPoint & point) const290 void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const TextRun&, const FloatPoint& point) const
291 {
292     // Draw each contiguous run of glyphs that use the same font data.
293     const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
294     FloatSize offset = glyphBuffer.offsetAt(0);
295     FloatPoint startPoint(point);
296     float nextX = startPoint.x();
297     int lastFrom = 0;
298     int nextGlyph = 0;
299     while (nextGlyph < glyphBuffer.size()) {
300         const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
301         FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
302         if (nextFontData != fontData || nextOffset != offset) {
303             drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
304 
305             lastFrom = nextGlyph;
306             fontData = nextFontData;
307             offset = nextOffset;
308             startPoint.setX(nextX);
309         }
310         nextX += glyphBuffer.advanceAt(nextGlyph);
311         nextGlyph++;
312     }
313 
314     drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
315 }
316 
floatWidthForSimpleText(const TextRun & run,GlyphBuffer * glyphBuffer,HashSet<const SimpleFontData * > * fallbackFonts) const317 float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts) const
318 {
319     WidthIterator it(this, run, fallbackFonts);
320     it.advance(run.length(), glyphBuffer);
321     return it.m_runWidthSoFar;
322 }
323 
selectionRectForSimpleText(const TextRun & run,const IntPoint & point,int h,int from,int to) const324 FloatRect Font::selectionRectForSimpleText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
325 {
326     WidthIterator it(this, run);
327     it.advance(from);
328     float beforeWidth = it.m_runWidthSoFar;
329     it.advance(to);
330     float afterWidth = it.m_runWidthSoFar;
331 
332     // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
333     if (run.rtl()) {
334         it.advance(run.length());
335         float totalWidth = it.m_runWidthSoFar;
336         return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
337     } else {
338         return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
339     }
340 }
341 
offsetForPositionForSimpleText(const TextRun & run,int x,bool includePartialGlyphs) const342 int Font::offsetForPositionForSimpleText(const TextRun& run, int x, bool includePartialGlyphs) const
343 {
344     float delta = (float)x;
345 
346     WidthIterator it(this, run);
347     GlyphBuffer localGlyphBuffer;
348     unsigned offset;
349     if (run.rtl()) {
350         delta -= floatWidthForSimpleText(run, 0);
351         while (1) {
352             offset = it.m_currentCharacter;
353             float w;
354             if (!it.advanceOneCharacter(w, &localGlyphBuffer))
355                 break;
356             delta += w;
357             if (includePartialGlyphs) {
358                 if (delta - w / 2 >= 0)
359                     break;
360             } else {
361                 if (delta >= 0)
362                     break;
363             }
364         }
365     } else {
366         while (1) {
367             offset = it.m_currentCharacter;
368             float w;
369             if (!it.advanceOneCharacter(w, &localGlyphBuffer))
370                 break;
371             delta -= w;
372             if (includePartialGlyphs) {
373                 if (delta + w / 2 <= 0)
374                     break;
375             } else {
376                 if (delta <= 0)
377                     break;
378             }
379         }
380     }
381 
382     return offset;
383 }
384 
385 }
386