2009-03-02 Kim Grönholm <kim.gronholm@nomovok.com>
[WebKit-https.git] / WebCore / platform / graphics / qt / FontQt.cpp
1 /*
2     Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
3     Copyright (C) 2008 Holger Hans Peter Freyther
4     Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
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 #include "config.h"
23 #include "Font.h"
24 #include "FontDescription.h"
25 #include "FontFallbackList.h"
26 #include "FontSelector.h"
27
28 #include "Gradient.h"
29 #include "GraphicsContext.h"
30 #include "Pattern.h"
31 #include "TransformationMatrix.h"
32
33 #include <QBrush>
34 #include <QFontInfo>
35 #include <QFontMetrics>
36 #include <QPainter>
37 #include <QPainterPath>
38 #include <QPen>
39 #include <QTextLayout>
40 #include <qalgorithms.h>
41 #include <qdebug.h>
42
43 #include <limits.h>
44
45 #if QT_VERSION >= 0x040400
46 namespace WebCore {
47
48 static QString qstring(const TextRun& run)
49 {
50     QString string((QChar *)run.characters(), run.length());
51     QChar *uc = string.data();
52     for (int i = 0; i < string.length(); ++i) {
53         if (Font::treatAsSpace(uc[i].unicode()))
54             uc[i] = 0x20;
55         else if (Font::treatAsZeroWidthSpace(uc[i].unicode()))
56             uc[i] = 0x200c;
57     }
58     return string;
59 }
60
61
62 static QTextLine setupLayout(QTextLayout* layout, const TextRun& style)
63 {
64     int flags = style.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
65     if (style.padding())
66         flags |= Qt::TextJustificationForced;
67     layout->setFlags(flags);
68     layout->beginLayout();
69     QTextLine line = layout->createLine();
70     line.setLineWidth(INT_MAX/256);
71     if (style.padding())
72         line.setLineWidth(line.naturalTextWidth() + style.padding());
73     layout->endLayout();
74     return line;
75 }
76
77 void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const
78 {
79     if (to < 0)
80         to = run.length();
81
82     QPainter *p = ctx->platformContext();
83
84     if (ctx->textDrawingMode() & cTextFill) {
85         if (ctx->fillGradient()) {
86             QBrush brush(*ctx->fillGradient()->platformGradient());
87             brush.setTransform(ctx->fillGradient()->gradientSpaceTransform());
88             p->setPen(QPen(brush, 0));
89         } else if (ctx->fillPattern()) {
90             TransformationMatrix affine;
91             p->setPen(QPen(QBrush(ctx->fillPattern()->createPlatformPattern(affine)), 0));
92         } else
93             p->setPen(QColor(ctx->fillColor()));
94     }
95
96     if (ctx->textDrawingMode() & cTextStroke) {
97         if (ctx->strokeGradient()) {
98             QBrush brush(*ctx->strokeGradient()->platformGradient());
99             brush.setTransform(ctx->strokeGradient()->gradientSpaceTransform());
100             p->setPen(QPen(brush, 0));
101         } else if (ctx->strokePattern()) {
102             TransformationMatrix affine;
103             p->setPen(QPen(QBrush(ctx->strokePattern()->createPlatformPattern(affine)), 0));
104         } else
105             p->setPen(QColor(ctx->strokeColor()));
106     }
107
108     QString string = qstring(run);
109
110     // text shadow
111     IntSize shadowSize;
112     int shadowBlur;
113     Color shadowColor;
114     bool hasShadow = ctx->textDrawingMode() == cTextFill && ctx->getShadow(shadowSize, shadowBlur, shadowColor);
115
116     if (from > 0 || to < run.length()) {
117         QTextLayout layout(string, font());
118         QTextLine line = setupLayout(&layout, run);
119         float x1 = line.cursorToX(from);
120         float x2 = line.cursorToX(to);
121         if (x2 < x1)
122             qSwap(x1, x2);
123
124         QFontMetrics fm(font());
125         int ascent = fm.ascent();
126         QRectF clip(point.x() + x1, point.y() - ascent, x2 - x1, fm.height());
127
128         if (hasShadow) {
129             // TODO: when blur support is added, the clip will need to account
130             // for the blur radius
131             qreal dx1 = 0, dx2 = 0, dy1 = 0, dy2 = 0;
132             if (shadowSize.width() > 0)
133                 dx2 = shadowSize.width();
134             else
135                 dx1 = -shadowSize.width();
136             if (shadowSize.height() > 0)
137                 dy2 = shadowSize.height();
138             else
139                 dy1 = -shadowSize.height();
140             // expand the clip rect to include the text shadow as well
141             clip.adjust(dx1, dx2, dy1, dy2);
142         }
143         p->save();
144         p->setClipRect(clip.toRect());
145         QPointF pt(point.x(), point.y() - ascent);
146         if (hasShadow) {
147             p->save();
148             p->setPen(QColor(shadowColor));
149             p->translate(shadowSize.width(), shadowSize.height());
150             line.draw(p, pt);
151             p->restore();
152         }
153         line.draw(p, pt);
154         p->restore();
155         return;
156     }
157
158     p->setFont(font());
159
160     QPointF pt(point.x(), point.y());
161     int flags = run.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
162     if (hasShadow) {
163         // TODO: text shadow blur support
164         p->save();
165         p->setPen(QColor(shadowColor));
166         p->translate(shadowSize.width(), shadowSize.height());
167         p->drawText(pt, string, flags, run.padding());
168         p->restore();
169     }
170     p->drawText(pt, string, flags, run.padding());
171 }
172
173 float Font::floatWidthForComplexText(const TextRun& run) const
174 {
175     if (!run.length())
176         return 0;
177     QString string = qstring(run);
178     QTextLayout layout(string, font());
179     QTextLine line = setupLayout(&layout, run);
180     int w = int(line.naturalTextWidth());
181     // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does)
182     if (treatAsSpace(run[0]))
183         w -= m_wordSpacing;
184
185     return w + run.padding();
186 }
187
188 int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool includePartialGlyphs) const
189 {
190     QString string = qstring(run);
191     QTextLayout layout(string, font());
192     QTextLine line = setupLayout(&layout, run);
193     return line.xToCursor(position);
194 }
195
196 FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& pt, int h, int from, int to) const
197 {
198     QString string = qstring(run);
199     QTextLayout layout(string, font());
200     QTextLine line = setupLayout(&layout, run);
201
202     float x1 = line.cursorToX(from);
203     float x2 = line.cursorToX(to);
204     if (x2 < x1)
205         qSwap(x1, x2);
206
207     return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h);
208 }
209
210 QFont Font::font() const
211 {
212     return primaryFont()->getQtFont();
213 }
214
215 }
216
217 #endif
218