blob: 196fca5a0464235b824eb4686f2a73057e775e32 [file] [log] [blame]
// 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