| // 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 "third_party/blink/renderer/modules/notifications/notification_data.h" |
| |
| #include "third_party/blink/public/common/notifications/notification_constants.h" |
| #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h" |
| #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value_factory.h" |
| #include "third_party/blink/renderer/core/execution_context/execution_context.h" |
| #include "third_party/blink/renderer/modules/notifications/notification.h" |
| #include "third_party/blink/renderer/modules/notifications/notification_options.h" |
| #include "third_party/blink/renderer/modules/notifications/timestamp_trigger.h" |
| #include "third_party/blink/renderer/modules/vibration/vibration_controller.h" |
| #include "third_party/blink/renderer/platform/bindings/exception_state.h" |
| #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" |
| #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" |
| #include "third_party/blink/renderer/platform/wtf/text/string_view.h" |
| |
| namespace blink { |
| namespace { |
| |
| mojom::blink::NotificationDirection ToDirectionEnumValue( |
| const String& direction) { |
| if (direction == "ltr") |
| return mojom::blink::NotificationDirection::LEFT_TO_RIGHT; |
| if (direction == "rtl") |
| return mojom::blink::NotificationDirection::RIGHT_TO_LEFT; |
| |
| return mojom::blink::NotificationDirection::AUTO; |
| } |
| |
| KURL CompleteURL(ExecutionContext* context, const String& string_url) { |
| KURL url = context->CompleteURL(string_url); |
| if (url.IsValid()) |
| return url; |
| return KURL(); |
| } |
| |
| } // namespace |
| |
| mojom::blink::NotificationDataPtr CreateNotificationData( |
| ExecutionContext* context, |
| const String& title, |
| const NotificationOptions* options, |
| ExceptionState& exception_state) { |
| // If silent is true, the notification must not have a vibration pattern. |
| if (options->hasVibrate() && options->silent()) { |
| exception_state.ThrowTypeError( |
| "Silent notifications must not specify vibration patterns."); |
| return nullptr; |
| } |
| |
| // If renotify is true, the notification must have a tag. |
| if (options->renotify() && options->tag().IsEmpty()) { |
| exception_state.ThrowTypeError( |
| "Notifications which set the renotify flag must specify a non-empty " |
| "tag."); |
| return nullptr; |
| } |
| |
| auto notification_data = mojom::blink::NotificationData::New(); |
| |
| notification_data->title = title; |
| notification_data->direction = ToDirectionEnumValue(options->dir()); |
| notification_data->lang = options->lang(); |
| notification_data->body = options->body(); |
| notification_data->tag = options->tag(); |
| |
| if (options->hasImage() && !options->image().IsEmpty()) |
| notification_data->image = CompleteURL(context, options->image()); |
| |
| if (options->hasIcon() && !options->icon().IsEmpty()) |
| notification_data->icon = CompleteURL(context, options->icon()); |
| |
| if (options->hasBadge() && !options->badge().IsEmpty()) |
| notification_data->badge = CompleteURL(context, options->badge()); |
| |
| VibrationController::VibrationPattern vibration_pattern = |
| VibrationController::SanitizeVibrationPattern(options->vibrate()); |
| notification_data->vibration_pattern = Vector<int32_t>(); |
| notification_data->vibration_pattern->Append(vibration_pattern.data(), |
| vibration_pattern.size()); |
| notification_data->timestamp = options->hasTimestamp() |
| ? static_cast<double>(options->timestamp()) |
| : base::Time::Now().ToDoubleT() * 1000.0; |
| notification_data->renotify = options->renotify(); |
| notification_data->silent = options->silent(); |
| notification_data->require_interaction = options->requireInteraction(); |
| |
| if (options->hasData()) { |
| const ScriptValue& data = options->data(); |
| v8::Isolate* isolate = data.GetIsolate(); |
| DCHECK(isolate->InContext()); |
| SerializedScriptValue::SerializeOptions serialize_options; |
| serialize_options.for_storage = SerializedScriptValue::kForStorage; |
| scoped_refptr<SerializedScriptValue> serialized_script_value = |
| SerializedScriptValue::Serialize(isolate, data.V8Value(), |
| serialize_options, exception_state); |
| if (exception_state.HadException()) |
| return nullptr; |
| |
| notification_data->data = Vector<uint8_t>(); |
| notification_data->data->Append( |
| serialized_script_value->Data(), |
| SafeCast<wtf_size_t>(serialized_script_value->DataLengthInBytes())); |
| } |
| |
| Vector<mojom::blink::NotificationActionPtr> actions; |
| |
| const size_t max_actions = Notification::maxActions(); |
| for (const NotificationAction* action : options->actions()) { |
| if (actions.size() >= max_actions) |
| break; |
| |
| auto notification_action = mojom::blink::NotificationAction::New(); |
| notification_action->action = action->action(); |
| notification_action->title = action->title(); |
| |
| if (action->type() == "button") |
| notification_action->type = mojom::blink::NotificationActionType::BUTTON; |
| else if (action->type() == "text") |
| notification_action->type = mojom::blink::NotificationActionType::TEXT; |
| else |
| NOTREACHED() << "Unknown action type: " << action->type(); |
| |
| if (action->hasPlaceholder() && |
| notification_action->type == |
| mojom::blink::NotificationActionType::BUTTON) { |
| exception_state.ThrowTypeError( |
| "Notifications of type \"button\" cannot specify a placeholder."); |
| return nullptr; |
| } |
| |
| notification_action->placeholder = action->placeholder(); |
| |
| if (action->hasIcon() && !action->icon().IsEmpty()) |
| notification_action->icon = CompleteURL(context, action->icon()); |
| |
| actions.push_back(std::move(notification_action)); |
| } |
| |
| notification_data->actions = std::move(actions); |
| |
| if (options->hasShowTrigger()) { |
| UseCounter::Count(context, WebFeature::kNotificationShowTrigger); |
| |
| auto* timestamp_trigger = options->showTrigger(); |
| auto timestamp = base::Time::FromJsTime(timestamp_trigger->timestamp()); |
| |
| if (timestamp - base::Time::Now() > kMaxNotificationShowTriggerDelay) { |
| exception_state.ThrowTypeError( |
| "Notification trigger timestamp too far ahead in the future."); |
| return nullptr; |
| } |
| |
| notification_data->show_trigger_timestamp = timestamp; |
| } |
| |
| return notification_data; |
| } |
| |
| } // namespace blink |