RoundedRect RenderStyle::getRoundedInnerBorderFor(const LayoutRect& borderRect,
    int topWidth, int bottomWidth, int leftWidth, int rightWidth, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
{
    LayoutRect innerRect(borderRect.x() + leftWidth,
               borderRect.y() + topWidth,
               borderRect.width() - leftWidth - rightWidth,
               borderRect.height() - topWidth - bottomWidth);

    RoundedRect roundedRect(pixelSnappedIntRect(innerRect));

    if (hasBorderRadius()) {
        RoundedRect::Radii radii = getRoundedBorderFor(borderRect).radii();
        radii.shrink(topWidth, bottomWidth, leftWidth, rightWidth);
        roundedRect.includeLogicalEdges(radii, includeLogicalLeftEdge, includeLogicalRightEdge);
    }
    return roundedRect;
}
void showLineLayoutForFlow(const RenderBlockFlow& flow, const Layout& layout, int depth)
{
    int printedCharacters = 0;
    printPrefix(printedCharacters, depth);

    fprintf(stderr, "SimpleLineLayout (%u lines, %u runs) (%p)\n", layout.lineCount(), layout.runCount(), &layout);
    ++depth;

    auto resolver = runResolver(flow, layout);
    for (auto it = resolver.begin(), end = resolver.end(); it != end; ++it) {
        const auto& run = *it;
        LayoutRect r = run.rect();
        printPrefix(printedCharacters, depth);
        fprintf(stderr, "line %u run(%u, %u) (%.2f, %.2f) (%.2f, %.2f) \"%s\"\n", run.lineIndex(), run.start(), run.end(),
            r.x().toFloat(), r.y().toFloat(), r.width().toFloat(), r.height().toFloat(), run.text().toStringWithoutCopying().utf8().data());
    }
}
// Checks if |node| is offscreen the visible area (viewport) of its container
// document. In case it is, one can scroll in direction or take any different
// desired action later on.
bool hasOffscreenRect(Node* node, FocusType type)
{
    // Get the FrameView in which |node| is (which means the current viewport if |node|
    // is not in an inner document), so we can check if its content rect is visible
    // before we actually move the focus to it.
    FrameView* frameView = node->document().view();
    if (!frameView)
        return true;

    ASSERT(!frameView->needsLayout());

    LayoutRect containerViewportRect = frameView->visibleContentRect();
    // We want to select a node if it is currently off screen, but will be
    // exposed after we scroll. Adjust the viewport to post-scrolling position.
    // If the container has overflow:hidden, we cannot scroll, so we do not pass direction
    // and we do not adjust for scrolling.
    switch (type) {
    case FocusTypeLeft:
        containerViewportRect.setX(containerViewportRect.x() - ScrollableArea::pixelsPerLineStep());
        containerViewportRect.setWidth(containerViewportRect.width() + ScrollableArea::pixelsPerLineStep());
        break;
    case FocusTypeRight:
        containerViewportRect.setWidth(containerViewportRect.width() + ScrollableArea::pixelsPerLineStep());
        break;
    case FocusTypeUp:
        containerViewportRect.setY(containerViewportRect.y() - ScrollableArea::pixelsPerLineStep());
        containerViewportRect.setHeight(containerViewportRect.height() + ScrollableArea::pixelsPerLineStep());
        break;
    case FocusTypeDown:
        containerViewportRect.setHeight(containerViewportRect.height() + ScrollableArea::pixelsPerLineStep());
        break;
    default:
        break;
    }

    RenderObject* render = node->renderer();
    if (!render)
        return true;

    LayoutRect rect(render->absoluteClippedOverflowRect());
    if (rect.isEmpty())
        return true;

    return !containerViewportRect.intersects(rect);
}
void RenderMultiColumnSet::adjustRegionBoundsFromFlowThreadPortionRect(const LayoutPoint& layerOffset, LayoutRect& regionBounds)
{
    LayoutUnit layerLogicalTop = isHorizontalWritingMode() ? layerOffset.y() : layerOffset.x();
    unsigned startColumn = columnIndexAtOffset(layerLogicalTop);
    
    LayoutUnit colGap = columnGap();
    LayoutUnit colLogicalWidth = computedColumnWidth();
    
    LayoutRect flowThreadPortion = flowThreadPortionRectAt(startColumn);
    LayoutPoint translationOffset;
    
    RenderBlockFlow* parentFlow = toRenderBlockFlow(parent());
    bool progressionReversed = parentFlow->multiColumnFlowThread()->progressionIsReversed();
    bool progressionIsInline = parentFlow->multiColumnFlowThread()->progressionIsInline();
    
    LayoutUnit initialBlockOffset = initialBlockOffsetForPainting();
    
    LayoutUnit inlineOffset = progressionIsInline ? startColumn * (colLogicalWidth + colGap) : LayoutUnit();
    
    bool leftToRight = style().isLeftToRightDirection() ^ progressionReversed;
    if (!leftToRight) {
        inlineOffset = -inlineOffset;
        if (progressionReversed)
            inlineOffset += contentLogicalWidth() - colLogicalWidth;
    }
    translationOffset.setX(inlineOffset);
    LayoutUnit blockOffset = initialBlockOffset + (isHorizontalWritingMode() ? -flowThreadPortion.y() : -flowThreadPortion.x());
    if (!progressionIsInline) {
        if (!progressionReversed)
            blockOffset = startColumn * colGap;
        else
            blockOffset -= startColumn * (computedColumnHeight() + colGap);
    }
    if (isFlippedBlocksWritingMode(style().writingMode()))
        blockOffset = -blockOffset;
    translationOffset.setY(blockOffset);
    
    if (!isHorizontalWritingMode())
        translationOffset = translationOffset.transposedPoint();

    // FIXME: The translation needs to include the multicolumn set's content offset within the
    // multicolumn block as well. This won't be an issue until we start creating multiple multicolumn sets.
    
    regionBounds.moveBy(roundedIntPoint(-translationOffset));
}
Exemple #5
0
bool RenderInputSpeech::paintInputFieldSpeechButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
{
    Element* element = object->node()->isElementNode() ? toElement(object->node()) : 0;
    if (!element || !element->isInputFieldSpeechButtonElement())
        return false;

    // Get the renderer of <input> element.
    Node* input = object->node()->shadowHost();
    if (!input->renderer()->isBox())
        return false;
    RenderBox* inputRenderBox = toRenderBox(input->renderer());
    LayoutRect inputContentBox = inputRenderBox->contentBoxRect();

    // Make sure the scaled button stays square and will fit in its parent's box.
    LayoutUnit buttonSize = std::min(inputContentBox.width(), std::min<LayoutUnit>(inputContentBox.height(), rect.height()));
    // Calculate button's coordinates relative to the input element.
    // Center the button vertically.  Round up though, so if it has to be one pixel off-center, it will
    // be one pixel closer to the bottom of the field.  This tends to look better with the text.
    LayoutRect buttonRect(object->offsetFromAncestorContainer(inputRenderBox).width(),
                          inputContentBox.y() + (inputContentBox.height() - buttonSize + 1) / 2,
                          buttonSize, buttonSize);

    // Compute an offset between the part renderer and the input renderer.
    LayoutSize offsetFromInputRenderer = -(object->offsetFromAncestorContainer(inputRenderBox));
    // Move the rect into partRenderer's coords.
    buttonRect.move(offsetFromInputRenderer);
    // Account for the local drawing offset.
    buttonRect.moveBy(rect.location());

    DEFINE_STATIC_LOCAL(RefPtr<Image>, imageStateNormal, (Image::loadPlatformResource("inputSpeech")));
    DEFINE_STATIC_LOCAL(RefPtr<Image>, imageStateRecording, (Image::loadPlatformResource("inputSpeechRecording")));
    DEFINE_STATIC_LOCAL(RefPtr<Image>, imageStateWaiting, (Image::loadPlatformResource("inputSpeechWaiting")));

    InputFieldSpeechButtonElement* speechButton = toInputFieldSpeechButtonElement(element);
    Image* image = imageStateNormal.get();
    if (speechButton->state() == InputFieldSpeechButtonElement::Recording)
        image = imageStateRecording.get();
    else if (speechButton->state() == InputFieldSpeechButtonElement::Recognizing)
        image = imageStateWaiting.get();
    paintInfo.context->drawImage(image, object->style()->colorSpace(), pixelSnappedIntRect(buttonRect));

    return false;
}
LayoutRect RootFrameViewport::scrollIntoView(const LayoutRect& rectInContent, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
{
    // We want to move the rect into the viewport that excludes the scrollbars so we intersect
    // the visual viewport with the scrollbar-excluded frameView content rect. However, we don't
    // use visibleContentRect directly since it floors the scroll position. Instead, we use
    // FrameView::scrollPositionDouble and construct a LayoutRect from that (the FrameView size
    // is always integer sized.

    LayoutRect frameRectInContent = LayoutRect(
        layoutViewport().scrollPositionDouble(),
        layoutViewport().visibleContentRect().size());
    LayoutRect visualRectInContent = LayoutRect(
        layoutViewport().scrollPositionDouble() + toDoubleSize(visualViewport().scrollPositionDouble()),
        visualViewport().visibleContentRect().size());

    LayoutRect viewRectInContent = intersection(visualRectInContent, frameRectInContent);
    LayoutRect targetViewport =
        ScrollAlignment::getRectToExpose(viewRectInContent, rectInContent, alignX, alignY);

    // visualViewport.scrollIntoView will attempt to center the given rect within the viewport
    // so to prevent it from adjusting r's coordinates the rect must match the viewport's size
    // i.e. add the subtracted scrollbars from above back in.
    // FIXME: This is hacky and required because getRectToExpose doesn't naturally account
    // for the two viewports. crbug.com/449340.
    targetViewport.setSize(LayoutSize(visualViewport().visibleContentRect().size()));

    // Snap the visible rect to layout units to match the calculated target viewport rect.
    FloatRect visible =
        LayoutRect(visualViewport().scrollPositionDouble(), visualViewport().visibleContentRect().size());

    float centeringOffsetX = (visible.width() - targetViewport.width()) / 2;
    float centeringOffsetY = (visible.height() - targetViewport.height()) / 2;

    DoublePoint targetOffset(
        targetViewport.x() - centeringOffsetX,
        targetViewport.y() - centeringOffsetY);

    setScrollPosition(targetOffset, ProgrammaticScroll);

    // RootFrameViewport only changes the viewport relative to the document so we can't change the input
    // rect's location relative to the document origin.
    return rectInContent;
}
static void adjustBubblePosition(const LayoutRect& hostRect, HTMLElement* bubble)
{
    ASSERT(bubble);
    if (hostRect.isEmpty())
        return;
    double hostX = hostRect.x();
    double hostY = hostRect.y();
    if (RenderBox* container = bubble->renderer()->containingBlock()) {
        FloatPoint containerLocation = container->localToAbsolute();
        hostX -= containerLocation.x() + container->borderLeft();
        hostY -= containerLocation.y() + container->borderTop();
    }
    bubble->getInlineStyleDecl()->setProperty(CSSPropertyTop, hostY + hostRect.height(), CSSPrimitiveValue::CSS_PX);
    // The 'left' value of ::-webkit-validation-bubble-arrow.
    const int bubbleArrowTopOffset = 32;
    double bubbleX = hostX;
    if (hostRect.width() / 2 < bubbleArrowTopOffset)
        bubbleX = max(hostX + hostRect.width() / 2 - bubbleArrowTopOffset, 0.0);
    bubble->getInlineStyleDecl()->setProperty(CSSPropertyLeft, bubbleX, CSSPrimitiveValue::CSS_PX);
}
bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseOutline && paintInfo.phase != PaintPhaseSelfOutline 
            && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseMask)
        return false;

    if (!paintInfo.shouldPaintWithinRoot(*this))
        return false;
        
    // if we're invisible or haven't received a layout yet, then just bail.
    if (style().visibility() != VISIBLE)
        return false;
    
    RenderNamedFlowFragment* namedFlowFragment = currentRenderNamedFlowFragment();
    // Check our region range to make sure we need to be painting in this region.
    if (namedFlowFragment && !namedFlowFragment->flowThread()->objectShouldFragmentInFlowRegion(this, namedFlowFragment))
        return false;

    LayoutPoint adjustedPaintOffset = paintOffset + location();

    // Early exit if the element touches the edges.
    LayoutUnit top = adjustedPaintOffset.y() + visualOverflowRect().y();
    LayoutUnit bottom = adjustedPaintOffset.y() + visualOverflowRect().maxY();
    if (isSelected() && m_inlineBoxWrapper) {
        const RootInlineBox& rootBox = m_inlineBoxWrapper->root();
        LayoutUnit selTop = paintOffset.y() + rootBox.selectionTop();
        LayoutUnit selBottom = paintOffset.y() + selTop + rootBox.selectionHeight();
        top = std::min(selTop, top);
        bottom = std::max(selBottom, bottom);
    }
    
    LayoutRect localRepaintRect = paintInfo.rect;
    adjustRectWithMaximumOutline(paintInfo.phase, localRepaintRect);
    if (adjustedPaintOffset.x() + visualOverflowRect().x() >= localRepaintRect.maxX() || adjustedPaintOffset.x() + visualOverflowRect().maxX() <= localRepaintRect.x())
        return false;

    if (top >= localRepaintRect.maxY() || bottom <= localRepaintRect.y())
        return false;

    return true;
}
Exemple #9
0
bool ThemePainterDefault::paintSearchFieldCancelButton(
    const LayoutObject& cancelButtonObject,
    const PaintInfo& paintInfo,
    const IntRect& r) {
  // Get the layoutObject of <input> element.
  if (!cancelButtonObject.node())
    return false;
  Node* input = cancelButtonObject.node()->ownerShadowHost();
  const LayoutObject& baseLayoutObject =
      input ? *input->layoutObject() : cancelButtonObject;
  if (!baseLayoutObject.isBox())
    return false;
  const LayoutBox& inputLayoutBox = toLayoutBox(baseLayoutObject);
  LayoutRect inputContentBox = inputLayoutBox.contentBoxRect();

  // Make sure the scaled button stays square and will fit in its parent's box.
  LayoutUnit cancelButtonSize =
      std::min(inputContentBox.width(),
               std::min(inputContentBox.height(), LayoutUnit(r.height())));
  // Calculate cancel button's coordinates relative to the input element.
  // Center the button vertically.  Round up though, so if it has to be one
  // pixel off-center, it will be one pixel closer to the bottom of the field.
  // This tends to look better with the text.
  LayoutRect cancelButtonRect(
      cancelButtonObject.offsetFromAncestorContainer(&inputLayoutBox).width(),
      inputContentBox.y() +
          (inputContentBox.height() - cancelButtonSize + 1) / 2,
      cancelButtonSize, cancelButtonSize);
  IntRect paintingRect = convertToPaintingRect(
      inputLayoutBox, cancelButtonObject, cancelButtonRect, r);

  DEFINE_STATIC_REF(Image, cancelImage,
                    (Image::loadPlatformResource("searchCancel")));
  DEFINE_STATIC_REF(Image, cancelPressedImage,
                    (Image::loadPlatformResource("searchCancelPressed")));
  paintInfo.context.drawImage(LayoutTheme::isPressed(cancelButtonObject)
                                  ? cancelPressedImage
                                  : cancelImage,
                              paintingRect);
  return false;
}
bool FilterEffectRendererHelper::prepareFilterEffect(RenderLayer* renderLayer, const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect)
{
    ASSERT(m_haveFilterEffect && renderLayer->filterRenderer());
    m_renderLayer = renderLayer;
    m_repaintRect = dirtyRect;

    // Get the zoom factor to scale the filterSourceRect input
    const RenderLayerModelObject* renderer = renderLayer->renderer();
    const RenderStyle* style = renderer ? renderer->style() : 0;
    float zoom = style ? style->effectiveZoom() : 1.0f;

    // Prepare a transformation that brings the coordinates into the space
    // filter coordinates are defined in.
    AffineTransform absoluteTransform;
    // FIXME: Should these really be upconverted to doubles and not rounded? crbug.com/350474
    absoluteTransform.translate(filterBoxRect.x().toDouble(), filterBoxRect.y().toDouble());
    absoluteTransform.scale(zoom, zoom);

    FilterEffectRenderer* filter = renderLayer->filterRenderer();
    filter->setAbsoluteTransform(absoluteTransform);

    IntRect filterSourceRect = pixelSnappedIntRect(filter->computeSourceImageRectForDirtyRect(filterBoxRect, dirtyRect));

    if (filterSourceRect.isEmpty()) {
        // The dirty rect is not in view, just bail out.
        m_haveFilterEffect = false;
        return false;
    }

    filter->setFilterRegion(filter->mapAbsoluteRectToLocalRect(filterSourceRect));
    filter->lastEffect()->determineFilterPrimitiveSubregion(MapRectForward);

    bool hasUpdatedBackingStore = filter->updateBackingStoreRect(filterSourceRect);
    if (filter->hasFilterThatMovesPixels()) {
        if (hasUpdatedBackingStore)
            m_repaintRect = filterSourceRect;
        else
            m_repaintRect.intersect(filterSourceRect);
    }
    return true;
}
Exemple #11
0
void RenderMathMLOperator::paint(PaintInfo& info, const LayoutPoint& paintOffset)
{
    RenderMathMLBlock::paint(info, paintOffset);

    if (info.context->paintingDisabled() || info.phase != PaintPhaseForeground)
        return;

    if (!m_isStretched && !m_stretchyCharacter) {
        RenderMathMLBlock::paint(info, paintOffset);
        return;
    }

    GraphicsContextStateSaver stateSaver(*info.context);
    info.context->setFillColor(style()->visitedDependentColor(CSSPropertyColor), style()->colorSpace());

    ASSERT(m_stretchyCharacter->topGlyph);
    ASSERT(m_stretchyCharacter->bottomGlyph);

    // We are positioning the glyphs so that the edge of the tight glyph bounds line up exactly with the edges of our paint box.
    LayoutPoint operatorTopLeft = ceiledIntPoint(paintOffset + location());
    FloatRect topGlyphBounds = glyphBoundsForCharacter(m_stretchyCharacter->topGlyph);
    LayoutPoint topGlyphOrigin(operatorTopLeft.x(), operatorTopLeft.y() - topGlyphBounds.y());
    LayoutRect topGlyphPaintRect = paintCharacter(info, m_stretchyCharacter->topGlyph, topGlyphOrigin, TrimBottom);

    FloatRect bottomGlyphBounds = glyphBoundsForCharacter(m_stretchyCharacter->bottomGlyph);
    LayoutPoint bottomGlyphOrigin(operatorTopLeft.x(), operatorTopLeft.y() + offsetHeight() - (bottomGlyphBounds.height() + bottomGlyphBounds.y()));
    LayoutRect bottomGlyphPaintRect = paintCharacter(info, m_stretchyCharacter->bottomGlyph, bottomGlyphOrigin, TrimTop);

    if (m_stretchyCharacter->middleGlyph) {
        // Center the glyph origin between the start and end glyph paint extents. Then shift it half the paint height toward the bottom glyph.
        FloatRect middleGlyphBounds = glyphBoundsForCharacter(m_stretchyCharacter->middleGlyph);
        LayoutPoint middleGlyphOrigin(operatorTopLeft.x(), topGlyphOrigin.y() + y());
        middleGlyphOrigin.moveBy(LayoutPoint(0, (bottomGlyphPaintRect.y() - topGlyphPaintRect.maxY()) / 2.0));
        middleGlyphOrigin.moveBy(LayoutPoint(0, middleGlyphBounds.height() / 2.0));

        LayoutRect middleGlyphPaintRect = paintCharacter(info, m_stretchyCharacter->middleGlyph, middleGlyphOrigin, TrimTopAndBottom);
        fillWithExtensionGlyph(info, topGlyphPaintRect.minXMaxYCorner(), middleGlyphPaintRect.minXMinYCorner());
        fillWithExtensionGlyph(info, middleGlyphPaintRect.minXMaxYCorner(), bottomGlyphPaintRect.minXMinYCorner());
    } else
        fillWithExtensionGlyph(info, topGlyphPaintRect.minXMaxYCorner(), bottomGlyphPaintRect.minXMinYCorner());
}
Exemple #12
0
LayoutRect RootInlineBox::paddedLayoutOverflowRect(LayoutUnit endPadding) const
{
    LayoutRect lineLayoutOverflow = layoutOverflowRect(lineTop(), lineBottom());
    if (!endPadding)
        return lineLayoutOverflow;
    
    // FIXME: Audit whether to use pixel snapped values when not using integers for layout: https://bugs.webkit.org/show_bug.cgi?id=63656
    if (isHorizontal()) {
        if (isLeftToRightDirection())
            lineLayoutOverflow.shiftMaxXEdgeTo(std::max<LayoutUnit>(lineLayoutOverflow.maxX(), pixelSnappedLogicalRight() + endPadding));
        else
            lineLayoutOverflow.shiftXEdgeTo(std::min<LayoutUnit>(lineLayoutOverflow.x(), pixelSnappedLogicalLeft() - endPadding));
    } else {
        if (isLeftToRightDirection())
            lineLayoutOverflow.shiftMaxYEdgeTo(std::max<LayoutUnit>(lineLayoutOverflow.maxY(), pixelSnappedLogicalRight() + endPadding));
        else
            lineLayoutOverflow.shiftYEdgeTo(std::min<LayoutUnit>(lineLayoutOverflow.y(), pixelSnappedLogicalLeft() - endPadding));
    }
    
    return lineLayoutOverflow;
}
LayoutRect MultiColumnFragmentainerGroup::flowThreadPortionOverflowRectAt(unsigned columnIndex) const
{
    // This function determines the portion of the flow thread that paints for the column. Along the inline axis, columns are
    // unclipped at outside edges (i.e., the first and last column in the set), and they clip to half the column
    // gap along interior edges.
    //
    // In the block direction, we will not clip overflow out of the top of the first column, or out of the bottom of
    // the last column. This applies only to the true first column and last column across all column sets.
    //
    // FIXME: Eventually we will know overflow on a per-column basis, but we can't do this until we have a painting
    // mode that understands not to paint contents from a previous column in the overflow area of a following column.
    bool isFirstColumnInRow = !columnIndex;
    bool isLastColumnInRow = columnIndex == actualColumnCount() - 1;
    bool isLTR = m_columnSet.style()->isLeftToRightDirection();
    bool isLeftmostColumn = isLTR ? isFirstColumnInRow : isLastColumnInRow;
    bool isRightmostColumn = isLTR ? isLastColumnInRow : isFirstColumnInRow;

    LayoutRect portionRect = flowThreadPortionRectAt(columnIndex);
    bool isFirstColumnInMulticolContainer = isFirstColumnInRow && this == &m_columnSet.firstFragmentainerGroup() && !m_columnSet.previousSiblingMultiColumnSet();
    bool isLastColumnInMulticolContainer = isLastColumnInRow && this == &m_columnSet.lastFragmentainerGroup() && !m_columnSet.nextSiblingMultiColumnSet();
    // Calculate the overflow rectangle, based on the flow thread's, clipped at column logical
    // top/bottom unless it's the first/last column.
    LayoutRect overflowRect = m_columnSet.overflowRectForFlowThreadPortion(portionRect, isFirstColumnInMulticolContainer, isLastColumnInMulticolContainer);

    // Avoid overflowing into neighboring columns, by clipping in the middle of adjacent column
    // gaps. Also make sure that we avoid rounding errors.
    LayoutUnit columnGap = m_columnSet.columnGap();
    if (m_columnSet.isHorizontalWritingMode()) {
        if (!isLeftmostColumn)
            overflowRect.shiftXEdgeTo(portionRect.x() - columnGap / 2);
        if (!isRightmostColumn)
            overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + columnGap - columnGap / 2);
    } else {
        if (!isLeftmostColumn)
            overflowRect.shiftYEdgeTo(portionRect.y() - columnGap / 2);
        if (!isRightmostColumn)
            overflowRect.shiftMaxYEdgeTo(portionRect.maxY() + columnGap - columnGap / 2);
    }
    return overflowRect;
}
Exemple #14
0
LayoutRect RenderMultiColumnSet::flowThreadPortionOverflowRect(const LayoutRect& portionRect, unsigned index, unsigned colCount, LayoutUnit colGap)
{
    // This function determines the portion of the flow thread that paints for the column. Along the inline axis, columns are
    // unclipped at outside edges (i.e., the first and last column in the set), and they clip to half the column
    // gap along interior edges.
    //
    // In the block direction, we will not clip overflow out of the top of the first column, or out of the bottom of
    // the last column. This applies only to the true first column and last column across all column sets.
    //
    // FIXME: Eventually we will know overflow on a per-column basis, but we can't do this until we have a painting
    // mode that understands not to paint contents from a previous column in the overflow area of a following column.
    // This problem applies to regions and pages as well and is not unique to columns.
    
    RenderBlockFlow* parentFlow = toRenderBlockFlow(parent());
    bool progressionReversed = parentFlow->multiColumnFlowThread()->progressionIsReversed();
    
    bool isFirstColumn = !index;
    bool isLastColumn = index == colCount - 1;
    bool isLeftmostColumn = style().isLeftToRightDirection() ^ progressionReversed ? isFirstColumn : isLastColumn;
    bool isRightmostColumn = style().isLeftToRightDirection() ^ progressionReversed ? isLastColumn : isFirstColumn;

    // Calculate the overflow rectangle, based on the flow thread's, clipped at column logical
    // top/bottom unless it's the first/last column.
    LayoutRect overflowRect = overflowRectForFlowThreadPortion(portionRect, isFirstColumn && isFirstRegion(), isLastColumn && isLastRegion(), VisualOverflow);

    // Avoid overflowing into neighboring columns, by clipping in the middle of adjacent column
    // gaps. Also make sure that we avoid rounding errors.
    if (isHorizontalWritingMode()) {
        if (!isLeftmostColumn)
            overflowRect.shiftXEdgeTo(portionRect.x() - colGap / 2);
        if (!isRightmostColumn)
            overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + colGap - colGap / 2);
    } else {
        if (!isLeftmostColumn)
            overflowRect.shiftYEdgeTo(portionRect.y() - colGap / 2);
        if (!isRightmostColumn)
            overflowRect.shiftMaxYEdgeTo(portionRect.maxY() + colGap - colGap / 2);
    }
    return overflowRect;
}
Exemple #15
0
bool RenderThemeChromiumSkia::paintSearchFieldResultsButton(RenderObject* magnifierObject, const PaintInfo& paintInfo, const IntRect& r)
{
    // Get the renderer of <input> element.
    Node* input = magnifierObject->node()->shadowHost();
    RenderObject* baseRenderer = input ? input->renderer() : magnifierObject;
    if (!baseRenderer->isBox())
        return false;
    RenderBox* inputRenderBox = toRenderBox(baseRenderer);
    LayoutRect inputContentBox = inputRenderBox->contentBoxRect();

    // Make sure the scaled decoration will fit in its parent's box.
    LayoutUnit magnifierHeight = std::min<LayoutUnit>(inputContentBox.height(), r.height());
    LayoutUnit magnifierWidth = std::min<LayoutUnit>(inputContentBox.width(), magnifierHeight * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize);
    LayoutRect magnifierRect(magnifierObject->offsetFromAncestorContainer(inputRenderBox).width(),
                             inputContentBox.y() + (inputContentBox.height() - magnifierHeight + 1) / 2,
                             magnifierWidth, magnifierHeight);
    IntRect paintingRect = convertToPaintingRect(inputRenderBox, magnifierObject, magnifierRect, r);

    static Image* magnifierImage = Image::loadPlatformResource("searchMagnifierResults").leakRef();
    paintInfo.context->drawImage(magnifierImage, magnifierObject->style()->colorSpace(), paintingRect);
    return false;
}
bool FilterEffectRendererHelper::prepareFilterEffect(RenderLayer* renderLayer, const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect, const LayoutRect& layerRepaintRect)
{
    ASSERT(m_haveFilterEffect && renderLayer->filterRenderer());
    m_renderLayer = renderLayer;
    m_repaintRect = dirtyRect;

    FilterEffectRenderer* filter = renderLayer->filterRenderer();
    LayoutRect filterSourceRect = filter->computeSourceImageRectForDirtyRect(filterBoxRect, dirtyRect);

    if (filterSourceRect.isEmpty()) {
        // The dirty rect is not in view, just bail out.
        m_haveFilterEffect = false;
        return false;
    }

    // Get the zoom factor to scale the filterSourceRect input
    const RenderLayerModelObject* renderer = renderLayer->renderer();
    const RenderStyle* style = renderer ? renderer->style() : 0;
    float zoom = style ? style->effectiveZoom() : 1.0f;

    AffineTransform absoluteTransform;
    absoluteTransform.translate(filterBoxRect.x(), filterBoxRect.y());
    filter->setAbsoluteTransform(absoluteTransform);
    filter->setAbsoluteFilterRegion(AffineTransform().scale(zoom).mapRect(filterSourceRect));
    filter->setFilterRegion(absoluteTransform.inverse().mapRect(filterSourceRect));
    filter->lastEffect()->determineFilterPrimitiveSubregion();

    bool hasUpdatedBackingStore = filter->updateBackingStoreRect(filterSourceRect);
    if (filter->hasFilterThatMovesPixels()) {
        if (hasUpdatedBackingStore)
            m_repaintRect = filterSourceRect;
        else {
            m_repaintRect.unite(layerRepaintRect);
            m_repaintRect.intersect(filterSourceRect);
        }
    }
    return true;
}
Exemple #17
0
void Paragraph::paint(Canvas* canvas, double x, double y) {
  SkCanvas* skCanvas = canvas->canvas();
  if (!skCanvas)
    return;

  FontCachePurgePreventer fontCachePurgePreventer;

  // Very simplified painting to allow painting an arbitrary (layer-less)
  // subtree.
  RenderBox* box = firstChildBox();
  skCanvas->translate(x, y);

  GraphicsContext context(skCanvas);
  Vector<RenderBox*> layers;
  LayoutRect bounds = box->absoluteBoundingBoxRect();
  FTL_DCHECK(bounds.x() == 0 && bounds.y() == 0);
  PaintInfo paintInfo(&context, enclosingIntRect(bounds), box);
  box->paint(paintInfo, LayoutPoint(), layers);
  // Note we're ignoring any layers encountered.
  // TODO(abarth): Remove the concept of RenderLayers.

  skCanvas->translate(-x, -y);
}
bool LineBoxList::rangeIntersectsRect(LayoutBoxModelObject* renderer, LayoutUnit logicalTop, LayoutUnit logicalBottom, const LayoutRect& rect, const LayoutPoint& offset) const
{
    LayoutBox* block;
    if (renderer->isBox())
        block = toLayoutBox(renderer);
    else
        block = renderer->containingBlock();
    LayoutUnit physicalStart = block->flipForWritingMode(logicalTop);
    LayoutUnit physicalEnd = block->flipForWritingMode(logicalBottom);
    LayoutUnit physicalExtent = absoluteValue(physicalEnd - physicalStart);
    physicalStart = std::min(physicalStart, physicalEnd);

    if (renderer->style()->isHorizontalWritingMode()) {
        physicalStart += offset.y();
        if (physicalStart >= rect.maxY() || physicalStart + physicalExtent <= rect.y())
            return false;
    } else {
        physicalStart += offset.x();
        if (physicalStart >= rect.maxX() || physicalStart + physicalExtent <= rect.x())
            return false;
    }

    return true;
}
Exemple #19
0
bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseOutline && paintInfo.phase != PaintPhaseSelfOutline 
            && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseMask)
        return false;

    if (!paintInfo.shouldPaintWithinRoot(*this))
        return false;
        
    // if we're invisible or haven't received a layout yet, then just bail.
    if (style().visibility() != VISIBLE)
        return false;

    LayoutPoint adjustedPaintOffset = paintOffset + location();

    // Early exit if the element touches the edges.
    LayoutUnit top = adjustedPaintOffset.y() + visualOverflowRect().y();
    LayoutUnit bottom = adjustedPaintOffset.y() + visualOverflowRect().maxY();
    if (isSelected() && m_inlineBoxWrapper) {
        const RootInlineBox& rootBox = m_inlineBoxWrapper->root();
        LayoutUnit selTop = paintOffset.y() + rootBox.selectionTop();
        LayoutUnit selBottom = paintOffset.y() + selTop + rootBox.selectionHeight();
        top = std::min(selTop, top);
        bottom = std::max(selBottom, bottom);
    }
    
    LayoutRect localRepaintRect = paintInfo.rect;
    localRepaintRect.inflate(maximalOutlineSize(paintInfo.phase));
    if (adjustedPaintOffset.x() + visualOverflowRect().x() >= localRepaintRect.maxX() || adjustedPaintOffset.x() + visualOverflowRect().maxX() <= localRepaintRect.x())
        return false;

    if (top >= localRepaintRect.maxY() || bottom <= localRepaintRect.y())
        return false;

    return true;
}
Exemple #20
0
bool RenderThemeChromiumSkia::paintSearchFieldResultsDecoration(RenderObject* magnifierObject, const PaintInfo& paintInfo, const IntRect& r)
{
    // Get the renderer of <input> element.
    Node* input = magnifierObject->node()->shadowHost();
    RenderObject* baseRenderer = input ? input->renderer() : magnifierObject;
    if (!baseRenderer->isBox())
        return false;
    RenderBox* inputRenderBox = toRenderBox(baseRenderer);
    LayoutRect inputContentBox = inputRenderBox->contentBoxRect();

    // Make sure the scaled decoration stays square and will fit in its parent's box.
    LayoutUnit magnifierSize = std::min(inputContentBox.width(), std::min<LayoutUnit>(inputContentBox.height(), r.height()));
    // Calculate decoration's coordinates relative to the input element.
    // Center the decoration vertically.  Round up though, so if it has to be one pixel off-center, it will
    // be one pixel closer to the bottom of the field.  This tends to look better with the text.
    LayoutRect magnifierRect(magnifierObject->offsetFromAncestorContainer(inputRenderBox).width(),
                             inputContentBox.y() + (inputContentBox.height() - magnifierSize + 1) / 2,
                             magnifierSize, magnifierSize);
    IntRect paintingRect = convertToPaintingRect(inputRenderBox, magnifierObject, magnifierRect, r);

    static Image* magnifierImage = Image::loadPlatformResource("searchMagnifier").leakRef();
    paintInfo.context->drawImage(magnifierImage, magnifierObject->style()->colorSpace(), paintingRect);
    return false;
}
Exemple #21
0
LayoutRect RenderRegion::rectFlowPortionForBox(const RenderBox* box, const LayoutRect& rect) const
{
    RenderRegion* startRegion = 0;
    RenderRegion* endRegion = 0;
    m_flowThread->getRegionRangeForBox(box, startRegion, endRegion);

    LayoutRect mappedRect = m_flowThread->mapFromLocalToFlowThread(box, rect);
    if (flowThread()->isHorizontalWritingMode()) {
        if (this != startRegion)
            mappedRect.shiftYEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.y()));

        if (this != endRegion)
            mappedRect.setHeight(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.y(), mappedRect.height())));
    } else {
        if (this != startRegion)
            mappedRect.shiftXEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.x()));
            
        if (this != endRegion)
            mappedRect.setWidth(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.x(), mappedRect.width())));
    }

    if (shouldClipFlowThreadContent()) {
        LayoutRect portionRect;
        if (isRenderNamedFlowFragment())
            portionRect = toRenderNamedFlowFragment(this)->flowThreadPortionRectForClipping(this == startRegion, this == endRegion);
        else
            portionRect = flowThreadPortionRect();
        
        mappedRect.intersect(portionRect);
    }

    return mappedRect.isEmpty() ? mappedRect : m_flowThread->mapFromFlowThreadToLocal(box, mappedRect);
}
Exemple #22
0
static void buildRendererHighlight(RenderObject* renderer, RenderRegion* region, const HighlightConfig& highlightConfig, Highlight* highlight, InspectorOverlay::CoordinateSystem coordinateSystem)
{
    Frame* containingFrame = renderer->document().frame();
    if (!containingFrame)
        return;

    highlight->setDataFromConfig(highlightConfig);
    FrameView* containingView = containingFrame->view();
    FrameView* mainView = containingFrame->page()->mainFrame().view();

    // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads().
    bool isSVGRenderer = renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot();

    if (isSVGRenderer) {
        highlight->type = HighlightTypeRects;
        renderer->absoluteQuads(highlight->quads);
        for (size_t i = 0; i < highlight->quads.size(); ++i)
            contentsQuadToCoordinateSystem(mainView, containingView, highlight->quads[i], coordinateSystem);
    } else if (renderer->isBox() || renderer->isRenderInline()) {
        LayoutRect contentBox;
        LayoutRect paddingBox;
        LayoutRect borderBox;
        LayoutRect marginBox;

        if (renderer->isBox()) {
            RenderBox* renderBox = toRenderBox(renderer);

            LayoutBoxExtent margins(renderBox->marginTop(), renderBox->marginRight(), renderBox->marginBottom(), renderBox->marginLeft());

            if (!renderBox->isOutOfFlowPositioned() && region) {
                RenderBox::LogicalExtentComputedValues computedValues;
                renderBox->computeLogicalWidthInRegion(computedValues, region);
                margins.mutableLogicalLeft(renderBox->style().writingMode()) = computedValues.m_margins.m_start;
                margins.mutableLogicalRight(renderBox->style().writingMode()) = computedValues.m_margins.m_end;
            }

            paddingBox = renderBox->clientBoxRectInRegion(region);
            contentBox = LayoutRect(paddingBox.x() + renderBox->paddingLeft(), paddingBox.y() + renderBox->paddingTop(),
                paddingBox.width() - renderBox->paddingLeft() - renderBox->paddingRight(), paddingBox.height() - renderBox->paddingTop() - renderBox->paddingBottom());
            borderBox = LayoutRect(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(),
                paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom());
            marginBox = LayoutRect(borderBox.x() - margins.left(), borderBox.y() - margins.top(),
                borderBox.width() + margins.left() + margins.right(), borderBox.height() + margins.top() + margins.bottom());
        } else {
            RenderInline* renderInline = toRenderInline(renderer);

            // RenderInline's bounding box includes paddings and borders, excludes margins.
            borderBox = renderInline->linesBoundingBox();
            paddingBox = LayoutRect(borderBox.x() + renderInline->borderLeft(), borderBox.y() + renderInline->borderTop(),
                borderBox.width() - renderInline->borderLeft() - renderInline->borderRight(), borderBox.height() - renderInline->borderTop() - renderInline->borderBottom());
            contentBox = LayoutRect(paddingBox.x() + renderInline->paddingLeft(), paddingBox.y() + renderInline->paddingTop(),
                paddingBox.width() - renderInline->paddingLeft() - renderInline->paddingRight(), paddingBox.height() - renderInline->paddingTop() - renderInline->paddingBottom());
            // Ignore marginTop and marginBottom for inlines.
            marginBox = LayoutRect(borderBox.x() - renderInline->marginLeft(), borderBox.y(),
                borderBox.width() + renderInline->horizontalMarginExtent(), borderBox.height());
        }

        FloatQuad absContentQuad;
        FloatQuad absPaddingQuad;
        FloatQuad absBorderQuad;
        FloatQuad absMarginQuad;

        if (region) {
            RenderFlowThread* flowThread = region->flowThread();

            // Figure out the quads in the space of the RenderFlowThread.
            absContentQuad = renderer->localToContainerQuad(FloatRect(contentBox), flowThread);
            absPaddingQuad = renderer->localToContainerQuad(FloatRect(paddingBox), flowThread);
            absBorderQuad = renderer->localToContainerQuad(FloatRect(borderBox), flowThread);
            absMarginQuad = renderer->localToContainerQuad(FloatRect(marginBox), flowThread);

            // Move the quad relative to the space of the current region.
            LayoutRect flippedRegionRect(region->flowThreadPortionRect());
            flowThread->flipForWritingMode(flippedRegionRect);

            FloatSize delta = region->contentBoxRect().location() - flippedRegionRect.location();
            absContentQuad.move(delta);
            absPaddingQuad.move(delta);
            absBorderQuad.move(delta);
            absMarginQuad.move(delta);

            // Resolve the absolute quads starting from the current region.
            absContentQuad = region->localToAbsoluteQuad(absContentQuad);
            absPaddingQuad = region->localToAbsoluteQuad(absPaddingQuad);
            absBorderQuad = region->localToAbsoluteQuad(absBorderQuad);
            absMarginQuad = region->localToAbsoluteQuad(absMarginQuad);
        } else {
            absContentQuad = renderer->localToAbsoluteQuad(FloatRect(contentBox));
            absPaddingQuad = renderer->localToAbsoluteQuad(FloatRect(paddingBox));
            absBorderQuad = renderer->localToAbsoluteQuad(FloatRect(borderBox));
            absMarginQuad = renderer->localToAbsoluteQuad(FloatRect(marginBox));
        }

        contentsQuadToCoordinateSystem(mainView, containingView, absContentQuad, coordinateSystem);
        contentsQuadToCoordinateSystem(mainView, containingView, absPaddingQuad, coordinateSystem);
        contentsQuadToCoordinateSystem(mainView, containingView, absBorderQuad, coordinateSystem);
        contentsQuadToCoordinateSystem(mainView, containingView, absMarginQuad, coordinateSystem);

        highlight->type = HighlightTypeNode;
        highlight->quads.append(absMarginQuad);
        highlight->quads.append(absBorderQuad);
        highlight->quads.append(absPaddingQuad);
        highlight->quads.append(absContentQuad);
    }
}
LayoutUnit RenderRegion::logicalTopOfFlowThreadContentRect(const LayoutRect& rect) const
{
    ASSERT(isValid());
    return flowThread()->isHorizontalWritingMode() ? rect.y() : rect.x();
}
Exemple #24
0
bool LayoutRect::contains(const LayoutRect& other) const
{
    return x() <= other.x() && maxX() >= other.maxX()
        && y() <= other.y() && maxY() >= other.maxY();
}
IntPoint AccessibilityObject::clickPoint()
{
    LayoutRect rect = elementRect();
    return roundedIntPoint(LayoutPoint(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2));
}
Exemple #26
0
IntRect::IntRect(const LayoutRect& r)
    : m_location(r.x(), r.y())
    , m_size(r.width(), r.height())
{
}
Exemple #27
0
void InlinePainter::paintOutlineForLine(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset,
    const LayoutRect& lastline, const LayoutRect& thisline, const LayoutRect& nextline, const Color outlineColor)
{
    RenderStyle* styleToUse = m_renderInline.style();
    int outlineWidth = styleToUse->outlineWidth();
    EBorderStyle outlineStyle = styleToUse->outlineStyle();

    bool antialias = BoxPainter::shouldAntialiasLines(graphicsContext);

    int offset = m_renderInline.style()->outlineOffset();

    LayoutRect box(LayoutPoint(paintOffset.x() + thisline.x() - offset, paintOffset.y() + thisline.y() - offset),
        LayoutSize(thisline.width() + offset, thisline.height() + offset));

    IntRect pixelSnappedBox = pixelSnappedIntRect(box);
    if (pixelSnappedBox.width() < 0 || pixelSnappedBox.height() < 0)
        return;
    IntRect pixelSnappedLastLine = pixelSnappedIntRect(paintOffset.x() + lastline.x(), 0, lastline.width(), 0);
    IntRect pixelSnappedNextLine = pixelSnappedIntRect(paintOffset.x() + nextline.x(), 0, nextline.width(), 0);

    // left edge
    ObjectPainter::drawLineForBoxSide(graphicsContext,
        pixelSnappedBox.x() - outlineWidth,
        pixelSnappedBox.y() - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
        pixelSnappedBox.x(),
        pixelSnappedBox.maxY() + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
        BSLeft,
        outlineColor, outlineStyle,
        (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
        (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
        antialias);

    // right edge
    ObjectPainter::drawLineForBoxSide(graphicsContext,
        pixelSnappedBox.maxX(),
        pixelSnappedBox.y() - (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : 0),
        pixelSnappedBox.maxX() + outlineWidth,
        pixelSnappedBox.maxY() + (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : 0),
        BSRight,
        outlineColor, outlineStyle,
        (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : -outlineWidth),
        (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : -outlineWidth),
        antialias);
    // upper edge
    if (thisline.x() < lastline.x()) {
        ObjectPainter::drawLineForBoxSide(graphicsContext,
            pixelSnappedBox.x() - outlineWidth,
            pixelSnappedBox.y() - outlineWidth,
            std::min(pixelSnappedBox.maxX() + outlineWidth, (lastline.isEmpty() ? 1000000 : pixelSnappedLastLine.x())),
            pixelSnappedBox.y(),
            BSTop, outlineColor, outlineStyle,
            outlineWidth,
            (!lastline.isEmpty() && paintOffset.x() + lastline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
            antialias);
    }

    if (lastline.maxX() < thisline.maxX()) {
        ObjectPainter::drawLineForBoxSide(graphicsContext,
            std::max(lastline.isEmpty() ? -1000000 : pixelSnappedLastLine.maxX(), pixelSnappedBox.x() - outlineWidth),
            pixelSnappedBox.y() - outlineWidth,
            pixelSnappedBox.maxX() + outlineWidth,
            pixelSnappedBox.y(),
            BSTop, outlineColor, outlineStyle,
            (!lastline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + lastline.maxX()) ? -outlineWidth : outlineWidth,
            outlineWidth, antialias);
    }

    if (thisline.x() == thisline.maxX()) {
        ObjectPainter::drawLineForBoxSide(graphicsContext,
            pixelSnappedBox.x() - outlineWidth,
            pixelSnappedBox.y() - outlineWidth,
            pixelSnappedBox.maxX() + outlineWidth,
            pixelSnappedBox.y(),
            BSTop, outlineColor, outlineStyle,
            outlineWidth,
            outlineWidth,
            antialias);
    }

    // lower edge
    if (thisline.x() < nextline.x()) {
        ObjectPainter::drawLineForBoxSide(graphicsContext,
            pixelSnappedBox.x() - outlineWidth,
            pixelSnappedBox.maxY(),
            std::min(pixelSnappedBox.maxX() + outlineWidth, !nextline.isEmpty() ? pixelSnappedNextLine.x() + 1 : 1000000),
            pixelSnappedBox.maxY() + outlineWidth,
            BSBottom, outlineColor, outlineStyle,
            outlineWidth,
            (!nextline.isEmpty() && paintOffset.x() + nextline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
            antialias);
    }

    if (nextline.maxX() < thisline.maxX()) {
        ObjectPainter::drawLineForBoxSide(graphicsContext,
            std::max(!nextline.isEmpty() ? pixelSnappedNextLine.maxX() : -1000000, pixelSnappedBox.x() - outlineWidth),
            pixelSnappedBox.maxY(),
            pixelSnappedBox.maxX() + outlineWidth,
            pixelSnappedBox.maxY() + outlineWidth,
            BSBottom, outlineColor, outlineStyle,
            (!nextline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + nextline.maxX()) ? -outlineWidth : outlineWidth,
            outlineWidth, antialias);
    }

    if (thisline.x() == thisline.maxX()) {
        ObjectPainter::drawLineForBoxSide(graphicsContext,
            pixelSnappedBox.x() - outlineWidth,
            pixelSnappedBox.maxY(),
            pixelSnappedBox.maxX() + outlineWidth,
            pixelSnappedBox.maxY() + outlineWidth,
            BSBottom, outlineColor, outlineStyle,
            outlineWidth,
            outlineWidth,
            antialias);
    }
}
Exemple #28
0
bool RenderEmbeddedObject::isReplacementObscured() const
{
    // Return whether or not the replacement content for blocked plugins is accessible to the user.

    // Check the opacity of each layer containing the element or its ancestors.
    float opacity = 1.0;
    for (RenderLayer* layer = enclosingLayer(); layer; layer = layer->parent()) {
        RenderLayerModelObject* renderer = layer->renderer();
        RenderStyle* style = renderer->style();
        opacity *= style->opacity();
        if (opacity < 0.1)
            return true;
    }

    // Calculate the absolute rect for the blocked plugin replacement text.
    IntRect absoluteBoundingBox = absoluteBoundingBoxRect();
    LayoutPoint absoluteLocation(absoluteBoundingBox.location());
    LayoutRect rect = replacementTextRect(absoluteLocation);
    if (rect.isEmpty())
        return true;

    RenderView* docRenderer = document()->renderView();
    ASSERT(docRenderer);
    if (!docRenderer)
        return true;
    
    HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent);
    HitTestResult result;
    HitTestLocation location;
    
    LayoutUnit x = rect.x();
    LayoutUnit y = rect.y();
    LayoutUnit width = rect.width();
    LayoutUnit height = rect.height();
    
    // Hit test the center and near the corners of the replacement text to ensure
    // it is visible and is not masked by other elements.
    bool hit = false;
    location = LayoutPoint(x + width / 2, y + height / 2);
    hit = docRenderer->hitTest(request, location, result);
    if (!hit || result.innerNode() != node())
        return true;
    
    location = LayoutPoint(x, y);
    hit = docRenderer->hitTest(request, location, result);
    if (!hit || result.innerNode() != node())
        return true;
    
    location = LayoutPoint(x + width, y);
    hit = docRenderer->hitTest(request, location, result);
    if (!hit || result.innerNode() != node())
        return true;
    
    location = LayoutPoint(x + width, y + height);
    hit = docRenderer->hitTest(request, location, result);
    if (!hit || result.innerNode() != node())
        return true;
    
    location = LayoutPoint(x, y + height);
    hit = docRenderer->hitTest(request, location, result);
    if (!hit || result.innerNode() != node())
        return true;

    return false;
}
void RenderMultiColumnSet::collectLayerFragments(LayerFragments& fragments, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect)
{
    // The two rectangles passed to this method are physical, except that we pretend that there's
    // only one long column (that's how a flow thread works).
    //
    // Then there's the output from this method - the stuff we put into the list of fragments. The
    // fragment.paginationOffset point is the actual physical translation required to get from a
    // location in the flow thread to a location in a given column. The fragment.paginationClip
    // rectangle, on the other hand, is in the same coordinate system as the two rectangles passed
    // to this method (flow thread coordinates).
    //
    // All other rectangles in this method are sized physically, and the inline direction coordinate
    // is physical too, but the block direction coordinate is "logical top". This is the same as
    // e.g. RenderBox::frameRect(). These rectangles also pretend that there's only one long column,
    // i.e. they are for the flow thread.

    // Put the layer bounds into flow thread-local coordinates by flipping it first. Since we're in
    // a renderer, most rectangles are represented this way.
    LayoutRect layerBoundsInFlowThread(layerBoundingBox);
    flowThread()->flipForWritingMode(layerBoundsInFlowThread);

    // Now we can compare with the flow thread portions owned by each column. First let's
    // see if the rect intersects our flow thread portion at all.
    LayoutRect clippedRect(layerBoundsInFlowThread);
    clippedRect.intersect(RenderRegion::flowThreadPortionOverflowRect());
    if (clippedRect.isEmpty())
        return;

    // Now we know we intersect at least one column. Let's figure out the logical top and logical
    // bottom of the area we're checking.
    LayoutUnit layerLogicalTop = isHorizontalWritingMode() ? layerBoundsInFlowThread.y() : layerBoundsInFlowThread.x();
    LayoutUnit layerLogicalBottom = (isHorizontalWritingMode() ? layerBoundsInFlowThread.maxY() : layerBoundsInFlowThread.maxX()) - 1;

    // Figure out the start and end columns and only check within that range so that we don't walk the
    // entire column set.
    unsigned startColumn = columnIndexAtOffset(layerLogicalTop);
    unsigned endColumn = columnIndexAtOffset(layerLogicalBottom);

    LayoutUnit colLogicalWidth = computedColumnWidth();
    LayoutUnit colGap = columnGap();
    unsigned colCount = columnCount();

    for (unsigned i = startColumn; i <= endColumn; i++) {
        // Get the portion of the flow thread that corresponds to this column.
        LayoutRect flowThreadPortion = flowThreadPortionRectAt(i);

        // Now get the overflow rect that corresponds to the column.
        LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap);

        // In order to create a fragment we must intersect the portion painted by this column.
        LayoutRect clippedRect(layerBoundsInFlowThread);
        clippedRect.intersect(flowThreadOverflowPortion);
        if (clippedRect.isEmpty())
            continue;

        // We also need to intersect the dirty rect. We have to apply a translation and shift based off
        // our column index.
        LayoutPoint translationOffset;
        LayoutUnit inlineOffset = i * (colLogicalWidth + colGap);
        if (!style()->isLeftToRightDirection())
            inlineOffset = -inlineOffset;
        translationOffset.setX(inlineOffset);
        LayoutUnit blockOffset = isHorizontalWritingMode() ? -flowThreadPortion.y() : -flowThreadPortion.x();
        if (isFlippedBlocksWritingMode(style()->writingMode()))
            blockOffset = -blockOffset;
        translationOffset.setY(blockOffset);
        if (!isHorizontalWritingMode())
            translationOffset = translationOffset.transposedPoint();
        // FIXME: The translation needs to include the multicolumn set's content offset within the
        // multicolumn block as well. This won't be an issue until we start creating multiple multicolumn sets.

        // Shift the dirty rect to be in flow thread coordinates with this translation applied.
        LayoutRect translatedDirtyRect(dirtyRect);
        translatedDirtyRect.moveBy(-translationOffset);

        // See if we intersect the dirty rect.
        clippedRect = layerBoundingBox;
        clippedRect.intersect(translatedDirtyRect);
        if (clippedRect.isEmpty())
            continue;

        // Something does need to paint in this column. Make a fragment now and supply the physical translation
        // offset and the clip rect for the column with that offset applied.
        LayerFragment fragment;
        fragment.paginationOffset = translationOffset;

        LayoutRect flippedFlowThreadOverflowPortion(flowThreadOverflowPortion);
        // Flip it into more a physical (RenderLayer-style) rectangle.
        flowThread()->flipForWritingMode(flippedFlowThreadOverflowPortion);
        fragment.paginationClip = flippedFlowThreadOverflowPortion;
        fragments.append(fragment);
    }
}
LayoutRect RenderNamedFlowThread::decorationsClipRectForBoxInNamedFlowFragment(const RenderBox& box, RenderNamedFlowFragment& fragment) const
{
    LayoutRect visualOverflowRect = fragment.visualOverflowRectForBox(&box);
    LayoutUnit initialLogicalX = style().isHorizontalWritingMode() ? visualOverflowRect.x() : visualOverflowRect.y();

    // The visual overflow rect returned by visualOverflowRectForBox is already flipped but the
    // RenderRegion::rectFlowPortionForBox method expects it unflipped.
    flipForWritingModeLocalCoordinates(visualOverflowRect);
    visualOverflowRect = fragment.rectFlowPortionForBox(&box, visualOverflowRect);
    
    // Now flip it again.
    flipForWritingModeLocalCoordinates(visualOverflowRect);

    // Take the scrolled offset of this object's parents into consideration.
    IntSize scrolledContentOffset;
    RenderBlock* containingBlock = box.containingBlock();
    while (containingBlock) {
        if (containingBlock->isRenderNamedFlowThread()) {
            // We've reached the flow thread, take the scrolled offset of the region into consideration.
            ASSERT(containingBlock == this);
            scrolledContentOffset += fragment.fragmentContainer().scrolledContentOffset();
            break;
        }
        
        scrolledContentOffset += containingBlock->scrolledContentOffset();
        containingBlock = containingBlock->containingBlock();
    }

    if (!scrolledContentOffset.isZero()) {
        if (style().isFlippedBlocksWritingMode())
            scrolledContentOffset = -scrolledContentOffset;
        
        visualOverflowRect.inflateX(scrolledContentOffset.width());
        visualOverflowRect.inflateY(scrolledContentOffset.height());
    }
    
    // Layers are in physical coordinates so the origin must be moved to the physical top-left of the flowthread.
    if (style().isFlippedBlocksWritingMode()) {
        if (style().isHorizontalWritingMode())
            visualOverflowRect.moveBy(LayoutPoint(0, height()));
        else
            visualOverflowRect.moveBy(LayoutPoint(width(), 0));
    }

    const RenderBox* iterBox = &box;
    while (iterBox && iterBox != this) {
        RenderBlock* containerBlock = iterBox->containingBlock();

        // FIXME: This doesn't work properly with flipped writing modes.
        // https://bugs.webkit.org/show_bug.cgi?id=125149
        if (iterBox->isPositioned()) {
            // For positioned elements, just use the layer's absolute bounding box.
            visualOverflowRect.moveBy(iterBox->layer()->absoluteBoundingBox().location());
            break;
        }

        LayoutRect currentBoxRect = iterBox->frameRect();
        if (iterBox->style().isFlippedBlocksWritingMode()) {
            if (iterBox->style().isHorizontalWritingMode())
                currentBoxRect.setY(currentBoxRect.height() - currentBoxRect.maxY());
            else
                currentBoxRect.setX(currentBoxRect.width() - currentBoxRect.maxX());
        }

        if (containerBlock->style().writingMode() != iterBox->style().writingMode())
            iterBox->flipForWritingMode(currentBoxRect);

        visualOverflowRect.moveBy(currentBoxRect.location());
        iterBox = containerBlock;
    }

    // Since the purpose of this method is to make sure the borders of a fragmented
    // element don't overflow the region in the fragmentation direction, there's no
    // point in restricting the clipping rect on the logical X axis. 
    // This also saves us the trouble of handling percent-based widths and margins
    // since the absolute bounding box of a positioned element would not contain
    // the correct coordinates relative to the region we're interested in, but rather
    // relative to the actual flow thread.
    if (style().isHorizontalWritingMode()) {
        if (initialLogicalX < visualOverflowRect.x())
            visualOverflowRect.shiftXEdgeTo(initialLogicalX);
        if (visualOverflowRect.width() < frameRect().width())
            visualOverflowRect.setWidth(frameRect().width());
    } else {
        if (initialLogicalX < visualOverflowRect.y())
            visualOverflowRect.shiftYEdgeTo(initialLogicalX);
        if (visualOverflowRect.height() < frameRect().height())
            visualOverflowRect.setHeight(frameRect().height());
    }

    return visualOverflowRect;
}