| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // 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/core/paint/box_model_object_painter.h" |
| |
| #include "third_party/blink/renderer/core/layout/layout_block.h" |
| #include "third_party/blink/renderer/core/layout/layout_box_model_object.h" |
| #include "third_party/blink/renderer/core/layout/line/root_inline_box.h" |
| #include "third_party/blink/renderer/core/paint/background_image_geometry.h" |
| #include "third_party/blink/renderer/core/paint/object_painter.h" |
| #include "third_party/blink/renderer/core/paint/paint_info.h" |
| #include "third_party/blink/renderer/core/paint/paint_layer.h" |
| #include "third_party/blink/renderer/platform/geometry/layout_point.h" |
| #include "third_party/blink/renderer/platform/geometry/layout_rect_outsets.h" |
| #include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h" |
| |
| namespace blink { |
| |
| namespace { |
| |
| Node* GeneratingNodeForObject(const LayoutBoxModelObject& box_model) { |
| Node* node = nullptr; |
| const LayoutObject* layout_object = &box_model; |
| for (; layout_object && !node; layout_object = layout_object->Parent()) { |
| node = layout_object->GeneratingNode(); |
| } |
| return node; |
| } |
| |
| LayoutSize LogicalOffsetOnLine(const InlineFlowBox& flow_box) { |
| // Compute the offset of the passed flow box when seen as part of an |
| // unbroken continuous strip (c.f box-decoration-break: slice.) |
| LayoutUnit logical_offset_on_line; |
| if (flow_box.IsLeftToRightDirection()) { |
| for (const InlineFlowBox* curr = flow_box.PrevForSameLayoutObject(); curr; |
| curr = curr->PrevForSameLayoutObject()) |
| logical_offset_on_line += curr->LogicalWidth(); |
| } else { |
| for (const InlineFlowBox* curr = flow_box.NextForSameLayoutObject(); curr; |
| curr = curr->NextForSameLayoutObject()) |
| logical_offset_on_line += curr->LogicalWidth(); |
| } |
| LayoutSize logical_offset(logical_offset_on_line, LayoutUnit()); |
| return flow_box.IsHorizontal() ? logical_offset |
| : logical_offset.TransposedSize(); |
| } |
| |
| } // anonymous namespace |
| |
| BoxModelObjectPainter::BoxModelObjectPainter(const LayoutBoxModelObject& box, |
| const InlineFlowBox* flow_box) |
| : BoxPainterBase(&box.GetDocument(), |
| box.StyleRef(), |
| GeneratingNodeForObject(box)), |
| box_model_(box), |
| flow_box_(flow_box) {} |
| |
| bool BoxModelObjectPainter::IsPaintingScrollingBackground( |
| const LayoutBoxModelObject* box_model_, |
| const PaintInfo& paint_info) { |
| if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { |
| // TODO(wangxianzhu): For CAP, remove this method and let callers use |
| // PaintInfo::IsPaintScrollingBackground() directly. |
| return paint_info.IsPaintingScrollingBackground(); |
| } |
| return paint_info.PaintFlags() & kPaintLayerPaintingOverflowContents && |
| !(paint_info.PaintFlags() & |
| kPaintLayerPaintingCompositingBackgroundPhase) && |
| box_model_ == paint_info.PaintContainer(); |
| } |
| |
| void BoxModelObjectPainter::PaintTextClipMask(GraphicsContext& context, |
| const IntRect& mask_rect, |
| const LayoutPoint& paint_offset, |
| bool object_has_multiple_boxes) { |
| PaintInfo paint_info(context, mask_rect, PaintPhase::kTextClip, |
| kGlobalPaintNormalPhase, 0); |
| if (flow_box_) { |
| LayoutSize local_offset = ToLayoutSize(flow_box_->Location()); |
| if (object_has_multiple_boxes && |
| box_model_.StyleRef().BoxDecorationBreak() == |
| EBoxDecorationBreak::kSlice) { |
| local_offset -= LogicalOffsetOnLine(*flow_box_); |
| } |
| const RootInlineBox& root = flow_box_->Root(); |
| flow_box_->Paint(paint_info, paint_offset - local_offset, root.LineTop(), |
| root.LineBottom()); |
| } else if (box_model_.IsLayoutBlock()) { |
| ToLayoutBlock(box_model_).PaintObject(paint_info, paint_offset); |
| } else { |
| // We should go through the above path for LayoutInlines. |
| DCHECK(!box_model_.IsLayoutInline()); |
| // Other types of objects don't have anything meaningful to paint for text |
| // clip mask. |
| } |
| } |
| |
| LayoutRect BoxModelObjectPainter::AdjustRectForScrolledContent( |
| const PaintInfo& paint_info, |
| const BoxPainterBase::FillLayerInfo& info, |
| const LayoutRect& rect) { |
| LayoutRect scrolled_paint_rect = rect; |
| GraphicsContext& context = paint_info.context; |
| if (info.is_clipped_with_local_scrolling && |
| !IsPaintingScrollingBackground(&box_model_, paint_info)) { |
| // Clip to the overflow area. |
| const LayoutBox& this_box = ToLayoutBox(box_model_); |
| // TODO(chrishtr): this should be pixel-snapped. |
| context.Clip(FloatRect(this_box.OverflowClipRect(rect.Location()))); |
| |
| // Adjust the paint rect to reflect a scrolled content box with borders at |
| // the ends. |
| IntSize offset = this_box.ScrolledContentOffset(); |
| scrolled_paint_rect.Move(-offset); |
| LayoutRectOutsets border = AdjustedBorderOutsets(info); |
| scrolled_paint_rect.SetWidth(border.Left() + this_box.ScrollWidth() + |
| border.Right()); |
| scrolled_paint_rect.SetHeight(this_box.BorderTop() + |
| this_box.ScrollHeight() + |
| this_box.BorderBottom()); |
| } |
| return scrolled_paint_rect; |
| } |
| |
| LayoutRectOutsets BoxModelObjectPainter::ComputeBorders() const { |
| return box_model_.BorderBoxOutsets(); |
| } |
| |
| LayoutRectOutsets BoxModelObjectPainter::ComputePadding() const { |
| return box_model_.PaddingOutsets(); |
| } |
| |
| BoxPainterBase::FillLayerInfo BoxModelObjectPainter::GetFillLayerInfo( |
| const Color& color, |
| const FillLayer& bg_layer, |
| BackgroundBleedAvoidance bleed_avoidance) const { |
| return BoxPainterBase::FillLayerInfo( |
| box_model_.GetDocument(), box_model_.StyleRef(), |
| box_model_.HasOverflowClip(), color, bg_layer, bleed_avoidance, |
| (flow_box_ ? flow_box_->IncludeLogicalLeftEdge() : true), |
| (flow_box_ ? flow_box_->IncludeLogicalRightEdge() : true)); |
| } |
| |
| } // namespace blink |