• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
3  * Copyright (C) 2007-2009 Torch Mobile, Inc.
4  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
5  * Copyright (C) 2008 Holger Hans Peter Freyther
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "config.h"
30 #include "Font.h"
31 
32 #include "AffineTransform.h"
33 #include "FloatRect.h"
34 #include "FontCache.h"
35 #include "FontData.h"
36 #include "FontFallbackList.h"
37 #include "GlyphBuffer.h"
38 #include "GraphicsContext.h"
39 #include "IntRect.h"
40 #include "NotImplemented.h"
41 #include "WidthIterator.h"
42 #include <wtf/MathExtras.h>
43 #include <wtf/OwnPtr.h>
44 #include <wtf/unicode/Unicode.h>
45 
46 #include <windows.h>
47 
48 using namespace WTF::Unicode;
49 
50 namespace WebCore {
51 
52 HDC g_screenDC = GetDC(0);
53 
54 class ScreenDcReleaser {
55 public:
~ScreenDcReleaser()56     ~ScreenDcReleaser()
57     {
58         ReleaseDC(0, g_screenDC);
59     }
60 };
61 
62 ScreenDcReleaser releaseScreenDc;
63 
drawGlyphs(GraphicsContext * graphicsContext,const SimpleFontData * fontData,const GlyphBuffer & glyphBuffer,int from,int numGlyphs,const FloatPoint & point) const64 void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer,
65                       int from, int numGlyphs, const FloatPoint& point) const
66 {
67     graphicsContext->drawText(fontData, glyphBuffer, from, numGlyphs, point);
68 }
69 
70 class TextRunComponent {
71 public:
TextRunComponent()72     TextRunComponent() : m_textRun(0, 0) {}
73     TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int offset);
74     TextRunComponent(int spaces, const Font &font, int offset);
~TextRunComponent()75     ~TextRunComponent() { m_textRun; }
76 
isSpace() const77     bool isSpace() const { return m_spaces; }
textLength() const78     int textLength() const { return m_spaces ? m_spaces : m_textRun.length(); }
79 
80     TextRun m_textRun;
81     float m_width;
82     int m_offset;
83     int m_spaces;
84 };
85 
TextRunComponent(const UChar * start,int length,const TextRun & parentTextRun,const Font & font,int o)86 TextRunComponent::TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int o)
87     : m_textRun(start, length, parentTextRun.allowTabs(), 0, 0
88         , parentTextRun.rtl()
89         , parentTextRun.directionalOverride()
90         , parentTextRun.applyRunRounding()
91         , parentTextRun.applyWordRounding())
92     , m_offset(o)
93     , m_spaces(0)
94 {
95     WidthIterator it(&font, m_textRun);
96     it.advance(m_textRun.length(), 0);
97     m_width = it.m_runWidthSoFar;
98 }
99 
TextRunComponent(int s,const Font & font,int o)100 TextRunComponent::TextRunComponent(int s, const Font &font, int o)
101     : m_textRun(0, 0)
102     , m_offset(o)
103     , m_spaces(s)
104 {
105     m_width = s * font.primaryFont()->widthForGlyph(' ');
106 }
107 
108 typedef Vector<TextRunComponent, 128> TextRunComponents;
109 
generateComponents(TextRunComponents * components,const Font & font,const TextRun & run)110 static int generateComponents(TextRunComponents* components, const Font &font, const TextRun &run)
111 {
112     int letterSpacing = font.letterSpacing();
113     int wordSpacing = font.wordSpacing();
114     int padding = run.padding();
115     int numSpaces = 0;
116     if (padding) {
117         for (int i = 0; i < run.length(); i++)
118             if (Font::treatAsSpace(run[i]))
119                 ++numSpaces;
120     }
121 
122     int offset = 0;
123     if (letterSpacing) {
124         // need to draw every letter on it's own
125         int start = 0;
126         if (Font::treatAsSpace(run[0])) {
127             int add = 0;
128             if (numSpaces) {
129                 add = padding/numSpaces;
130                 padding -= add;
131                 --numSpaces;
132             }
133             components->append(TextRunComponent(1, font, offset));
134             offset += add + letterSpacing + components->last().m_width;
135             start = 1;
136         }
137         for (int i = 1; i < run.length(); ++i) {
138             uint ch = run[i];
139             if (isHighSurrogate(ch) && isLowSurrogate(run[i-1]))
140                 ch = surrogateToUcs4(ch, run[i-1]);
141             if (isLowSurrogate(ch) || category(ch) == Mark_NonSpacing)
142                 continue;
143             if (Font::treatAsSpace(run[i])) {
144                 int add = 0;
145                 if (i - start > 0) {
146                     components->append(TextRunComponent(run.characters() + start, i - start,
147                                                         run, font, offset));
148                     offset += components->last().m_width + letterSpacing;
149                 }
150                 if (numSpaces) {
151                     add = padding/numSpaces;
152                     padding -= add;
153                     --numSpaces;
154                 }
155                 components->append(TextRunComponent(1, font, offset));
156                 offset += wordSpacing + add + components->last().m_width + letterSpacing;
157                 start = i + 1;
158                 continue;
159             }
160             if (i - start > 0) {
161                 components->append(TextRunComponent(run.characters() + start, i - start,
162                                                     run,
163                                                     font, offset));
164                 offset += components->last().m_width + letterSpacing;
165             }
166             start = i;
167         }
168         if (run.length() - start > 0) {
169             components->append(TextRunComponent(run.characters() + start, run.length() - start,
170                                                 run,
171                                                 font, offset));
172             offset += components->last().m_width;
173         }
174         offset += letterSpacing;
175     } else {
176         int start = 0;
177         for (int i = 0; i < run.length(); ++i) {
178             if (Font::treatAsSpace(run[i])) {
179                 if (i - start > 0) {
180                     components->append(TextRunComponent(run.characters() + start, i - start,
181                                                         run,
182                                                         font, offset));
183                     offset += components->last().m_width;
184                 }
185                 int add = 0;
186                 if (numSpaces) {
187                     add = padding/numSpaces;
188                     padding -= add;
189                     --numSpaces;
190                 }
191                 components->append(TextRunComponent(1, font, offset));
192                 offset += add + components->last().m_width;
193                 if (i)
194                     offset += wordSpacing;
195                 start = i + 1;
196             }
197         }
198         if (run.length() - start > 0) {
199             components->append(TextRunComponent(run.characters() + start, run.length() - start,
200                                                 run,
201                                                 font, offset));
202             offset += components->last().m_width;
203         }
204     }
205     return offset;
206 }
207 
drawComplexText(GraphicsContext * context,const TextRun & run,const FloatPoint & point,int from,int to) const208 void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point,
209                            int from, int to) const
210 {
211     if (to < 0)
212         to = run.length();
213     if (from < 0)
214         from = 0;
215 
216     TextRunComponents components;
217     int w = generateComponents(&components, *this, run);
218 
219     int curPos = 0;
220     for (int i = 0; i < (int)components.size(); ++i) {
221         const TextRunComponent& comp = components.at(i);
222         int len = comp.textLength();
223         int curEnd = curPos + len;
224         if (curPos < to && from < curEnd && !comp.isSpace()) {
225             FloatPoint pt = point;
226             if (run.rtl())
227                 pt.setX(point.x() + w - comp.m_offset - comp.m_width);
228             else
229                 pt.setX(point.x() + comp.m_offset);
230             drawSimpleText(context, comp.m_textRun, pt, from - curPos, std::min(to, curEnd) - curPos);
231         }
232         curPos += len;
233         if (from < curPos)
234             from = curPos;
235     }
236 }
237 
floatWidthForComplexText(const TextRun & run,HashSet<const SimpleFontData * > * fallbackFonts) const238 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const
239 {
240     TextRunComponents components;
241     int w = generateComponents(&components, *this, run);
242     return w;
243 }
244 
offsetForPositionForComplexText(const TextRun & run,int position,bool includePartialGlyphs) const245 int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool includePartialGlyphs) const
246 {
247     TextRunComponents components;
248     int w = generateComponents(&components, *this, run);
249 
250     if (position >= w)
251         return run.length();
252 
253     int offset = 0;
254     if (run.rtl()) {
255         for (size_t i = 0; i < components.size(); ++i) {
256             const TextRunComponent& comp = components.at(i);
257             int xe = w - comp.m_offset;
258             int xs = xe - comp.m_width;
259             if (position >= xs)
260                 return offset + (comp.isSpace()
261                     ? static_cast<int>((position - xe) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5)
262                     : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs));
263 
264             offset += comp.textLength();
265         }
266     } else {
267         for (size_t i = 0; i < components.size(); ++i) {
268             const TextRunComponent& comp = components.at(i);
269             int xs = comp.m_offset;
270             int xe = xs + comp.m_width;
271             if (position <= xe) {
272                 if (position - xs >= xe)
273                     return offset + comp.textLength();
274                 return offset + (comp.isSpace()
275                     ? static_cast<int>((position - xs) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5)
276                     : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs));
277             }
278             offset += comp.textLength();
279         }
280     }
281     return run.length();
282 }
283 
284 
cursorToX(const Font * font,const TextRunComponents & components,int width,bool rtl,int cursor)285 static float cursorToX(const Font* font, const TextRunComponents& components, int width, bool rtl, int cursor)
286 {
287     int start = 0;
288     for (size_t i = 0; i < components.size(); ++i) {
289         const TextRunComponent& comp = components.at(i);
290         if (start + comp.textLength() <= cursor) {
291             start += comp.textLength();
292             continue;
293         }
294         int xs = comp.m_offset;
295         if (rtl)
296             xs = width - xs - comp.m_width;
297 
298         int pos = cursor - start;
299         if (comp.isSpace()) {
300             if (rtl)
301                 pos = comp.textLength() - pos;
302             return xs + pos * comp.m_width / comp.m_spaces;
303         }
304         WidthIterator it(font, comp.m_textRun);
305         it.advance(pos);
306         return xs + it.m_runWidthSoFar;
307     }
308     return width;
309 }
310 
selectionRectForComplexText(const TextRun & run,const IntPoint & pt,int h,int from,int to) const311 FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& pt,
312                                      int h, int from, int to) const
313 {
314     TextRunComponents components;
315     int w = generateComponents(&components, *this, run);
316 
317     if (!from && to == run.length())
318         return FloatRect(pt.x(), pt.y(), w, h);
319 
320     float x1 = cursorToX(this, components, w, run.rtl(), from);
321     float x2 = cursorToX(this, components, w, run.rtl(), to);
322     if (x2 < x1)
323         std::swap(x1, x2);
324 
325     return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h);
326 }
327 
canReturnFallbackFontsForComplexText()328 bool Font::canReturnFallbackFontsForComplexText()
329 {
330     return false;
331 }
332 
333 }
334