blob: 4554db4b4659f39f9849ccdfe28c87406fc960fd [file]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/notifications/NotificationData.h"
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/SerializedScriptValue.h"
#include "bindings/core/v8/SerializedScriptValueFactory.h"
#include "core/dom/ExecutionContext.h"
#include "modules/notifications/Notification.h"
#include "modules/notifications/NotificationOptions.h"
#include "modules/vibration/VibrationController.h"
#include "public/platform/WebURL.h"
#include "wtf/CurrentTime.h"
namespace blink {
namespace {
WebNotificationData::Direction toDirectionEnumValue(const String& direction) {
if (direction == "ltr")
return WebNotificationData::DirectionLeftToRight;
if (direction == "rtl")
return WebNotificationData::DirectionRightToLeft;
return WebNotificationData::DirectionAuto;
}
WebURL completeURL(ExecutionContext* executionContext,
const String& stringUrl) {
WebURL url = executionContext->completeURL(stringUrl);
if (url.isValid())
return url;
return WebURL();
}
} // namespace
WebNotificationData createWebNotificationData(
ExecutionContext* executionContext,
const String& title,
const NotificationOptions& options,
ExceptionState& exceptionState) {
// If silent is true, the notification must not have a vibration pattern.
if (options.hasVibrate() && options.silent()) {
exceptionState.throwTypeError(
"Silent notifications must not specify vibration patterns.");
return WebNotificationData();
}
// If renotify is true, the notification must have a tag.
if (options.renotify() && options.tag().isEmpty()) {
exceptionState.throwTypeError(
"Notifications which set the renotify flag must specify a non-empty "
"tag.");
return WebNotificationData();
}
WebNotificationData webData;
webData.title = title;
webData.direction = toDirectionEnumValue(options.dir());
webData.lang = options.lang();
webData.body = options.body();
webData.tag = options.tag();
if (options.hasImage() && !options.image().isEmpty())
webData.image = completeURL(executionContext, options.image());
if (options.hasIcon() && !options.icon().isEmpty())
webData.icon = completeURL(executionContext, options.icon());
if (options.hasBadge() && !options.badge().isEmpty())
webData.badge = completeURL(executionContext, options.badge());
webData.vibrate =
VibrationController::sanitizeVibrationPattern(options.vibrate());
webData.timestamp = options.hasTimestamp()
? static_cast<double>(options.timestamp())
: WTF::currentTimeMS();
webData.renotify = options.renotify();
webData.silent = options.silent();
webData.requireInteraction = options.requireInteraction();
if (options.hasData()) {
const ScriptValue& data = options.data();
v8::Isolate* isolate = data.isolate();
DCHECK(isolate->InContext());
RefPtr<SerializedScriptValue> serializedScriptValue =
SerializedScriptValue::serialize(isolate, data.v8Value(), nullptr,
nullptr, exceptionState);
if (exceptionState.hadException())
return WebNotificationData();
Vector<char> serializedData;
serializedScriptValue->toWireBytes(serializedData);
webData.data = serializedData;
}
Vector<WebNotificationAction> actions;
const size_t maxActions = Notification::maxActions();
for (const NotificationAction& action : options.actions()) {
if (actions.size() >= maxActions)
break;
WebNotificationAction webAction;
webAction.action = action.action();
webAction.title = action.title();
if (action.type() == "button")
webAction.type = WebNotificationAction::Button;
else if (action.type() == "text")
webAction.type = WebNotificationAction::Text;
else
NOTREACHED() << "Unknown action type: " << action.type();
if (action.hasPlaceholder() &&
webAction.type == WebNotificationAction::Button) {
exceptionState.throwTypeError(
"Notifications of type \"button\" cannot specify a placeholder.");
return WebNotificationData();
}
webAction.placeholder = action.placeholder();
if (action.hasIcon() && !action.icon().isEmpty())
webAction.icon = completeURL(executionContext, action.icon());
actions.push_back(webAction);
}
webData.actions = actions;
return webData;
}
} // namespace blink