void InlineFlowBoxPainter::paintBoxDecorationBackground(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, const LayoutRect& cullRect) { ASSERT(paintInfo.phase == PaintPhaseForeground); if (!paintInfo.shouldPaintWithinRoot(&m_inlineFlowBox.layoutObject()) || m_inlineFlowBox.layoutObject().style()->visibility() != VISIBLE) return; // You can use p::first-line to specify a background. If so, the root line boxes for // a line may actually have to paint a background. const ComputedStyle* styleToUse = m_inlineFlowBox.layoutObject().style(m_inlineFlowBox.isFirstLineStyle()); bool shouldPaintBoxDecorationBackground; if (m_inlineFlowBox.parent()) shouldPaintBoxDecorationBackground = m_inlineFlowBox.layoutObject().hasBoxDecorationBackground(); else shouldPaintBoxDecorationBackground = m_inlineFlowBox.isFirstLineStyle() && styleToUse != m_inlineFlowBox.layoutObject().style(); if (!shouldPaintBoxDecorationBackground) return; if (DrawingRecorder::useCachedDrawingIfPossible(*paintInfo.context, m_inlineFlowBox, DisplayItem::BoxDecorationBackground)) return; DrawingRecorder recorder(*paintInfo.context, m_inlineFlowBox, DisplayItem::BoxDecorationBackground, pixelSnappedIntRect(cullRect)); LayoutRect frameRect = roundedFrameRectClampedToLineTopAndBottomIfNeeded(); // Move x/y to our coordinates. LayoutRect localRect(frameRect); m_inlineFlowBox.flipForWritingMode(localRect); LayoutPoint adjustedPaintOffset = paintOffset + localRect.location(); LayoutRect adjustedFrameRect = LayoutRect(adjustedPaintOffset, frameRect.size()); LayoutRect adjustedClipRect; BorderPaintingType borderPaintingType = getBorderPaintType(adjustedFrameRect, adjustedClipRect); // Shadow comes first and is behind the background and border. if (!m_inlineFlowBox.deprecatedBoxModelObject()->boxShadowShouldBeAppliedToBackground(BackgroundBleedNone, &m_inlineFlowBox)) paintBoxShadow(paintInfo, *styleToUse, Normal, adjustedFrameRect); Color backgroundColor = m_inlineFlowBox.layoutObject().resolveColor(*styleToUse, CSSPropertyBackgroundColor); paintFillLayers(paintInfo, backgroundColor, styleToUse->backgroundLayers(), adjustedFrameRect); paintBoxShadow(paintInfo, *styleToUse, Inset, adjustedFrameRect); switch (borderPaintingType) { case DontPaintBorders: break; case PaintBordersWithoutClip: BoxPainter::paintBorder(*m_inlineFlowBox.deprecatedBoxModelObject(), paintInfo, adjustedFrameRect, m_inlineFlowBox.layoutObject().styleRef(m_inlineFlowBox.isFirstLineStyle()), BackgroundBleedNone, m_inlineFlowBox.includeLogicalLeftEdge(), m_inlineFlowBox.includeLogicalRightEdge()); break; case PaintBordersWithClip: // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right, // but it isn't even clear how this should work at all. LayoutRect imageStripPaintRect = paintRectForImageStrip(adjustedPaintOffset, frameRect.size(), LTR); GraphicsContextStateSaver stateSaver(*paintInfo.context); paintInfo.context->clip(adjustedClipRect); BoxPainter::paintBorder(*m_inlineFlowBox.deprecatedBoxModelObject(), paintInfo, imageStripPaintRect, m_inlineFlowBox.layoutObject().styleRef(m_inlineFlowBox.isFirstLineStyle())); break; } }
void InlineFlowBoxPainter::paintMask(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!paintInfo.shouldPaintWithinRoot(&m_inlineFlowBox.layoutObject()) || m_inlineFlowBox.layoutObject().style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) return; LayoutRect frameRect = roundedFrameRectClampedToLineTopAndBottomIfNeeded(); // Move x/y to our coordinates. LayoutRect localRect(frameRect); m_inlineFlowBox.flipForWritingMode(localRect); LayoutPoint adjustedPaintOffset = paintOffset + localRect.location(); const NinePieceImage& maskNinePieceImage = m_inlineFlowBox.layoutObject().style()->maskBoxImage(); StyleImage* maskBoxImage = m_inlineFlowBox.layoutObject().style()->maskBoxImage().image(); // Figure out if we need to push a transparency layer to render our mask. bool pushTransparencyLayer = false; bool compositedMask = m_inlineFlowBox.layoutObject().hasLayer() && m_inlineFlowBox.boxModelObject()->layer()->hasCompositedMask(); bool flattenCompositingLayers = m_inlineFlowBox.layoutObject().view()->frameView() && m_inlineFlowBox.layoutObject().view()->frameView()->paintBehavior() & PaintBehaviorFlattenCompositingLayers; SkXfermode::Mode compositeOp = SkXfermode::kSrcOver_Mode; if (!compositedMask || flattenCompositingLayers) { if ((maskBoxImage && m_inlineFlowBox.layoutObject().style()->maskLayers().hasImage()) || m_inlineFlowBox.layoutObject().style()->maskLayers().next()) { pushTransparencyLayer = true; paintInfo.context->beginLayer(1.0f, SkXfermode::kDstIn_Mode); } else { // TODO(fmalita): passing a dst-in xfer mode down to paintFillLayers/paintNinePieceImage // seems dangerous: it is only correct if applied atomically (single draw call). While // the heuristic above presumably ensures that is the case, this approach seems super // fragile. We should investigate dropping this optimization in favour of the more // robust layer branch above. compositeOp = SkXfermode::kDstIn_Mode; } } LayoutRect paintRect = LayoutRect(adjustedPaintOffset, frameRect.size()); paintFillLayers(paintInfo, Color::transparent, m_inlineFlowBox.layoutObject().style()->maskLayers(), paintRect, compositeOp); bool hasBoxImage = maskBoxImage && maskBoxImage->canRender(m_inlineFlowBox.layoutObject(), m_inlineFlowBox.layoutObject().style()->effectiveZoom()); if (!hasBoxImage || !maskBoxImage->isLoaded()) { if (pushTransparencyLayer) paintInfo.context->endLayer(); return; // Don't paint anything while we wait for the image to load. } // The simple case is where we are the only box for this object. In those // cases only a single call to draw is required. if (!m_inlineFlowBox.prevLineBox() && !m_inlineFlowBox.nextLineBox()) { BoxPainter::paintNinePieceImage(*m_inlineFlowBox.boxModelObject(), paintInfo.context, paintRect, m_inlineFlowBox.layoutObject().styleRef(), maskNinePieceImage, compositeOp); } else { // We have a mask image that spans multiple lines. // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right, // but it isn't even clear how this should work at all. LayoutRect imageStripPaintRect = paintRectForImageStrip(adjustedPaintOffset, frameRect.size(), LTR); LayoutRect clipRect = clipRectForNinePieceImageStrip(&m_inlineFlowBox, maskNinePieceImage, paintRect); GraphicsContextStateSaver stateSaver(*paintInfo.context); paintInfo.context->clip(clipRect); BoxPainter::paintNinePieceImage(*m_inlineFlowBox.boxModelObject(), paintInfo.context, imageStripPaintRect, m_inlineFlowBox.layoutObject().styleRef(), maskNinePieceImage, compositeOp); } if (pushTransparencyLayer) paintInfo.context->endLayer(); }