1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "config.h" 6 #include "core/paint/InlinePainter.h" 7 8 #include "core/paint/BoxPainter.h" 9 #include "core/paint/LineBoxListPainter.h" 10 #include "core/paint/ObjectPainter.h" 11 #include "core/rendering/GraphicsContextAnnotator.h" 12 #include "core/rendering/PaintInfo.h" 13 #include "core/rendering/RenderInline.h" 14 #include "core/rendering/RenderTheme.h" 15 #include "core/rendering/RootInlineBox.h" 16 #include "platform/geometry/LayoutPoint.h" 17 18 namespace blink { 19 20 void InlinePainter::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 21 { 22 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, &m_renderInline); 23 LineBoxListPainter(*m_renderInline.lineBoxes()).paint(&m_renderInline, paintInfo, paintOffset); 24 } 25 26 void InlinePainter::paintOutline(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 27 { 28 RenderStyle* styleToUse = m_renderInline.style(); 29 if (!styleToUse->hasOutline()) 30 return; 31 32 if (styleToUse->outlineStyleIsAuto()) { 33 if (RenderTheme::theme().shouldDrawDefaultFocusRing(&m_renderInline)) { 34 // Only paint the focus ring by hand if the theme isn't able to draw the focus ring. 35 ObjectPainter(m_renderInline).paintFocusRing(paintInfo, paintOffset, styleToUse); 36 } 37 return; 38 } 39 40 if (styleToUse->outlineStyle() == BNONE) 41 return; 42 43 Vector<LayoutRect> rects; 44 45 rects.append(LayoutRect()); 46 for (InlineFlowBox* curr = m_renderInline.firstLineBox(); curr; curr = curr->nextLineBox()) { 47 RootInlineBox& root = curr->root(); 48 LayoutUnit top = std::max<LayoutUnit>(root.lineTop(), curr->logicalTop()); 49 LayoutUnit bottom = std::min<LayoutUnit>(root.lineBottom(), curr->logicalBottom()); 50 rects.append(LayoutRect(curr->x(), top, curr->logicalWidth(), bottom - top)); 51 } 52 rects.append(LayoutRect()); 53 54 Color outlineColor = m_renderInline.resolveColor(styleToUse, CSSPropertyOutlineColor); 55 bool useTransparencyLayer = outlineColor.hasAlpha(); 56 57 GraphicsContext* graphicsContext = paintInfo.context; 58 if (useTransparencyLayer) { 59 graphicsContext->beginTransparencyLayer(static_cast<float>(outlineColor.alpha()) / 255); 60 outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineColor.blue()); 61 } 62 63 for (unsigned i = 1; i < rects.size() - 1; i++) 64 paintOutlineForLine(graphicsContext, paintOffset, rects.at(i - 1), rects.at(i), rects.at(i + 1), outlineColor); 65 66 if (useTransparencyLayer) 67 graphicsContext->endLayer(); 68 } 69 70 void InlinePainter::paintOutlineForLine(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset, 71 const LayoutRect& lastline, const LayoutRect& thisline, const LayoutRect& nextline, const Color outlineColor) 72 { 73 RenderStyle* styleToUse = m_renderInline.style(); 74 int outlineWidth = styleToUse->outlineWidth(); 75 EBorderStyle outlineStyle = styleToUse->outlineStyle(); 76 77 bool antialias = BoxPainter::shouldAntialiasLines(graphicsContext); 78 79 int offset = m_renderInline.style()->outlineOffset(); 80 81 LayoutRect box(LayoutPoint(paintOffset.x() + thisline.x() - offset, paintOffset.y() + thisline.y() - offset), 82 LayoutSize(thisline.width() + offset, thisline.height() + offset)); 83 84 IntRect pixelSnappedBox = pixelSnappedIntRect(box); 85 if (pixelSnappedBox.width() < 0 || pixelSnappedBox.height() < 0) 86 return; 87 IntRect pixelSnappedLastLine = pixelSnappedIntRect(paintOffset.x() + lastline.x(), 0, lastline.width(), 0); 88 IntRect pixelSnappedNextLine = pixelSnappedIntRect(paintOffset.x() + nextline.x(), 0, nextline.width(), 0); 89 90 // left edge 91 ObjectPainter::drawLineForBoxSide(graphicsContext, 92 pixelSnappedBox.x() - outlineWidth, 93 pixelSnappedBox.y() - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : 0), 94 pixelSnappedBox.x(), 95 pixelSnappedBox.maxY() + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : 0), 96 BSLeft, 97 outlineColor, outlineStyle, 98 (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth), 99 (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth), 100 antialias); 101 102 // right edge 103 ObjectPainter::drawLineForBoxSide(graphicsContext, 104 pixelSnappedBox.maxX(), 105 pixelSnappedBox.y() - (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : 0), 106 pixelSnappedBox.maxX() + outlineWidth, 107 pixelSnappedBox.maxY() + (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : 0), 108 BSRight, 109 outlineColor, outlineStyle, 110 (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : -outlineWidth), 111 (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : -outlineWidth), 112 antialias); 113 // upper edge 114 if (thisline.x() < lastline.x()) { 115 ObjectPainter::drawLineForBoxSide(graphicsContext, 116 pixelSnappedBox.x() - outlineWidth, 117 pixelSnappedBox.y() - outlineWidth, 118 std::min(pixelSnappedBox.maxX() + outlineWidth, (lastline.isEmpty() ? 1000000 : pixelSnappedLastLine.x())), 119 pixelSnappedBox.y(), 120 BSTop, outlineColor, outlineStyle, 121 outlineWidth, 122 (!lastline.isEmpty() && paintOffset.x() + lastline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth, 123 antialias); 124 } 125 126 if (lastline.maxX() < thisline.maxX()) { 127 ObjectPainter::drawLineForBoxSide(graphicsContext, 128 std::max(lastline.isEmpty() ? -1000000 : pixelSnappedLastLine.maxX(), pixelSnappedBox.x() - outlineWidth), 129 pixelSnappedBox.y() - outlineWidth, 130 pixelSnappedBox.maxX() + outlineWidth, 131 pixelSnappedBox.y(), 132 BSTop, outlineColor, outlineStyle, 133 (!lastline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + lastline.maxX()) ? -outlineWidth : outlineWidth, 134 outlineWidth, antialias); 135 } 136 137 if (thisline.x() == thisline.maxX()) { 138 ObjectPainter::drawLineForBoxSide(graphicsContext, 139 pixelSnappedBox.x() - outlineWidth, 140 pixelSnappedBox.y() - outlineWidth, 141 pixelSnappedBox.maxX() + outlineWidth, 142 pixelSnappedBox.y(), 143 BSTop, outlineColor, outlineStyle, 144 outlineWidth, 145 outlineWidth, 146 antialias); 147 } 148 149 // lower edge 150 if (thisline.x() < nextline.x()) { 151 ObjectPainter::drawLineForBoxSide(graphicsContext, 152 pixelSnappedBox.x() - outlineWidth, 153 pixelSnappedBox.maxY(), 154 std::min(pixelSnappedBox.maxX() + outlineWidth, !nextline.isEmpty() ? pixelSnappedNextLine.x() + 1 : 1000000), 155 pixelSnappedBox.maxY() + outlineWidth, 156 BSBottom, outlineColor, outlineStyle, 157 outlineWidth, 158 (!nextline.isEmpty() && paintOffset.x() + nextline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth, 159 antialias); 160 } 161 162 if (nextline.maxX() < thisline.maxX()) { 163 ObjectPainter::drawLineForBoxSide(graphicsContext, 164 std::max(!nextline.isEmpty() ? pixelSnappedNextLine.maxX() : -1000000, pixelSnappedBox.x() - outlineWidth), 165 pixelSnappedBox.maxY(), 166 pixelSnappedBox.maxX() + outlineWidth, 167 pixelSnappedBox.maxY() + outlineWidth, 168 BSBottom, outlineColor, outlineStyle, 169 (!nextline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + nextline.maxX()) ? -outlineWidth : outlineWidth, 170 outlineWidth, antialias); 171 } 172 173 if (thisline.x() == thisline.maxX()) { 174 ObjectPainter::drawLineForBoxSide(graphicsContext, 175 pixelSnappedBox.x() - outlineWidth, 176 pixelSnappedBox.maxY(), 177 pixelSnappedBox.maxX() + outlineWidth, 178 pixelSnappedBox.maxY() + outlineWidth, 179 BSBottom, outlineColor, outlineStyle, 180 outlineWidth, 181 outlineWidth, 182 antialias); 183 } 184 } 185 186 } // namespace blink 187