1 /*
2  * This file is part of the html renderer for KDE.
3  *
4  * Copyright (C) 2000-2003 Lars Knoll (knoll@kde.org)
5  *           (C) 2000 Antti Koivisto (koivisto@kde.org)
6  *           (C) 2000 Dirk Mueller (mueller@kde.org)
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24 
25 #ifndef KHTMLFONT_H
26 #define KHTMLFONT_H
27 
28 #include <khtml_global.h>
29 #include <khtml_settings.h>
30 
31 #include <QCache>
32 #include <QFont>
33 #include <QFontMetrics>
34 #include <QPainter>
35 
36 #include "misc/shared.h"
37 
38 namespace DOM
39 {
40 class DOMString;
41 }
42 
43 namespace khtml
44 {
45 class RenderStyle;
46 class CSSStyleSelector;
47 
48 class CachedFontFamily;
49 
50 class CachedFontInstance: public Shared<CachedFontInstance>
51 {
52 public:
53     CachedFontInstance(CachedFontFamily *parent, int size);
54 
55     QFont        f;
56     QFontMetrics fm; // note:stuff below is faster when applicable.
57     // Also, do not rearrange these two fields --- one neefs f to initialize fm
58 
59     // We store cached width metrics as a two-level tree ---
60     // top-level is row for the codepoint, second is column.
61     // Some rows may have no information on them.
62     // For a cell, value 255 means no known width (or a width >= 255)
cachedCharWidth(unsigned short codePoint)63     unsigned cachedCharWidth(unsigned short codePoint)
64     {
65         unsigned width = 0xFF;
66         if (RowInfo *row = rows[codePoint >> 8]) {
67             width = row->widths[codePoint & 0xFF];
68         }
69         if (width != 0xFF) {
70             return width;
71         } else {
72             return calcAndCacheWidth(codePoint);
73         }
74     }
75 
cachedCharWidth(const QChar & c)76     unsigned cachedCharWidth(const QChar &c)
77     {
78         return cachedCharWidth(c.unicode());
79     }
80 
81     // query again all metrics
82     void invalidate();
83 
84     // Simple cached metrics, set on creation
85     int ascent;
86     int descent;
87     int height;
88     int lineSpacing;
89     int xHeight;
90     int m_zeroCharWidth;
91     mutable bool invalidated;
92 
93     ~CachedFontInstance();
94 private:
95     unsigned calcAndCacheWidth(unsigned short codePoint);
96 
97     struct RowInfo {
98         unsigned char widths[256];
99 
RowInfoRowInfo100         RowInfo()
101         {
102             for (int i = 0; i < 256; ++i) {
103                 widths[i] = 0xFF;
104             }
105         }
106     };
107 
108     RowInfo *rows[256];
109     CachedFontFamily *parent;
110     int size; // the size we were created with
111 };
112 
113 class FontDef
114 {
115 public:
FontDef()116     FontDef()
117         : family(KHTMLGlobal::defaultHTMLSettings()->stdFontName()), size(0), italic(false), smallCaps(false), weight(QFont::Normal) {}
118     bool operator == (const FontDef &other) const
119     {
120         return (family == other.family &&
121                 size == other.size &&
122                 italic == other.italic &&
123                 smallCaps == other.smallCaps &&
124                 weight == other.weight);
125     }
126 
127     QString family;
128     short int size;
129     bool italic         : 1;
130     bool smallCaps      : 1;
131     unsigned int weight         : 8;
132 };
133 
134 class Font
135 {
136     friend class RenderStyle;
137     friend class CSSStyleSelector;
138 
139     static CachedFontInstance *defaultCFI;
140 public:
141     static void initDefault();
142 
Font()143     Font() : fontDef(), cfi(defaultCFI), scFont(nullptr), letterSpacing(0), wordSpacing(0) {}
Font(const FontDef & fd)144     Font(const FontDef &fd)
145         :  fontDef(fd), cfi(defaultCFI), scFont(nullptr), letterSpacing(0), wordSpacing(0)
146     {}
Font(const Font & o)147     Font(const Font &o)
148         : fontDef(o.fontDef), cfi(o.cfi), scFont(o.scFont), letterSpacing(o.letterSpacing), wordSpacing(o.wordSpacing)
149     {
150         if (o.scFont) {
151             scFont = new QFont(*o.scFont);
152         }
153     }
~Font()154     ~Font()
155     {
156         delete scFont;
157     }
158 
159     bool operator == (const Font &other) const
160     {
161         return (fontDef == other.fontDef &&
162                 letterSpacing == other.letterSpacing &&
163                 wordSpacing == other.wordSpacing);
164     }
165 
getFontDef()166     const FontDef &getFontDef() const
167     {
168         return fontDef;
169     }
170 
171     void update(int logicalDpiY) const;
172 
173     static void invalidateCachedFontFamily(const QString &familyName);
174     static void markAllCachedFontsAsValid();
175 
176     /**
177      * Draws a piece from the given piece of text.
178      * @param p painter
179      * @param x x-coordinate to begin drawing, always denotes leftmost position
180      * @param y y-coordinate of baseline of text
181      * @param str string to draw a piece from
182      * @param slen total length of string
183      * @param pos zero-based offset of beginning of piece
184      * @param len length of piece
185      * @param width additional pixels to be distributed equally among all
186      *      spaces
187      * @param d text direction
188      * @param from begin with this position relative to @p pos, -1 to start
189      *      at @p pos
190      * @param to stop before this position relative to @p pos, -1 to use full
191      *      length of piece
192      * @param bg if valid, fill the background of the drawn piece with this
193      *      color
194      * @param uy y-coordinate of top position, used for background and text
195      *      decoration painting
196      * @param h total height of line, only used for background and text
197      *      decoration painting
198      * @param deco combined text decoration (see Decoration)
199      */
200     void drawText(QPainter *p, int x, int y, const QChar *str, const int slen, int pos, int len, int width,
201                   Qt::LayoutDirection d, int from = -1, int to = -1, QColor bg = QColor(),
202                   int uy = -1, int h = -1, int deco = 0) const;
203 
204     /** returns the width of the given string chunk in pixels.
205      *
206      * The method also considers various styles like text-align and font-variant
207      * @param str pointer to string
208      * @param slen total length of string
209      * @param pos zero-based position in string where to start measuring
210      * @param len count of characters up to which the width should be determined
211      * @param fast Use simplest/fastest algorithm (for e.g strings without special/combining chars)
212      * @param start starting position of inline text box within str, only
213      * used when toAdd is specified.
214      * @param end ending position of inline text box within str, only
215      * used when toAdd is specified.
216      * @param toAdd amount of pixels to distribute evenly among all spaces of
217      * str. Note that toAdd applies to all spaces within str, but only those
218      * within [pos, pos+len) are counted towards the width.
219      */
220     int width(const QChar *str, int slen, int pos, int len, bool fast, int start = 0, int end = 0, int toAdd = 0) const;
221     /** return the width of the given char in pixels.
222      *
223      * The method also considers various styles like text-align and font-variant
224      * @param str pointer to string
225      * @param slen total length of string
226      * @param pos zero-based position of char in string
227      */
228     int charWidth(const QChar *str, int slen, int pos, bool fast) const;
229 
230     /** Text decoration constants.
231      *
232      * The enumeration constant values match those of ETextDecoration, but only
233      * a subset is supported.
234      */
235     enum Decoration { UNDERLINE = 0x1, OVERLINE = 0x2, LINE_THROUGH = 0x4 };
236     // Keep in sync with ETextDecoration
237 
238     /** draws text decoration
239      * @param p painter
240      * @param x x-coordinate
241      * @param y top y-coordinate of line box
242      * @param baseline baseline
243      * @param width length of decoration in pixels
244      * @param height height of line box
245      * @param deco decoration to be drawn (see Decoration). The enumeration
246      *      constants may be combined.
247      */
248     void drawDecoration(QPainter *p, int x, int y, int baseline, int width, int height, int deco) const;
249 
250     /** returns letter spacing
251      */
getLetterSpacing()252     int getLetterSpacing() const
253     {
254         return letterSpacing;
255     }
256     /** returns word spacing
257      */
getWordSpacing()258     int getWordSpacing() const
259     {
260         return wordSpacing;
261     }
262 
263     // for SVG
ascent()264     int ascent() const
265     {
266         return cfi->ascent;
267     }
descent()268     int descent() const
269     {
270         return cfi->descent;
271     }
height()272     int height() const
273     {
274         return cfi->height;
275     }
lineSpacing()276     int lineSpacing() const
277     {
278         return cfi->lineSpacing;
279     }
xHeight()280     int xHeight() const
281     {
282         return cfi->xHeight;
283     }
284 
285     // return -1 if '0' char glyph not in font
zeroCharWidth()286     int zeroCharWidth() const
287     {
288         return cfi->m_zeroCharWidth;
289     }
290     //FIXME: IMPLEMENT ME
unitsPerEm()291     unsigned unitsPerEm() const
292     {
293         return 0;
294     }
spaceWidth()295     int spaceWidth() const
296     {
297         return 0;
298     }
tabWidth()299     int tabWidth() const
300     {
301         return 8 * spaceWidth();
302     }
303 
isInvalidated()304     bool isInvalidated() const
305     {
306         return cfi->invalidated;
307     }
validate()308     void validate() const
309     {
310         cfi->invalidated = false;
311     }
312 
313     // SVG helper function
314     float floatWidth(QChar *str, int pos, int len, int extraCharsAvailable, int &charsConsumed, DOM::DOMString &glyphName) const;
315 
316     float floatWidth(QChar *str, int pos, int len) const;
317 
318 private:
319     static CachedFontFamily *queryFamily(const QString &name, int weight, bool italic);
320 
321     mutable FontDef fontDef;
322     mutable WTF::SharedPtr<CachedFontInstance> cfi;
323     mutable QFont *scFont;
324     short letterSpacing;
325     short wordSpacing;
326 };
327 
328 } // namespace
329 
330 #endif
331