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 "TextRun.h"
42#include "WidthIterator.h"
43#include <wtf/MathExtras.h>
44#include <wtf/OwnPtr.h>
45#include <wtf/unicode/Unicode.h>
46
47#include <windows.h>
48
49using namespace WTF::Unicode;
50
51namespace WebCore {
52
53HDC g_screenDC = GetDC(0);
54
55class ScreenDcReleaser {
56public:
57    ~ScreenDcReleaser()
58    {
59        ReleaseDC(0, g_screenDC);
60    }
61};
62
63ScreenDcReleaser releaseScreenDc;
64
65void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer,
66                      int from, int numGlyphs, const FloatPoint& point) const
67{
68    graphicsContext->drawText(fontData, glyphBuffer, from, numGlyphs, point);
69}
70
71class TextRunComponent {
72public:
73    TextRunComponent() : m_textRun(0, 0) {}
74    TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int offset);
75    TextRunComponent(int spaces, const Font &font, int offset);
76    ~TextRunComponent() { m_textRun; }
77
78    bool isSpace() const { return m_spaces; }
79    int textLength() const { return m_spaces ? m_spaces : m_textRun.length(); }
80
81    TextRun m_textRun;
82    float m_width;
83    int m_offset;
84    int m_spaces;
85};
86
87TextRunComponent::TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int o)
88    : m_textRun(start, length, parentTextRun.allowTabs(), 0, 0
89        , parentTextRun.allowsTrailingExpansion() ? TextRun::AllowTrailingExpansion : TextRun::ForbidTrailingExpansion
90        , parentTextRun.rtl()
91        , parentTextRun.directionalOverride())
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
100TextRunComponent::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
108typedef Vector<TextRunComponent, 128> TextRunComponents;
109
110static 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.expansion();
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
208void 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
238void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const
239{
240    notImplemented();
241}
242
243float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
244{
245    TextRunComponents components;
246    int w = generateComponents(&components, *this, run);
247    return w;
248}
249
250int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool includePartialGlyphs) const
251{
252    // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers
253    // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem.
254    int position = static_cast<int>(xFloat);
255
256    TextRunComponents components;
257    int w = generateComponents(&components, *this, run);
258
259    if (position >= w)
260        return run.length();
261
262    int offset = 0;
263    if (run.rtl()) {
264        for (size_t i = 0; i < components.size(); ++i) {
265            const TextRunComponent& comp = components.at(i);
266            int xe = w - comp.m_offset;
267            int xs = xe - comp.m_width;
268            if (position >= xs)
269                return offset + (comp.isSpace()
270                    ? static_cast<int>((position - xe) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5)
271                    : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs));
272
273            offset += comp.textLength();
274        }
275    } else {
276        for (size_t i = 0; i < components.size(); ++i) {
277            const TextRunComponent& comp = components.at(i);
278            int xs = comp.m_offset;
279            int xe = xs + comp.m_width;
280            if (position <= xe) {
281                if (position - xs >= xe)
282                    return offset + comp.textLength();
283                return offset + (comp.isSpace()
284                    ? static_cast<int>((position - xs) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5)
285                    : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs));
286            }
287            offset += comp.textLength();
288        }
289    }
290    return run.length();
291}
292
293
294static float cursorToX(const Font* font, const TextRunComponents& components, int width, bool rtl, int cursor)
295{
296    int start = 0;
297    for (size_t i = 0; i < components.size(); ++i) {
298        const TextRunComponent& comp = components.at(i);
299        if (start + comp.textLength() <= cursor) {
300            start += comp.textLength();
301            continue;
302        }
303        int xs = comp.m_offset;
304        if (rtl)
305            xs = width - xs - comp.m_width;
306
307        int pos = cursor - start;
308        if (comp.isSpace()) {
309            if (rtl)
310                pos = comp.textLength() - pos;
311            return xs + pos * comp.m_width / comp.m_spaces;
312        }
313        WidthIterator it(font, comp.m_textRun);
314        it.advance(pos);
315        return xs + it.m_runWidthSoFar;
316    }
317    return width;
318}
319
320FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& pt,
321                                     int h, int from, int to) const
322{
323    TextRunComponents components;
324    int w = generateComponents(&components, *this, run);
325
326    if (!from && to == run.length())
327        return FloatRect(pt.x(), pt.y(), w, h);
328
329    float x1 = cursorToX(this, components, w, run.rtl(), from);
330    float x2 = cursorToX(this, components, w, run.rtl(), to);
331    if (x2 < x1)
332        std::swap(x1, x2);
333
334    return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h);
335}
336
337bool Font::canReturnFallbackFontsForComplexText()
338{
339    return false;
340}
341
342bool Font::canExpandAroundIdeographsInComplexText()
343{
344    return false;
345}
346
347} // namespace WebCore
348