1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "content/common/page_state_serialization.h" 6 7#include <algorithm> 8#include <limits> 9 10#include "base/pickle.h" 11#include "base/strings/string_number_conversions.h" 12#include "base/strings/string_util.h" 13#include "base/strings/utf_string_conversions.h" 14#include "ui/gfx/screen.h" 15 16namespace content { 17namespace { 18 19#if defined(OS_ANDROID) 20float g_device_scale_factor_for_testing = 0.0; 21#endif 22 23//----------------------------------------------------------------------------- 24 25void AppendDataToHttpBody(ExplodedHttpBody* http_body, const char* data, 26 int data_length) { 27 ExplodedHttpBodyElement element; 28 element.type = blink::WebHTTPBody::Element::TypeData; 29 element.data.assign(data, data_length); 30 http_body->elements.push_back(element); 31} 32 33void AppendFileRangeToHttpBody(ExplodedHttpBody* http_body, 34 const base::NullableString16& file_path, 35 int file_start, 36 int file_length, 37 double file_modification_time) { 38 ExplodedHttpBodyElement element; 39 element.type = blink::WebHTTPBody::Element::TypeFile; 40 element.file_path = file_path; 41 element.file_start = file_start; 42 element.file_length = file_length; 43 element.file_modification_time = file_modification_time; 44 http_body->elements.push_back(element); 45} 46 47void AppendURLRangeToHttpBody(ExplodedHttpBody* http_body, 48 const GURL& url, 49 int file_start, 50 int file_length, 51 double file_modification_time) { 52 ExplodedHttpBodyElement element; 53 element.type = blink::WebHTTPBody::Element::TypeFileSystemURL; 54 element.filesystem_url = url; 55 element.file_start = file_start; 56 element.file_length = file_length; 57 element.file_modification_time = file_modification_time; 58 http_body->elements.push_back(element); 59} 60 61void AppendBlobToHttpBody(ExplodedHttpBody* http_body, 62 const std::string& uuid) { 63 ExplodedHttpBodyElement element; 64 element.type = blink::WebHTTPBody::Element::TypeBlob; 65 element.blob_uuid = uuid; 66 http_body->elements.push_back(element); 67} 68 69//---------------------------------------------------------------------------- 70 71void AppendReferencedFilesFromHttpBody( 72 const std::vector<ExplodedHttpBodyElement>& elements, 73 std::vector<base::NullableString16>* referenced_files) { 74 for (size_t i = 0; i < elements.size(); ++i) { 75 if (elements[i].type == blink::WebHTTPBody::Element::TypeFile) 76 referenced_files->push_back(elements[i].file_path); 77 } 78} 79 80bool AppendReferencedFilesFromDocumentState( 81 const std::vector<base::NullableString16>& document_state, 82 std::vector<base::NullableString16>* referenced_files) { 83 if (document_state.empty()) 84 return true; 85 86 // This algorithm is adapted from Blink's core/html/FormController.cpp code. 87 // We only care about how that code worked when this code snapshot was taken 88 // as this code is only needed for backwards compat. 89 // 90 // For reference, see FormController::formStatesFromStateVector at: 91 // http://src.chromium.org/viewvc/blink/trunk/Source/core/html/FormController.cpp?pathrev=152274 92 93 size_t index = 0; 94 95 if (document_state.size() < 3) 96 return false; 97 98 index++; // Skip over magic signature. 99 index++; // Skip over form key. 100 101 size_t item_count; 102 if (!base::StringToSizeT(document_state[index++].string(), &item_count)) 103 return false; 104 105 while (item_count--) { 106 if (index + 1 >= document_state.size()) 107 return false; 108 109 index++; // Skip over name. 110 const base::NullableString16& type = document_state[index++]; 111 112 if (index >= document_state.size()) 113 return false; 114 115 size_t value_size; 116 if (!base::StringToSizeT(document_state[index++].string(), &value_size)) 117 return false; 118 119 if (index + value_size > document_state.size() || 120 index + value_size < index) // Check for overflow. 121 return false; 122 123 if (EqualsASCII(type.string(), "file")) { 124 if (value_size != 2) 125 return false; 126 127 referenced_files->push_back(document_state[index++]); 128 index++; // Skip over display name. 129 } else { 130 index += value_size; 131 } 132 } 133 134 return true; 135} 136 137bool RecursivelyAppendReferencedFiles( 138 const ExplodedFrameState& frame_state, 139 std::vector<base::NullableString16>* referenced_files) { 140 if (!frame_state.http_body.is_null) { 141 AppendReferencedFilesFromHttpBody(frame_state.http_body.elements, 142 referenced_files); 143 } 144 145 if (!AppendReferencedFilesFromDocumentState(frame_state.document_state, 146 referenced_files)) 147 return false; 148 149 for (size_t i = 0; i < frame_state.children.size(); ++i) { 150 if (!RecursivelyAppendReferencedFiles(frame_state.children[i], 151 referenced_files)) 152 return false; 153 } 154 155 return true; 156} 157 158//---------------------------------------------------------------------------- 159 160struct SerializeObject { 161 SerializeObject() 162 : version(0), 163 parse_error(false) { 164 } 165 166 SerializeObject(const char* data, int len) 167 : pickle(data, len), 168 version(0), 169 parse_error(false) { 170 iter = PickleIterator(pickle); 171 } 172 173 std::string GetAsString() { 174 return std::string(static_cast<const char*>(pickle.data()), pickle.size()); 175 } 176 177 Pickle pickle; 178 PickleIterator iter; 179 int version; 180 bool parse_error; 181}; 182 183// Version ID of serialized format. 184// 11: Min version 185// 12: Adds support for contains_passwords in HTTP body 186// 13: Adds support for URL (FileSystem URL) 187// 14: Adds list of referenced files, version written only for first item. 188// 15: Removes a bunch of values we defined but never used. 189// 16: Switched from blob urls to blob uuids. 190// 17: Add a target frame id number. 191// 18: Add referrer policy. 192// 19: Remove target frame id, which was a bad idea, and original url string, 193// which is no longer used. 194// 20: Add pinch viewport scroll offset, the offset of the pinched zoomed 195// viewport within the unzoomed main frame. 196// 21: Add frame sequence number 197// 198// NOTE: If the version is -1, then the pickle contains only a URL string. 199// See ReadPageState. 200// 201const int kMinVersion = 11; 202const int kCurrentVersion = 21; 203 204// A bunch of convenience functions to read/write to SerializeObjects. The 205// de-serializers assume the input data will be in the correct format and fall 206// back to returning safe defaults when not. 207 208void WriteData(const void* data, int length, SerializeObject* obj) { 209 obj->pickle.WriteData(static_cast<const char*>(data), length); 210} 211 212void ReadData(SerializeObject* obj, const void** data, int* length) { 213 const char* tmp; 214 if (obj->pickle.ReadData(&obj->iter, &tmp, length)) { 215 *data = tmp; 216 } else { 217 obj->parse_error = true; 218 *data = NULL; 219 *length = 0; 220 } 221} 222 223void WriteInteger(int data, SerializeObject* obj) { 224 obj->pickle.WriteInt(data); 225} 226 227int ReadInteger(SerializeObject* obj) { 228 int tmp; 229 if (obj->pickle.ReadInt(&obj->iter, &tmp)) 230 return tmp; 231 obj->parse_error = true; 232 return 0; 233} 234 235void ConsumeInteger(SerializeObject* obj) { 236 int unused ALLOW_UNUSED = ReadInteger(obj); 237} 238 239void WriteInteger64(int64 data, SerializeObject* obj) { 240 obj->pickle.WriteInt64(data); 241} 242 243int64 ReadInteger64(SerializeObject* obj) { 244 int64 tmp = 0; 245 if (obj->pickle.ReadInt64(&obj->iter, &tmp)) 246 return tmp; 247 obj->parse_error = true; 248 return 0; 249} 250 251void ConsumeInteger64(SerializeObject* obj) { 252 int64 unused ALLOW_UNUSED = ReadInteger64(obj); 253} 254 255void WriteReal(double data, SerializeObject* obj) { 256 WriteData(&data, sizeof(double), obj); 257} 258 259double ReadReal(SerializeObject* obj) { 260 const void* tmp = NULL; 261 int length = 0; 262 double value = 0.0; 263 ReadData(obj, &tmp, &length); 264 if (length == static_cast<int>(sizeof(double))) { 265 // Use memcpy, as tmp may not be correctly aligned. 266 memcpy(&value, tmp, sizeof(double)); 267 } else { 268 obj->parse_error = true; 269 } 270 return value; 271} 272 273void ConsumeReal(SerializeObject* obj) { 274 double unused ALLOW_UNUSED = ReadReal(obj); 275} 276 277void WriteBoolean(bool data, SerializeObject* obj) { 278 obj->pickle.WriteInt(data ? 1 : 0); 279} 280 281bool ReadBoolean(SerializeObject* obj) { 282 bool tmp; 283 if (obj->pickle.ReadBool(&obj->iter, &tmp)) 284 return tmp; 285 obj->parse_error = true; 286 return false; 287} 288 289void ConsumeBoolean(SerializeObject* obj) { 290 bool unused ALLOW_UNUSED = ReadBoolean(obj); 291} 292 293void WriteGURL(const GURL& url, SerializeObject* obj) { 294 obj->pickle.WriteString(url.possibly_invalid_spec()); 295} 296 297GURL ReadGURL(SerializeObject* obj) { 298 std::string spec; 299 if (obj->pickle.ReadString(&obj->iter, &spec)) 300 return GURL(spec); 301 obj->parse_error = true; 302 return GURL(); 303} 304 305void WriteStdString(const std::string& s, SerializeObject* obj) { 306 obj->pickle.WriteString(s); 307} 308 309std::string ReadStdString(SerializeObject* obj) { 310 std::string s; 311 if (obj->pickle.ReadString(&obj->iter, &s)) 312 return s; 313 obj->parse_error = true; 314 return std::string(); 315} 316 317// WriteString pickles the NullableString16 as <int length><char16* data>. 318// If length == -1, then the NullableString16 itself is null. Otherwise the 319// length is the number of char16 (not bytes) in the NullableString16. 320void WriteString(const base::NullableString16& str, SerializeObject* obj) { 321 if (str.is_null()) { 322 obj->pickle.WriteInt(-1); 323 } else { 324 const base::char16* data = str.string().data(); 325 size_t length_in_bytes = str.string().length() * sizeof(base::char16); 326 327 CHECK_LT(length_in_bytes, 328 static_cast<size_t>(std::numeric_limits<int>::max())); 329 obj->pickle.WriteInt(length_in_bytes); 330 obj->pickle.WriteBytes(data, length_in_bytes); 331 } 332} 333 334// This reads a serialized NullableString16 from obj. If a string can't be 335// read, NULL is returned. 336const base::char16* ReadStringNoCopy(SerializeObject* obj, int* num_chars) { 337 int length_in_bytes; 338 if (!obj->pickle.ReadInt(&obj->iter, &length_in_bytes)) { 339 obj->parse_error = true; 340 return NULL; 341 } 342 343 if (length_in_bytes < 0) 344 return NULL; 345 346 const char* data; 347 if (!obj->pickle.ReadBytes(&obj->iter, &data, length_in_bytes)) { 348 obj->parse_error = true; 349 return NULL; 350 } 351 352 if (num_chars) 353 *num_chars = length_in_bytes / sizeof(base::char16); 354 return reinterpret_cast<const base::char16*>(data); 355} 356 357base::NullableString16 ReadString(SerializeObject* obj) { 358 int num_chars; 359 const base::char16* chars = ReadStringNoCopy(obj, &num_chars); 360 return chars ? 361 base::NullableString16(base::string16(chars, num_chars), false) : 362 base::NullableString16(); 363} 364 365void ConsumeString(SerializeObject* obj) { 366 const base::char16* unused ALLOW_UNUSED = ReadStringNoCopy(obj, NULL); 367} 368 369template <typename T> 370void WriteAndValidateVectorSize(const std::vector<T>& v, SerializeObject* obj) { 371 CHECK_LT(v.size(), std::numeric_limits<int>::max() / sizeof(T)); 372 WriteInteger(static_cast<int>(v.size()), obj); 373} 374 375size_t ReadAndValidateVectorSize(SerializeObject* obj, size_t element_size) { 376 size_t num_elements = static_cast<size_t>(ReadInteger(obj)); 377 378 // Ensure that resizing a vector to size num_elements makes sense. 379 if (std::numeric_limits<int>::max() / element_size <= num_elements) { 380 obj->parse_error = true; 381 return 0; 382 } 383 384 // Ensure that it is plausible for the pickle to contain num_elements worth 385 // of data. 386 if (obj->pickle.payload_size() <= num_elements) { 387 obj->parse_error = true; 388 return 0; 389 } 390 391 return num_elements; 392} 393 394// Writes a Vector of strings into a SerializeObject for serialization. 395void WriteStringVector( 396 const std::vector<base::NullableString16>& data, SerializeObject* obj) { 397 WriteAndValidateVectorSize(data, obj); 398 for (size_t i = 0; i < data.size(); ++i) { 399 WriteString(data[i], obj); 400 } 401} 402 403void ReadStringVector(SerializeObject* obj, 404 std::vector<base::NullableString16>* result) { 405 size_t num_elements = 406 ReadAndValidateVectorSize(obj, sizeof(base::NullableString16)); 407 408 result->resize(num_elements); 409 for (size_t i = 0; i < num_elements; ++i) 410 (*result)[i] = ReadString(obj); 411} 412 413// Writes an ExplodedHttpBody object into a SerializeObject for serialization. 414void WriteHttpBody(const ExplodedHttpBody& http_body, SerializeObject* obj) { 415 WriteBoolean(!http_body.is_null, obj); 416 417 if (http_body.is_null) 418 return; 419 420 WriteAndValidateVectorSize(http_body.elements, obj); 421 for (size_t i = 0; i < http_body.elements.size(); ++i) { 422 const ExplodedHttpBodyElement& element = http_body.elements[i]; 423 WriteInteger(element.type, obj); 424 if (element.type == blink::WebHTTPBody::Element::TypeData) { 425 WriteData(element.data.data(), static_cast<int>(element.data.size()), 426 obj); 427 } else if (element.type == blink::WebHTTPBody::Element::TypeFile) { 428 WriteString(element.file_path, obj); 429 WriteInteger64(element.file_start, obj); 430 WriteInteger64(element.file_length, obj); 431 WriteReal(element.file_modification_time, obj); 432 } else if (element.type == 433 blink::WebHTTPBody::Element::TypeFileSystemURL) { 434 WriteGURL(element.filesystem_url, obj); 435 WriteInteger64(element.file_start, obj); 436 WriteInteger64(element.file_length, obj); 437 WriteReal(element.file_modification_time, obj); 438 } else { 439 DCHECK(element.type == blink::WebHTTPBody::Element::TypeBlob); 440 WriteStdString(element.blob_uuid, obj); 441 } 442 } 443 WriteInteger64(http_body.identifier, obj); 444 WriteBoolean(http_body.contains_passwords, obj); 445} 446 447void ReadHttpBody(SerializeObject* obj, ExplodedHttpBody* http_body) { 448 // An initial boolean indicates if we have an HTTP body. 449 if (!ReadBoolean(obj)) 450 return; 451 http_body->is_null = false; 452 453 int num_elements = ReadInteger(obj); 454 455 for (int i = 0; i < num_elements; ++i) { 456 int type = ReadInteger(obj); 457 if (type == blink::WebHTTPBody::Element::TypeData) { 458 const void* data; 459 int length = -1; 460 ReadData(obj, &data, &length); 461 if (length >= 0) { 462 AppendDataToHttpBody(http_body, static_cast<const char*>(data), 463 length); 464 } 465 } else if (type == blink::WebHTTPBody::Element::TypeFile) { 466 base::NullableString16 file_path = ReadString(obj); 467 int64 file_start = ReadInteger64(obj); 468 int64 file_length = ReadInteger64(obj); 469 double file_modification_time = ReadReal(obj); 470 AppendFileRangeToHttpBody(http_body, file_path, file_start, file_length, 471 file_modification_time); 472 } else if (type == blink::WebHTTPBody::Element::TypeFileSystemURL) { 473 GURL url = ReadGURL(obj); 474 int64 file_start = ReadInteger64(obj); 475 int64 file_length = ReadInteger64(obj); 476 double file_modification_time = ReadReal(obj); 477 AppendURLRangeToHttpBody(http_body, url, file_start, file_length, 478 file_modification_time); 479 } else if (type == blink::WebHTTPBody::Element::TypeBlob) { 480 if (obj->version >= 16) { 481 std::string blob_uuid = ReadStdString(obj); 482 AppendBlobToHttpBody(http_body, blob_uuid); 483 } else { 484 ReadGURL(obj); // Skip the obsolete blob url value. 485 } 486 } 487 } 488 http_body->identifier = ReadInteger64(obj); 489 490 if (obj->version >= 12) 491 http_body->contains_passwords = ReadBoolean(obj); 492} 493 494// Writes the ExplodedFrameState data into the SerializeObject object for 495// serialization. 496void WriteFrameState( 497 const ExplodedFrameState& state, SerializeObject* obj, bool is_top) { 498 // WARNING: This data may be persisted for later use. As such, care must be 499 // taken when changing the serialized format. If a new field needs to be 500 // written, only adding at the end will make it easier to deal with loading 501 // older versions. Similarly, this should NOT save fields with sensitive 502 // data, such as password fields. 503 504 WriteString(state.url_string, obj); 505 WriteString(state.target, obj); 506 WriteInteger(state.scroll_offset.x(), obj); 507 WriteInteger(state.scroll_offset.y(), obj); 508 WriteString(state.referrer, obj); 509 510 WriteStringVector(state.document_state, obj); 511 512 WriteReal(state.page_scale_factor, obj); 513 WriteInteger64(state.item_sequence_number, obj); 514 WriteInteger64(state.document_sequence_number, obj); 515 WriteInteger64(state.frame_sequence_number, obj); 516 WriteInteger(state.referrer_policy, obj); 517 WriteReal(state.pinch_viewport_scroll_offset.x(), obj); 518 WriteReal(state.pinch_viewport_scroll_offset.y(), obj); 519 520 bool has_state_object = !state.state_object.is_null(); 521 WriteBoolean(has_state_object, obj); 522 if (has_state_object) 523 WriteString(state.state_object, obj); 524 525 WriteHttpBody(state.http_body, obj); 526 527 // NOTE: It is a quirk of the format that we still have to write the 528 // http_content_type field when the HTTP body is null. That's why this code 529 // is here instead of inside WriteHttpBody. 530 WriteString(state.http_body.http_content_type, obj); 531 532 // Subitems 533 const std::vector<ExplodedFrameState>& children = state.children; 534 WriteAndValidateVectorSize(children, obj); 535 for (size_t i = 0; i < children.size(); ++i) 536 WriteFrameState(children[i], obj, false); 537} 538 539void ReadFrameState(SerializeObject* obj, bool is_top, 540 ExplodedFrameState* state) { 541 if (obj->version < 14 && !is_top) 542 ConsumeInteger(obj); // Skip over redundant version field. 543 544 state->url_string = ReadString(obj); 545 546 if (obj->version < 19) 547 ConsumeString(obj); // Skip obsolete original url string field. 548 549 state->target = ReadString(obj); 550 if (obj->version < 15) { 551 ConsumeString(obj); // Skip obsolete parent field. 552 ConsumeString(obj); // Skip obsolete title field. 553 ConsumeString(obj); // Skip obsolete alternate title field. 554 ConsumeReal(obj); // Skip obsolete visited time field. 555 } 556 557 int x = ReadInteger(obj); 558 int y = ReadInteger(obj); 559 state->scroll_offset = gfx::Point(x, y); 560 561 if (obj->version < 15) { 562 ConsumeBoolean(obj); // Skip obsolete target item flag. 563 ConsumeInteger(obj); // Skip obsolete visit count field. 564 } 565 state->referrer = ReadString(obj); 566 567 ReadStringVector(obj, &state->document_state); 568 569 state->page_scale_factor = ReadReal(obj); 570 state->item_sequence_number = ReadInteger64(obj); 571 state->document_sequence_number = ReadInteger64(obj); 572 if (obj->version >= 21) 573 state->frame_sequence_number = ReadInteger64(obj); 574 575 if (obj->version >= 17 && obj->version < 19) 576 ConsumeInteger64(obj); // Skip obsolete target frame id number. 577 578 if (obj->version >= 18) { 579 state->referrer_policy = 580 static_cast<blink::WebReferrerPolicy>(ReadInteger(obj)); 581 } 582 583 if (obj->version >= 20) { 584 double x = ReadReal(obj); 585 double y = ReadReal(obj); 586 state->pinch_viewport_scroll_offset = gfx::PointF(x, y); 587 } else { 588 state->pinch_viewport_scroll_offset = gfx::PointF(-1, -1); 589 } 590 591 bool has_state_object = ReadBoolean(obj); 592 if (has_state_object) 593 state->state_object = ReadString(obj); 594 595 ReadHttpBody(obj, &state->http_body); 596 597 // NOTE: It is a quirk of the format that we still have to read the 598 // http_content_type field when the HTTP body is null. That's why this code 599 // is here instead of inside ReadHttpBody. 600 state->http_body.http_content_type = ReadString(obj); 601 602 if (obj->version < 14) 603 ConsumeString(obj); // Skip unused referrer string. 604 605#if defined(OS_ANDROID) 606 if (obj->version == 11) { 607 // Now-unused values that shipped in this version of Chrome for Android when 608 // it was on a private branch. 609 ReadReal(obj); 610 ReadBoolean(obj); 611 612 // In this version, page_scale_factor included device_scale_factor and 613 // scroll offsets were premultiplied by pageScaleFactor. 614 if (state->page_scale_factor) { 615 float device_scale_factor = g_device_scale_factor_for_testing; 616 if (!device_scale_factor) { 617 device_scale_factor = 618 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay(). 619 device_scale_factor(); 620 } 621 state->scroll_offset = 622 gfx::Point(state->scroll_offset.x() / state->page_scale_factor, 623 state->scroll_offset.y() / state->page_scale_factor); 624 state->page_scale_factor /= device_scale_factor; 625 } 626 } 627#endif 628 629 // Subitems 630 size_t num_children = 631 ReadAndValidateVectorSize(obj, sizeof(ExplodedFrameState)); 632 state->children.resize(num_children); 633 for (size_t i = 0; i < num_children; ++i) 634 ReadFrameState(obj, false, &state->children[i]); 635} 636 637void WritePageState(const ExplodedPageState& state, SerializeObject* obj) { 638 WriteInteger(obj->version, obj); 639 WriteStringVector(state.referenced_files, obj); 640 WriteFrameState(state.top, obj, true); 641} 642 643void ReadPageState(SerializeObject* obj, ExplodedPageState* state) { 644 obj->version = ReadInteger(obj); 645 646 if (obj->version == -1) { 647 GURL url = ReadGURL(obj); 648 // NOTE: GURL::possibly_invalid_spec() always returns valid UTF-8. 649 state->top.url_string = 650 base::NullableString16( 651 base::UTF8ToUTF16(url.possibly_invalid_spec()), false); 652 return; 653 } 654 655 if (obj->version > kCurrentVersion || obj->version < kMinVersion) { 656 obj->parse_error = true; 657 return; 658 } 659 660 if (obj->version >= 14) 661 ReadStringVector(obj, &state->referenced_files); 662 663 ReadFrameState(obj, true, &state->top); 664 665 if (obj->version < 14) 666 RecursivelyAppendReferencedFiles(state->top, &state->referenced_files); 667 668 // De-dupe 669 state->referenced_files.erase( 670 std::unique(state->referenced_files.begin(), 671 state->referenced_files.end()), 672 state->referenced_files.end()); 673} 674 675} // namespace 676 677ExplodedHttpBodyElement::ExplodedHttpBodyElement() 678 : type(blink::WebHTTPBody::Element::TypeData), 679 file_start(0), 680 file_length(-1), 681 file_modification_time(std::numeric_limits<double>::quiet_NaN()) { 682} 683 684ExplodedHttpBodyElement::~ExplodedHttpBodyElement() { 685} 686 687ExplodedHttpBody::ExplodedHttpBody() 688 : identifier(0), 689 contains_passwords(false), 690 is_null(true) { 691} 692 693ExplodedHttpBody::~ExplodedHttpBody() { 694} 695 696ExplodedFrameState::ExplodedFrameState() 697 : item_sequence_number(0), 698 document_sequence_number(0), 699 frame_sequence_number(0), 700 page_scale_factor(0.0), 701 referrer_policy(blink::WebReferrerPolicyDefault) { 702} 703 704ExplodedFrameState::ExplodedFrameState(const ExplodedFrameState& other) { 705 assign(other); 706} 707 708ExplodedFrameState::~ExplodedFrameState() { 709} 710 711void ExplodedFrameState::operator=(const ExplodedFrameState& other) { 712 if (&other != this) 713 assign(other); 714} 715 716void ExplodedFrameState::assign(const ExplodedFrameState& other) { 717 url_string = other.url_string; 718 referrer = other.referrer; 719 target = other.target; 720 state_object = other.state_object; 721 document_state = other.document_state; 722 pinch_viewport_scroll_offset = other.pinch_viewport_scroll_offset; 723 scroll_offset = other.scroll_offset; 724 item_sequence_number = other.item_sequence_number; 725 document_sequence_number = other.document_sequence_number; 726 frame_sequence_number = other.frame_sequence_number; 727 page_scale_factor = other.page_scale_factor; 728 referrer_policy = other.referrer_policy; 729 http_body = other.http_body; 730 children = other.children; 731} 732 733ExplodedPageState::ExplodedPageState() { 734} 735 736ExplodedPageState::~ExplodedPageState() { 737} 738 739bool DecodePageState(const std::string& encoded, ExplodedPageState* exploded) { 740 *exploded = ExplodedPageState(); 741 742 if (encoded.empty()) 743 return true; 744 745 SerializeObject obj(encoded.data(), static_cast<int>(encoded.size())); 746 ReadPageState(&obj, exploded); 747 return !obj.parse_error; 748} 749 750bool EncodePageState(const ExplodedPageState& exploded, std::string* encoded) { 751 SerializeObject obj; 752 obj.version = kCurrentVersion; 753 WritePageState(exploded, &obj); 754 *encoded = obj.GetAsString(); 755 return true; 756} 757 758#if defined(OS_ANDROID) 759bool DecodePageStateWithDeviceScaleFactorForTesting( 760 const std::string& encoded, 761 float device_scale_factor, 762 ExplodedPageState* exploded) { 763 g_device_scale_factor_for_testing = device_scale_factor; 764 bool rv = DecodePageState(encoded, exploded); 765 g_device_scale_factor_for_testing = 0.0; 766 return rv; 767} 768#endif 769 770} // namespace content 771