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 16 namespace content { 17 namespace { 18 19 #if defined(OS_ANDROID) 20 float g_device_scale_factor_for_testing = 0.0; 21 #endif 22 23 //----------------------------------------------------------------------------- 24 25 void 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 33 void 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 47 void 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 61 void 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 71 void 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 80 bool 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 137 bool 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 160 struct 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 // 201 const int kMinVersion = 11; 202 const 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 208 void WriteData(const void* data, int length, SerializeObject* obj) { 209 obj->pickle.WriteData(static_cast<const char*>(data), length); 210 } 211 212 void 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 223 void WriteInteger(int data, SerializeObject* obj) { 224 obj->pickle.WriteInt(data); 225 } 226 227 int 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 235 void ConsumeInteger(SerializeObject* obj) { 236 int unused ALLOW_UNUSED = ReadInteger(obj); 237 } 238 239 void WriteInteger64(int64 data, SerializeObject* obj) { 240 obj->pickle.WriteInt64(data); 241 } 242 243 int64 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 251 void ConsumeInteger64(SerializeObject* obj) { 252 int64 unused ALLOW_UNUSED = ReadInteger64(obj); 253 } 254 255 void WriteReal(double data, SerializeObject* obj) { 256 WriteData(&data, sizeof(double), obj); 257 } 258 259 double 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 273 void ConsumeReal(SerializeObject* obj) { 274 double unused ALLOW_UNUSED = ReadReal(obj); 275 } 276 277 void WriteBoolean(bool data, SerializeObject* obj) { 278 obj->pickle.WriteInt(data ? 1 : 0); 279 } 280 281 bool 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 289 void ConsumeBoolean(SerializeObject* obj) { 290 bool unused ALLOW_UNUSED = ReadBoolean(obj); 291 } 292 293 void WriteGURL(const GURL& url, SerializeObject* obj) { 294 obj->pickle.WriteString(url.possibly_invalid_spec()); 295 } 296 297 GURL 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 305 void WriteStdString(const std::string& s, SerializeObject* obj) { 306 obj->pickle.WriteString(s); 307 } 308 309 std::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. 320 void 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. 336 const 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 357 base::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 365 void ConsumeString(SerializeObject* obj) { 366 const base::char16* unused ALLOW_UNUSED = ReadStringNoCopy(obj, NULL); 367 } 368 369 template <typename T> 370 void 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 375 size_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. 395 void 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 403 void 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. 414 void 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 447 void 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. 496 void 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 539 void 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 637 void 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 643 void 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 677 ExplodedHttpBodyElement::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 684 ExplodedHttpBodyElement::~ExplodedHttpBodyElement() { 685 } 686 687 ExplodedHttpBody::ExplodedHttpBody() 688 : identifier(0), 689 contains_passwords(false), 690 is_null(true) { 691 } 692 693 ExplodedHttpBody::~ExplodedHttpBody() { 694 } 695 696 ExplodedFrameState::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 704 ExplodedFrameState::ExplodedFrameState(const ExplodedFrameState& other) { 705 assign(other); 706 } 707 708 ExplodedFrameState::~ExplodedFrameState() { 709 } 710 711 void ExplodedFrameState::operator=(const ExplodedFrameState& other) { 712 if (&other != this) 713 assign(other); 714 } 715 716 void 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 733 ExplodedPageState::ExplodedPageState() { 734 } 735 736 ExplodedPageState::~ExplodedPageState() { 737 } 738 739 bool 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 750 bool 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) 759 bool 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