• 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         UChar c16 = c;
139         if (Font::treatAsSpace(c16))
140             codeUnits[0] = ' ';
141         else if (Font::treatAsZeroWidthSpace(c16))
142             codeUnits[0] = zeroWidthSpace;
143         else
144             codeUnits[0] = c16;
145         codeUnitsLength = 1;
146     } else {
147         codeUnits[0] = U16_LEAD(c);
148         codeUnits[1] = U16_TRAIL(c);
149         codeUnitsLength = 2;
150     }
151     const SimpleFontData* characterFontData = fontCache()->getFontDataForCharacters(*this, codeUnits, codeUnitsLength);
152     if (useSmallCapsFont && characterFontData)
153         characterFontData = characterFontData->smallCapsFontData(m_fontDescription);
154     if (characterFontData) {
155         // Got the fallback glyph and font.
156         GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page();
157         GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
158         // Cache it so we don't have to do system fallback again next time.
159         if (!useSmallCapsFont) {
160 #if PLATFORM(WINCE)
161             // missingGlyphData returns a null character, which is not suitable for GDI to display.
162             // Also, sometimes we cannot map a font for the character on WINCE, but GDI can still
163             // display the character, probably because the font package is not installed correctly.
164             // So we just always set the glyph to be same as the character, and let GDI solve it.
165             page->setGlyphDataForCharacter(c, c, characterFontData);
166             return page->glyphDataForCharacter(c);
167 #else
168             page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
169 #endif
170         }
171         return data;
172     }
173 
174     // Even system fallback can fail; use the missing glyph in that case.
175     // FIXME: It would be nicer to use the missing glyph from the last resort font instead.
176     GlyphData data = primaryFont()->missingGlyphData();
177     if (!useSmallCapsFont) {
178 #if PLATFORM(WINCE)
179         // See comment about WINCE GDI handling near setGlyphDataForCharacter above.
180         page->setGlyphDataForCharacter(c, c, data.fontData);
181         return page->glyphDataForCharacter(c);
182 #else
183         page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
184 #endif
185     }
186     return data;
187 }
188 
setCodePath(CodePath p)189 void Font::setCodePath(CodePath p)
190 {
191     s_codePath = p;
192 }
193 
codePath()194 Font::CodePath Font::codePath()
195 {
196     return s_codePath;
197 }
198 
canUseGlyphCache(const TextRun & run) const199 bool Font::canUseGlyphCache(const TextRun& run) const
200 {
201     switch (s_codePath) {
202         case Auto:
203             break;
204         case Simple:
205             return true;
206         case Complex:
207             return false;
208     }
209 
210     // Start from 0 since drawing and highlighting also measure the characters before run->from
211     for (int i = 0; i < run.length(); i++) {
212         const UChar c = run[i];
213         if (c < 0x300)      // U+0300 through U+036F Combining diacritical marks
214             continue;
215         if (c <= 0x36F)
216             return false;
217 
218         if (c < 0x0591 || c == 0x05BE)     // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
219             continue;
220         if (c <= 0x05CF)
221             return false;
222 
223         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
224             continue;
225         if (c <= 0x1059)
226             return false;
227 
228         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)
229             continue;
230         if (c <= 0x11FF)
231             return false;
232 
233         if (c < 0x1780)     // U+1780 through U+18AF Khmer, Mongolian
234             continue;
235         if (c <= 0x18AF)
236             return false;
237 
238         if (c < 0x1900)     // U+1900 through U+194F Limbu (Unicode 4.0)
239             continue;
240         if (c <= 0x194F)
241             return false;
242 
243         if (c < 0x20D0)     // U+20D0 through U+20FF Combining marks for symbols
244             continue;
245         if (c <= 0x20FF)
246             return false;
247 
248         if (c < 0xFE20)     // U+FE20 through U+FE2F Combining half marks
249             continue;
250         if (c <= 0xFE2F)
251             return false;
252     }
253 
254     return true;
255 
256 }
257 
drawSimpleText(GraphicsContext * context,const TextRun & run,const FloatPoint & point,int from,int to) const258 void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
259 {
260     // This glyph buffer holds our glyphs+advances+font data for each glyph.
261     GlyphBuffer glyphBuffer;
262 
263     float startX = point.x();
264     WidthIterator it(this, run);
265     it.advance(from);
266     float beforeWidth = it.m_runWidthSoFar;
267     it.advance(to, &glyphBuffer);
268 
269     // We couldn't generate any glyphs for the run.  Give up.
270     if (glyphBuffer.isEmpty())
271         return;
272 
273     float afterWidth = it.m_runWidthSoFar;
274 
275     if (run.rtl()) {
276         float finalRoundingWidth = it.m_finalRoundingWidth;
277         it.advance(run.length());
278         startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
279     } else
280         startX += beforeWidth;
281 
282     // Swap the order of the glyphs if right-to-left.
283     if (run.rtl())
284         for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
285             glyphBuffer.swap(i, end);
286 
287     // Calculate the starting point of the glyphs to be displayed by adding
288     // all the advances up to the first glyph.
289     FloatPoint startPoint(startX, point.y());
290     drawGlyphBuffer(context, glyphBuffer, run, startPoint);
291 }
292 
drawGlyphBuffer(GraphicsContext * context,const GlyphBuffer & glyphBuffer,const TextRun &,const FloatPoint & point) const293 void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const TextRun&, const FloatPoint& point) const
294 {
295     // Draw each contiguous run of glyphs that use the same font data.
296     const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
297     FloatSize offset = glyphBuffer.offsetAt(0);
298     FloatPoint startPoint(point);
299     float nextX = startPoint.x();
300     int lastFrom = 0;
301     int nextGlyph = 0;
302     while (nextGlyph < glyphBuffer.size()) {
303         const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
304         FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
305         if (nextFontData != fontData || nextOffset != offset) {
306             drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
307 
308             lastFrom = nextGlyph;
309             fontData = nextFontData;
310             offset = nextOffset;
311             startPoint.setX(nextX);
312         }
313         nextX += glyphBuffer.advanceAt(nextGlyph);
314         nextGlyph++;
315     }
316 
317     drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
318 }
319 
floatWidthForSimpleText(const TextRun & run,GlyphBuffer * glyphBuffer,HashSet<const SimpleFontData * > * fallbackFonts) const320 float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts) const
321 {
322     WidthIterator it(this, run, fallbackFonts);
323     it.advance(run.length(), glyphBuffer);
324     return it.m_runWidthSoFar;
325 }
326 
selectionRectForSimpleText(const TextRun & run,const IntPoint & point,int h,int from,int to) const327 FloatRect Font::selectionRectForSimpleText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
328 {
329     WidthIterator it(this, run);
330     it.advance(from);
331     float beforeWidth = it.m_runWidthSoFar;
332     it.advance(to);
333     float afterWidth = it.m_runWidthSoFar;
334 
335     // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
336     if (run.rtl()) {
337         it.advance(run.length());
338         float totalWidth = it.m_runWidthSoFar;
339         return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
340     } else {
341         return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
342     }
343 }
344 
offsetForPositionForSimpleText(const TextRun & run,int x,bool includePartialGlyphs) const345 int Font::offsetForPositionForSimpleText(const TextRun& run, int x, bool includePartialGlyphs) const
346 {
347     float delta = (float)x;
348 
349     WidthIterator it(this, run);
350     GlyphBuffer localGlyphBuffer;
351     unsigned offset;
352     if (run.rtl()) {
353         delta -= floatWidthForSimpleText(run, 0);
354         while (1) {
355             offset = it.m_currentCharacter;
356             float w;
357             if (!it.advanceOneCharacter(w, &localGlyphBuffer))
358                 break;
359             delta += w;
360             if (includePartialGlyphs) {
361                 if (delta - w / 2 >= 0)
362                     break;
363             } else {
364                 if (delta >= 0)
365                     break;
366             }
367         }
368     } else {
369         while (1) {
370             offset = it.m_currentCharacter;
371             float w;
372             if (!it.advanceOneCharacter(w, &localGlyphBuffer))
373                 break;
374             delta -= w;
375             if (includePartialGlyphs) {
376                 if (delta + w / 2 <= 0)
377                     break;
378             } else {
379                 if (delta <= 0)
380                     break;
381             }
382         }
383     }
384 
385     return offset;
386 }
387 
388 }
389