Bug 1472386 - Take overflow-wrap into account when calculating min-content intrinsic size. r=jfkthame
authorXidorn Quan <me@upsuper.org>
Mon, 09 Jul 2018 14:54:34 +1000
changeset 818991 f52422f008ed88d270b9af0ba0379e07a7c2268c
parent 818990 465f6e311e6db2cfda4ca5400c43cbd7ced82619
child 818992 633b1aae6b2ebb4af909cfa85cd51a02c66242dd
push id116413
push userbgrinstead@mozilla.com
push dateMon, 16 Jul 2018 22:40:17 +0000
reviewersjfkthame
bugs1472386
milestone63.0a1
Bug 1472386 - Take overflow-wrap into account when calculating min-content intrinsic size. r=jfkthame MozReview-Commit-ID: Fu6Gbmxs4PN
gfx/thebes/gfxTextRun.cpp
gfx/thebes/gfxTextRun.h
layout/generic/nsTextFrame.cpp
testing/web-platform/meta/MANIFEST.json
testing/web-platform/meta/css/css-text/overflow-wrap/overflow-wrap-min-content-size-001.html.ini
testing/web-platform/tests/css/css-text/overflow-wrap/overflow-wrap-min-content-size-002.html
testing/web-platform/tests/css/css-text/overflow-wrap/reference/overflow-wrap-min-content-size-002-ref.html
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -1228,16 +1228,44 @@ gfxTextRun::GetAdvanceWidth(Range aRange
                 aSpacing->mAfter = spacingBuffer.LastElement().mAfter;
             }
         }
     }
 
     return result + GetAdvanceForGlyphs(ligatureRange);
 }
 
+gfxFloat
+gfxTextRun::GetMinAdvanceWidth(Range aRange)
+{
+    MOZ_ASSERT(aRange.end <= GetLength(), "Substring out of range");
+
+    Range ligatureRange = aRange;
+    ShrinkToLigatureBoundaries(&ligatureRange);
+
+    gfxFloat result = std::max(
+        ComputePartialLigatureWidth(Range(aRange.start, ligatureRange.start),
+                                    nullptr),
+        ComputePartialLigatureWidth(Range(ligatureRange.end, aRange.end),
+                                    nullptr));
+
+    // XXX Do we need to take spacing into account? When each grapheme cluster
+    // takes its own line, we shouldn't be adding spacings around them.
+    gfxFloat clusterAdvance = 0;
+    for (uint32_t i = ligatureRange.start; i < ligatureRange.end; ++i) {
+        clusterAdvance += GetAdvanceForGlyph(i);
+        if (i + 1 == ligatureRange.end || IsClusterStart(i + 1)) {
+            result = std::max(result, clusterAdvance);
+            clusterAdvance = 0;
+        }
+    }
+
+    return result;
+}
+
 bool
 gfxTextRun::SetLineBreaks(Range aRange,
                           bool aLineBreakBefore, bool aLineBreakAfter,
                           gfxFloat *aAdvanceWidthDelta)
 {
     // Do nothing because our shaping does not currently take linebreaks into
     // account. There is no change in advance width.
     if (aAdvanceWidthDelta) {
--- a/gfx/thebes/gfxTextRun.h
+++ b/gfx/thebes/gfxTextRun.h
@@ -322,16 +322,22 @@ public:
                              PropertyProvider::Spacing*
                                  aSpacing = nullptr) const;
 
     gfxFloat GetAdvanceWidth() const {
         return GetAdvanceWidth(Range(this), nullptr);
     }
 
     /**
+     * Computes the minimum advance width for a substring assuming line
+     * breaking is allowed everywhere.
+     */
+    gfxFloat GetMinAdvanceWidth(Range aRange);
+
+    /**
      * Clear all stored line breaks for the given range (both before and after),
      * and then set the line-break state before aRange.start to aBreakBefore and
      * after the last cluster to aBreakAfter.
      *
      * We require that before and after line breaks be consistent. For clusters
      * i and i+1, we require that if there is a break after cluster i, a break
      * will be specified before cluster i+1. This may be temporarily violated
      * (e.g. after reflowing line L and before reflowing line L+1); to handle
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -8544,16 +8544,26 @@ nsTextFrame::AddInlineMinISizeForFlow(gf
     if (start < flowEndInTextRun && textRun->CanBreakLineBefore(start)) {
       aData->OptionallyBreak();
     }
     aData->mCurrentLine += provider.GetFontMetrics()->EmHeight();
     aData->mTrailingWhitespace = 0;
     return;
   }
 
+  // If overflow-wrap is break-word, we can wrap everywhere.
+  if (textStyle->WordCanWrap(this)) {
+    aData->OptionallyBreak();
+    aData->mCurrentLine +=
+      textRun->GetMinAdvanceWidth(Range(start, flowEndInTextRun));
+    aData->mTrailingWhitespace = 0;
+    aData->OptionallyBreak();
+    return;
+  }
+
   AutoTArray<gfxTextRun::HyphenType, BIG_TEXT_NODE_SIZE> hyphBuffer;
   if (hyphenating) {
     if (hyphBuffer.AppendElements(flowEndInTextRun - start, fallible)) {
       provider.GetHyphenationBreaks(Range(start, flowEndInTextRun),
                                     hyphBuffer.Elements());
     } else {
       hyphenating = false;
     }
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -135074,16 +135074,28 @@
       [
        "/css/css-text/overflow-wrap/reference/overflow-wrap-min-content-size-001-ref.html",
        "=="
       ]
      ],
      {}
     ]
    ],
+   "css/css-text/overflow-wrap/overflow-wrap-min-content-size-002.html": [
+    [
+     "/css/css-text/overflow-wrap/overflow-wrap-min-content-size-002.html",
+     [
+      [
+       "/css/css-text/overflow-wrap/reference/overflow-wrap-min-content-size-002-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-text/overflow-wrap/word-wrap-001.html": [
     [
      "/css/css-text/overflow-wrap/word-wrap-001.html",
      [
       [
        "/css/css-text/overflow-wrap/overflow-wrap-001-ref.html",
        "=="
       ]
@@ -257587,16 +257599,21 @@
      {}
     ]
    ],
    "css/css-text/overflow-wrap/reference/overflow-wrap-min-content-size-001-ref.html": [
     [
      {}
     ]
    ],
+   "css/css-text/overflow-wrap/reference/overflow-wrap-min-content-size-002-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-text/support/1x1-green.png": [
     [
      {}
     ]
    ],
    "css/css-text/support/1x1-lime.png": [
     [
      {}
@@ -534171,16 +534188,20 @@
   "css/css-text/overflow-wrap/overflow-wrap-break-word-fit-content-001.html": [
    "9f88a667825f8cb725dc348e17081e1a25b3f4de",
    "reftest"
   ],
   "css/css-text/overflow-wrap/overflow-wrap-min-content-size-001.html": [
    "5858dbb88a775bb8975f338d866b6fc837485364",
    "reftest"
   ],
+  "css/css-text/overflow-wrap/overflow-wrap-min-content-size-002.html": [
+   "ae7abc617493b9e2c9313215a3f38b77c37d9450",
+   "reftest"
+  ],
   "css/css-text/overflow-wrap/reference/overflow-wrap-break-word-001-ref.html": [
    "0b16a0bdb25ddd647ad96dd82e3430274667ee87",
    "support"
   ],
   "css/css-text/overflow-wrap/reference/overflow-wrap-break-word-002-ref.html": [
    "e049fce2e9861c0386d47dced6f5ab15fb989063",
    "support"
   ],
@@ -534191,16 +534212,20 @@
   "css/css-text/overflow-wrap/reference/overflow-wrap-break-word-fit-content-001.html": [
    "7daf4c0482ae02fdd5a6855b3f750e664373efcd",
    "support"
   ],
   "css/css-text/overflow-wrap/reference/overflow-wrap-min-content-size-001-ref.html": [
    "f3e09183b565f71e38158cc5cd4d96ab5fbf25d4",
    "support"
   ],
+  "css/css-text/overflow-wrap/reference/overflow-wrap-min-content-size-002-ref.html": [
+   "3686ae6a0e278a970b861c165f0f840df302db70",
+   "support"
+  ],
   "css/css-text/overflow-wrap/word-wrap-001.html": [
    "8bafc4d48bbfee1e6c465a95b29792ba33c30346",
    "reftest"
   ],
   "css/css-text/overflow-wrap/word-wrap-002.html": [
    "1fc206422060160f3d987240f5fc946e7f8f2341",
    "reftest"
   ],
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-text/overflow-wrap/overflow-wrap-min-content-size-001.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[overflow-wrap-min-content-size-001.html]
-  expected: FAIL
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/overflow-wrap/overflow-wrap-min-content-size-002.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text Test: overflow-wrap: break-word and intrinsic sizing</title>
+<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org/">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#overflow-wrap-property">
+<meta name="flags" content="">
+<link rel="match" href="reference/overflow-wrap-min-content-size-002-ref.html">
+<meta name="assert" content="overflow-wrap:break-word doesn't break grapheme cluster and min-content intrinsic size should take that into account.">
+<style>
+#wrapper {
+  width: 0px;
+  overflow-wrap: break-word;
+}
+#test {
+  float: left;
+  border: 2px solid blue;
+}
+</style>
+
+<p>Test passes if the glyphs are completely inside the blue box.
+<div id="wrapper">
+  <div id="test">&#x0ba8;&#x0bbf;&#x0bbf;&#x0bbf;&#x0bbf;&#x0ba8;&#x0bbf;&#x0bbf;&#x0bbf;&#x0bbf;</div>
+</div>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-text/overflow-wrap/reference/overflow-wrap-min-content-size-002-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text Test reference</title>
+<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org/">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org/">
+<style>
+#test {
+  float: left;
+  border: 2px solid blue;
+}
+</style>
+
+<p>Test passes if the glyphs are completely inside the blue box.
+<div id="wrapper">
+  <div id="test">&#x0ba8;&#x0bbf;&#x0bbf;&#x0bbf;&#x0bbf;<br>&#x0ba8;&#x0bbf;&#x0bbf;&#x0bbf;&#x0bbf;</div>
+</div>