1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4 *           (C) 2000 Simon Hausmann <hausmann@kde.org>
5 * Copyright (C) 2003, 2006, 2008, 2010 Apple Inc. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB.  If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23#include "config.h"
24#include "HTMLFontElement.h"
25
26#include "Attribute.h"
27#include "CSSPropertyNames.h"
28#include "CSSStyleSheet.h"
29#include "CSSValueKeywords.h"
30#include "CSSValueList.h"
31#include "CSSValuePool.h"
32#include "HTMLNames.h"
33#include "HTMLParserIdioms.h"
34#include "StyleProperties.h"
35#include <wtf/text/StringBuilder.h>
36
37using namespace WTF;
38
39namespace WebCore {
40
41using namespace HTMLNames;
42
43HTMLFontElement::HTMLFontElement(const QualifiedName& tagName, Document& document)
44    : HTMLElement(tagName, document)
45{
46    ASSERT(hasTagName(fontTag));
47}
48
49PassRefPtr<HTMLFontElement> HTMLFontElement::create(const QualifiedName& tagName, Document& document)
50{
51    return adoptRef(new HTMLFontElement(tagName, document));
52}
53
54// http://www.whatwg.org/specs/web-apps/current-work/multipage/rendering.html#fonts-and-colors
55template <typename CharacterType>
56static bool parseFontSize(const CharacterType* characters, unsigned length, int& size)
57{
58
59    // Step 1
60    // Step 2
61    const CharacterType* position = characters;
62    const CharacterType* end = characters + length;
63
64    // Step 3
65    while (position < end) {
66        if (!isHTMLSpace(*position))
67            break;
68        ++position;
69    }
70
71    // Step 4
72    if (position == end)
73        return false;
74    ASSERT_WITH_SECURITY_IMPLICATION(position < end);
75
76    // Step 5
77    enum {
78        RelativePlus,
79        RelativeMinus,
80        Absolute
81    } mode;
82
83    switch (*position) {
84    case '+':
85        mode = RelativePlus;
86        ++position;
87        break;
88    case '-':
89        mode = RelativeMinus;
90        ++position;
91        break;
92    default:
93        mode = Absolute;
94        break;
95    }
96
97    // Step 6
98    StringBuilder digits;
99    digits.reserveCapacity(16);
100    while (position < end) {
101        if (!isASCIIDigit(*position))
102            break;
103        digits.append(*position++);
104    }
105
106    // Step 7
107    if (digits.isEmpty())
108        return false;
109
110    // Step 8
111    int value;
112
113    if (digits.is8Bit())
114        value = charactersToIntStrict(digits.characters8(), digits.length());
115    else
116        value = charactersToIntStrict(digits.characters16(), digits.length());
117
118    // Step 9
119    if (mode == RelativePlus)
120        value += 3;
121    else if (mode == RelativeMinus)
122        value = 3 - value;
123
124    // Step 10
125    if (value > 7)
126        value = 7;
127
128    // Step 11
129    if (value < 1)
130        value = 1;
131
132    size = value;
133    return true;
134}
135
136static bool parseFontSize(const String& input, int& size)
137{
138    if (input.isEmpty())
139        return false;
140
141    if (input.is8Bit())
142        return parseFontSize(input.characters8(), input.length(), size);
143
144    return parseFontSize(input.characters16(), input.length(), size);
145}
146
147bool HTMLFontElement::cssValueFromFontSizeNumber(const String& s, CSSValueID& size)
148{
149    int num = 0;
150    if (!parseFontSize(s, num))
151        return false;
152
153    switch (num) {
154    case 1:
155        // FIXME: The spec says that we're supposed to use CSSValueXxSmall here.
156        size = CSSValueXSmall;
157        break;
158    case 2:
159        size = CSSValueSmall;
160        break;
161    case 3:
162        size = CSSValueMedium;
163        break;
164    case 4:
165        size = CSSValueLarge;
166        break;
167    case 5:
168        size = CSSValueXLarge;
169        break;
170    case 6:
171        size = CSSValueXxLarge;
172        break;
173    case 7:
174        size = CSSValueWebkitXxxLarge;
175        break;
176    default:
177        ASSERT_NOT_REACHED();
178    }
179    return true;
180}
181
182bool HTMLFontElement::isPresentationAttribute(const QualifiedName& name) const
183{
184    if (name == sizeAttr || name == colorAttr || name == faceAttr)
185        return true;
186    return HTMLElement::isPresentationAttribute(name);
187}
188
189void HTMLFontElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStyleProperties& style)
190{
191    if (name == sizeAttr) {
192        CSSValueID size = CSSValueInvalid;
193        if (cssValueFromFontSizeNumber(value, size))
194            addPropertyToPresentationAttributeStyle(style, CSSPropertyFontSize, size);
195    } else if (name == colorAttr)
196        addHTMLColorToStyle(style, CSSPropertyColor, value);
197    else if (name == faceAttr) {
198        if (RefPtr<CSSValueList> fontFaceValue = cssValuePool().createFontFaceValue(value))
199            style.setProperty(CSSProperty(CSSPropertyFontFamily, fontFaceValue.release()));
200    } else
201        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
202}
203
204}
205