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 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 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 "FontGlyphs.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
46#include <windows.h>
47
48using namespace WTF::Unicode;
49
50namespace WebCore {
51
52HDC g_screenDC = GetDC(0);
53
54class ScreenDcReleaser {
55public:
56    ~ScreenDcReleaser()
57    {
58        ReleaseDC(0, g_screenDC);
59    }
60};
61
62ScreenDcReleaser releaseScreenDc;
63
64void 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
70class TextRunComponent {
71public:
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);
75    ~TextRunComponent() { m_textRun; }
76
77    bool isSpace() const { return m_spaces; }
78    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
86TextRunComponent::TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int o)
87    : m_textRun(start, length, 0, 0
88        , parentTextRun.allowsTrailingExpansion() ? TextRun::AllowTrailingExpansion : TextRun::ForbidTrailingExpansion
89        , parentTextRun.direction()
90        , parentTextRun.directionalOverride())
91    , m_offset(o)
92    , m_spaces(0)
93{
94    m_textRun.setTabSize(parentTextRun.allowTabs(), parentTextRun.tabSize());
95
96    WidthIterator it(&font, m_textRun);
97    it.advance(m_textRun.length(), 0);
98    m_width = it.m_runWidthSoFar;
99}
100
101TextRunComponent::TextRunComponent(int s, const Font &font, int o)
102    : m_textRun(0, 0)
103    , m_offset(o)
104    , m_spaces(s)
105{
106    m_width = s * font.primaryFont()->widthForGlyph(' ');
107}
108
109typedef Vector<TextRunComponent, 128> TextRunComponents;
110
111static int generateComponents(TextRunComponents* components, const Font &font, const TextRun &run)
112{
113    int letterSpacing = font.letterSpacing();
114    int wordSpacing = font.wordSpacing();
115    int padding = run.expansion();
116    int numSpaces = 0;
117    if (padding) {
118        for (int i = 0; i < run.length(); i++)
119            if (Font::treatAsSpace(run[i]))
120                ++numSpaces;
121    }
122
123    int offset = 0;
124    if (letterSpacing) {
125        // need to draw every letter on it's own
126        int start = 0;
127        if (Font::treatAsSpace(run[0])) {
128            int add = 0;
129            if (numSpaces) {
130                add = padding/numSpaces;
131                padding -= add;
132                --numSpaces;
133            }
134            components->append(TextRunComponent(1, font, offset));
135            offset += add + letterSpacing + components->last().m_width;
136            start = 1;
137        }
138        for (int i = 1; i < run.length(); ++i) {
139            UChar ch = run[i];
140            if (U16_IS_LEAD(ch) && U16_IS_TRAIL(run[i-1]))
141                ch = U16_GET_SUPPLEMENTARY(ch, run[i-1]);
142            if (U16_IS_TRAIL(ch) || U_GET_GC_MASK(ch) & U_GC_MN_MASK)
143                continue;
144            if (Font::treatAsSpace(run[i])) {
145                int add = 0;
146                if (i - start > 0) {
147                    components->append(TextRunComponent(run.characters16() + start, i - start,
148                                                        run, font, offset));
149                    offset += components->last().m_width + letterSpacing;
150                }
151                if (numSpaces) {
152                    add = padding/numSpaces;
153                    padding -= add;
154                    --numSpaces;
155                }
156                components->append(TextRunComponent(1, font, offset));
157                offset += wordSpacing + add + components->last().m_width + letterSpacing;
158                start = i + 1;
159                continue;
160            }
161            if (i - start > 0) {
162                components->append(TextRunComponent(run.characters16() + start, i - start,
163                                                    run,
164                                                    font, offset));
165                offset += components->last().m_width + letterSpacing;
166            }
167            start = i;
168        }
169        if (run.length() - start > 0) {
170            components->append(TextRunComponent(run.characters16() + start, run.length() - start,
171                                                run,
172                                                font, offset));
173            offset += components->last().m_width;
174        }
175        offset += letterSpacing;
176    } else {
177        int start = 0;
178        for (int i = 0; i < run.length(); ++i) {
179            if (Font::treatAsSpace(run[i])) {
180                if (i - start > 0) {
181                    components->append(TextRunComponent(run.characters16() + start, i - start,
182                                                        run,
183                                                        font, offset));
184                    offset += components->last().m_width;
185                }
186                int add = 0;
187                if (numSpaces) {
188                    add = padding/numSpaces;
189                    padding -= add;
190                    --numSpaces;
191                }
192                components->append(TextRunComponent(1, font, offset));
193                offset += add + components->last().m_width;
194                if (i)
195                    offset += wordSpacing;
196                start = i + 1;
197            }
198        }
199        if (run.length() - start > 0) {
200            components->append(TextRunComponent(run.characters16() + start, run.length() - start,
201                                                run,
202                                                font, offset));
203            offset += components->last().m_width;
204        }
205    }
206    return offset;
207}
208
209float Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, 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    float widthOfDrawnText = 0;
220    int curPos = 0;
221    for (int i = 0; i < (int)components.size(); ++i) {
222        const TextRunComponent& comp = components.at(i);
223        int len = comp.textLength();
224        int curEnd = curPos + len;
225        if (curPos < to && from < curEnd && !comp.isSpace()) {
226            FloatPoint pt = point;
227            if (run.rtl())
228                pt.setX(point.x() + w - comp.m_offset - comp.m_width);
229            else
230                pt.setX(point.x() + comp.m_offset);
231            widthOfDrawnText += drawSimpleText(context, comp.m_textRun, pt, from - curPos, std::min(to, curEnd) - curPos);
232        }
233        curPos += len;
234        if (from < curPos)
235            from = curPos;
236    }
237    return widthOfDrawnText;
238}
239
240void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const
241{
242    notImplemented();
243}
244
245float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
246{
247    TextRunComponents components;
248    int w = generateComponents(&components, *this, run);
249    return w;
250}
251
252int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool includePartialGlyphs) const
253{
254    // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers
255    // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem.
256    int position = static_cast<int>(xFloat);
257
258    TextRunComponents components;
259    int w = generateComponents(&components, *this, run);
260
261    if (position >= w)
262        return run.length();
263
264    int offset = 0;
265    if (run.rtl()) {
266        for (size_t i = 0; i < components.size(); ++i) {
267            const TextRunComponent& comp = components.at(i);
268            int xe = w - comp.m_offset;
269            int xs = xe - comp.m_width;
270            if (position >= xs)
271                return offset + (comp.isSpace()
272                    ? static_cast<int>((position - xe) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5)
273                    : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs));
274
275            offset += comp.textLength();
276        }
277    } else {
278        for (size_t i = 0; i < components.size(); ++i) {
279            const TextRunComponent& comp = components.at(i);
280            int xs = comp.m_offset;
281            int xe = xs + comp.m_width;
282            if (position <= xe) {
283                if (position - xs >= xe)
284                    return offset + comp.textLength();
285                return offset + (comp.isSpace()
286                    ? static_cast<int>((position - xs) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5)
287                    : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs));
288            }
289            offset += comp.textLength();
290        }
291    }
292    return run.length();
293}
294
295
296static float cursorToX(const Font* font, const TextRunComponents& components, int width, bool rtl, int cursor)
297{
298    int start = 0;
299    for (size_t i = 0; i < components.size(); ++i) {
300        const TextRunComponent& comp = components.at(i);
301        if (start + comp.textLength() <= cursor) {
302            start += comp.textLength();
303            continue;
304        }
305        int xs = comp.m_offset;
306        if (rtl)
307            xs = width - xs - comp.m_width;
308
309        int pos = cursor - start;
310        if (comp.isSpace()) {
311            if (rtl)
312                pos = comp.textLength() - pos;
313            return xs + pos * comp.m_width / comp.m_spaces;
314        }
315        WidthIterator it(font, comp.m_textRun);
316        GlyphBuffer glyphBuffer;
317        it.advance(pos, &glyphBuffer);
318        return xs + it.m_runWidthSoFar;
319    }
320    return width;
321}
322
323FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& pt,
324    int h, int from, int to) const
325{
326    TextRunComponents components;
327    int w = generateComponents(&components, *this, run);
328
329    if (!from && to == run.length())
330        return FloatRect(pt.x(), pt.y(), w, h);
331
332    float x1 = cursorToX(this, components, w, run.rtl(), from);
333    float x2 = cursorToX(this, components, w, run.rtl(), to);
334    if (x2 < x1)
335        std::swap(x1, x2);
336
337    return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h);
338}
339
340bool Font::canReturnFallbackFontsForComplexText()
341{
342    return false;
343}
344
345bool Font::canExpandAroundIdeographsInComplexText()
346{
347    return false;
348}
349
350} // namespace WebCore
351