1/*
2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "UserData.h"
28
29#include "APIArray.h"
30#include "APIData.h"
31#include "APIDictionary.h"
32#include "APIError.h"
33#include "APIFrameHandle.h"
34#include "APIGeometry.h"
35#include "APINumber.h"
36#include "APIPageGroupHandle.h"
37#include "APIPageHandle.h"
38#include "APISerializedScriptValue.h"
39#include "APIString.h"
40#include "APIURL.h"
41#include "APIURLRequest.h"
42#include "APIURLResponse.h"
43#include "APIUserContentURLPattern.h"
44#include "ArgumentCoders.h"
45#include "Encoder.h"
46#include "ShareableBitmap.h"
47#include "WebCertificateInfo.h"
48#include "WebImage.h"
49#include "WebRenderLayer.h"
50#include "WebRenderObject.h"
51
52#if PLATFORM(COCOA)
53#include "ObjCObjectGraph.h"
54#endif
55
56namespace WebKit {
57
58UserData::UserData()
59{
60}
61
62UserData::UserData(RefPtr<API::Object>&& object)
63 : m_object(WTFMove(object))
64{
65}
66
67UserData::~UserData()
68{
69}
70
71static bool shouldTransform(const API::Object& object, const UserData::Transformer& transformer)
72{
73 if (object.type() == API::Object::Type::Array) {
74 const auto& array = static_cast<const API::Array&>(object);
75
76 for (const auto& element : array.elements()) {
77 if (!element)
78 continue;
79
80 if (shouldTransform(*element, transformer))
81 return true;
82 }
83 }
84
85 if (object.type() == API::Object::Type::Dictionary) {
86 const auto& dictionary = static_cast<const API::Dictionary&>(object);
87
88 for (const auto& keyValuePair : dictionary.map()) {
89 if (!keyValuePair.value)
90 continue;
91
92 if (shouldTransform(*keyValuePair.value, transformer))
93 return true;
94 }
95 }
96
97 return transformer.shouldTransformObject(object);
98}
99
100static RefPtr<API::Object> transformGraph(API::Object& object, const UserData::Transformer& transformer)
101{
102 if (object.type() == API::Object::Type::Array) {
103 auto& array = static_cast<API::Array&>(object);
104
105 Vector<RefPtr<API::Object>> elements;
106 elements.reserveInitialCapacity(array.elements().size());
107 for (const auto& element : array.elements()) {
108 if (!element)
109 elements.uncheckedAppend(nullptr);
110 else
111 elements.uncheckedAppend(transformGraph(*element, transformer));
112 }
113
114 return API::Array::create(WTFMove(elements));
115 }
116
117 if (object.type() == API::Object::Type::Dictionary) {
118 auto& dictionary = static_cast<API::Dictionary&>(object);
119
120 API::Dictionary::MapType map;
121 for (const auto& keyValuePair : dictionary.map()) {
122 if (!keyValuePair.value)
123 map.add(keyValuePair.key, nullptr);
124 else
125 map.add(keyValuePair.key, transformGraph(*keyValuePair.value, transformer));
126 }
127 return API::Dictionary::create(WTFMove(map));
128 }
129
130 return transformer.transformObject(object);
131}
132
133RefPtr<API::Object> UserData::transform(API::Object* object, const Transformer& transformer)
134{
135 if (!object)
136 return nullptr;
137
138 if (!shouldTransform(*object, transformer))
139 return object;
140
141 return transformGraph(*object, transformer);
142}
143
144void UserData::encode(IPC::Encoder& encoder) const
145{
146 encode(encoder, m_object.get());
147}
148
149bool UserData::decode(IPC::Decoder& decoder, UserData& userData)
150{
151 return decode(decoder, userData.m_object);
152}
153
154void UserData::encode(IPC::Encoder& encoder, const API::Object* object)
155{
156 if (!object) {
157 encoder.encodeEnum(API::Object::Type::Null);
158 return;
159 }
160
161 encode(encoder, *object);
162}
163
164void UserData::encode(IPC::Encoder& encoder, const API::Object& object)
165{
166 API::Object::Type type = object.type();
167 encoder.encodeEnum(type);
168
169 switch (object.type()) {
170 case API::Object::Type::Array: {
171 auto& array = static_cast<const API::Array&>(object);
172 encoder << static_cast<uint64_t>(array.size());
173 for (size_t i = 0; i < array.size(); ++i)
174 encode(encoder, array.at(i));
175 break;
176 }
177
178 case API::Object::Type::Boolean:
179 static_cast<const API::Boolean&>(object).encode(encoder);
180 break;
181
182 case API::Object::Type::CertificateInfo: {
183 const auto& certificateInfo = static_cast<const WebCertificateInfo&>(object);
184 encoder << certificateInfo.certificateInfo();
185 break;
186 }
187
188 case API::Object::Type::Data:
189 static_cast<const API::Data&>(object).encode(encoder);
190 break;
191
192 case API::Object::Type::Dictionary: {
193 auto& dictionary = static_cast<const API::Dictionary&>(object);
194 auto& map = dictionary.map();
195
196 encoder << static_cast<uint64_t>(map.size());
197 for (const auto& keyValuePair : map) {
198 encoder << keyValuePair.key;
199 encode(encoder, keyValuePair.value.get());
200 }
201 break;
202 }
203
204 case API::Object::Type::Double:
205 static_cast<const API::Double&>(object).encode(encoder);
206 break;
207
208 case API::Object::Type::Error:
209 static_cast<const API::Error&>(object).encode(encoder);
210 break;
211
212 case API::Object::Type::FrameHandle:
213 static_cast<const API::FrameHandle&>(object).encode(encoder);
214 break;
215
216 case API::Object::Type::Image: {
217 auto& image = static_cast<const WebImage&>(object);
218
219 ShareableBitmap::Handle handle;
220 ASSERT(image.bitmap().isBackedBySharedMemory());
221 if (!image.bitmap().isBackedBySharedMemory() || !image.bitmap().createHandle(handle)) {
222 // Initial false indicates no allocated bitmap or is not shareable.
223 encoder << false;
224 break;
225 }
226
227 // Initial true indicates a bitmap was allocated and is shareable.
228 encoder << true;
229 encoder << handle;
230 break;
231 }
232
233 case API::Object::Type::PageGroupHandle:
234 static_cast<const API::PageGroupHandle&>(object).encode(encoder);
235 break;
236
237 case API::Object::Type::PageHandle:
238 static_cast<const API::PageHandle&>(object).encode(encoder);
239 break;
240
241 case API::Object::Type::Point:
242 static_cast<const API::Point&>(object).encode(encoder);
243 break;
244
245 case API::Object::Type::Rect:
246 static_cast<const API::Rect&>(object).encode(encoder);
247 break;
248
249 case API::Object::Type::RenderLayer: {
250 auto& renderLayer = static_cast<const WebRenderLayer&>(object);
251
252 encode(encoder, renderLayer.renderer());
253 encoder << renderLayer.isReflection();
254 encoder << renderLayer.isClipping();
255 encoder << renderLayer.isClipped();
256 encoder << static_cast<uint32_t>(renderLayer.compositingLayerType());
257 encoder << renderLayer.absoluteBoundingBox();
258 encoder << renderLayer.backingStoreMemoryEstimate();
259 encode(encoder, renderLayer.negativeZOrderList());
260 encode(encoder, renderLayer.normalFlowList());
261 encode(encoder, renderLayer.positiveZOrderList());
262 encode(encoder, renderLayer.frameContentsLayer());
263 break;
264 }
265
266 case API::Object::Type::RenderObject: {
267 auto& renderObject = static_cast<const WebRenderObject&>(object);
268
269 encoder << renderObject.name();
270 encoder << renderObject.elementTagName();
271 encoder << renderObject.elementID();
272 encode(encoder, renderObject.elementClassNames());
273 encoder << renderObject.absolutePosition();
274 encoder << renderObject.frameRect();
275 encoder << renderObject.textSnippet();
276 encoder << renderObject.textLength();
277 encode(encoder, renderObject.children());
278 break;
279 }
280
281 case API::Object::Type::SerializedScriptValue: {
282 auto& serializedScriptValue = static_cast<const API::SerializedScriptValue&>(object);
283 encoder << serializedScriptValue.dataReference();
284 break;
285 }
286
287 case API::Object::Type::Size:
288 static_cast<const API::Size&>(object).encode(encoder);
289 break;
290
291 case API::Object::Type::String: {
292 auto& string = static_cast<const API::String&>(object);
293 encoder << string.string();
294 break;
295 }
296
297 case API::Object::Type::URL:
298 static_cast<const API::URL&>(object).encode(encoder);
299 break;
300
301 case API::Object::Type::URLRequest:
302 static_cast<const API::URLRequest&>(object).encode(encoder);
303 break;
304
305 case API::Object::Type::URLResponse:
306 static_cast<const API::URLResponse&>(object).encode(encoder);
307 break;
308
309 case API::Object::Type::UInt64:
310 static_cast<const API::UInt64&>(object).encode(encoder);
311 break;
312
313 case API::Object::Type::Int64:
314 static_cast<const API::Int64&>(object).encode(encoder);
315 break;
316
317 case API::Object::Type::UserContentURLPattern: {
318 auto& urlPattern = static_cast<const API::UserContentURLPattern&>(object);
319 encoder << urlPattern.patternString();
320 break;
321 }
322
323#if PLATFORM(COCOA)
324 case API::Object::Type::ObjCObjectGraph:
325 static_cast<const ObjCObjectGraph&>(object).encode(encoder);
326 break;
327#endif
328
329 default:
330 ASSERT_NOT_REACHED();
331 }
332}
333
334bool UserData::decode(IPC::Decoder& decoder, RefPtr<API::Object>& result)
335{
336 API::Object::Type type;
337 if (!decoder.decodeEnum(type))
338 return false;
339
340 switch (type) {
341 case API::Object::Type::Array: {
342 uint64_t size;
343 if (!decoder.decode(size))
344 return false;
345
346 Vector<RefPtr<API::Object>> elements;
347 for (size_t i = 0; i < size; ++i) {
348 RefPtr<API::Object> element;
349 if (!decode(decoder, element))
350 return false;
351
352 elements.append(WTFMove(element));
353 }
354
355 result = API::Array::create(WTFMove(elements));
356 break;
357 }
358
359 case API::Object::Type::Boolean:
360 if (!API::Boolean::decode(decoder, result))
361 return false;
362 break;
363
364 case API::Object::Type::CertificateInfo: {
365 WebCore::CertificateInfo certificateInfo;
366 if (!decoder.decode(certificateInfo))
367 return false;
368 result = WebCertificateInfo::create(certificateInfo);
369 break;
370 }
371
372 case API::Object::Type::Data:
373 if (!API::Data::decode(decoder, result))
374 return false;
375 break;
376
377 case API::Object::Type::Dictionary: {
378 uint64_t size;
379 if (!decoder.decode(size))
380 return false;
381
382 API::Dictionary::MapType map;
383 for (size_t i = 0; i < size; ++i) {
384 String key;
385 if (!decoder.decode(key))
386 return false;
387
388 RefPtr<API::Object> value;
389 if (!decode(decoder, value))
390 return false;
391
392 if (!map.add(WTFMove(key), WTFMove(value)).isNewEntry)
393 return false;
394 }
395
396 result = API::Dictionary::create(WTFMove(map));
397 break;
398 }
399
400 case API::Object::Type::Double:
401 if (!API::Double::decode(decoder, result))
402 return false;
403 break;
404
405 case API::Object::Type::Error:
406 if (!API::Error::decode(decoder, result))
407 return false;
408 break;
409
410 case API::Object::Type::FrameHandle:
411 if (!API::FrameHandle::decode(decoder, result))
412 return false;
413 break;
414
415 case API::Object::Type::Image: {
416 bool didEncode = false;
417 if (!decoder.decode(didEncode))
418 return false;
419
420 if (!didEncode)
421 break;
422
423 ShareableBitmap::Handle handle;
424 if (!decoder.decode(handle))
425 return false;
426
427 auto bitmap = ShareableBitmap::create(handle);
428 if (!bitmap)
429 return false;
430
431 result = WebImage::create(bitmap.releaseNonNull());
432 break;
433 }
434
435 case API::Object::Type::Null:
436 result = nullptr;
437 break;
438
439 case API::Object::Type::PageGroupHandle:
440 if (!API::PageGroupHandle::decode(decoder, result))
441 return false;
442 break;
443
444 case API::Object::Type::PageHandle:
445 if (!API::PageHandle::decode(decoder, result))
446 return false;
447 break;
448
449 case API::Object::Type::Point:
450 if (!API::Point::decode(decoder, result))
451 return false;
452 break;
453
454 case API::Object::Type::Rect:
455 if (!API::Rect::decode(decoder, result))
456 return false;
457 break;
458
459 case API::Object::Type::RenderLayer: {
460 RefPtr<API::Object> renderer;
461 bool isReflection;
462 bool isClipping;
463 bool isClipped;
464 uint32_t compositingLayerTypeAsUInt32;
465 WebCore::IntRect absoluteBoundingBox;
466 double backingStoreMemoryEstimate;
467 RefPtr<API::Object> negativeZOrderList;
468 RefPtr<API::Object> normalFlowList;
469 RefPtr<API::Object> positiveZOrderList;
470 RefPtr<API::Object> frameContentsLayer;
471
472 if (!decode(decoder, renderer))
473 return false;
474 if (renderer->type() != API::Object::Type::RenderObject)
475 return false;
476 if (!decoder.decode(isReflection))
477 return false;
478 if (!decoder.decode(isClipping))
479 return false;
480 if (!decoder.decode(isClipped))
481 return false;
482 if (!decoder.decode(compositingLayerTypeAsUInt32))
483 return false;
484 if (!decoder.decode(absoluteBoundingBox))
485 return false;
486 if (!decoder.decode(backingStoreMemoryEstimate))
487 return false;
488 if (!decode(decoder, negativeZOrderList))
489 return false;
490 if (!decode(decoder, normalFlowList))
491 return false;
492 if (!decode(decoder, positiveZOrderList))
493 return false;
494 if (!decode(decoder, frameContentsLayer))
495 return false;
496
497 result = WebRenderLayer::create(static_pointer_cast<WebRenderObject>(renderer), isReflection, isClipping, isClipped, static_cast<WebRenderLayer::CompositingLayerType>(compositingLayerTypeAsUInt32), absoluteBoundingBox, backingStoreMemoryEstimate, static_pointer_cast<API::Array>(negativeZOrderList), static_pointer_cast<API::Array>(normalFlowList), static_pointer_cast<API::Array>(positiveZOrderList), static_pointer_cast<WebRenderLayer>(frameContentsLayer));
498 break;
499 }
500
501 case API::Object::Type::RenderObject: {
502 String name;
503 String textSnippet;
504 String elementTagName;
505 String elementID;
506 unsigned textLength;
507 RefPtr<API::Object> elementClassNames;
508 WebCore::IntPoint absolutePosition;
509 WebCore::IntRect frameRect;
510 RefPtr<API::Object> children;
511
512 if (!decoder.decode(name))
513 return false;
514 if (!decoder.decode(elementTagName))
515 return false;
516 if (!decoder.decode(elementID))
517 return false;
518 if (!decode(decoder, elementClassNames))
519 return false;
520 if (!decoder.decode(absolutePosition))
521 return false;
522 if (!decoder.decode(frameRect))
523 return false;
524 if (!decoder.decode(textSnippet))
525 return false;
526 if (!decoder.decode(textLength))
527 return false;
528 if (!decode(decoder, children))
529 return false;
530 if (children && children->type() != API::Object::Type::Array)
531 return false;
532 result = WebRenderObject::create(name, elementTagName, elementID, static_pointer_cast<API::Array>(elementClassNames), absolutePosition, frameRect, textSnippet, textLength, static_pointer_cast<API::Array>(children));
533 break;
534 }
535
536 case API::Object::Type::SerializedScriptValue: {
537 IPC::DataReference dataReference;
538 if (!decoder.decode(dataReference))
539 return false;
540
541 result = API::SerializedScriptValue::adopt(dataReference.vector());
542 break;
543 }
544
545 case API::Object::Type::Size:
546 if (!API::Size::decode(decoder, result))
547 return false;
548 break;
549
550 case API::Object::Type::String: {
551 String string;
552 if (!decoder.decode(string))
553 return false;
554
555 result = API::String::create(string);
556 break;
557 }
558
559 case API::Object::Type::URL:
560 if (!API::URL::decode(decoder, result))
561 return false;
562 break;
563
564 case API::Object::Type::URLRequest:
565 if (!API::URLRequest::decode(decoder, result))
566 return false;
567 break;
568
569 case API::Object::Type::URLResponse:
570 if (!API::URLResponse::decode(decoder, result))
571 return false;
572 break;
573
574 case API::Object::Type::UInt64:
575 if (!API::UInt64::decode(decoder, result))
576 return false;
577 break;
578
579 case API::Object::Type::Int64:
580 if (!API::Int64::decode(decoder, result))
581 return false;
582 break;
583
584 case API::Object::Type::UserContentURLPattern: {
585 String string;
586 if (!decoder.decode(string))
587 return false;
588 result = API::UserContentURLPattern::create(string);
589 break;
590 }
591
592#if PLATFORM(COCOA)
593 case API::Object::Type::ObjCObjectGraph:
594 if (!ObjCObjectGraph::decode(decoder, result))
595 return false;
596 break;
597#endif
598
599 default:
600 ASSERT_NOT_REACHED();
601 }
602
603 return true;
604}
605
606} // namespace WebKit
607