TextPainter::Style TextPainter::selectionPaintingStyle( LineLayoutItem lineLayoutItem, bool haveSelection, const PaintInfo& paintInfo, const TextPainter::Style& textStyle) { const LayoutObject& layoutObject = *LineLayoutAPIShim::constLayoutObjectFrom(lineLayoutItem); TextPainter::Style selectionStyle = textStyle; bool usesTextAsClip = paintInfo.phase == PaintPhaseTextClip; bool isPrinting = paintInfo.isPrinting(); if (haveSelection) { if (!usesTextAsClip) { selectionStyle.fillColor = layoutObject.selectionForegroundColor( paintInfo.getGlobalPaintFlags()); selectionStyle.emphasisMarkColor = layoutObject.selectionEmphasisMarkColor( paintInfo.getGlobalPaintFlags()); } if (const ComputedStyle* pseudoStyle = layoutObject.getCachedPseudoStyle(PseudoIdSelection)) { selectionStyle.strokeColor = usesTextAsClip ? Color::black : layoutObject.resolveColor( *pseudoStyle, CSSPropertyWebkitTextStrokeColor); selectionStyle.strokeWidth = pseudoStyle->textStrokeWidth(); selectionStyle.shadow = usesTextAsClip ? 0 : pseudoStyle->textShadow(); } // Text shadows are disabled when printing. http://crbug.com/258321 if (isPrinting) selectionStyle.shadow = 0; } return selectionStyle; }
void ViewPainter::paintBoxDecorationBackground(const PaintInfo& paintInfo) { if (paintInfo.skipRootBackground()) return; // This function overrides background painting for the LayoutView. // View background painting is special in the following ways: // 1. The view paints background for the root element, the background // positioning respects the positioning and transformation of the root // element. // 2. CSS background-clip is ignored, the background layers always expand to // cover the whole canvas. None of the stacking context effects (except // transformation) on the root element affects the background. // 3. The main frame is also responsible for painting the user-agent-defined // base background color. Conceptually it should be painted by the embedder // but painting it here allows culling and pre-blending optimization when // possible. GraphicsContext& context = paintInfo.context; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible( context, m_layoutView, DisplayItem::kDocumentBackground)) return; // The background fill rect is the size of the LayoutView's main // GraphicsLayer. IntRect backgroundRect = pixelSnappedIntRect(m_layoutView.layer()->boundingBoxForCompositing()); const Document& document = m_layoutView.document(); const FrameView& frameView = *m_layoutView.frameView(); bool isMainFrame = document.isInMainFrame(); bool paintsBaseBackground = isMainFrame && !frameView.isTransparent(); bool shouldClearCanvas = paintsBaseBackground && (document.settings() && document.settings()->shouldClearDocumentBackground()); Color baseBackgroundColor = paintsBaseBackground ? frameView.baseBackgroundColor() : Color(); Color rootBackgroundColor = m_layoutView.style()->visitedDependentColor(CSSPropertyBackgroundColor); const LayoutObject* rootObject = document.documentElement() ? document.documentElement()->layoutObject() : nullptr; LayoutObjectDrawingRecorder recorder( context, m_layoutView, DisplayItem::kDocumentBackground, backgroundRect); // Special handling for print economy mode. bool forceBackgroundToWhite = BoxPainter::shouldForceWhiteBackgroundForPrintEconomy( m_layoutView.styleRef(), document); if (forceBackgroundToWhite) { // If for any reason the view background is not transparent, paint white // instead, otherwise keep transparent as is. if (paintsBaseBackground || rootBackgroundColor.alpha() || m_layoutView.style()->backgroundLayers().image()) context.fillRect(backgroundRect, Color::white, SkBlendMode::kSrc); return; } // Compute the enclosing rect of the view, in root element space. // // For background colors we can simply paint the document rect in the default // space. However for background image, the root element transform applies. // The strategy is to apply root element transform on the context and issue // draw commands in the local space, therefore we need to apply inverse // transform on the document rect to get to the root element space. bool backgroundRenderable = true; TransformationMatrix transform; IntRect paintRect = backgroundRect; if (!rootObject || !rootObject->isBox()) { backgroundRenderable = false; } else if (rootObject->hasLayer()) { const PaintLayer& rootLayer = *toLayoutBoxModelObject(rootObject)->layer(); LayoutPoint offset; rootLayer.convertToLayerCoords(nullptr, offset); transform.translate(offset.x(), offset.y()); transform.multiply( rootLayer.renderableTransform(paintInfo.getGlobalPaintFlags())); if (!transform.isInvertible()) { backgroundRenderable = false; } else { bool isClamped; paintRect = transform.inverse() .projectQuad(FloatQuad(backgroundRect), &isClamped) .enclosingBoundingBox(); backgroundRenderable = !isClamped; } } if (!backgroundRenderable) { if (baseBackgroundColor.alpha()) { context.fillRect( backgroundRect, baseBackgroundColor, shouldClearCanvas ? SkBlendMode::kSrc : SkBlendMode::kSrcOver); } else if (shouldClearCanvas) { context.fillRect(backgroundRect, Color(), SkBlendMode::kClear); } return; } BoxPainter::FillLayerOcclusionOutputList reversedPaintList; bool shouldDrawBackgroundInSeparateBuffer = BoxPainter(m_layoutView) .calculateFillLayerOcclusionCulling( reversedPaintList, m_layoutView.style()->backgroundLayers()); DCHECK(reversedPaintList.size()); // If the root background color is opaque, isolation group can be skipped // because the canvas // will be cleared by root background color. if (!rootBackgroundColor.hasAlpha()) shouldDrawBackgroundInSeparateBuffer = false; // We are going to clear the canvas with transparent pixels, isolation group // can be skipped. if (!baseBackgroundColor.alpha() && shouldClearCanvas) shouldDrawBackgroundInSeparateBuffer = false; if (shouldDrawBackgroundInSeparateBuffer) { if (baseBackgroundColor.alpha()) { context.fillRect( backgroundRect, baseBackgroundColor, shouldClearCanvas ? SkBlendMode::kSrc : SkBlendMode::kSrcOver); } context.beginLayer(); } Color combinedBackgroundColor = shouldDrawBackgroundInSeparateBuffer ? rootBackgroundColor : baseBackgroundColor.blend(rootBackgroundColor); if (combinedBackgroundColor.alpha()) { if (!combinedBackgroundColor.hasAlpha() && RuntimeEnabledFeatures::slimmingPaintV2Enabled()) recorder.setKnownToBeOpaque(); context.fillRect(backgroundRect, combinedBackgroundColor, (shouldDrawBackgroundInSeparateBuffer || shouldClearCanvas) ? SkBlendMode::kSrc : SkBlendMode::kSrcOver); } else if (shouldClearCanvas && !shouldDrawBackgroundInSeparateBuffer) { context.fillRect(backgroundRect, Color(), SkBlendMode::kClear); } for (auto it = reversedPaintList.rbegin(); it != reversedPaintList.rend(); ++it) { DCHECK((*it)->clip() == BorderFillBox); bool shouldPaintInViewportSpace = (*it)->attachment() == FixedBackgroundAttachment; if (shouldPaintInViewportSpace) { BoxPainter::paintFillLayer(m_layoutView, paintInfo, Color(), **it, LayoutRect(LayoutRect::infiniteIntRect()), BackgroundBleedNone); } else { context.save(); // TODO(trchen): We should be able to handle 3D-transformed root // background with slimming paint by using transform display items. context.concatCTM(transform.toAffineTransform()); BoxPainter::paintFillLayer(m_layoutView, paintInfo, Color(), **it, LayoutRect(paintRect), BackgroundBleedNone); context.restore(); } } if (shouldDrawBackgroundInSeparateBuffer) context.endLayer(); }