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) { LayoutUnit selTop = paintOffset.y() + m_inlineBoxWrapper->root()->selectionTop(); LayoutUnit selBottom = paintOffset.y() + selTop + m_inlineBoxWrapper->root()->selectionHeight(); top = min(selTop, top); bottom = 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; }
void RenderMathMLBlock::paint(PaintInfo& info, const LayoutPoint& paintOffset) { RenderBlock::paint(info, paintOffset); if (info.context->paintingDisabled() || info.phase != PaintPhaseForeground) return; LayoutPoint adjustedPaintOffset = paintOffset + location(); GraphicsContextStateSaver stateSaver(*info.context); info.context->setStrokeThickness(1.0f); info.context->setStrokeStyle(SolidStroke); info.context->setStrokeColor(Color(0, 0, 255), ColorSpaceSRGB); info.context->drawLine(adjustedPaintOffset, LayoutPoint(adjustedPaintOffset.x() + offsetWidth(), adjustedPaintOffset.y())); info.context->drawLine(LayoutPoint(adjustedPaintOffset.x() + offsetWidth(), adjustedPaintOffset.y()), LayoutPoint(adjustedPaintOffset.x() + offsetWidth(), adjustedPaintOffset.y() + offsetHeight())); info.context->drawLine(LayoutPoint(adjustedPaintOffset.x(), adjustedPaintOffset.y() + offsetHeight()), LayoutPoint(adjustedPaintOffset.x() + offsetWidth(), adjustedPaintOffset.y() + offsetHeight())); info.context->drawLine(adjustedPaintOffset, LayoutPoint(adjustedPaintOffset.x(), adjustedPaintOffset.y() + offsetHeight())); int topStart = paddingTop(); info.context->setStrokeColor(Color(0, 255, 0), ColorSpaceSRGB); info.context->drawLine(LayoutPoint(adjustedPaintOffset.x(), adjustedPaintOffset.y() + topStart), LayoutPoint(adjustedPaintOffset.x() + offsetWidth(), adjustedPaintOffset.y() + topStart)); int baseline = baselinePosition(AlphabeticBaseline, true, HorizontalLine); info.context->setStrokeColor(Color(255, 0, 0), ColorSpaceSRGB); info.context->drawLine(LayoutPoint(adjustedPaintOffset.x(), adjustedPaintOffset.y() + baseline), LayoutPoint(adjustedPaintOffset.x() + offsetWidth(), adjustedPaintOffset.y() + baseline)); }
VisiblePosition RenderReplaced::positionForPoint(const LayoutPoint& point, const RenderRegion* region) { // FIXME: This code is buggy if the replaced element is relative positioned. InlineBox* box = inlineBoxWrapper(); const RootInlineBox* rootBox = box ? &box->root() : 0; LayoutUnit top = rootBox ? rootBox->selectionTop() : logicalTop(); LayoutUnit bottom = rootBox ? rootBox->selectionBottom() : logicalBottom(); LayoutUnit blockDirectionPosition = isHorizontalWritingMode() ? point.y() + y() : point.x() + x(); LayoutUnit lineDirectionPosition = isHorizontalWritingMode() ? point.x() + x() : point.y() + y(); if (blockDirectionPosition < top) return createVisiblePosition(caretMinOffset(), DOWNSTREAM); // coordinates are above if (blockDirectionPosition >= bottom) return createVisiblePosition(caretMaxOffset(), DOWNSTREAM); // coordinates are below if (element()) { if (lineDirectionPosition <= logicalLeft() + (logicalWidth() / 2)) return createVisiblePosition(0, DOWNSTREAM); return createVisiblePosition(1, DOWNSTREAM); } return RenderBox::positionForPoint(point, region); }
void FrameSetPainter::paintBorders(const PaintInfo& paintInfo, const LayoutPoint& adjustedPaintOffset) { LayoutRect adjustedFrameRect(adjustedPaintOffset, m_layoutFrameSet.size()); LayoutObjectDrawingRecorder recorder(*paintInfo.context, m_layoutFrameSet, paintInfo.phase, adjustedFrameRect); if (recorder.canUseCachedDrawing()) return; LayoutObject* child = m_layoutFrameSet.firstChild(); size_t rows = m_layoutFrameSet.rows().m_sizes.size(); size_t cols = m_layoutFrameSet.columns().m_sizes.size(); LayoutUnit borderThickness = m_layoutFrameSet.frameSet()->border(); LayoutUnit yPos = 0; for (size_t r = 0; r < rows; r++) { LayoutUnit xPos = 0; for (size_t c = 0; c < cols; c++) { xPos += m_layoutFrameSet.columns().m_sizes[c]; if (borderThickness && m_layoutFrameSet.columns().m_allowBorder[c + 1]) { paintColumnBorder(paintInfo, pixelSnappedIntRect( LayoutRect(adjustedPaintOffset.x() + xPos, adjustedPaintOffset.y() + yPos, borderThickness, m_layoutFrameSet.size().height()))); xPos += borderThickness; } child = child->nextSibling(); if (!child) return; } yPos += m_layoutFrameSet.rows().m_sizes[r]; if (borderThickness && m_layoutFrameSet.rows().m_allowBorder[r + 1]) { paintRowBorder(paintInfo, pixelSnappedIntRect( LayoutRect(adjustedPaintOffset.x(), adjustedPaintOffset.y() + yPos, m_layoutFrameSet.size().width(), borderThickness))); yPos += borderThickness; } } }
PositionWithAffinity LayoutReplaced::positionForPoint( const LayoutPoint& point) { // FIXME: This code is buggy if the replaced element is relative positioned. InlineBox* box = inlineBoxWrapper(); RootInlineBox* rootBox = box ? &box->root() : 0; LayoutUnit top = rootBox ? rootBox->selectionTop() : logicalTop(); LayoutUnit bottom = rootBox ? rootBox->selectionBottom() : logicalBottom(); LayoutUnit blockDirectionPosition = isHorizontalWritingMode() ? point.y() + location().y() : point.x() + location().x(); LayoutUnit lineDirectionPosition = isHorizontalWritingMode() ? point.x() + location().x() : point.y() + location().y(); if (blockDirectionPosition < top) return createPositionWithAffinity( caretMinOffset()); // coordinates are above if (blockDirectionPosition >= bottom) return createPositionWithAffinity( caretMaxOffset()); // coordinates are below if (node()) { if (lineDirectionPosition <= logicalLeft() + (logicalWidth() / 2)) return createPositionWithAffinity(0); return createPositionWithAffinity(1); } return LayoutBox::positionForPoint(point); }
bool LineBoxList::hitTest(LayoutBoxModelObject* renderer, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) const { if (hitTestAction != HitTestForeground) return false; ASSERT(renderer->isLayoutBlock() || (renderer->isLayoutInline() && renderer->hasLayer())); // The only way an inline could hit test like this is if it has a layer. // If we have no lines then we have no work to do. if (!firstLineBox()) return false; LayoutPoint point = locationInContainer.point(); LayoutRect rect(firstLineBox()->isHorizontal() ? IntRect(point.x(), point.y() - locationInContainer.topPadding(), 1, locationInContainer.topPadding() + locationInContainer.bottomPadding() + 1) : IntRect(point.x() - locationInContainer.leftPadding(), point.y(), locationInContainer.rightPadding() + locationInContainer.leftPadding() + 1, 1)); if (!anyLineIntersectsRect(renderer, rect, accumulatedOffset)) return false; // See if our root lines contain the point. If so, then we hit test // them further. Note that boxes can easily overlap, so we can't make any assumptions // based off positions of our first line box or our last line box. for (InlineFlowBox* curr = lastLineBox(); curr; curr = curr->prevLineBox()) { RootInlineBox& root = curr->root(); if (rangeIntersectsRect(renderer, curr->logicalTopVisualOverflow(root.lineTop()), curr->logicalBottomVisualOverflow(root.lineBottom()), rect, accumulatedOffset)) { bool inside = curr->nodeAtPoint(result, locationInContainer, accumulatedOffset, root.lineTop(), root.lineBottom()); if (inside) { renderer->updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); return true; } } } return false; }
void FileUploadControlPainter::paintObject(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (m_layoutFileUploadControl.style()->visibility() != VISIBLE) return; // Push a clip. Optional<ClipRecorder> clipRecorder; if (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseDescendantBlockBackgroundsOnly) { IntRect clipRect = enclosingIntRect(LayoutRect( LayoutPoint(paintOffset.x() + m_layoutFileUploadControl.borderLeft(), paintOffset.y() + m_layoutFileUploadControl.borderTop()), m_layoutFileUploadControl.size() + LayoutSize(0, -m_layoutFileUploadControl.borderWidth() + buttonShadowHeight))); if (clipRect.isEmpty()) return; clipRecorder.emplace(paintInfo.context, m_layoutFileUploadControl, DisplayItem::ClipFileUploadControlRect, clipRect); } if (paintInfo.phase == PaintPhaseForeground && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_layoutFileUploadControl, paintInfo.phase)) { const String& displayedFilename = m_layoutFileUploadControl.fileTextValue(); const Font& font = m_layoutFileUploadControl.style()->font(); TextRun textRun = constructTextRun(font, displayedFilename, m_layoutFileUploadControl.styleRef(), RespectDirection | RespectDirectionOverride); textRun.setExpansionBehavior(TextRun::AllowTrailingExpansion); // Determine where the filename should be placed LayoutUnit contentLeft = paintOffset.x() + m_layoutFileUploadControl.borderLeft() + m_layoutFileUploadControl.paddingLeft(); Node* button = m_layoutFileUploadControl.uploadButton(); if (!button) return; int buttonWidth = (button && button->layoutBox()) ? button->layoutBox()->pixelSnappedWidth() : 0; LayoutUnit buttonAndSpacingWidth(buttonWidth + LayoutFileUploadControl::afterButtonSpacing); float textWidth = font.width(textRun); LayoutUnit textX; if (m_layoutFileUploadControl.style()->isLeftToRightDirection()) textX = contentLeft + buttonAndSpacingWidth; else textX = LayoutUnit(contentLeft + m_layoutFileUploadControl.contentWidth() - buttonAndSpacingWidth - textWidth); LayoutUnit textY; // We want to match the button's baseline // FIXME: Make this work with transforms. if (LayoutButton* buttonLayoutObject = toLayoutButton(button->layoutObject())) textY = paintOffset.y() + m_layoutFileUploadControl.borderTop() + m_layoutFileUploadControl.paddingTop() + buttonLayoutObject->baselinePosition(AlphabeticBaseline, true, HorizontalLine, PositionOnContainingLine); else textY = LayoutUnit(m_layoutFileUploadControl.baselinePosition(AlphabeticBaseline, true, HorizontalLine, PositionOnContainingLine)); TextRunPaintInfo textRunPaintInfo(textRun); // FIXME: Shouldn't these offsets be rounded? crbug.com/350474 textRunPaintInfo.bounds = FloatRect(textX.toFloat(), textY.toFloat() - m_layoutFileUploadControl.style()->getFontMetrics().ascent(), textWidth, m_layoutFileUploadControl.style()->getFontMetrics().height()); // Draw the filename. LayoutObjectDrawingRecorder recorder(paintInfo.context, m_layoutFileUploadControl, paintInfo.phase, textRunPaintInfo.bounds); paintInfo.context.setFillColor(m_layoutFileUploadControl.resolveColor(CSSPropertyColor)); paintInfo.context.drawBidiText(font, textRunPaintInfo, FloatPoint(roundToInt(textX), roundToInt(textY))); } // Paint the children. m_layoutFileUploadControl.LayoutBlockFlow::paintObject(paintInfo, paintOffset); }
void SliderThumbElement::setPositionFromPoint(const LayoutPoint& point) { RefPtrWillBeRawPtr<HTMLInputElement> input(hostInput()); Element* trackElement = input->closedShadowRoot()->getElementById(ShadowElementNames::sliderTrack()); if (!input->layoutObject() || !layoutBox() || !trackElement->layoutBox()) return; LayoutPoint offset = roundedLayoutPoint(input->layoutObject()->absoluteToLocal(FloatPoint(point), UseTransforms)); bool isVertical = hasVerticalAppearance(input.get()); bool isLeftToRightDirection = layoutBox()->style()->isLeftToRightDirection(); LayoutUnit trackSize; LayoutUnit position; LayoutUnit currentPosition; // We need to calculate currentPosition from absolute points becaue the // renderer for this node is usually on a layer and layoutBox()->x() and // y() are unusable. // FIXME: This should probably respect transforms. LayoutPoint absoluteThumbOrigin = layoutBox()->absoluteBoundingBoxRectIgnoringTransforms().location(); LayoutPoint absoluteSliderContentOrigin = roundedLayoutPoint(input->layoutObject()->localToAbsolute()); IntRect trackBoundingBox = trackElement->layoutObject()->absoluteBoundingBoxRectIgnoringTransforms(); IntRect inputBoundingBox = input->layoutObject()->absoluteBoundingBoxRectIgnoringTransforms(); if (isVertical) { trackSize = trackElement->layoutBox()->contentHeight() - layoutBox()->size().height(); position = offset.y() - layoutBox()->size().height() / 2 - trackBoundingBox.y() + inputBoundingBox.y() - layoutBox()->marginBottom(); currentPosition = absoluteThumbOrigin.y() - absoluteSliderContentOrigin.y(); } else { trackSize = trackElement->layoutBox()->contentWidth() - layoutBox()->size().width(); position = offset.x() - layoutBox()->size().width() / 2 - trackBoundingBox.x() + inputBoundingBox.x(); position -= isLeftToRightDirection ? layoutBox()->marginLeft() : layoutBox()->marginRight(); currentPosition = absoluteThumbOrigin.x() - absoluteSliderContentOrigin.x(); } position = std::max<LayoutUnit>(0, std::min(position, trackSize)); const Decimal ratio = Decimal::fromDouble(static_cast<double>(position) / trackSize); const Decimal fraction = isVertical || !isLeftToRightDirection ? Decimal(1) - ratio : ratio; StepRange stepRange(input->createStepRange(RejectAny)); Decimal value = stepRange.clampValue(stepRange.valueFromProportion(fraction)); Decimal closest = input->findClosestTickMarkValue(value); if (closest.isFinite()) { double closestFraction = stepRange.proportionFromValue(closest).toDouble(); double closestRatio = isVertical || !isLeftToRightDirection ? 1.0 - closestFraction : closestFraction; LayoutUnit closestPosition = trackSize * closestRatio; const LayoutUnit snappingThreshold = 5; if ((closestPosition - position).abs() <= snappingThreshold) value = closest; } String valueString = serializeForNumberType(value); if (valueString == input->value()) return; // FIXME: This is no longer being set from renderer. Consider updating the method name. input->setValueFromRenderer(valueString); if (layoutObject()) layoutObject()->setNeedsLayoutAndFullPaintInvalidation(LayoutInvalidationReason::SliderValueChanged); }
SliderContainerElement::Direction SliderContainerElement::getDirection( LayoutPoint& point1, LayoutPoint& point2) { if (point1 == point2) { return NoMove; } if ((point1.x() - point2.x()).abs() >= (point1.y() - point2.y()).abs()) { return Horizontal; } return Vertical; }
LayoutPoint InlineBox::logicalPositionToPhysicalPoint(const LayoutPoint& point, const LayoutSize& size) const { if (!UNLIKELY(lineLayoutItem().hasFlippedBlocksWritingMode())) return LayoutPoint(point.x(), point.y()); LayoutBlockFlow& block = root().block(); if (block.style()->isHorizontalWritingMode()) return LayoutPoint(point.x(), block.size().height() - size.height() - point.y()); return LayoutPoint(block.size().width() - size.width() - point.x(), point.y()); }
void distanceDataForNode(FocusType type, const FocusCandidate& current, FocusCandidate& candidate) { if (areElementsOnSameLine(current, candidate)) { if ((type == FocusTypeUp && current.rect.y() > candidate.rect.y()) || (type == FocusTypeDown && candidate.rect.y() > current.rect.y())) { candidate.distance = 0; candidate.alignment = Full; return; } } LayoutRect nodeRect = candidate.rect; LayoutRect currentRect = current.rect; deflateIfOverlapped(currentRect, nodeRect); if (!isRectInDirection(type, currentRect, nodeRect)) return; LayoutPoint exitPoint; LayoutPoint entryPoint; entryAndExitPointsForDirection(type, currentRect, nodeRect, exitPoint, entryPoint); LayoutUnit xAxis = exitPoint.x() - entryPoint.x(); LayoutUnit yAxis = exitPoint.y() - entryPoint.y(); LayoutUnit navigationAxisDistance; LayoutUnit orthogonalAxisDistance; switch (type) { case FocusTypeLeft: case FocusTypeRight: navigationAxisDistance = xAxis.abs(); orthogonalAxisDistance = yAxis.abs(); break; case FocusTypeUp: case FocusTypeDown: navigationAxisDistance = yAxis.abs(); orthogonalAxisDistance = xAxis.abs(); break; default: ASSERT_NOT_REACHED(); return; } double euclidianDistancePow2 = (xAxis * xAxis + yAxis * yAxis).toDouble(); LayoutRect intersectionRect = intersection(currentRect, nodeRect); double overlap = (intersectionRect.width() * intersectionRect.height()).toDouble(); // Distance calculation is based on http://www.w3.org/TR/WICD/#focus-handling candidate.distance = sqrt(euclidianDistancePow2) + navigationAxisDistance+ orthogonalAxisDistance * 2 - sqrt(overlap); LayoutSize viewSize = candidate.visibleNode->document().page()->deprecatedLocalMainFrame()->view()->visibleContentRect().size(); candidate.alignment = alignmentForRects(type, currentRect, nodeRect, viewSize); }
void BlockFlowPainter::paintFloats(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!m_layoutBlockFlow.floatingObjects()) return; DCHECK(paintInfo.phase == PaintPhaseFloat || paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip); PaintInfo floatPaintInfo(paintInfo); if (paintInfo.phase == PaintPhaseFloat) floatPaintInfo.phase = PaintPhaseForeground; for (const auto& floatingObject : m_layoutBlockFlow.floatingObjects()->set()) { if (!floatingObject->shouldPaint()) continue; const LayoutBox* floatingLayoutObject = floatingObject->layoutObject(); // FIXME: LayoutPoint version of xPositionForFloatIncludingMargin would make // this much cleaner. LayoutPoint childPoint = m_layoutBlockFlow.flipFloatForWritingModeForChild( *floatingObject, LayoutPoint(paintOffset.x() + m_layoutBlockFlow.xPositionForFloatIncludingMargin( *floatingObject) - floatingLayoutObject->location().x(), paintOffset.y() + m_layoutBlockFlow.yPositionForFloatIncludingMargin( *floatingObject) - floatingLayoutObject->location().y())); ObjectPainter(*floatingLayoutObject) .paintAllPhasesAtomically(floatPaintInfo, childPoint); } }
void RenderMultiColumnFlowThread::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const { // First get the transform state's point into the block flow thread's physical coordinate space. parent()->mapAbsoluteToLocalPoint(mode, transformState); LayoutPoint transformPoint = roundedLayoutPoint(transformState.mappedPoint()); // Now walk through each region. const RenderMultiColumnSet* candidateColumnSet = nullptr; LayoutPoint candidatePoint; LayoutSize candidateContainerOffset; for (const auto& columnSet : childrenOfType<RenderMultiColumnSet>(*parent())) { candidateContainerOffset = columnSet.offsetFromContainer(parent(), LayoutPoint()); candidatePoint = transformPoint - candidateContainerOffset; candidateColumnSet = &columnSet; // We really have no clue what to do with overflow. We'll just use the closest region to the point in that case. LayoutUnit pointOffset = isHorizontalWritingMode() ? candidatePoint.y() : candidatePoint.x(); LayoutUnit regionOffset = isHorizontalWritingMode() ? columnSet.topLeftLocation().y() : columnSet.topLeftLocation().x(); if (pointOffset < regionOffset + columnSet.logicalHeight()) break; } // Once we have a good guess as to which region we hit tested through (and yes, this was just a heuristic, but it's // the best we could do), then we can map from the region into the flow thread. LayoutSize translationOffset = physicalTranslationFromRegionToFlow(candidateColumnSet, candidatePoint) + candidateContainerOffset; bool preserve3D = mode & UseTransforms && (parent()->style().preserves3D() || style().preserves3D()); if (mode & UseTransforms && shouldUseTransformFromContainer(parent())) { TransformationMatrix t; getTransformFromContainer(parent(), translationOffset, t); transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform); } else transformState.move(translationOffset.width(), translationOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform); }
unsigned MultiColumnFragmentainerGroup::columnIndexAtVisualPoint( const LayoutPoint& visualPoint) const { bool isColumnProgressionInline = m_columnSet.multiColumnFlowThread()->progressionIsInline(); bool isHorizontalWritingMode = m_columnSet.isHorizontalWritingMode(); LayoutUnit columnLengthInColumnProgressionDirection = isColumnProgressionInline ? m_columnSet.pageLogicalWidth() : logicalHeight(); LayoutUnit offsetInColumnProgressionDirection = isHorizontalWritingMode == isColumnProgressionInline ? visualPoint.x() : visualPoint.y(); if (!m_columnSet.style()->isLeftToRightDirection() && isColumnProgressionInline) offsetInColumnProgressionDirection = m_columnSet.logicalWidth() - offsetInColumnProgressionDirection; LayoutUnit columnGap = m_columnSet.columnGap(); if (columnLengthInColumnProgressionDirection + columnGap <= 0) return 0; // Column boundaries are in the middle of the column gap. int index = ((offsetInColumnProgressionDirection + columnGap / 2) / (columnLengthInColumnProgressionDirection + columnGap)) .toInt(); if (index < 0) return 0; return std::min(unsigned(index), actualColumnCount() - 1); }
bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { LayoutPoint pointInParent = pointInContainer - toLayoutSize(accumulatedOffset); LayoutPoint pointInBorderBox(pointInParent.x() - x(), pointInParent.y() - y()); // Note: For now, we're ignoring hits to border and padding for <svg> if (!contentBoxRect().contains(pointInBorderBox)) return false; FloatPoint localPoint = localToParentTransform().inverse().mapPoint(FloatPoint(pointInParent)); for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) { // FIXME: CSS/HTML assumes the local point is relative to the border box, right? updateHitTestResult(result, pointInBorderBox); // FIXME: nodeAtFloatPoint() doesn't handle rect-based hit tests yet. result.addNodeToRectBasedTestResult(child->node(), pointInContainer); return true; } } // If we didn't early exit above, we've just hit the container <svg> element. Unlike SVG 1.1, 2nd Edition allows container elements to be hit. if (hitTestAction == HitTestBlockBackground && style()->pointerEvents() != PE_NONE) { // Only return true here, if the last hit testing phase 'BlockBackground' is executed. If we'd return true in the 'Foreground' phase, // hit testing would stop immediately. For SVG only trees this doesn't matter. Though when we have a <foreignObject> subtree we need // to be able to detect hits on the background of a <div> element. If we'd return true here in the 'Foreground' phase, we are not able // to detect these hits anymore. updateHitTestResult(result, roundedLayoutPoint(localPoint)); return true; } return false; }
void RenderWidget::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutPoint adjustedPaintOffset = paintOffset + location(); Widget* widget = this->widget(); RELEASE_ASSERT(widget); // Tell the widget to paint now. This is the only time the widget is allowed // to paint itself. That way it will composite properly with z-indexed layers. IntPoint widgetLocation = widget->frameRect().location(); IntPoint paintLocation(roundToInt(adjustedPaintOffset.x() + borderLeft() + paddingLeft()), roundToInt(adjustedPaintOffset.y() + borderTop() + paddingTop())); IntRect paintRect = paintInfo.rect; IntSize widgetPaintOffset = paintLocation - widgetLocation; // When painting widgets into compositing layers, tx and ty are relative to the enclosing compositing layer, // not the root. In this case, shift the CTM and adjust the paintRect to be root-relative to fix plug-in drawing. if (!widgetPaintOffset.isZero()) { paintInfo.context->translate(widgetPaintOffset.width(), widgetPaintOffset.height()); paintRect.move(-widgetPaintOffset); } widget->paint(paintInfo.context, paintRect); if (!widgetPaintOffset.isZero()) paintInfo.context->translate(-widgetPaintOffset.width(), -widgetPaintOffset.height()); }
bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { LayoutPoint adjustedLocation = accumulatedOffset + roundedLayoutPoint(topLeft()); // Hit test the markup box. if (InlineBox* markupBox = this->markupBox()) { RenderStyle* style = renderer().style(isFirstLineStyle()); LayoutUnit mtx = adjustedLocation.x() + m_logicalWidth - markupBox->x(); LayoutUnit mty = adjustedLocation.y() + style->fontMetrics().ascent() - (markupBox->y() + markupBox->renderer().style(isFirstLineStyle())->fontMetrics().ascent()); if (markupBox->nodeAtPoint(request, result, locationInContainer, LayoutPoint(mtx, mty), lineTop, lineBottom)) { renderer().updateHitTestResult(result, locationInContainer.point() - LayoutSize(mtx, mty)); return true; } } FloatPoint boxOrigin = locationIncludingFlipping(); boxOrigin.moveBy(accumulatedOffset); FloatRect boundsRect(boxOrigin, size()); if (visibleToHitTestRequest(request) && boundsRect.intersects(HitTestLocation::rectForPoint(locationInContainer.point(), 0, 0, 0, 0))) { renderer().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation)); if (!result.addNodeToRectBasedTestResult(renderer().node(), request, locationInContainer, boundsRect)) return true; } return false; }
// FIXME: This should take a RenderBoxModelObject&. bool RenderLineBoxList::rangeIntersectsRect(RenderBoxModelObject* renderer, LayoutUnit logicalTop, LayoutUnit logicalBottom, const LayoutRect& rect, const LayoutPoint& offset) const { LayoutUnit physicalStart = logicalTop; LayoutUnit physicalEnd = logicalBottom; if (renderer->view().frameView().hasFlippedBlockRenderers()) { RenderBox* block; if (is<RenderBox>(*renderer)) block = downcast<RenderBox>(renderer); else block = renderer->containingBlock(); physicalStart = block->flipForWritingMode(logicalTop); 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; }
LayoutRect InlineFlowBoxPainter::paintRectForImageStrip(const LayoutPoint& paintOffset, const LayoutSize& frameSize, TextDirection direction) const { // We have a fill/border/mask image that spans multiple lines. // We need to adjust the offset by the width of all previous lines. // Think of background painting on inlines as though you had one long line, a single continuous // strip. Even though that strip has been broken up across multiple lines, you still paint it // as though you had one single line. This means each line has to pick up the background where // the previous line left off. LayoutUnit logicalOffsetOnLine = 0; LayoutUnit totalLogicalWidth; if (direction == LTR) { for (const InlineFlowBox* curr = m_inlineFlowBox.prevLineBox(); curr; curr = curr->prevLineBox()) logicalOffsetOnLine += curr->logicalWidth(); totalLogicalWidth = logicalOffsetOnLine; for (const InlineFlowBox* curr = &m_inlineFlowBox; curr; curr = curr->nextLineBox()) totalLogicalWidth += curr->logicalWidth(); } else { for (const InlineFlowBox* curr = m_inlineFlowBox.nextLineBox(); curr; curr = curr->nextLineBox()) logicalOffsetOnLine += curr->logicalWidth(); totalLogicalWidth = logicalOffsetOnLine; for (const InlineFlowBox* curr = &m_inlineFlowBox; curr; curr = curr->prevLineBox()) totalLogicalWidth += curr->logicalWidth(); } LayoutUnit stripX = paintOffset.x() - (m_inlineFlowBox.isHorizontal() ? logicalOffsetOnLine : LayoutUnit()); LayoutUnit stripY = paintOffset.y() - (m_inlineFlowBox.isHorizontal() ? LayoutUnit() : logicalOffsetOnLine); LayoutUnit stripWidth = m_inlineFlowBox.isHorizontal() ? totalLogicalWidth : frameSize.width(); LayoutUnit stripHeight = m_inlineFlowBox.isHorizontal() ? frameSize.height() : totalLogicalWidth; return LayoutRect(stripX, stripY, stripWidth, stripHeight); }
void BackgroundImageGeometry::useFixedAttachment( const LayoutPoint& attachmentPoint) { LayoutPoint alignedPoint = attachmentPoint; m_phase.move(std::max(alignedPoint.x() - m_destRect.x(), LayoutUnit()), std::max(alignedPoint.y() - m_destRect.y(), LayoutUnit())); setPhase(LayoutPoint(roundedIntPoint(m_phase))); }
void RenderMathMLFraction::paint(PaintInfo& info, const LayoutPoint& paintOffset) { RenderMathMLBlock::paint(info, paintOffset); if (info.context->paintingDisabled() || info.phase != PaintPhaseForeground) return; if (!firstChild() ||!m_lineThickness) return; LayoutUnit verticalOffset = 0; // The children are always RenderMathMLBlock instances if (firstChild()->isRenderMathMLBlock()) { int adjustForThickness = m_lineThickness > 1 ? int(m_lineThickness / 2) : 1; if (int(m_lineThickness) % 2 == 1) adjustForThickness++; RenderMathMLBlock* numerator = toRenderMathMLBlock(firstChild()); if (numerator->isRenderMathMLRow()) verticalOffset = numerator->offsetHeight() + adjustForThickness; else verticalOffset = numerator->offsetHeight(); } LayoutPoint adjustedPaintOffset = paintOffset + location(); adjustedPaintOffset.setY(adjustedPaintOffset.y() + verticalOffset); GraphicsContextStateSaver stateSaver(*info.context); info.context->setStrokeThickness(m_lineThickness); info.context->setStrokeStyle(SolidStroke); info.context->setStrokeColor(style()->visitedDependentColor(CSSPropertyColor), ColorSpaceSRGB); info.context->drawLine(adjustedPaintOffset, IntPoint(adjustedPaintOffset.x() + offsetWidth(), adjustedPaintOffset.y())); }
LayoutSize RenderMultiColumnFlowThread::physicalTranslationOffsetFromFlowToRegion(const RenderRegion* renderRegion, const LayoutUnit logicalOffset) const { // Now that we know which multicolumn set we hit, we need to get the appropriate translation offset for the column. const RenderMultiColumnSet* columnSet = toRenderMultiColumnSet(renderRegion); LayoutPoint translationOffset = columnSet->columnTranslationForOffset(logicalOffset); // Now we know how we want the rect to be translated into the region. At this point we're converting // back to physical coordinates. if (style().isFlippedBlocksWritingMode()) { LayoutRect portionRect(columnSet->flowThreadPortionRect()); LayoutRect columnRect = columnSet->columnRectAt(0); LayoutUnit physicalDeltaFromPortionBottom = logicalHeight() - columnSet->logicalBottomInFlowThread(); if (isHorizontalWritingMode()) columnRect.setHeight(portionRect.height()); else columnRect.setWidth(portionRect.width()); columnSet->flipForWritingMode(columnRect); if (isHorizontalWritingMode()) translationOffset.move(0, columnRect.y() - portionRect.y() - physicalDeltaFromPortionBottom); else translationOffset.move(columnRect.x() - portionRect.x() - physicalDeltaFromPortionBottom, 0); } return LayoutSize(translationOffset.x(), translationOffset.y()); }
Path RenderDetailsMarker::getPath(const LayoutPoint& origin) const { Path result = getCanonicalPath(); result.transform(AffineTransform().scale(contentWidth().toFloat(), contentHeight().toFloat())); result.translate(FloatSize(origin.x().toFloat(), origin.y().toFloat())); return result; }
bool RenderFlowThread::hitTestRegion(RenderRegion* region, const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset) { LayoutRect regionRect(region->regionRect()); LayoutRect regionOverflowRect = region->regionOverflowRect(); LayoutRect regionClippingRect(accumulatedOffset + (regionOverflowRect.location() - regionRect.location()), regionOverflowRect.size()); if (!regionClippingRect.contains(pointInContainer)) return false; LayoutPoint renderFlowThreadOffset; if (style()->isFlippedBlocksWritingMode()) { LayoutRect flippedRegionRect(regionRect); flipForWritingMode(flippedRegionRect); renderFlowThreadOffset = LayoutPoint(accumulatedOffset - flippedRegionRect.location()); } else renderFlowThreadOffset = LayoutPoint(accumulatedOffset - regionRect.location()); LayoutPoint transformedPoint(pointInContainer.x() - renderFlowThreadOffset.x(), pointInContainer.y() - renderFlowThreadOffset.y()); // Always ignore clipping, since the RenderFlowThread has nothing to do with the bounds of the FrameView. HitTestRequest newRequest(request.type() | HitTestRequest::IgnoreClipping); RenderRegion* oldRegion = result.region(); result.setRegion(region); LayoutPoint oldPoint = result.point(); result.setPoint(transformedPoint); bool isPointInsideFlowThread = layer()->hitTest(newRequest, result); result.setPoint(oldPoint); result.setRegion(oldRegion); // FIXME: Should we set result.m_localPoint back to the RenderRegion's coordinate space or leave it in the RenderFlowThread's coordinate // space? Right now it's staying in the RenderFlowThread's coordinate space, which may end up being ok. We will know more when we get around to // patching positionForPoint. return isPointInsideFlowThread; }
MouseRelatedEvent::MouseRelatedEvent(const AtomicString& eventType, bool canBubble, bool cancelable, PassRefPtr<AbstractView> abstractView, int detail, const LayoutPoint& screenLocation, const LayoutPoint& windowLocation, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool isSimulated) : UIEventWithKeyState(eventType, canBubble, cancelable, abstractView, detail, ctrlKey, altKey, shiftKey, metaKey) , m_screenLocation(screenLocation) , m_isSimulated(isSimulated) { LayoutPoint adjustedPageLocation; LayoutPoint scrollPosition; Frame* frame = view() ? view()->frame() : 0; if (frame && !isSimulated) { if (FrameView* frameView = frame->view()) { scrollPosition = frameView->scrollPosition(); adjustedPageLocation = frameView->windowToContents(windowLocation); float pageZoom = frame->pageZoomFactor(); if (pageZoom != 1.0f) { // Adjust our pageX and pageY to account for the page zoom. adjustedPageLocation.scale(1 / pageZoom, 1 / pageZoom); // FIXME: Change this to use float math and proper rounding (or // better yet, use LayoutPoint::scale). scrollPosition.setX(scrollPosition.x() / pageZoom); scrollPosition.setY(scrollPosition.y() / pageZoom); } } } m_clientLocation = adjustedPageLocation - toSize(scrollPosition); m_pageLocation = adjustedPageLocation; initCoordinates(); }
LayoutPoint RenderGrid::findChildLogicalPosition(RenderBox* child, const Vector<GridTrack>& columnTracks, const Vector<GridTrack>& rowTracks) { Length column = child->style()->gridItemColumn(); Length row = child->style()->gridItemRow(); // FIXME: What does a non-positive integer mean for a column/row? if (!column.isPositive() || !row.isPositive()) return LayoutPoint(); // FIXME: Handle other values for grid-{row,column} like ranges or line names. if (!column.isFixed() || !row.isFixed()) return LayoutPoint(); size_t columnTrack = static_cast<size_t>(column.intValue()) - 1; size_t rowTrack = static_cast<size_t>(row.intValue()) - 1; LayoutPoint offset; for (size_t i = 0; i < columnTrack && i < columnTracks.size(); ++i) offset.setX(offset.x() + columnTracks[i].m_usedBreadth); for (size_t i = 0; i < rowTrack && i < rowTracks.size(); ++i) offset.setY(offset.y() + rowTracks[i].m_usedBreadth); // FIXME: Handle margins on the grid item. return offset; }
void RenderWidget::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutPoint adjustedPaintOffset = paintOffset + location(); // Tell the widget to paint now. This is the only time the widget is allowed // to paint itself. That way it will composite properly with z-indexed layers. IntPoint widgetLocation = m_widget->frameRect().location(); IntPoint paintLocation(roundToInt(adjustedPaintOffset.x() + borderLeft() + paddingLeft()), roundToInt(adjustedPaintOffset.y() + borderTop() + paddingTop())); IntRect paintRect = paintInfo.rect; IntSize widgetPaintOffset = paintLocation - widgetLocation; // When painting widgets into compositing layers, tx and ty are relative to the enclosing compositing layer, // not the root. In this case, shift the CTM and adjust the paintRect to be root-relative to fix plug-in drawing. if (!widgetPaintOffset.isZero()) { paintInfo.context->translate(widgetPaintOffset); paintRect.move(-widgetPaintOffset); } m_widget->paint(paintInfo.context, paintRect); if (!widgetPaintOffset.isZero()) paintInfo.context->translate(-widgetPaintOffset); if (m_widget->isFrameView()) { FrameView* frameView = toFrameView(m_widget.get()); bool runOverlapTests = !frameView->useSlowRepaintsIfNotOverlapped() || frameView->hasCompositedContentIncludingDescendants(); if (paintInfo.overlapTestRequests && runOverlapTests) { ASSERT(!paintInfo.overlapTestRequests->contains(this)); paintInfo.overlapTestRequests->set(this, m_widget->frameRect()); } } }
void RenderFileUploadControl::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (style()->visibility() != VISIBLE) return; // Push a clip. GraphicsContextStateSaver stateSaver(*paintInfo.context, false); if (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseChildBlockBackgrounds) { IntRect clipRect = enclosingIntRect(LayoutRect(paintOffset.x() + borderLeft(), paintOffset.y() + borderTop(), width() - borderLeft() - borderRight(), height() - borderBottom() - borderTop() + buttonShadowHeight)); if (clipRect.isEmpty()) return; stateSaver.save(); paintInfo.context->clip(clipRect); } if (paintInfo.phase == PaintPhaseForeground) { const String& displayedFilename = fileTextValue(); const Font& font = style()->font(); TextRun textRun = constructTextRun(this, font, displayedFilename, style(), TextRun::AllowTrailingExpansion, RespectDirection | RespectDirectionOverride); textRun.disableRoundingHacks(); // Determine where the filename should be placed LayoutUnit contentLeft = paintOffset.x() + borderLeft() + paddingLeft(); HTMLInputElement* button = uploadButton(); if (!button) return; LayoutUnit buttonWidth = nodeWidth(button); LayoutUnit buttonAndSpacingWidth = buttonWidth + afterButtonSpacing; float textWidth = font.width(textRun); LayoutUnit textX; if (style()->isLeftToRightDirection()) textX = contentLeft + buttonAndSpacingWidth; else textX = contentLeft + contentWidth() - buttonAndSpacingWidth - textWidth; LayoutUnit textY = 0; // We want to match the button's baseline // FIXME: Make this work with transforms. if (RenderButton* buttonRenderer = toRenderButton(button->renderer())) textY = paintOffset.y() + borderTop() + paddingTop() + buttonRenderer->baselinePosition(AlphabeticBaseline, true, HorizontalLine, PositionOnContainingLine); else textY = baselinePosition(AlphabeticBaseline, true, HorizontalLine, PositionOnContainingLine); TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.bounds = FloatRect(textX, textY - style()->fontMetrics().ascent(), textWidth, style()->fontMetrics().height()); paintInfo.context->setFillColor(resolveColor(CSSPropertyColor)); // Draw the filename paintInfo.context->drawBidiText(font, textRunPaintInfo, IntPoint(roundToInt(textX), roundToInt(textY))); } // Paint the children. RenderBlockFlow::paintObject(paintInfo, paintOffset); }
void RenderView::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // If we ever require layout but receive a paint anyway, something has gone horribly wrong. ASSERT(!needsLayout()); // RenderViews should never be called to paint with an offset not on device pixels. ASSERT(LayoutPoint(IntPoint(paintOffset.x(), paintOffset.y())) == paintOffset); paintObject(paintInfo, paintOffset); }
LayoutRect RenderMenuList::controlClipRect(const LayoutPoint& additionalOffset) const { // Clip to the intersection of the content box and the content box for the inner box // This will leave room for the arrows which sit in the inner box padding, // and if the inner box ever spills out of the outer box, that will get clipped too. LayoutRect outerBox(additionalOffset.x() + borderLeft() + paddingLeft(), additionalOffset.y() + borderTop() + paddingTop(), contentWidth(), contentHeight()); LayoutRect innerBox(additionalOffset.x() + m_innerBlock->x() + m_innerBlock->paddingLeft(), additionalOffset.y() + m_innerBlock->y() + m_innerBlock->paddingTop(), m_innerBlock->contentWidth(), m_innerBlock->contentHeight()); return intersection(outerBox, innerBox); }