1/*
2 *  Copyright (C) 2000 Harri Porten (porten@kde.org)
3 *  Copyright (C) 2006 Jon Shier (jshier@iastate.edu)
4 *  Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reseved.
5 *  Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
6 *
7 *  This library is free software; you can redistribute it and/or
8 *  modify it under the terms of the GNU Lesser 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 *  Lesser General Public License for more details.
16 *
17 *  You should have received a copy of the GNU Lesser General Public
18 *  License along with this library; if not, write to the Free Software
19 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
20 *  USA
21 */
22
23#include "config.h"
24#include "WindowFeatures.h"
25
26#include "PlatformString.h"
27#include "StringHash.h"
28#include <wtf/Assertions.h>
29#include <wtf/HashMap.h>
30#include <wtf/MathExtras.h>
31
32namespace WebCore {
33
34// Though isspace() considers \t and \v to be whitespace, Win IE doesn't.
35static bool isSeparator(UChar c)
36{
37    return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' || c == ',' || c == '\0';
38}
39
40WindowFeatures::WindowFeatures(const String& features)
41    : xSet(false)
42    , ySet(false)
43    , widthSet(false)
44    , heightSet(false)
45    , fullscreen(false)
46    , dialog(false)
47{
48    /*
49     The IE rule is: all features except for channelmode and fullscreen default to YES, but
50     if the user specifies a feature string, all features default to NO. (There is no public
51     standard that applies to this method.)
52
53     <http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/open_0.asp>
54     We always allow a window to be resized, which is consistent with Firefox.
55     */
56
57    if (features.length() == 0) {
58        menuBarVisible = true;
59        statusBarVisible = true;
60        toolBarVisible = true;
61        locationBarVisible = true;
62        scrollbarsVisible = true;
63        resizable = true;
64        return;
65    }
66
67    menuBarVisible = false;
68    statusBarVisible = false;
69    toolBarVisible = false;
70    locationBarVisible = false;
71    scrollbarsVisible = false;
72    resizable = true;
73
74    // Tread lightly in this code -- it was specifically designed to mimic Win IE's parsing behavior.
75    int keyBegin, keyEnd;
76    int valueBegin, valueEnd;
77
78    int i = 0;
79    int length = features.length();
80    String buffer = features.lower();
81    while (i < length) {
82        // skip to first non-separator, but don't skip past the end of the string
83        while (isSeparator(buffer[i])) {
84            if (i >= length)
85                break;
86            i++;
87        }
88        keyBegin = i;
89
90        // skip to first separator
91        while (!isSeparator(buffer[i]))
92            i++;
93        keyEnd = i;
94
95        // skip to first '=', but don't skip past a ',' or the end of the string
96        while (buffer[i] != '=') {
97            if (buffer[i] == ',' || i >= length)
98                break;
99            i++;
100        }
101
102        // skip to first non-separator, but don't skip past a ',' or the end of the string
103        while (isSeparator(buffer[i])) {
104            if (buffer[i] == ',' || i >= length)
105                break;
106            i++;
107        }
108        valueBegin = i;
109
110        // skip to first separator
111        while (!isSeparator(buffer[i]))
112            i++;
113        valueEnd = i;
114
115        ASSERT(i <= length);
116
117        String keyString(buffer.substring(keyBegin, keyEnd - keyBegin));
118        String valueString(buffer.substring(valueBegin, valueEnd - valueBegin));
119        setWindowFeature(keyString, valueString);
120    }
121}
122
123void WindowFeatures::setWindowFeature(const String& keyString, const String& valueString)
124{
125    int value;
126
127    // Listing a key with no value is shorthand for key=yes
128    if (valueString.length() == 0 || valueString == "yes")
129        value = 1;
130    else
131        value = valueString.toInt();
132
133    // We ignore a keyString of "resizable", which is consistent with Firefox.
134    if (keyString == "left" || keyString == "screenx") {
135        xSet = true;
136        x = value;
137    } else if (keyString == "top" || keyString == "screeny") {
138        ySet = true;
139        y = value;
140    } else if (keyString == "width" || keyString == "innerwidth") {
141        widthSet = true;
142        width = value;
143    } else if (keyString == "height" || keyString == "innerheight") {
144        heightSet = true;
145        height = value;
146    } else if (keyString == "menubar")
147        menuBarVisible = value;
148    else if (keyString == "toolbar")
149        toolBarVisible = value;
150    else if (keyString == "location")
151        locationBarVisible = value;
152    else if (keyString == "status")
153        statusBarVisible = value;
154    else if (keyString == "fullscreen")
155        fullscreen = value;
156    else if (keyString == "scrollbars")
157        scrollbarsVisible = value;
158}
159
160bool WindowFeatures::boolFeature(const HashMap<String, String>& features, const char* key, bool defaultValue)
161{
162    HashMap<String, String>::const_iterator it = features.find(key);
163    if (it == features.end())
164        return defaultValue;
165    const String& value = it->second;
166    return value.isNull() || value == "1" || value == "yes" || value == "on";
167}
168
169float WindowFeatures::floatFeature(const HashMap<String, String>& features, const char* key, float min, float max, float defaultValue)
170{
171    HashMap<String, String>::const_iterator it = features.find(key);
172    if (it == features.end())
173        return defaultValue;
174    // FIXME: Can't distinguish "0q" from string with no digits in it -- both return d == 0 and ok == false.
175    // Would be good to tell them apart somehow since string with no digits should be default value and
176    // "0q" should be minimum value.
177    bool ok;
178    double d = it->second.toDouble(&ok);
179    if ((d == 0 && !ok) || isnan(d))
180        return defaultValue;
181    if (d < min || max <= min)
182        return min;
183    if (d > max)
184        return max;
185    return static_cast<int>(d);
186}
187
188} // namespace WebCore
189