File: distiller_page_utils.mm

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (102 lines) | stat: -rw-r--r-- 3,772 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "components/dom_distiller/ios/distiller_page_utils.h"

#import "base/check_op.h"
#import "base/logging.h"
#import "base/notreached.h"
#import "third_party/dom_distiller_js/dom_distiller.pb.h"
#import "third_party/dom_distiller_js/dom_distiller_json_converter.h"

namespace dom_distiller {
namespace {

// This is duplicated here from ios/web/js_messaging/web_view_js_utils.mm in
// order to handle numbers. The dom distiller proto expects integers and the
// generated JSON deserializer does not accept doubles in the place of ints.
// However WKWebView only returns "numbers." However, here the proto expects
// integers and doubles, which is done by checking if the number has a fraction
// or not; since this is a hacky method it's isolated to this file so as to
// limit the risk of broken JS calls.
int const kMaximumParsingRecursionDepth = 6;

// Returns a clone of `value` where double values are converted to integers if
// the numbers has no fraction. `value` is only processed up to `max_depth`.
// TODO(crbug.com/404833789): Remove this workaround when the DOMDistillerResult
// JSON converter no longer requires double to int conversion.
base::Value ConvertedResultFromScriptResult(const base::Value* value,
                                            int max_depth) {
  base::Value result;
  if (!value || value->is_none()) {
    DCHECK_EQ(result.type(), base::Value::Type::NONE);
    return result;
  }

  if (max_depth < 0) {
    DLOG(WARNING) << "JS maximum recursion depth exceeded.";
    return result;
  }

  if (value->is_string()) {
    result = base::Value(value->GetString());
    DCHECK_EQ(result.type(), base::Value::Type::STRING);
  } else if (value->is_double()) {
    // Different implementation is here.
    double double_value = value->GetDouble();
    int int_value = round(double_value);
    if (double_value == int_value) {
      result = base::Value(int_value);
      DCHECK_EQ(result.type(), base::Value::Type::INTEGER);
    } else {
      result = base::Value(double_value);
      DCHECK_EQ(result.type(), base::Value::Type::DOUBLE);
    }
    // End of different implementation.
  } else if (value->is_int()) {
    result = base::Value(value->GetInt());
    DCHECK_EQ(result.type(), base::Value::Type::INTEGER);
  } else if (value->is_bool()) {
    result = base::Value(value->GetBool());
    DCHECK_EQ(result.type(), base::Value::Type::BOOLEAN);
  } else if (value->is_dict()) {
    base::Value::Dict dictionary;
    for (const auto kv : value->GetDict()) {
      base::Value item_value =
          ConvertedResultFromScriptResult(&kv.second, max_depth - 1);

      if (item_value.type() == base::Value::Type::NONE) {
        return result;
      }
      dictionary.SetByDottedPath(kv.first, std::move(item_value));
    }
    result = base::Value(std::move(dictionary));
    DCHECK_EQ(result.type(), base::Value::Type::DICT);

  } else if (value->is_list()) {
    base::Value::List list;
    for (const base::Value& list_item : value->GetList()) {
      base::Value converted_item =
          ConvertedResultFromScriptResult(&list_item, max_depth - 1);
      if (converted_item.type() == base::Value::Type::NONE) {
        return result;
      }

      list.Append(std::move(converted_item));
    }
    result = base::Value(std::move(list));
    DCHECK_EQ(result.type(), base::Value::Type::LIST);
  } else {
    NOTREACHED();  // Convert other types as needed.
  }
  return result;
}

}  // namespace

base::Value ParseValueFromScriptResult(const base::Value* value) {
  return ConvertedResultFromScriptResult(value, kMaximumParsingRecursionDepth);
}

}  // namespace dom_distiller