blob: 572970a51b3ec1dff40b56ff9b6c38e62261c21e [file] [log] [blame]
// 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.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.append(webAction);
}
webData.actions = actions;
return webData;
}
} // namespace blink