Home | History | Annotate | Download | only in paint
      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