OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "modules/permissions/Permissions.h" | 5 #include "modules/permissions/Permissions.h" |
6 | 6 |
7 #include "bindings/core/v8/Dictionary.h" | 7 #include "bindings/core/v8/Dictionary.h" |
8 #include "bindings/core/v8/Nullable.h" | 8 #include "bindings/core/v8/Nullable.h" |
9 #include "bindings/core/v8/ScriptPromise.h" | 9 #include "bindings/core/v8/ScriptPromise.h" |
10 #include "bindings/core/v8/ScriptPromiseResolver.h" | 10 #include "bindings/core/v8/ScriptPromiseResolver.h" |
11 #include "bindings/modules/v8/V8MidiPermissionDescriptor.h" | 11 #include "bindings/modules/v8/V8MidiPermissionDescriptor.h" |
12 #include "bindings/modules/v8/V8PermissionDescriptor.h" | 12 #include "bindings/modules/v8/V8PermissionDescriptor.h" |
13 #include "bindings/modules/v8/V8PushPermissionDescriptor.h" | 13 #include "bindings/modules/v8/V8PushPermissionDescriptor.h" |
14 #include "core/dom/DOMException.h" | 14 #include "core/dom/DOMException.h" |
15 #include "core/dom/Document.h" | 15 #include "core/dom/Document.h" |
16 #include "core/dom/ExceptionCode.h" | 16 #include "core/dom/ExceptionCode.h" |
17 #include "modules/permissions/PermissionCallback.h" | 17 #include "core/frame/LocalFrame.h" |
18 #include "modules/permissions/PermissionController.h" | |
19 #include "modules/permissions/PermissionDescriptor.h" | 18 #include "modules/permissions/PermissionDescriptor.h" |
20 #include "modules/permissions/PermissionStatus.h" | 19 #include "modules/permissions/PermissionStatus.h" |
21 #include "modules/permissions/PermissionsCallback.h" | |
22 #include "platform/Logging.h" | 20 #include "platform/Logging.h" |
| 21 #include "platform/UserGestureIndicator.h" |
23 #include "public/platform/Platform.h" | 22 #include "public/platform/Platform.h" |
24 #include "public/platform/modules/permissions/WebPermissionClient.h" | 23 #include "public/platform/ServiceRegistry.h" |
| 24 #include "wtf/Functional.h" |
25 #include "wtf/NotFound.h" | 25 #include "wtf/NotFound.h" |
26 #include "wtf/PtrUtil.h" | 26 #include "wtf/PtrUtil.h" |
27 #include "wtf/Vector.h" | 27 #include "wtf/Vector.h" |
28 #include <memory> | 28 #include <memory> |
29 | 29 |
30 namespace blink { | 30 namespace blink { |
31 | 31 |
| 32 using mojom::blink::PermissionName; |
| 33 using mojom::blink::PermissionService; |
| 34 |
32 namespace { | 35 namespace { |
33 | 36 |
34 // Websites will be able to run code when `name()` is called, changing the | 37 // Websites will be able to run code when `name()` is called, changing the |
35 // current context. The caller should make sure that no assumption is made | 38 // current context. The caller should make sure that no assumption is made |
36 // after this has been called. | 39 // after this has been called. |
37 WebPermissionType getPermissionType(ScriptState* scriptState, const Dictionary&
rawPermission, const PermissionDescriptor& permission, ExceptionState& exception
State) | 40 PermissionName getPermissionName(ScriptState* scriptState, const Dictionary& raw
Permission, const PermissionDescriptor& permission, ExceptionState& exceptionSta
te) |
38 { | 41 { |
39 const String& name = permission.name(); | 42 const String& name = permission.name(); |
40 if (name == "geolocation") | 43 if (name == "geolocation") |
41 return WebPermissionTypeGeolocation; | 44 return PermissionName::GEOLOCATION; |
42 if (name == "notifications") | 45 if (name == "notifications") |
43 return WebPermissionTypeNotifications; | 46 return PermissionName::NOTIFICATIONS; |
44 if (name == "push") | 47 if (name == "push") |
45 return WebPermissionTypePushNotifications; | 48 return PermissionName::PUSH_NOTIFICATIONS; |
46 if (name == "midi") { | 49 if (name == "midi") { |
47 MidiPermissionDescriptor midiPermission = NativeValueTraits<MidiPermissi
onDescriptor>::nativeValue(scriptState->isolate(), rawPermission.v8Value(), exce
ptionState); | 50 MidiPermissionDescriptor midiPermission = NativeValueTraits<MidiPermissi
onDescriptor>::nativeValue(scriptState->isolate(), rawPermission.v8Value(), exce
ptionState); |
48 return midiPermission.sysex() ? WebPermissionTypeMidiSysEx : WebPermissi
onTypeMidi; | 51 return midiPermission.sysex() ? PermissionName::MIDI_SYSEX : PermissionN
ame::MIDI; |
49 } | 52 } |
50 if (name == "background-sync") | 53 if (name == "background-sync") |
51 return WebPermissionTypeBackgroundSync; | 54 return PermissionName::BACKGROUND_SYNC; |
52 | 55 |
53 ASSERT_NOT_REACHED(); | 56 ASSERT_NOT_REACHED(); |
54 return WebPermissionTypeGeolocation; | 57 return PermissionName::GEOLOCATION; |
55 } | 58 } |
56 | 59 |
57 // Parses the raw permission dictionary and returns the PermissionType if | 60 // Parses the raw permission dictionary and returns the PermissionType if |
58 // parsing was successful. If an exception occurs, it will be stored in | 61 // parsing was successful. If an exception occurs, it will be stored in |
59 // |exceptionState| and null will be returned. Therefore, the |exceptionState| | 62 // |exceptionState| and null will be returned. Therefore, the |exceptionState| |
60 // should be checked before attempting to use the returned permission as the | 63 // should be checked before attempting to use the returned permission as the |
61 // non-null assert will be fired otherwise. | 64 // non-null assert will be fired otherwise. |
62 Nullable<WebPermissionType> parsePermission(ScriptState* scriptState, const Dict
ionary rawPermission, ExceptionState& exceptionState) | 65 Nullable<PermissionName> parsePermission(ScriptState* scriptState, const Diction
ary rawPermission, ExceptionState& exceptionState) |
63 { | 66 { |
64 PermissionDescriptor permission = NativeValueTraits<PermissionDescriptor>::n
ativeValue(scriptState->isolate(), rawPermission.v8Value(), exceptionState); | 67 PermissionDescriptor permission = NativeValueTraits<PermissionDescriptor>::n
ativeValue(scriptState->isolate(), rawPermission.v8Value(), exceptionState); |
65 | 68 |
66 if (exceptionState.hadException()) { | 69 if (exceptionState.hadException()) { |
67 exceptionState.throwTypeError(exceptionState.message()); | 70 exceptionState.throwTypeError(exceptionState.message()); |
68 return Nullable<WebPermissionType>(); | 71 return Nullable<PermissionName>(); |
69 } | 72 } |
70 | 73 |
71 WebPermissionType type = getPermissionType(scriptState, rawPermission, permi
ssion, exceptionState); | 74 PermissionName name = getPermissionName(scriptState, rawPermission, permissi
on, exceptionState); |
72 if (exceptionState.hadException()) { | 75 if (exceptionState.hadException()) { |
73 exceptionState.throwTypeError(exceptionState.message()); | 76 exceptionState.throwTypeError(exceptionState.message()); |
74 return Nullable<WebPermissionType>(); | 77 return Nullable<PermissionName>(); |
75 } | 78 } |
76 | 79 |
77 // Here we reject any permissions which are not yet supported by Blink. | 80 // Here we reject any permissions which are not yet supported by Blink. |
78 if (type == WebPermissionTypePushNotifications) { | 81 if (name == PermissionName::PUSH_NOTIFICATIONS) { |
79 PushPermissionDescriptor pushPermission = NativeValueTraits<PushPermissi
onDescriptor>::nativeValue(scriptState->isolate(), rawPermission.v8Value(), exce
ptionState); | 82 PushPermissionDescriptor pushPermission = NativeValueTraits<PushPermissi
onDescriptor>::nativeValue(scriptState->isolate(), rawPermission.v8Value(), exce
ptionState); |
80 if (exceptionState.hadException()) { | 83 if (exceptionState.hadException()) { |
81 exceptionState.throwTypeError(exceptionState.message()); | 84 exceptionState.throwTypeError(exceptionState.message()); |
82 return Nullable<WebPermissionType>(); | 85 return Nullable<PermissionName>(); |
83 } | 86 } |
84 | 87 |
85 // Only "userVisibleOnly" push is supported for now. | 88 // Only "userVisibleOnly" push is supported for now. |
86 if (!pushPermission.userVisibleOnly()) { | 89 if (!pushPermission.userVisibleOnly()) { |
87 exceptionState.throwDOMException(NotSupportedError, "Push Permission
without userVisibleOnly:true isn't supported yet."); | 90 exceptionState.throwDOMException(NotSupportedError, "Push Permission
without userVisibleOnly:true isn't supported yet."); |
88 return Nullable<WebPermissionType>(); | 91 return Nullable<PermissionName>(); |
89 } | 92 } |
90 } | 93 } |
91 | 94 |
92 return Nullable<WebPermissionType>(type); | 95 return Nullable<PermissionName>(name); |
93 } | 96 } |
94 | 97 |
95 } // anonymous namespace | 98 } // anonymous namespace |
96 | 99 |
97 // static | 100 // static |
98 WebPermissionClient* Permissions::getClient(ExecutionContext* executionContext) | 101 bool Permissions::connectToService(ExecutionContext* executionContext, mojom::bl
ink::PermissionServiceRequest request) |
99 { | 102 { |
| 103 ServiceRegistry* serviceRegistry = nullptr; |
100 if (executionContext->isDocument()) { | 104 if (executionContext->isDocument()) { |
101 Document* document = toDocument(executionContext); | 105 Document* document = toDocument(executionContext); |
102 if (!document->frame()) | 106 if (document->frame()) |
103 return nullptr; | 107 serviceRegistry = document->frame()->serviceRegistry(); |
104 PermissionController* controller = PermissionController::from(*document-
>frame()); | 108 } else { |
105 return controller ? controller->client() : nullptr; | 109 serviceRegistry = Platform::current()->serviceRegistry(); |
106 } | 110 } |
107 return Platform::current()->permissionClient(); | 111 |
| 112 if (serviceRegistry) |
| 113 serviceRegistry->connectToRemoteService(std::move(request)); |
| 114 return serviceRegistry; |
108 } | 115 } |
109 | 116 |
110 ScriptPromise Permissions::query(ScriptState* scriptState, const Dictionary& raw
Permission) | 117 ScriptPromise Permissions::query(ScriptState* scriptState, const Dictionary& raw
Permission) |
111 { | 118 { |
112 ExceptionState exceptionState(ExceptionState::GetterContext, "query", "Perm
issions", scriptState->context()->Global(), scriptState->isolate()); | 119 ExceptionState exceptionState(ExceptionState::GetterContext, "query", "Perm
issions", scriptState->context()->Global(), scriptState->isolate()); |
113 Nullable<WebPermissionType> type = parsePermission(scriptState, rawPermissio
n, exceptionState); | 120 Nullable<PermissionName> name = parsePermission(scriptState, rawPermission,
exceptionState); |
114 if (exceptionState.hadException()) | 121 if (exceptionState.hadException()) |
115 return exceptionState.reject(scriptState); | 122 return exceptionState.reject(scriptState); |
116 | 123 |
117 // This must be called after `parsePermission` because the website might | 124 // This must be called after `parsePermission` because the website might |
118 // be able to run code. | 125 // be able to run code. |
119 WebPermissionClient* client = getClient(scriptState->getExecutionContext()); | 126 PermissionService* service = getService(scriptState->getExecutionContext()); |
120 if (!client) | 127 if (!service) |
121 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "In its current state, the global scope can't query pe
rmissions.")); | 128 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "In its current state, the global scope can't query pe
rmissions.")); |
122 | 129 |
123 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; | 130 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; |
124 ScriptPromise promise = resolver->promise(); | 131 ScriptPromise promise = resolver->promise(); |
125 | 132 |
126 // If the current origin is a file scheme, it will unlikely return a | 133 // If the current origin is a file scheme, it will unlikely return a |
127 // meaningful value because most APIs are broken on file scheme and no | 134 // meaningful value because most APIs are broken on file scheme and no |
128 // permission prompt will be shown even if the returned permission will most | 135 // permission prompt will be shown even if the returned permission will most |
129 // likely be "prompt". | 136 // likely be "prompt". |
130 client->queryPermission(type.get(), KURL(KURL(), scriptState->getExecutionCo
ntext()->getSecurityOrigin()->toString()), new PermissionCallback(resolver, type
.get())); | 137 service->HasPermission(name.get(), scriptState->getExecutionContext()->getSe
curityOrigin()->toString(), convertToBaseCallback(WTF::bind(&Permissions::taskCo
mplete, wrapPersistent(this), wrapPersistent(resolver), name.get()))); |
131 return promise; | 138 return promise; |
132 } | 139 } |
133 | 140 |
134 ScriptPromise Permissions::request(ScriptState* scriptState, const Dictionary& r
awPermission) | 141 ScriptPromise Permissions::request(ScriptState* scriptState, const Dictionary& r
awPermission) |
135 { | 142 { |
136 ExceptionState exceptionState(ExceptionState::GetterContext, "request", "Pe
rmissions", scriptState->context()->Global(), scriptState->isolate()); | 143 ExceptionState exceptionState(ExceptionState::GetterContext, "request", "Pe
rmissions", scriptState->context()->Global(), scriptState->isolate()); |
137 Nullable<WebPermissionType> type = parsePermission(scriptState, rawPermissio
n, exceptionState); | 144 Nullable<PermissionName> name = parsePermission(scriptState, rawPermission,
exceptionState); |
138 if (exceptionState.hadException()) | 145 if (exceptionState.hadException()) |
139 return exceptionState.reject(scriptState); | 146 return exceptionState.reject(scriptState); |
140 | 147 |
141 // This must be called after `parsePermission` because the website might | 148 // This must be called after `parsePermission` because the website might |
142 // be able to run code. | 149 // be able to run code. |
143 WebPermissionClient* client = getClient(scriptState->getExecutionContext()); | 150 PermissionService* service = getService(scriptState->getExecutionContext()); |
144 if (!client) | 151 if (!service) |
145 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "In its current state, the global scope can't request
permissions.")); | 152 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "In its current state, the global scope can't request
permissions.")); |
146 | 153 |
147 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; | 154 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; |
148 ScriptPromise promise = resolver->promise(); | 155 ScriptPromise promise = resolver->promise(); |
149 | 156 |
150 client->requestPermission(type.get(), KURL(KURL(), scriptState->getExecution
Context()->getSecurityOrigin()->toString()), new PermissionCallback(resolver, ty
pe.get())); | 157 service->RequestPermission(name.get(), scriptState->getExecutionContext()->g
etSecurityOrigin()->toString(), UserGestureIndicator::processingUserGesture(), c
onvertToBaseCallback(WTF::bind(&Permissions::taskComplete, wrapPersistent(this),
wrapPersistent(resolver), name.get()))); |
151 return promise; | 158 return promise; |
152 } | 159 } |
153 | 160 |
154 ScriptPromise Permissions::revoke(ScriptState* scriptState, const Dictionary& ra
wPermission) | 161 ScriptPromise Permissions::revoke(ScriptState* scriptState, const Dictionary& ra
wPermission) |
155 { | 162 { |
156 ExceptionState exceptionState(ExceptionState::GetterContext, "revoke", "Per
missions", scriptState->context()->Global(), scriptState->isolate()); | 163 ExceptionState exceptionState(ExceptionState::GetterContext, "revoke", "Per
missions", scriptState->context()->Global(), scriptState->isolate()); |
157 Nullable<WebPermissionType> type = parsePermission(scriptState, rawPermissio
n, exceptionState); | 164 Nullable<PermissionName> name = parsePermission(scriptState, rawPermission,
exceptionState); |
158 if (exceptionState.hadException()) | 165 if (exceptionState.hadException()) |
159 return exceptionState.reject(scriptState); | 166 return exceptionState.reject(scriptState); |
160 | 167 |
161 // This must be called after `parsePermission` because the website might | 168 // This must be called after `parsePermission` because the website might |
162 // be able to run code. | 169 // be able to run code. |
163 WebPermissionClient* client = getClient(scriptState->getExecutionContext()); | 170 PermissionService* service = getService(scriptState->getExecutionContext()); |
164 if (!client) | 171 if (!service) |
165 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "In its current state, the global scope can't revoke p
ermissions.")); | 172 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "In its current state, the global scope can't revoke p
ermissions.")); |
166 | 173 |
167 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; | 174 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; |
168 ScriptPromise promise = resolver->promise(); | 175 ScriptPromise promise = resolver->promise(); |
169 | 176 |
170 client->revokePermission(type.get(), KURL(KURL(), scriptState->getExecutionC
ontext()->getSecurityOrigin()->toString()), new PermissionCallback(resolver, typ
e.get())); | 177 service->RevokePermission(name.get(), scriptState->getExecutionContext()->ge
tSecurityOrigin()->toString(), convertToBaseCallback(WTF::bind(&Permissions::tas
kComplete, wrapPersistent(this), wrapPersistent(resolver), name.get()))); |
171 return promise; | 178 return promise; |
172 } | 179 } |
173 | 180 |
174 ScriptPromise Permissions::requestAll(ScriptState* scriptState, const Vector<Dic
tionary>& rawPermissions) | 181 ScriptPromise Permissions::requestAll(ScriptState* scriptState, const Vector<Dic
tionary>& rawPermissions) |
175 { | 182 { |
176 ExceptionState exceptionState(ExceptionState::GetterContext, "request", "Pe
rmissions", scriptState->context()->Global(), scriptState->isolate()); | 183 ExceptionState exceptionState(ExceptionState::GetterContext, "request", "Pe
rmissions", scriptState->context()->Global(), scriptState->isolate()); |
177 std::unique_ptr<Vector<WebPermissionType>> internalPermissions = wrapUnique(
new Vector<WebPermissionType>()); | 184 Vector<PermissionName> internalPermissions; |
178 std::unique_ptr<Vector<int>> callerIndexToInternalIndex = wrapUnique(new Vec
tor<int>(rawPermissions.size())); | 185 Vector<int> callerIndexToInternalIndex; |
| 186 callerIndexToInternalIndex.resize(rawPermissions.size()); |
179 for (size_t i = 0; i < rawPermissions.size(); ++i) { | 187 for (size_t i = 0; i < rawPermissions.size(); ++i) { |
180 const Dictionary& rawPermission = rawPermissions[i]; | 188 const Dictionary& rawPermission = rawPermissions[i]; |
181 | 189 |
182 Nullable<WebPermissionType> type = parsePermission(scriptState, rawPermi
ssion, exceptionState); | 190 Nullable<PermissionName> name = parsePermission(scriptState, rawPermissi
on, exceptionState); |
183 if (exceptionState.hadException()) | 191 if (exceptionState.hadException()) |
184 return exceptionState.reject(scriptState); | 192 return exceptionState.reject(scriptState); |
185 | 193 |
186 // Only append permissions to the vector that is passed to the client if
it is not already | 194 // Only append permissions to the vector that is passed to the client if
it is not already |
187 // in the vector (i.e. do not duplicate permisison types). | 195 // in the vector (i.e. do not duplicate permisison types). |
188 int internalIndex; | 196 int internalIndex; |
189 auto it = internalPermissions->find(type.get()); | 197 auto it = internalPermissions.find(name.get()); |
190 if (it == kNotFound) { | 198 if (it == kNotFound) { |
191 internalIndex = internalPermissions->size(); | 199 internalIndex = internalPermissions.size(); |
192 internalPermissions->append(type.get()); | 200 internalPermissions.append(name.get()); |
193 } else { | 201 } else { |
194 internalIndex = it; | 202 internalIndex = it; |
195 } | 203 } |
196 callerIndexToInternalIndex->operator[](i) = internalIndex; | 204 callerIndexToInternalIndex[i] = internalIndex; |
197 } | 205 } |
198 | 206 |
199 // This must be called after `parsePermission` because the website might | 207 // This must be called after `parsePermission` because the website might |
200 // be able to run code. | 208 // be able to run code. |
201 WebPermissionClient* client = getClient(scriptState->getExecutionContext()); | 209 PermissionService* service = getService(scriptState->getExecutionContext()); |
202 if (!client) | 210 if (!service) |
203 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "In its current state, the global scope can't request
permissions.")); | 211 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "In its current state, the global scope can't request
permissions.")); |
204 | 212 |
205 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; | 213 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; |
206 ScriptPromise promise = resolver->promise(); | 214 ScriptPromise promise = resolver->promise(); |
207 | 215 |
208 WebVector<WebPermissionType> internalWebPermissions = *internalPermissions; | 216 Vector<PermissionName> internalPermissionsCopy(internalPermissions); |
209 client->requestPermissions(internalWebPermissions, KURL(KURL(), scriptState-
>getExecutionContext()->getSecurityOrigin()->toString()), | 217 service->RequestPermissions(std::move(internalPermissions), scriptState->get
ExecutionContext()->getSecurityOrigin()->toString(), UserGestureIndicator::proce
ssingUserGesture(), |
210 new PermissionsCallback(resolver, std::move(internalPermissions), std::m
ove(callerIndexToInternalIndex))); | 218 convertToBaseCallback(WTF::bind(&Permissions::batchTaskComplete, wrapPer
sistent(this), wrapPersistent(resolver), std::move(internalPermissionsCopy), std
::move(callerIndexToInternalIndex)))); |
211 return promise; | 219 return promise; |
212 } | 220 } |
213 | 221 |
| 222 PermissionService* Permissions::getService(ExecutionContext* executionContext) |
| 223 { |
| 224 if (!m_service && connectToService(executionContext, mojo::GetProxy(&m_servi
ce))) |
| 225 m_service.set_connection_error_handler(convertToBaseCallback(WTF::bind(&
Permissions::serviceConnectionError, wrapWeakPersistent(this)))); |
| 226 return m_service.get(); |
| 227 } |
| 228 |
| 229 void Permissions::serviceConnectionError() |
| 230 { |
| 231 m_service.reset(); |
| 232 } |
| 233 |
| 234 void Permissions::taskComplete(ScriptPromiseResolver* resolver, PermissionName n
ame, mojom::blink::PermissionStatus result) |
| 235 { |
| 236 if (!resolver->getExecutionContext() || resolver->getExecutionContext()->act
iveDOMObjectsAreStopped()) |
| 237 return; |
| 238 resolver->resolve(PermissionStatus::take(resolver, result, name)); |
| 239 } |
| 240 |
| 241 void Permissions::batchTaskComplete(ScriptPromiseResolver* resolver, Vector<Perm
issionName> names, Vector<int> callerIndexToInternalIndex, mojo::WTFArray<mojom:
:blink::PermissionStatus> results) |
| 242 { |
| 243 if (!resolver->getExecutionContext() || resolver->getExecutionContext()->act
iveDOMObjectsAreStopped()) |
| 244 return; |
| 245 |
| 246 // Create the response vector by finding the status for each index by |
| 247 // using the caller to internal index mapping and looking up the status |
| 248 // using the internal index obtained. |
| 249 HeapVector<Member<PermissionStatus>> result; |
| 250 result.reserveInitialCapacity(callerIndexToInternalIndex.size()); |
| 251 for (int internalIndex : callerIndexToInternalIndex) |
| 252 result.append(PermissionStatus::createAndListen(resolver->getExecutionCo
ntext(), results[internalIndex], names[internalIndex])); |
| 253 resolver->resolve(result); |
| 254 } |
| 255 |
214 } // namespace blink | 256 } // namespace blink |
OLD | NEW |