WindowFeatures.cpp [plain text]
#include "config.h"
#include "WindowFeatures.h"
#include "FloatRect.h"
#include <wtf/Assertions.h>
#include <wtf/HashMap.h>
#include <wtf/MathExtras.h>
#include <wtf/text/StringHash.h>
namespace WebCore {
typedef HashMap<String, String, ASCIICaseInsensitiveHash> DialogFeaturesMap;
static void setWindowFeature(WindowFeatures&, StringView key, StringView value);
static DialogFeaturesMap parseDialogFeaturesMap(const String&);
static Optional<bool> boolFeature(const DialogFeaturesMap&, const char* key);
static Optional<float> floatFeature(const DialogFeaturesMap&, const char* key, float min, float max);
static bool isSeparator(UChar character)
{
return character == ' ' || character == '\t' || character == '\n' || character == '\r' || character == '=' || character == ',';
}
WindowFeatures parseWindowFeatures(StringView featuresString)
{
WindowFeatures features;
if (featuresString.isEmpty())
return features;
features.menuBarVisible = false;
features.statusBarVisible = false;
features.toolBarVisible = false;
features.locationBarVisible = false;
features.scrollbarsVisible = false;
processFeaturesString(featuresString, [&features](StringView key, StringView value) {
setWindowFeature(features, key, value);
});
return features;
}
void processFeaturesString(StringView features, std::function<void(StringView type, StringView value)> callback)
{
unsigned length = features.length();
for (unsigned i = 0; i < length; ) {
while (i < length && isSeparator(features[i]))
++i;
unsigned keyBegin = i;
while (i < length && !isSeparator(features[i]))
i++;
unsigned keyEnd = i;
while (i < length && features[i] != '=' && features[i] != ',')
++i;
while (i < length && isSeparator(features[i]) && features[i] != ',')
++i;
unsigned valueBegin = i;
while (i < length && !isSeparator(features[i]))
++i;
unsigned valueEnd = i;
callback(features.substring(keyBegin, keyEnd - keyBegin), features.substring(valueBegin, valueEnd - valueBegin));
}
}
static void setWindowFeature(WindowFeatures& features, StringView key, StringView value)
{
int numericValue;
if (value.isEmpty() || equalLettersIgnoringASCIICase(value, "yes"))
numericValue = 1;
else
numericValue = value.toInt();
if (equalLettersIgnoringASCIICase(key, "left") || equalLettersIgnoringASCIICase(key, "screenx"))
features.x = numericValue;
else if (equalLettersIgnoringASCIICase(key, "top") || equalLettersIgnoringASCIICase(key, "screeny"))
features.y = numericValue;
else if (equalLettersIgnoringASCIICase(key, "width") || equalLettersIgnoringASCIICase(key, "innerwidth"))
features.width = numericValue;
else if (equalLettersIgnoringASCIICase(key, "height") || equalLettersIgnoringASCIICase(key, "innerheight"))
features.height = numericValue;
else if (equalLettersIgnoringASCIICase(key, "menubar"))
features.menuBarVisible = numericValue;
else if (equalLettersIgnoringASCIICase(key, "toolbar"))
features.toolBarVisible = numericValue;
else if (equalLettersIgnoringASCIICase(key, "location"))
features.locationBarVisible = numericValue;
else if (equalLettersIgnoringASCIICase(key, "status"))
features.statusBarVisible = numericValue;
else if (equalLettersIgnoringASCIICase(key, "fullscreen"))
features.fullscreen = numericValue;
else if (equalLettersIgnoringASCIICase(key, "scrollbars"))
features.scrollbarsVisible = numericValue;
else if (numericValue == 1)
features.additionalFeatures.append(key.toString());
}
WindowFeatures parseDialogFeatures(const String& dialogFeaturesString, const FloatRect& screenAvailableRect)
{
auto featuresMap = parseDialogFeaturesMap(dialogFeaturesString);
WindowFeatures features;
features.menuBarVisible = false;
features.toolBarVisible = false;
features.locationBarVisible = false;
features.dialog = true;
float width = floatFeature(featuresMap, "dialogwidth", 100, screenAvailableRect.width()).valueOr(620); float height = floatFeature(featuresMap, "dialogheight", 100, screenAvailableRect.height()).valueOr(450);
features.width = width;
features.height = height;
features.x = floatFeature(featuresMap, "dialogleft", screenAvailableRect.x(), screenAvailableRect.maxX() - width);
features.y = floatFeature(featuresMap, "dialogtop", screenAvailableRect.y(), screenAvailableRect.maxY() - height);
if (boolFeature(featuresMap, "center").valueOr(true)) {
if (!features.x)
features.x = screenAvailableRect.x() + (screenAvailableRect.width() - width) / 2;
if (!features.y)
features.y = screenAvailableRect.y() + (screenAvailableRect.height() - height) / 2;
}
features.resizable = boolFeature(featuresMap, "resizable").valueOr(false);
features.scrollbarsVisible = boolFeature(featuresMap, "scroll").valueOr(true);
features.statusBarVisible = boolFeature(featuresMap, "status").valueOr(false);
return features;
}
static Optional<bool> boolFeature(const DialogFeaturesMap& features, const char* key)
{
auto it = features.find(key);
if (it == features.end())
return Nullopt;
auto& value = it->value;
return value.isNull()
|| value == "1"
|| equalLettersIgnoringASCIICase(value, "yes")
|| equalLettersIgnoringASCIICase(value, "on");
}
static Optional<float> floatFeature(const DialogFeaturesMap& features, const char* key, float min, float max)
{
auto it = features.find(key);
if (it == features.end())
return Nullopt;
bool ok;
double parsedNumber = it->value.toDouble(&ok);
if ((!parsedNumber && !ok) || std::isnan(parsedNumber))
return Nullopt;
if (parsedNumber < min || max <= min)
return min;
if (parsedNumber > max)
return max;
return static_cast<int>(parsedNumber);
}
static DialogFeaturesMap parseDialogFeaturesMap(const String& string)
{
DialogFeaturesMap features;
Vector<String> vector;
string.split(';', vector);
for (auto& featureString : vector) {
size_t separatorPosition = featureString.find('=');
size_t colonPosition = featureString.find(':');
if (separatorPosition != notFound && colonPosition != notFound)
continue; if (separatorPosition == notFound)
separatorPosition = colonPosition;
String key = featureString.left(separatorPosition).stripWhiteSpace();
String value;
if (separatorPosition != notFound) {
value = featureString.substring(separatorPosition + 1).stripWhiteSpace();
value = value.left(value.find(' '));
}
features.set(key, value);
}
return features;
}
}