File: physical_size.cc

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (96 lines) | stat: -rw-r--r-- 3,165 bytes parent folder | download | duplicates (5)
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
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/platform/geometry/physical_size.h"

#include "base/numerics/safe_conversions.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"

namespace blink {

PhysicalSize PhysicalSize::FitToAspectRatio(const PhysicalSize& aspect_ratio,
                                            AspectRatioFit fit) const {
  DCHECK_GT(aspect_ratio.width, 0);
  DCHECK_GT(aspect_ratio.height, 0);
  const LayoutUnit constrained_height =
      width.MulDiv(aspect_ratio.height, aspect_ratio.width);
  const bool grow = fit == kAspectRatioFitGrow;
  if ((grow && constrained_height < height) ||
      (!grow && constrained_height > height)) {
    const LayoutUnit constrained_width =
        height.MulDiv(aspect_ratio.width, aspect_ratio.height);
    return {constrained_width, height};
  }
  return {width, constrained_height};
}

String PhysicalSize::ToString() const {
  return String::Format("%sx%s", width.ToString().Ascii().c_str(),
                        height.ToString().Ascii().c_str());
}

std::ostream& operator<<(std::ostream& os, const PhysicalSize& value) {
  return os << value.ToString();
}

// static
PhysicalSize LayoutRatioFromSizeF(gfx::SizeF ratio) {
  // Check if we can convert without any error.
  LayoutUnit width(ratio.width()), height(ratio.height());
  if ((width.ToFloat() == ratio.width() &&
       height.ToFloat() == ratio.height()) ||
      ratio.IsEmpty()) {
    return {width, height};
  }
  if (ratio.width() == ratio.height()) {
    return {LayoutUnit(1), LayoutUnit(1)};
  }

  // If we can't get a precise ratio we use the continued fraction algorithm to
  // get an approximation. See: https://en.wikipedia.org/wiki/Continued_fraction
  float initial = ratio.AspectRatio();
  float x = initial;

  // Use ints for the direct conversion using |LayoutUnit::FromRawValue| below.
  using ClampedInt = base::ClampedNumeric<int>;
  ClampedInt h0 = 0, h1 = 1, k0 = 1, k1 = 0;

  // The worst case for this algorithm is the golden ratio, which requires 16
  // iterations to reach our desired error.
  for (wtf_size_t i = 0; i < 16; ++i) {
    // Break if we've gone Inf, or NaN.
    if (!std::isfinite(x)) {
      break;
    }
    // Break if we've hit a good approximation.
    float estimate = static_cast<float>(h1) / k1;
    if (fabs(initial - estimate) < 0.000001f) {
      break;
    }

    const int a = base::ClampFloor<int>(x);
    ClampedInt h2 = (h1 * a) + h0;
    ClampedInt k2 = (k1 * a) + k0;

    // Break if we've saturated (the ratio becomes meaningless).
    if (h2 == std::numeric_limits<int>::max() ||
        k2 == std::numeric_limits<int>::max()) {
      break;
    }

    // Update our convergents.
    h0 = h1, k0 = k1, h1 = h2, k1 = k2;
    x = 1 / (x - a);
  }

  // Don't return an invalid ratio - instead just return the truncated ratio.
  if (h1 == 0 || k1 == 0) {
    return {width, height};
  }

  return {LayoutUnit::FromRawValue(h1.RawValue()),
          LayoutUnit::FromRawValue(k1.RawValue())};
}

}  // namespace blink