blob: 5943adfbbd354b648e08c90c477d24db64ebd03b [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 "core/paint/PartPainter.h"
#include "core/layout/LayoutPart.h"
#include "core/paint/BoxPainter.h"
#include "core/paint/LayoutObjectDrawingRecorder.h"
#include "core/paint/ObjectPainter.h"
#include "core/paint/PaintInfo.h"
#include "core/paint/PaintLayer.h"
#include "core/paint/ReplacedPainter.h"
#include "core/paint/RoundedInnerRectClipper.h"
#include "core/paint/ScrollableAreaPainter.h"
#include "core/paint/TransformRecorder.h"
#include "wtf/Optional.h"
namespace blink {
bool PartPainter::isSelected() const {
SelectionState s = m_layoutPart.getSelectionState();
if (s == SelectionNone)
return false;
if (s == SelectionInside)
return true;
int selectionStart, selectionEnd;
m_layoutPart.selectionStartEnd(selectionStart, selectionEnd);
if (s == SelectionStart)
return selectionStart == 0;
int end = m_layoutPart.node()->hasChildren()
? m_layoutPart.node()->countChildren()
: 1;
if (s == SelectionEnd)
return selectionEnd == end;
if (s == SelectionBoth)
return selectionStart == 0 && selectionEnd == end;
ASSERT(0);
return false;
}
void PartPainter::paint(const PaintInfo& paintInfo,
const LayoutPoint& paintOffset) {
LayoutPoint adjustedPaintOffset = paintOffset + m_layoutPart.location();
if (!ReplacedPainter(m_layoutPart)
.shouldPaint(paintInfo, adjustedPaintOffset))
return;
LayoutRect borderRect(adjustedPaintOffset, m_layoutPart.size());
if (m_layoutPart.hasBoxDecorationBackground() &&
(paintInfo.phase == PaintPhaseForeground ||
paintInfo.phase == PaintPhaseSelection))
BoxPainter(m_layoutPart)
.paintBoxDecorationBackground(paintInfo, adjustedPaintOffset);
if (paintInfo.phase == PaintPhaseMask) {
BoxPainter(m_layoutPart).paintMask(paintInfo, adjustedPaintOffset);
return;
}
if (shouldPaintSelfOutline(paintInfo.phase))
ObjectPainter(m_layoutPart).paintOutline(paintInfo, adjustedPaintOffset);
if (paintInfo.phase != PaintPhaseForeground)
return;
if (m_layoutPart.widget()) {
// TODO(schenney) crbug.com/93805 Speculative release assert to verify that
// the crashes we see in widget painting are due to a destroyed LayoutPart
// object.
RELEASE_ASSERT(m_layoutPart.node());
Optional<RoundedInnerRectClipper> clipper;
if (m_layoutPart.style()->hasBorderRadius()) {
if (borderRect.isEmpty())
return;
FloatRoundedRect roundedInnerRect =
m_layoutPart.style()->getRoundedInnerBorderFor(
borderRect,
LayoutRectOutsets(
-(m_layoutPart.paddingTop() + m_layoutPart.borderTop()),
-(m_layoutPart.paddingRight() + m_layoutPart.borderRight()),
-(m_layoutPart.paddingBottom() + m_layoutPart.borderBottom()),
-(m_layoutPart.paddingLeft() + m_layoutPart.borderLeft())),
true, true);
clipper.emplace(m_layoutPart, paintInfo, borderRect, roundedInnerRect,
ApplyToDisplayList);
}
m_layoutPart.paintContents(paintInfo, paintOffset);
}
// Paint a partially transparent wash over selected widgets.
if (isSelected() && !paintInfo.isPrinting() &&
!LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(
paintInfo.context, m_layoutPart, paintInfo.phase)) {
LayoutRect rect = m_layoutPart.localSelectionRect();
rect.moveBy(adjustedPaintOffset);
IntRect selectionRect = pixelSnappedIntRect(rect);
LayoutObjectDrawingRecorder drawingRecorder(paintInfo.context, m_layoutPart,
paintInfo.phase, selectionRect);
paintInfo.context.fillRect(selectionRect,
m_layoutPart.selectionBackgroundColor());
}
if (m_layoutPart.canResize())
ScrollableAreaPainter(*m_layoutPart.layer()->getScrollableArea())
.paintResizer(paintInfo.context, roundedIntPoint(adjustedPaintOffset),
paintInfo.cullRect());
}
void PartPainter::paintContents(const PaintInfo& paintInfo,
const LayoutPoint& paintOffset) {
LayoutPoint adjustedPaintOffset = paintOffset + m_layoutPart.location();
Widget* widget = m_layoutPart.widget();
RELEASE_ASSERT(widget);
IntPoint paintLocation(roundedIntPoint(
adjustedPaintOffset + m_layoutPart.replacedContentRect().location()));
// Widgets don't support painting with a paint offset, but instead offset
// themselves using the frame rect location. To paint widgets at our desired
// location, we need to apply paint offset as a transform, with the frame rect
// neutralized.
IntSize widgetPaintOffset = paintLocation - widget->frameRect().location();
TransformRecorder transform(
paintInfo.context, m_layoutPart,
AffineTransform::translation(widgetPaintOffset.width(),
widgetPaintOffset.height()));
CullRect adjustedCullRect(paintInfo.cullRect(), -widgetPaintOffset);
widget->paint(paintInfo.context, adjustedCullRect);
}
} // namespace blink