[go: up one dir, main page]

Allocate memory for borders and padding members of NGPhysicalBoxFragment if needed

This patch changes memory layout of |NGPhysicalBoxFragment| based on value of
borders and padding as
 - No borders and no padding
  |NGPhysicalBoxFragment|, children[]
 - having both borders no padding
  |NGPhysicalBoxFragment|, children[], borders, padding
 - borders and no padding
  |NGPhysicalBoxFragment|, children[], borders
 - no borders and padding
  |NGPhysicalBoxFragment|, children[], padding
for reducing memory usage, since borders and padding are frequently zero.

(cherry picked from commit 8318aa75176654769ece376cd71fd9fc5deef823)

TBR=yosin@chromium.org

Bug: 962108
Change-Id: I2af0ed3a3c3f111d2d4cd567073ebcba628c7279
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1662094
Reviewed-by: Yoshifumi Inoue <yosin@chromium.org>
Cr-Commit-Position: refs/branch-heads/3809@{#335}
Cr-Branched-From: d82dec1a818f378c464ba307ddd9c92133eac355-refs/heads/master@{#665002}
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
index d1a4dce9..e4e8a9e 100644
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
@@ -204,6 +204,8 @@
            left == other.left;
   }
 
+  bool IsZero() const { return !top && !right && !bottom && !left; }
+
   LayoutUnit top;
   LayoutUnit right;
   LayoutUnit bottom;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
index ef21edf..cea020a 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -22,7 +22,7 @@
 
 struct SameSizeAsNGPhysicalBoxFragment : NGPhysicalContainerFragment {
   NGBaselineList baselines;
-  NGPhysicalBoxStrut box_struts[2];
+  NGLink children[];
 };
 
 static_assert(sizeof(NGPhysicalBoxFragment) ==
@@ -43,21 +43,32 @@
 scoped_refptr<const NGPhysicalBoxFragment> NGPhysicalBoxFragment::Create(
     NGBoxFragmentBuilder* builder,
     WritingMode block_or_line_writing_mode) {
+  const NGPhysicalBoxStrut borders =
+      builder->initial_fragment_geometry_->border.ConvertToPhysical(
+          builder->GetWritingMode(), builder->Direction());
+  const NGPhysicalBoxStrut padding =
+      builder->initial_fragment_geometry_->padding.ConvertToPhysical(
+          builder->GetWritingMode(), builder->Direction());
+  const size_t byte_size = sizeof(NGPhysicalBoxFragment) +
+                           sizeof(NGLink) * builder->children_.size() +
+                           (borders.IsZero() ? 0 : sizeof(borders)) +
+                           (padding.IsZero() ? 0 : sizeof(padding));
   // We store the children list inline in the fragment as a flexible
   // array. Therefore, we need to make sure to allocate enough space for
   // that array here, which requires a manual allocation + placement new.
   // The initialization of the array is done by NGPhysicalContainerFragment;
   // we pass the buffer as a constructor argument.
   void* data = ::WTF::Partitions::FastMalloc(
-      sizeof(NGPhysicalBoxFragment) +
-          builder->children_.size() * sizeof(NGLink),
-      ::WTF::GetStringWithTypeName<NGPhysicalBoxFragment>());
-  new (data) NGPhysicalBoxFragment(builder, block_or_line_writing_mode);
+      byte_size, ::WTF::GetStringWithTypeName<NGPhysicalBoxFragment>());
+  new (data) NGPhysicalBoxFragment(builder, borders, padding,
+                                   block_or_line_writing_mode);
   return base::AdoptRef(static_cast<NGPhysicalBoxFragment*>(data));
 }
 
 NGPhysicalBoxFragment::NGPhysicalBoxFragment(
     NGBoxFragmentBuilder* builder,
+    const NGPhysicalBoxStrut& borders,
+    const NGPhysicalBoxStrut& padding,
     WritingMode block_or_line_writing_mode)
     : NGPhysicalContainerFragment(
           builder,
@@ -67,14 +78,14 @@
               ? kFragmentRenderedLegend
               : kFragmentBox,
           builder->BoxType()),
-      baselines_(builder->baselines_),
-      borders_(builder->initial_fragment_geometry_->border.ConvertToPhysical(
-          builder->GetWritingMode(),
-          builder->Direction())),
-      padding_(builder->initial_fragment_geometry_->padding.ConvertToPhysical(
-          builder->GetWritingMode(),
-          builder->Direction())) {
+      baselines_(builder->baselines_) {
   DCHECK(GetLayoutObject() && GetLayoutObject()->IsBoxModelObject());
+  has_borders_ = !borders.IsZero();
+  if (has_borders_)
+    *const_cast<NGPhysicalBoxStrut*>(ComputeBordersAddress()) = borders;
+  has_padding_ = !padding.IsZero();
+  if (has_padding_)
+    *const_cast<NGPhysicalBoxStrut*>(ComputePaddingAddress()) = padding;
   is_fieldset_container_ = builder->is_fieldset_container_;
   is_legacy_layout_root_ = builder->is_legacy_layout_root_;
   border_edge_ = builder->border_edges_.ToPhysical(builder->GetWritingMode());
@@ -278,8 +289,8 @@
   // Legacy layout can (incorrectly) shift baseline position(s) during
   // "simplified" layout.
   DCHECK(IsLegacyLayoutRoot() || baselines_ == other.baselines_);
-  DCHECK(borders_ == other.borders_);
-  DCHECK(padding_ == other.padding_);
+  DCHECK(Borders() == other.Borders());
+  DCHECK(Padding() == other.Padding());
 }
 #endif
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
index ab1747ef7..ada1b07c 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
@@ -33,12 +33,22 @@
     return baselines_.Offset(request);
   }
 
-  const NGPhysicalBoxStrut Borders() const { return borders_; }
+  const NGPhysicalBoxStrut Borders() const {
+    if (!has_borders_)
+      return NGPhysicalBoxStrut();
+    return *ComputeBordersAddress();
+  }
 
-  const NGPhysicalBoxStrut Padding() const { return padding_; }
+  const NGPhysicalBoxStrut Padding() const {
+    if (!has_padding_)
+      return NGPhysicalBoxStrut();
+    return *ComputePaddingAddress();
+  }
 
   NGPixelSnappedPhysicalBoxStrut PixelSnappedPadding() const {
-    return padding_.SnapToDevicePixels();
+    if (!has_padding_)
+      return NGPixelSnappedPhysicalBoxStrut();
+    return ComputePaddingAddress()->SnapToDevicePixels();
   }
 
   bool HasSelfPaintingLayer() const;
@@ -77,12 +87,27 @@
 
  private:
   NGPhysicalBoxFragment(NGBoxFragmentBuilder* builder,
+                        const NGPhysicalBoxStrut& borders,
+                        const NGPhysicalBoxStrut& padding,
                         WritingMode block_or_line_writing_mode);
 
+  const NGPhysicalBoxStrut* ComputeBordersAddress() const {
+    DCHECK(has_borders_);
+    return reinterpret_cast<const NGPhysicalBoxStrut*>(children_ +
+                                                       Children().size());
+  }
+
+  const NGPhysicalBoxStrut* ComputePaddingAddress() const {
+    DCHECK(has_padding_);
+    const NGPhysicalBoxStrut* address =
+        reinterpret_cast<const NGPhysicalBoxStrut*>(children_ +
+                                                    Children().size());
+    return has_borders_ ? address + 1 : address;
+  }
+
   NGBaselineList baselines_;
-  NGPhysicalBoxStrut borders_;
-  NGPhysicalBoxStrut padding_;
   NGLink children_[];
+  // borders and padding come from after |children_| if they are not zero.
 };
 
 template <>
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
index 868db0e..caa75ac 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
@@ -307,6 +307,8 @@
   // (it's defined here to save memory, since that class has no bitfields).
   unsigned children_inline_ : 1;
   unsigned border_edge_ : 4;  // NGBorderEdges::Physical
+  unsigned has_borders_ : 1;
+  unsigned has_padding_ : 1;
 
   // The following are only used by NGPhysicalBoxFragment but are initialized
   // for all types to allow methods using them to be inlined.