transform-box: content-box, stroke-box missing
https://bugs.webkit.org/show_bug.cgi?id=201892

Patch by Dirk Schulze <krit@webkit.org> on 2019-10-17
Reviewed by Simon Fraser.

Source/WebCore:

Added the keywords content-box and stroke-box to the
transform-box CSS property.
Those keywords were added to the spec after the implementation
in WebKit.

Test: transforms/transform-box.html

* css/CSSPrimitiveValueMappings.h:
(WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
(WebCore::CSSPrimitiveValue::operator TransformBox const):
* css/CSSProperties.json:
* css/CSSValueKeywords.in:
* css/parser/CSSPropertyParser.cpp:
(WebCore::CSSPropertyParser::parseSingleValue):
* rendering/RenderLayer.cpp:
(WebCore::computeReferenceBox):
(WebCore::transformBoxToCSSBoxType):
(WebCore::RenderLayer::currentTransform const):
* rendering/style/RenderStyleConstants.h:
* svg/SVGGraphicsElement.cpp:
(WebCore::SVGGraphicsElement::animatedLocalTransform const):

LayoutTests:

* fast/css/transform-box-parsing.html:
* svg/transforms/svg-transform-box-expected.html:
* svg/transforms/svg-transform-box.html:
* transforms/transform-box-expected.html: Added.
* transforms/transform-box.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@251252 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index de22a57..3241276 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,16 @@
+2019-10-17  Dirk Schulze  <krit@webkit.org>
+
+        transform-box: content-box, stroke-box missing
+        https://bugs.webkit.org/show_bug.cgi?id=201892
+
+        Reviewed by Simon Fraser.
+
+        * fast/css/transform-box-parsing.html:
+        * svg/transforms/svg-transform-box-expected.html:
+        * svg/transforms/svg-transform-box.html:
+        * transforms/transform-box-expected.html: Added.
+        * transforms/transform-box.html: Added.
+
 2019-10-17  Simon Fraser  <simon.fraser@apple.com>
 
         [iOS Sim] Layout Test scrollingcoordinator/ios/ui-scroll-fixed.html is a flaky failure
diff --git a/LayoutTests/fast/css/transform-box-parsing-expected.txt b/LayoutTests/fast/css/transform-box-parsing-expected.txt
index 795ff69..1b98c81 100644
--- a/LayoutTests/fast/css/transform-box-parsing-expected.txt
+++ b/LayoutTests/fast/css/transform-box-parsing-expected.txt
@@ -6,14 +6,20 @@
 PASS testPropertyValue("transform-box: border-box", "transform-box") is "border-box"
 PASS testPropertyValue("transform-box: fill-box", "transform-box") is "fill-box"
 PASS testPropertyValue("transform-box: view-box", "transform-box") is "view-box"
+PASS testPropertyValue("transform-box: content-box", "transform-box") is "content-box"
+PASS testPropertyValue("transform-box: stroke-box", "transform-box") is "stroke-box"
 
 PASS testComputedStyle("", "transform-box") is "border-box"
 PASS testComputedStyle("transform-box: fill-box", "transform-box") is "fill-box"
 PASS testComputedStyle("transform-box: view-box", "transform-box") is "view-box"
+PASS testComputedStyle("transform-box: content-box", "transform-box") is "content-box"
+PASS testComputedStyle("transform-box: stroke-box", "transform-box") is "stroke-box"
 
 PASS testSVGComputedStyle("", "transform-box") is "view-box"
 PASS testSVGComputedStyle("transform-box: fill-box", "transform-box") is "fill-box"
 PASS testSVGComputedStyle("transform-box: border-box", "transform-box") is "border-box"
+PASS testSVGComputedStyle("transform-box: content-box", "transform-box") is "content-box"
+PASS testSVGComputedStyle("transform-box: stroke-box", "transform-box") is "stroke-box"
 
 PASS testComputedStyleOnElementWithId("foreignObject") is "view-box"
 
diff --git a/LayoutTests/fast/css/transform-box-parsing.html b/LayoutTests/fast/css/transform-box-parsing.html
index 52918b5..63d84fa 100644
--- a/LayoutTests/fast/css/transform-box-parsing.html
+++ b/LayoutTests/fast/css/transform-box-parsing.html
@@ -62,16 +62,22 @@
         shouldBeEqualToString('testPropertyValue("transform-box: border-box", "transform-box")', 'border-box');
         shouldBeEqualToString('testPropertyValue("transform-box: fill-box", "transform-box")', 'fill-box');
         shouldBeEqualToString('testPropertyValue("transform-box: view-box", "transform-box")', 'view-box');
+        shouldBeEqualToString('testPropertyValue("transform-box: content-box", "transform-box")', 'content-box');
+        shouldBeEqualToString('testPropertyValue("transform-box: stroke-box", "transform-box")', 'stroke-box');
 
         debug('');
         shouldBeEqualToString('testComputedStyle("", "transform-box")', 'border-box');
         shouldBeEqualToString('testComputedStyle("transform-box: fill-box", "transform-box")', 'fill-box');
         shouldBeEqualToString('testComputedStyle("transform-box: view-box", "transform-box")', 'view-box');
+        shouldBeEqualToString('testComputedStyle("transform-box: content-box", "transform-box")', 'content-box');
+        shouldBeEqualToString('testComputedStyle("transform-box: stroke-box", "transform-box")', 'stroke-box');
 
         debug('');
         shouldBeEqualToString('testSVGComputedStyle("", "transform-box")', 'view-box');
         shouldBeEqualToString('testSVGComputedStyle("transform-box: fill-box", "transform-box")', 'fill-box');
         shouldBeEqualToString('testSVGComputedStyle("transform-box: border-box", "transform-box")', 'border-box');
+        shouldBeEqualToString('testSVGComputedStyle("transform-box: content-box", "transform-box")', 'content-box');
+        shouldBeEqualToString('testSVGComputedStyle("transform-box: stroke-box", "transform-box")', 'stroke-box');
 
         debug('');
         shouldBeEqualToString('testComputedStyleOnElementWithId("foreignObject")', 'view-box');
diff --git a/LayoutTests/svg/transforms/svg-transform-box-expected.html b/LayoutTests/svg/transforms/svg-transform-box-expected.html
index 90c617f..f479460 100644
--- a/LayoutTests/svg/transforms/svg-transform-box-expected.html
+++ b/LayoutTests/svg/transforms/svg-transform-box-expected.html
@@ -1,28 +1,21 @@
 <!DOCTYPE html>
-
 <html>
 <head>
   <style>
-    svg {
-        border: 1px solid black;
+    * {
+      margin: 0;
+      padding: 0;
     }
   </style>
 </head>
-
 <body>
-
-    <div class="container">
-        <p>You should see no red boxes below</p>
-        <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 600 400" style=" width: 600px; height: 400px;">
-            <!-- transform-box: view-box -->
-            <rect x="20" y="10" width="100" height="50" fill="green" />
-            <rect x="480" y="40" width="50" height="50" fill="green" />
-            <rect x="120" y="120" width="50" height="50" fill="green" />
-            <rect x="20" y="200" width="100" height="50" fill="green" />
-            <rect x="480" y="260" width="50" height="50" fill="green" />
-            <rect x="120" y="320" width="50" height="50" fill="green" />
-        </svg>
-    </div>
-
+  <p>You should see no red boxes below</p>
+  <svg width="600" height="300" viewBox="0 0 600 300">
+    <rect width="120" height="60" fill="green" />
+    <rect x="150" y="0" width="120" height="60" fill="green" />
+    <rect x="300" y="0" width="120" height="60" fill="green" />
+    <rect y="90" width="120" height="60" fill="green" />
+    <rect x="150" y="90" width="120" height="60" fill="green" />
+  </svg>
 </body>
-</html>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/svg/transforms/svg-transform-box.html b/LayoutTests/svg/transforms/svg-transform-box.html
index 2506f53..d07d40d 100644
--- a/LayoutTests/svg/transforms/svg-transform-box.html
+++ b/LayoutTests/svg/transforms/svg-transform-box.html
@@ -1,42 +1,41 @@
 <!DOCTYPE html>
-
 <html>
 <head>
   <style>
-    svg {
-        border: 1px solid black;
+    * {
+      margin: 0;
+      padding: 0;
     }
   </style>
 </head>
-
 <body>
-
-    <div class="container">
-        <p>You should see no red boxes below</p>
-        <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 600 400" style=" width: 600px; height: 400px;">
-            <!-- transform-box: view-box -->
-            <rect x="20" y="10" width="100" height="50" fill="red" />
-            <rect x="20" y="5" width="50" height="25" fill="green" style="transform: scale(2, 2); transform-origin: 20px 0; transform-box: view-box;" />
-
-            <rect x="480" y="40" width="50" height="50" fill="red" />
-            <rect x="0" y="0" width="50" height="50" fill="green" style="transform: translate(80%, 10%); transform-box: view-box;" />
-
-            <rect x="120" y="120" width="50" height="50" fill="red" />
-            <rect x="180" y="10" width="50" height="50" fill="green" style="transform: rotate(90deg); transform-origin: 120px 60px; transform-box: view-box;" />
-            <rect x="180" y="10" width="50" height="50" fill="green" style="transform: rotate(90deg); transform-origin: 20% 15%; transform-box: view-box;" />
-
-            <!-- transform-box: fill-box -->
-            <rect x="20" y="200" width="100" height="50" fill="red" />
-            <rect x="20" y="200" width="50" height="25" fill="green" style="transform: scale(2, 2); transform-box: fill-box;" />
-
-            <rect x="480" y="260" width="50" height="50" fill="red" />
-            <rect x="430" y="310" width="50" height="50" fill="green" style="transform: translate(100%, -100%); transform-box: fill-box;" />
-
-            <rect x="120" y="320" width="50" height="50" fill="red" />
-            <rect x="70" y="270" width="50" height="50" fill="green" style="transform: rotate(180deg); transform-origin: 50px 50px; transform-box: fill-box;" />
-            <rect x="95" y="345" width="50" height="50" fill="green" style="transform: rotate(90deg); transform-origin: 100% 50%; transform-box: fill-box;" />
-        </svg>
-    </div>
-
+  <p>You should see no red boxes below</p>
+  <svg width="600" height="300" viewBox="0 0 600 300">
+    <g style="transform: translate(20px, 20px)">
+        <!-- transform-box: border-box -->
+        <rect x="-19" y="-19" width="118" height="58" fill="red" />
+        <rect style="transform-box: border-box; transform: rotate(90deg) scale(1, 2) translate(30px, -75%); transform-origin: 50% 0;" width="20" height="20" stroke="green" stroke-width="40" fill="green" />
+      </g>
+      <g style="transform: translate(160px, 10px)">
+        <!-- transform-box: view-box -->
+        <rect x="-9" y="-9" width="118" height="58" fill="red" />
+        <rect style="transform-box: view-box; transform: rotate(90deg) scale(1,2) translate(310px, calc(50% - 35px)); transform-origin: 50% 0;" width="20" height="20" stroke="green" stroke-width="40" fill="green" />
+      </g>
+      <g style="transform: translate(320px, 20px)">
+        <!-- transform-box: stroke-box -->
+        <rect x="-19" y="-19" width="118" height="58" fill="red" />
+        <rect style="transform-box: stroke-box; transform: rotate(90deg) scale(1, 2) translate(30px, -75%); transform-origin: 50% 0;" width="20" height="20" stroke="green" stroke-width="40" fill="green" />
+      </g>
+      <g style="transform: translate(10px, 100px)">
+        <!-- transform-box: content-box -->
+        <rect x="-9" y="-9" width="118" height="58" fill="red" />
+        <rect style="transform-box: content-box; transform: rotate(90deg) scale(1, 2) translate(20px, -87.5%); transform-origin: 50% 0;" width="40" height="40" stroke="green" stroke-width="20" fill="green" />
+      </g>
+      <g style="transform: translate(160px, 100px)">
+        <!-- transform-box: fill-box -->
+        <rect x="-9" y="-9" width="118" height="58" fill="red" />
+        <rect style="transform-box: fill-box; transform: rotate(90deg) scale(1, 2) translate(20px, -87.5%); transform-origin: 50% 0;" width="40" height="40" stroke="green" stroke-width="20" fill="green" />
+      </g>
+  </svg>
 </body>
-</html>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/transforms/transform-box-expected.html b/LayoutTests/transforms/transform-box-expected.html
new file mode 100644
index 0000000..2546a0f
--- /dev/null
+++ b/LayoutTests/transforms/transform-box-expected.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <style>
+        * {
+            margin: 0;
+            padding: 0;
+        }
+
+        div {
+            width: 120px;
+            height: 60px;
+            background-color: green;
+            position: absolute;
+        }
+    </style>
+</head>
+
+<body>
+    <p>You should see no red boxes below</p>
+    <div>
+    </div>
+    <div style="transform: translateX(150px)">
+    </div>
+    <div style="transform: translateX(300px)">
+    </div>
+    <div style="transform: translate(0, 90px)">
+    </div>
+    <div style="transform: translate(150px, 90px)">
+    </div>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/LayoutTests/transforms/transform-box.html b/LayoutTests/transforms/transform-box.html
new file mode 100644
index 0000000..a6d084d
--- /dev/null
+++ b/LayoutTests/transforms/transform-box.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <style>
+    * {
+        margin: 0;
+        padding: 0;
+    }
+    .container {
+        width: 500px;
+        height: 400px;
+        overflow: hidden;
+    }
+    .fail {
+        margin: 1px;
+        width: 118px;
+        height: 58px;
+        background-color: red;
+        position: absolute;
+    }
+    .pass {
+        width: 40px;
+        height: 40px;
+        border: solid green 10px;
+        background-color: green;
+        position: absolute;
+        transform-origin: 50% 0;
+    }
+  </style>
+</head>
+<body>
+<div class="container">
+    <p>You should see no red boxes below</p>
+    <div>
+        <div class="fail"></div>
+        <div class="pass" style="transform-box: border-box; transform: rotate(90deg) scale(1, 2) translate(30px, -75%)"></div>
+    </div>
+    <div style="transform: translateX(150px)">
+        <div class="fail"></div>
+        <div class="pass" style="transform-box: view-box; transform: rotate(90deg) scale(1, 2) translate(30px, -75%)"></div>
+    </div>
+    <div style="transform: translateX(300px)">
+        <div class="fail" style="width: 50px; height: 50px;"></div>
+        <div class="pass" style="transform-box: stroke-box; transform: rotate(90deg) scale(1, 2) translate(30px, -75%)"></div>
+    </div>
+    <div style="transform: translate(0, 90px)">
+        <div class="fail"></div>
+        <div class="pass" style="transform-box: content-box; transform: rotate(90deg) scale(1, 2) translate(20px, -87.5%);"></div>
+    </div>
+    <div style="transform: translate(150px, 90px)">
+        <div class="fail"></div>
+        <div class="pass" style="transform-box: fill-box; transform: rotate(90deg) scale(1, 2) translate(20px, -87.5%);"></div>
+    </div>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 729b01e..17ee39b 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,32 @@
+2019-10-17  Dirk Schulze  <krit@webkit.org>
+
+        transform-box: content-box, stroke-box missing
+        https://bugs.webkit.org/show_bug.cgi?id=201892
+
+        Reviewed by Simon Fraser.
+
+        Added the keywords content-box and stroke-box to the
+        transform-box CSS property.
+        Those keywords were added to the spec after the implementation
+        in WebKit.
+
+        Test: transforms/transform-box.html
+
+        * css/CSSPrimitiveValueMappings.h:
+        (WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
+        (WebCore::CSSPrimitiveValue::operator TransformBox const):
+        * css/CSSProperties.json:
+        * css/CSSValueKeywords.in:
+        * css/parser/CSSPropertyParser.cpp:
+        (WebCore::CSSPropertyParser::parseSingleValue):
+        * rendering/RenderLayer.cpp:
+        (WebCore::computeReferenceBox):
+        (WebCore::transformBoxToCSSBoxType):
+        (WebCore::RenderLayer::currentTransform const):
+        * rendering/style/RenderStyleConstants.h:
+        * svg/SVGGraphicsElement.cpp:
+        (WebCore::SVGGraphicsElement::animatedLocalTransform const):
+
 2019-10-17  Youenn Fablet  <youenn@apple.com>
 
         SincResampler does not need to create a new AudioBus for each consumeSource call
diff --git a/Source/WebCore/css/CSSPrimitiveValueMappings.h b/Source/WebCore/css/CSSPrimitiveValueMappings.h
index 53cbd96..4631d94 100644
--- a/Source/WebCore/css/CSSPrimitiveValueMappings.h
+++ b/Source/WebCore/css/CSSPrimitiveValueMappings.h
@@ -4391,6 +4391,12 @@
 {
     m_primitiveUnitType = CSS_VALUE_ID;
     switch (box) {
+    case TransformBox::StrokeBox:
+        m_value.valueID = CSSValueStrokeBox;
+        break;
+    case TransformBox::ContentBox:
+        m_value.valueID = CSSValueContentBox;
+        break;
     case TransformBox::BorderBox:
         m_value.valueID = CSSValueBorderBox;
         break;
@@ -4408,6 +4414,10 @@
     ASSERT(isValueID());
 
     switch (m_value.valueID) {
+    case CSSValueStrokeBox:
+        return TransformBox::StrokeBox;
+    case CSSValueContentBox:
+        return TransformBox::ContentBox;
     case CSSValueBorderBox:
         return TransformBox::BorderBox;
     case CSSValueFillBox:
diff --git a/Source/WebCore/css/CSSProperties.json b/Source/WebCore/css/CSSProperties.json
index 306aaca..4bdb4ff 100644
--- a/Source/WebCore/css/CSSProperties.json
+++ b/Source/WebCore/css/CSSProperties.json
@@ -6378,7 +6378,9 @@
             "values" : [
                 "border-box",
                 "fill-box",
-                "view-box"
+                "view-box",
+                "stroke-box",
+                "content-box"
             ],
             "codegen-properties": {
             },
diff --git a/Source/WebCore/css/CSSValueKeywords.in b/Source/WebCore/css/CSSValueKeywords.in
index c4767f5..cf74a68 100644
--- a/Source/WebCore/css/CSSValueKeywords.in
+++ b/Source/WebCore/css/CSSValueKeywords.in
@@ -1297,6 +1297,8 @@
 // transform-box
 // border-box
 // view-box
+// stroke-box
+// content-box
 fill-box
 
 // motion path
diff --git a/Source/WebCore/css/parser/CSSPropertyParser.cpp b/Source/WebCore/css/parser/CSSPropertyParser.cpp
index 8ca4a56..cc05ef0 100644
--- a/Source/WebCore/css/parser/CSSPropertyParser.cpp
+++ b/Source/WebCore/css/parser/CSSPropertyParser.cpp
@@ -4054,7 +4054,7 @@
     case CSSPropertyTransform:
         return consumeTransform(m_range, m_context.mode);
     case CSSPropertyTransformBox:
-        return consumeIdent<CSSValueBorderBox, CSSValueViewBox, CSSValueFillBox>(m_range);
+        return consumeIdent<CSSValueBorderBox, CSSValueViewBox, CSSValueFillBox, CSSValueStrokeBox, CSSValueContentBox>(m_range);
     case CSSPropertyTransformOriginX:
     case CSSPropertyPerspectiveOriginX:
         return consumePositionX(m_range, m_context.mode);
diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp
index 39d8a51..a873fd9 100644
--- a/Source/WebCore/rendering/RenderLayer.cpp
+++ b/Source/WebCore/rendering/RenderLayer.cpp
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2019 Adobe. All rights reserved.
  *
  * Portions are Copyright (C) 1998 Netscape Communications Corporation.
  *
@@ -1243,6 +1244,65 @@
 }
 #endif
 
+static inline LayoutRect computeReferenceRectFromBox(const RenderBox& box, const CSSBoxType& boxType, const LayoutSize& offsetFromRoot)
+{
+    LayoutRect referenceBox;
+    switch (boxType) {
+    case CSSBoxType::ContentBox:
+    case CSSBoxType::FillBox:
+        referenceBox = box.contentBoxRect();
+        referenceBox.move(offsetFromRoot);
+        break;
+    case CSSBoxType::PaddingBox:
+        referenceBox = box.paddingBoxRect();
+        referenceBox.move(offsetFromRoot);
+        break;
+    case CSSBoxType::MarginBox:
+        referenceBox = box.marginBoxRect();
+        referenceBox.move(offsetFromRoot);
+        break;
+    // stroke-box, view-box compute to border-box for HTML elements.
+    case CSSBoxType::StrokeBox:
+    case CSSBoxType::ViewBox:
+    case CSSBoxType::BorderBox:
+    case CSSBoxType::BoxMissing:
+        referenceBox = box.borderBoxRect();
+        referenceBox.move(offsetFromRoot);
+        break;
+    }
+
+    return referenceBox;
+}
+
+static inline LayoutRect computeReferenceBox(const RenderObject& renderer, const CSSBoxType& boxType, const LayoutSize& offsetFromRoot, const LayoutRect& rootRelativeBounds)
+{
+    // FIXME: Support different reference boxes for inline content.
+    // https://bugs.webkit.org/show_bug.cgi?id=129047
+    if (!renderer.isBox())
+        return rootRelativeBounds;
+    
+    return computeReferenceRectFromBox(downcast<RenderBox>(renderer), boxType, offsetFromRoot);
+}
+
+static inline CSSBoxType transformBoxToCSSBoxType(TransformBox transformBox)
+{
+    switch (transformBox) {
+    case TransformBox::StrokeBox:
+        return CSSBoxType::StrokeBox;
+    case TransformBox::ContentBox:
+        return CSSBoxType::ContentBox;
+    case TransformBox::BorderBox:
+        return CSSBoxType::BorderBox;
+    case TransformBox::FillBox:
+        return CSSBoxType::FillBox;
+    case TransformBox::ViewBox:
+        return CSSBoxType::ViewBox;
+    default:
+        ASSERT_NOT_REACHED();
+        return CSSBoxType::BorderBox;
+    }
+}
+
 void RenderLayer::updateTransform()
 {
     bool hasTransform = renderer().hasTransform();
@@ -1263,7 +1323,9 @@
         RenderBox* box = renderBox();
         ASSERT(box);
         m_transform->makeIdentity();
-        box->style().applyTransform(*m_transform, snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor()), RenderStyle::IncludeTransformOrigin);
+        LayoutSize offsetFromRoot;
+        auto computedReferenceBox = computeReferenceRectFromBox(*box, transformBoxToCSSBoxType(box->style().transformBox()), offsetFromRoot);
+        box->style().applyTransform(*m_transform, snapRectToDevicePixels(computedReferenceBox, box->document().deviceScaleFactor()), RenderStyle::IncludeTransformOrigin);
         makeMatrixRenderable(*m_transform, canRender3DTransforms());
     }
 
@@ -1285,8 +1347,10 @@
         if (auto* timeline = renderer().documentTimeline()) {
             if (timeline->isRunningAcceleratedAnimationOnRenderer(renderer(), CSSPropertyTransform)) {
                 TransformationMatrix currTransform;
-                FloatRect pixelSnappedBorderRect = snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor());
+                LayoutSize offsetFromRoot;
                 std::unique_ptr<RenderStyle> style = timeline->animatedStyleForRenderer(renderer());
+                auto computedReferenceBox = computeReferenceBox(renderer(), transformBoxToCSSBoxType(style->transformBox()), offsetFromRoot, box->borderBoxRect());
+                FloatRect pixelSnappedBorderRect = snapRectToDevicePixels(computedReferenceBox, box->document().deviceScaleFactor());
                 style->applyTransform(currTransform, pixelSnappedBorderRect, applyOrigin);
                 makeMatrixRenderable(currTransform, canRender3DTransforms());
                 return currTransform;
@@ -1295,8 +1359,10 @@
     } else {
         if (renderer().animation().isRunningAcceleratedAnimationOnRenderer(renderer(), CSSPropertyTransform)) {
             TransformationMatrix currTransform;
-            FloatRect pixelSnappedBorderRect = snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor());
             std::unique_ptr<RenderStyle> style = renderer().animation().animatedStyleForRenderer(renderer());
+            LayoutSize offsetFromRoot;
+            auto computedReferenceBox = computeReferenceBox(renderer(), transformBoxToCSSBoxType(style->transformBox()), offsetFromRoot, box->borderBoxRect());
+            FloatRect pixelSnappedBorderRect = snapRectToDevicePixels(computedReferenceBox, box->document().deviceScaleFactor());
             style->applyTransform(currTransform, pixelSnappedBorderRect, applyOrigin);
             makeMatrixRenderable(currTransform, canRender3DTransforms());
             return currTransform;
@@ -1307,7 +1373,10 @@
     // m_transform includes transform-origin, so we need to recompute the transform here.
     if (applyOrigin == RenderStyle::ExcludeTransformOrigin) {
         TransformationMatrix currTransform;
-        FloatRect pixelSnappedBorderRect = snapRectToDevicePixels(box->borderBoxRect(), box->document().deviceScaleFactor());
+        LayoutSize offsetFromRoot;
+        std::unique_ptr<RenderStyle> style = renderer().animation().animatedStyleForRenderer(renderer());
+        auto computedReferenceBox = computeReferenceBox(renderer(), transformBoxToCSSBoxType(style->transformBox()), offsetFromRoot, box->borderBoxRect());
+        FloatRect pixelSnappedBorderRect = snapRectToDevicePixels(computedReferenceBox, box->document().deviceScaleFactor());
         box->style().applyTransform(currTransform, pixelSnappedBorderRect, RenderStyle::ExcludeTransformOrigin);
         makeMatrixRenderable(currTransform, canRender3DTransforms());
         return currTransform;
@@ -4273,42 +4342,6 @@
     return false;
 }
 
-static inline LayoutRect computeReferenceBox(const RenderObject& renderer, const CSSBoxType& boxType, const LayoutSize& offsetFromRoot, const LayoutRect& rootRelativeBounds)
-{
-    // FIXME: Support different reference boxes for inline content.
-    // https://bugs.webkit.org/show_bug.cgi?id=129047
-    if (!renderer.isBox())
-        return rootRelativeBounds;
-
-    LayoutRect referenceBox;
-    const auto& box = downcast<RenderBox>(renderer);
-    switch (boxType) {
-    case CSSBoxType::ContentBox:
-    case CSSBoxType::FillBox:
-        referenceBox = box.contentBoxRect();
-        referenceBox.move(offsetFromRoot);
-        break;
-    case CSSBoxType::PaddingBox:
-        referenceBox = box.paddingBoxRect();
-        referenceBox.move(offsetFromRoot);
-        break;
-    case CSSBoxType::MarginBox:
-        referenceBox = box.marginBoxRect();
-        referenceBox.move(offsetFromRoot);
-        break;
-    // stroke-box, view-box compute to border-box for HTML elements.
-    case CSSBoxType::StrokeBox:
-    case CSSBoxType::ViewBox:
-    case CSSBoxType::BorderBox:
-    case CSSBoxType::BoxMissing:
-        referenceBox = box.borderBoxRect();
-        referenceBox.move(offsetFromRoot);
-        break;
-    }
-
-    return referenceBox;
-}
-
 Path RenderLayer::computeClipPath(const LayoutSize& offsetFromRoot, LayoutRect& rootRelativeBounds, WindRule& windRule) const
 {
     const RenderStyle& style = renderer().style();
diff --git a/Source/WebCore/rendering/style/RenderStyleConstants.cpp b/Source/WebCore/rendering/style/RenderStyleConstants.cpp
index d0c7873..ac54d0a 100644
--- a/Source/WebCore/rendering/style/RenderStyleConstants.cpp
+++ b/Source/WebCore/rendering/style/RenderStyleConstants.cpp
@@ -1224,6 +1224,8 @@
     case TransformBox::BorderBox: ts << "border-box"; break;
     case TransformBox::FillBox: ts << "fill-box"; break;
     case TransformBox::ViewBox: ts << "view-box"; break;
+    case TransformBox::StrokeBox: ts << "stroke-box"; break;
+    case TransformBox::ContentBox: ts << "content-box"; break;
     }
     return ts;
 }
diff --git a/Source/WebCore/rendering/style/RenderStyleConstants.h b/Source/WebCore/rendering/style/RenderStyleConstants.h
index 3aebba6..f372420 100644
--- a/Source/WebCore/rendering/style/RenderStyleConstants.h
+++ b/Source/WebCore/rendering/style/RenderStyleConstants.h
@@ -920,6 +920,8 @@
 };
 
 enum class TransformBox : uint8_t {
+    StrokeBox,
+    ContentBox,
     BorderBox,
     FillBox,
     ViewBox
diff --git a/Source/WebCore/svg/SVGGraphicsElement.cpp b/Source/WebCore/svg/SVGGraphicsElement.cpp
index 80ec7fc..19f037e 100644
--- a/Source/WebCore/svg/SVGGraphicsElement.cpp
+++ b/Source/WebCore/svg/SVGGraphicsElement.cpp
@@ -80,11 +80,16 @@
         
         FloatRect boundingBox;
         switch (style->transformBox()) {
+        case TransformBox::BorderBox:
+            // For SVG elements without an associated CSS layout box, the used value for border-box is stroke-box.
+        case TransformBox::StrokeBox:
+            boundingBox = renderer()->strokeBoundingBox();
+            break;
+        case TransformBox::ContentBox:
+            // For SVG elements without an associated CSS layout box, the used value for content-box is fill-box.
         case TransformBox::FillBox:
             boundingBox = renderer()->objectBoundingBox();
             break;
-        case TransformBox::BorderBox:
-            // For SVG elements without an associated CSS layout box, the used value for border-box is view-box.
         case TransformBox::ViewBox: {
             FloatSize viewportSize;
             SVGLengthContext(this).determineViewport(viewportSize);