| // 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/frame_set_painter.h" |
| |
| #include "third_party/blink/renderer/core/html/html_frame_set_element.h" |
| #include "third_party/blink/renderer/core/layout/layout_frame_set.h" |
| #include "third_party/blink/renderer/core/paint/paint_info.h" |
| #include "third_party/blink/renderer/core/paint/scoped_paint_state.h" |
| #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h" |
| |
| namespace blink { |
| |
| static Color BorderStartEdgeColor() { |
| return Color(170, 170, 170); |
| } |
| |
| static Color BorderEndEdgeColor() { |
| return Color::kBlack; |
| } |
| |
| static Color BorderFillColor() { |
| return Color(208, 208, 208); |
| } |
| |
| void FrameSetPainter::PaintColumnBorder(const PaintInfo& paint_info, |
| const IntRect& border_rect) { |
| if (!paint_info.GetCullRect().Intersects(border_rect)) |
| return; |
| |
| // FIXME: We should do something clever when borders from distinct framesets |
| // meet at a join. |
| |
| // Fill first. |
| GraphicsContext& context = paint_info.context; |
| context.FillRect(border_rect, layout_frame_set_.FrameSet()->HasBorderColor() |
| ? layout_frame_set_.ResolveColor( |
| GetCSSPropertyBorderLeftColor()) |
| : BorderFillColor()); |
| |
| // Now stroke the edges but only if we have enough room to paint both edges |
| // with a little bit of the fill color showing through. |
| if (border_rect.Width() >= 3) { |
| context.FillRect( |
| IntRect(border_rect.Location(), IntSize(1, border_rect.Height())), |
| BorderStartEdgeColor()); |
| context.FillRect(IntRect(IntPoint(border_rect.MaxX() - 1, border_rect.Y()), |
| IntSize(1, border_rect.Height())), |
| BorderEndEdgeColor()); |
| } |
| } |
| |
| void FrameSetPainter::PaintRowBorder(const PaintInfo& paint_info, |
| const IntRect& border_rect) { |
| // FIXME: We should do something clever when borders from distinct framesets |
| // meet at a join. |
| |
| // Fill first. |
| GraphicsContext& context = paint_info.context; |
| context.FillRect(border_rect, layout_frame_set_.FrameSet()->HasBorderColor() |
| ? layout_frame_set_.ResolveColor( |
| GetCSSPropertyBorderLeftColor()) |
| : BorderFillColor()); |
| |
| // Now stroke the edges but only if we have enough room to paint both edges |
| // with a little bit of the fill color showing through. |
| if (border_rect.Height() >= 3) { |
| context.FillRect( |
| IntRect(border_rect.Location(), IntSize(border_rect.Width(), 1)), |
| BorderStartEdgeColor()); |
| context.FillRect(IntRect(IntPoint(border_rect.X(), border_rect.MaxY() - 1), |
| IntSize(border_rect.Width(), 1)), |
| BorderEndEdgeColor()); |
| } |
| } |
| |
| static bool ShouldPaintBorderAfter(const LayoutFrameSet::GridAxis& axis, |
| wtf_size_t index) { |
| // Should not paint a border after the last frame along the axis. |
| return index + 1 < axis.sizes_.size() && axis.allow_border_[index + 1]; |
| } |
| |
| void FrameSetPainter::PaintBorders(const PaintInfo& paint_info, |
| const LayoutPoint& paint_offset) { |
| if (DrawingRecorder::UseCachedDrawingIfPossible( |
| paint_info.context, layout_frame_set_, paint_info.phase)) |
| return; |
| |
| DrawingRecorder recorder(paint_info.context, layout_frame_set_, |
| paint_info.phase); |
| |
| LayoutUnit border_thickness(layout_frame_set_.FrameSet()->Border()); |
| if (!border_thickness) |
| return; |
| |
| LayoutObject* child = layout_frame_set_.FirstChild(); |
| wtf_size_t rows = layout_frame_set_.Rows().sizes_.size(); |
| wtf_size_t cols = layout_frame_set_.Columns().sizes_.size(); |
| LayoutUnit y_pos; |
| for (wtf_size_t r = 0; r < rows; r++) { |
| LayoutUnit x_pos; |
| for (wtf_size_t c = 0; c < cols; c++) { |
| x_pos += layout_frame_set_.Columns().sizes_[c]; |
| if (ShouldPaintBorderAfter(layout_frame_set_.Columns(), c)) { |
| PaintColumnBorder( |
| paint_info, |
| PixelSnappedIntRect(LayoutRect( |
| paint_offset.X() + x_pos, paint_offset.Y() + y_pos, |
| border_thickness, layout_frame_set_.Size().Height() - y_pos))); |
| x_pos += border_thickness; |
| } |
| child = child->NextSibling(); |
| if (!child) |
| return; |
| } |
| y_pos += layout_frame_set_.Rows().sizes_[r]; |
| if (ShouldPaintBorderAfter(layout_frame_set_.Rows(), r)) { |
| PaintRowBorder(paint_info, |
| PixelSnappedIntRect(LayoutRect( |
| paint_offset.X(), paint_offset.Y() + y_pos, |
| layout_frame_set_.Size().Width(), border_thickness))); |
| y_pos += border_thickness; |
| } |
| } |
| } |
| |
| void FrameSetPainter::PaintChildren(const PaintInfo& paint_info) { |
| // Paint only those children that fit in the grid. |
| // Remaining frames are "hidden". |
| // See also LayoutFrameSet::positionFrames. |
| LayoutObject* child = layout_frame_set_.FirstChild(); |
| size_t rows = layout_frame_set_.Rows().sizes_.size(); |
| size_t cols = layout_frame_set_.Columns().sizes_.size(); |
| for (size_t r = 0; r < rows; r++) { |
| for (size_t c = 0; c < cols; c++) { |
| // Self-painting layers are painted during the PaintLayer paint recursion, |
| // not LayoutObject. |
| if (!child->IsBoxModelObject() || |
| !ToLayoutBoxModelObject(child)->HasSelfPaintingLayer()) |
| child->Paint(paint_info); |
| child = child->NextSibling(); |
| if (!child) |
| return; |
| } |
| } |
| } |
| |
| void FrameSetPainter::Paint(const PaintInfo& paint_info) { |
| if (paint_info.phase != PaintPhase::kForeground) |
| return; |
| |
| LayoutObject* child = layout_frame_set_.FirstChild(); |
| if (!child) |
| return; |
| |
| ScopedPaintState paint_state(layout_frame_set_, paint_info); |
| const auto& local_paint_info = paint_state.GetPaintInfo(); |
| PaintChildren(local_paint_info); |
| PaintBorders(local_paint_info, paint_state.PaintOffset()); |
| } |
| |
| } // namespace blink |