void RenderSVGText::layout() { ASSERT(needsLayout()); LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); bool updateCachedBoundariesInParents = false; if (m_needsTransformUpdate) { SVGTextElement* text = static_cast<SVGTextElement*>(node()); m_localTransform = text->animatedLocalTransform(); m_needsTransformUpdate = false; updateCachedBoundariesInParents = true; } if (m_needsPositioningValuesUpdate) { // Perform SVG text layout phase one (see SVGTextLayoutAttributesBuilder for details). SVGTextLayoutAttributesBuilder layoutAttributesBuilder; layoutAttributesBuilder.buildLayoutAttributesForTextSubtree(this); m_needsPositioningValuesUpdate = false; updateCachedBoundariesInParents = true; } // Reduced version of RenderBlock::layoutBlock(), which only takes care of SVG text. // All if branches that could cause early exit in RenderBlocks layoutBlock() method are turned into assertions. ASSERT(!isInline()); ASSERT(!layoutOnlyPositionedObjects()); ASSERT(!scrollsOverflow()); ASSERT(!hasControlClip()); ASSERT(!hasColumns()); ASSERT(!positionedObjects()); ASSERT(!m_overflow); ASSERT(!isAnonymousBlock()); if (!firstChild()) setChildrenInline(true); // FIXME: We need to find a way to only layout the child boxes, if needed. FloatRect oldBoundaries = objectBoundingBox(); ASSERT(childrenInline()); forceLayoutInlineChildren(); if (!updateCachedBoundariesInParents) updateCachedBoundariesInParents = oldBoundaries != objectBoundingBox(); // Invalidate all resources of this client if our layout changed. if (m_everHadLayout && selfNeedsLayout()) SVGResourcesCache::clientLayoutChanged(this); // If our bounds changed, notify the parents. if (updateCachedBoundariesInParents) RenderSVGBlock::setNeedsBoundariesUpdate(); repainter.repaintAfterLayout(); setNeedsLayout(false); }
bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) { // Give RenderSVGViewportContainer a chance to apply its viewport clip if (!pointIsInsideViewportClip(pointInParent)) return false; FloatPoint localPoint; if (!SVGRenderSupport::transformToUserSpaceAndCheckClipping(this, localToParentTransform(), pointInParent, localPoint)) return false; for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) { updateHitTestResult(result, roundedLayoutPoint(localPoint)); return true; } } // pointer-events=boundingBox makes it possible for containers to be direct targets if (style()->pointerEvents() == PE_BOUNDINGBOX) { ASSERT(isObjectBoundingBoxValid()); if (objectBoundingBox().contains(localPoint)) { updateHitTestResult(result, roundedLayoutPoint(localPoint)); return true; } } // 16.4: "If there are no graphics elements whose relevant graphics content is under the pointer (i.e., there is no target element), the event is not dispatched." return false; }
FloatRect RenderSVGText::strokeBoundingBox() const { FloatRect strokeBoundaries = objectBoundingBox(); const SVGRenderStyle& svgStyle = style().svgStyle(); if (!svgStyle.hasStroke()) return strokeBoundaries; SVGLengthContext lengthContext(&textElement()); strokeBoundaries.inflate(lengthContext.valueForLength(svgStyle.strokeWidth())); return strokeBoundaries; }
FloatRect RenderSVGText::strokeBoundingBox() const { FloatRect strokeBoundaries = objectBoundingBox(); const SVGRenderStyle* svgStyle = style()->svgStyle(); if (!svgStyle->hasStroke()) return strokeBoundaries; ASSERT(node()); ASSERT(node()->isSVGElement()); strokeBoundaries.inflate(svgStyle->strokeWidth().value(static_cast<SVGElement*>(node()))); return strokeBoundaries; }
void LayoutSVGShape::layout() { LayoutAnalyzer::Scope analyzer(*this); // Invalidate all resources of this client if our layout changed. if (everHadLayout() && selfNeedsLayout()) SVGResourcesCache::clientLayoutChanged(this); bool updateParentBoundaries = false; // updateShapeFromElement() also updates the object & stroke bounds - which // feeds into the visual rect - so we need to call it for both the // shape-update and the bounds-update flag. if (m_needsShapeUpdate || m_needsBoundariesUpdate) { FloatRect oldObjectBoundingBox = objectBoundingBox(); updateShapeFromElement(); if (oldObjectBoundingBox != objectBoundingBox()) setShouldDoFullPaintInvalidation(); m_needsShapeUpdate = false; m_localVisualRect = strokeBoundingBox(); SVGLayoutSupport::adjustVisualRectWithResources(this, m_localVisualRect); m_needsBoundariesUpdate = false; updateParentBoundaries = true; } if (m_needsTransformUpdate) { updateLocalTransform(); m_needsTransformUpdate = false; updateParentBoundaries = true; } // If our bounds changed, notify the parents. if (updateParentBoundaries) LayoutSVGModelObject::setNeedsBoundariesUpdate(); ASSERT(!m_needsShapeUpdate); ASSERT(!m_needsBoundariesUpdate); ASSERT(!m_needsTransformUpdate); clearNeedsLayout(); }
bool RenderSVGText::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) { PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, request, style()->pointerEvents()); bool isVisible = (style()->visibility() == VISIBLE); if (isVisible || !hitRules.requireVisible) { if ((hitRules.canHitBoundingBox && !objectBoundingBox().isEmpty()) || (hitRules.canHitStroke && (style()->svgStyle()->hasStroke() || !hitRules.requireStroke)) || (hitRules.canHitFill && (style()->svgStyle()->hasFill() || !hitRules.requireFill))) { FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); if (!SVGRenderSupport::pointInClippingArea(this, localPoint)) return false; if (hitRules.canHitBoundingBox && !objectBoundingBox().contains(localPoint)) return false; HitTestLocation hitTestLocation(LayoutPoint(flooredIntPoint(localPoint))); return RenderBlock::nodeAtPoint(request, result, hitTestLocation, LayoutPoint(), hitTestAction); } } return false; }
FloatRect LayoutSVGText::strokeBoundingBox() const { FloatRect strokeBoundaries = objectBoundingBox(); const SVGComputedStyle& svgStyle = style()->svgStyle(); if (!svgStyle.hasStroke()) return strokeBoundaries; ASSERT(node()); ASSERT(node()->isSVGElement()); SVGLengthContext lengthContext(toSVGElement(node())); strokeBoundaries.inflate(lengthContext.valueForLength(svgStyle.strokeWidth())); return strokeBoundaries; }
bool LayoutSVGText::nodeAtFloatPoint(HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) { PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, result.hitTestRequest(), style()->pointerEvents()); bool isVisible = (style()->visibility() == VISIBLE); if (isVisible || !hitRules.requireVisible) { if ((hitRules.canHitBoundingBox && !objectBoundingBox().isEmpty()) || (hitRules.canHitStroke && (style()->svgStyle().hasStroke() || !hitRules.requireStroke)) || (hitRules.canHitFill && (style()->svgStyle().hasFill() || !hitRules.requireFill))) { FloatPoint localPoint; if (!SVGLayoutSupport::transformToUserSpaceAndCheckClipping(this, localToParentTransform(), pointInParent, localPoint)) return false; if (hitRules.canHitBoundingBox && !objectBoundingBox().contains(localPoint)) return false; HitTestLocation hitTestLocation(LayoutPoint(flooredIntPoint(localPoint))); return LayoutBlock::nodeAtPoint(result, hitTestLocation, LayoutPoint(), hitTestAction); } } return false; }
FloatRect RenderSVGText::strokeBoundingBox() const { FloatRect strokeBoundaries = objectBoundingBox(); const SVGRenderStyle* svgStyle = style()->svgStyle(); if (!svgStyle->hasStroke()) return strokeBoundaries; ASSERT(node()); ASSERT(node()->isSVGElement()); SVGLengthContext lengthContext(toSVGElement(node())); strokeBoundaries.inflate(svgStyle->strokeWidth().value(lengthContext)); return strokeBoundaries; }
bool LayoutSVGShape::nodeAtFloatPointInternal(const HitTestRequest& request, const FloatPoint& localPoint, PointerEventsHitRules hitRules) { bool isVisible = (style()->visibility() == VISIBLE); if (isVisible || !hitRules.requireVisible) { const SVGComputedStyle& svgStyle = style()->svgStyle(); WindRule fillRule = svgStyle.fillRule(); if (request.svgClipContent()) fillRule = svgStyle.clipRule(); if ((hitRules.canHitBoundingBox && objectBoundingBox().contains(localPoint)) || (hitRules.canHitStroke && (svgStyle.hasStroke() || !hitRules.requireStroke) && strokeContains(localPoint, hitRules.requireStroke)) || (hitRules.canHitFill && (svgStyle.hasFill() || !hitRules.requireFill) && fillContains(localPoint, hitRules.requireFill, fillRule))) return true; } return false; }
vector<Event> Eventgen::checkForEvents() { vector<Event> to_trigger; for(const auto& group : m_grouped_event_boxes) { ///////////////////////////////// //check if the group has the "single" property bool single = false; map<string, string>::const_iterator pip = group.properties.find(PROPERTY_GROUP_SINGLE_IDENTIFIER); if(pip != group.properties.end() && pip->second == "true") { single = true; } for (const auto& object : group.objects) { //TODO: optimize map translation SDL_Rect objectBoundingBox(object.bbox); objectBoundingBox.y += mViewport.h - (mMap->getTileMap().height * mMap->getTileMap().tileheight); if (SDL_HasIntersection(&objectBoundingBox, &mPlayerBoundingBox)) { Event event; event.groupname = group.name; event.objectname = object.name; if(single) { auto singleIterator = std::find(m_triggered_single_events.begin(), m_triggered_single_events.end(), event); if(singleIterator != m_triggered_single_events.end()) { LogDebug("Not triggering single event again: " << object.name); continue; } else { m_triggered_single_events.push_back(event); } } LogDebug("Triggering event for object: " << object.name); to_trigger.push_back(event); } } } return to_trigger; }
FloatRect RenderPath::strokeBoundingBox() const { if (m_path.isEmpty()) return FloatRect(); if (!m_cachedLocalStrokeBBox.isEmpty()) return m_cachedLocalStrokeBBox; m_cachedLocalStrokeBBox = objectBoundingBox(); if (style()->svgStyle()->hasStroke()) { BoundingRectStrokeStyleApplier strokeStyle(this, style()); m_cachedLocalStrokeBBox.unite(m_path.strokeBoundingRect(&strokeStyle)); } return m_cachedLocalStrokeBBox; }
bool LayoutSVGContainer::nodeAtFloatPoint(HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) { // Give LayoutSVGViewportContainer a chance to apply its viewport clip if (!pointIsInsideViewportClip(pointInParent)) return false; FloatPoint localPoint; if (!SVGLayoutSupport::transformToUserSpaceAndCheckClipping( *this, localToSVGParentTransform(), pointInParent, localPoint)) return false; for (LayoutObject* child = lastChild(); child; child = child->previousSibling()) { if (child->nodeAtFloatPoint(result, localPoint, hitTestAction)) { const LayoutPoint& localLayoutPoint = roundedLayoutPoint(localPoint); updateHitTestResult(result, localLayoutPoint); if (result.addNodeToListBasedTestResult( child->node(), localLayoutPoint) == StopHitTesting) return true; } } // pointer-events: bounding-box makes it possible for containers to be direct // targets. if (style()->pointerEvents() == PE_BOUNDINGBOX) { // Check for a valid bounding box because it will be invalid for empty // containers. if (isObjectBoundingBoxValid() && objectBoundingBox().contains(localPoint)) { const LayoutPoint& localLayoutPoint = roundedLayoutPoint(localPoint); updateHitTestResult(result, localLayoutPoint); if (result.addNodeToListBasedTestResult(element(), localLayoutPoint) == StopHitTesting) return true; } } // 16.4: "If there are no graphics elements whose relevant graphics content is // under the pointer (i.e., there is no target element), the event is not // dispatched." return false; }
FloatRect RenderPath::repaintRectInLocalCoordinates() const { if (m_path.isEmpty()) return FloatRect(); // If we already have a cached repaint rect, return that if (!m_cachedLocalRepaintRect.isEmpty()) return m_cachedLocalRepaintRect; if (!style()->svgStyle()->hasStroke()) m_cachedLocalRepaintRect = objectBoundingBox(); else { BoundingRectStrokeStyleApplier strokeStyle(this, style()); m_cachedLocalRepaintRect = m_path.strokeBoundingRect(&strokeStyle); } // Markers and filters can paint outside of the stroke path m_cachedLocalRepaintRect.unite(m_markerBounds); m_cachedLocalRepaintRect.unite(filterBoundingBoxForRenderer(this)); return m_cachedLocalRepaintRect; }
FloatRect RenderSVGText::strokeBoundingBox() const { FloatRect repaintRect = objectBoundingBox(); // SVG needs to include the strokeWidth(), not the textStrokeWidth(). if (style()->svgStyle()->hasStroke()) { float strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, style()->svgStyle()->strokeWidth(), 1.0f); #if ENABLE(SVG_FONTS) const Font& font = style()->font(); if (font.primaryFont()->isSVGFont()) { float scale = font.unitsPerEm() > 0 ? font.size() / font.unitsPerEm() : 0.0f; if (scale != 0.0f) strokeWidth /= scale; } #endif repaintRect.inflate(strokeWidth); } return repaintRect; }
void LayoutSVGText::layout() { ASSERT(needsLayout()); LayoutAnalyzer::Scope analyzer(*this); subtreeStyleDidChange(); bool updateCachedBoundariesInParents = false; if (m_needsTransformUpdate) { m_localTransform = toSVGTextElement(node())->calculateAnimatedLocalTransform(); m_needsTransformUpdate = false; updateCachedBoundariesInParents = true; } if (!everHadLayout()) { // When laying out initially, collect all layout attributes, build the character data map, // and propogate resulting SVGLayoutAttributes to all LayoutSVGInlineText children in the subtree. ASSERT(m_layoutAttributes.isEmpty()); collectLayoutAttributes(this, m_layoutAttributes); updateFontInAllDescendants(this); m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(*this); m_needsReordering = true; m_needsTextMetricsUpdate = false; m_needsPositioningValuesUpdate = false; updateCachedBoundariesInParents = true; } else if (m_needsPositioningValuesUpdate) { // When the x/y/dx/dy/rotate lists change, recompute the layout attributes, and eventually // update the on-screen font objects as well in all descendants. if (m_needsTextMetricsUpdate) { updateFontInAllDescendants(this); m_needsTextMetricsUpdate = false; } m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(*this); m_needsReordering = true; m_needsPositioningValuesUpdate = false; updateCachedBoundariesInParents = true; } else if (m_needsTextMetricsUpdate || SVGLayoutSupport::findTreeRootObject(this)->isLayoutSizeChanged()) { // If the root layout size changed (eg. window size changes) or the transform to the root // context has changed then recompute the on-screen font size. updateFontInAllDescendants(this, &m_layoutAttributesBuilder); ASSERT(!m_needsReordering); ASSERT(!m_needsPositioningValuesUpdate); m_needsTextMetricsUpdate = false; updateCachedBoundariesInParents = true; } checkLayoutAttributesConsistency(this, m_layoutAttributes); // Reduced version of LayoutBlock::layoutBlock(), which only takes care of SVG text. // All if branches that could cause early exit in LayoutBlocks layoutBlock() method are turned into assertions. ASSERT(!isInline()); ASSERT(!simplifiedLayout()); ASSERT(!scrollsOverflow()); ASSERT(!hasControlClip()); ASSERT(!positionedObjects()); ASSERT(!isAnonymousBlock()); if (!firstChild()) setChildrenInline(true); // FIXME: We need to find a way to only layout the child boxes, if needed. FloatRect oldBoundaries = objectBoundingBox(); ASSERT(childrenInline()); rebuildFloatsFromIntruding(); LayoutUnit beforeEdge = borderBefore() + paddingBefore(); LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight(); setLogicalHeight(beforeEdge); LayoutState state(*this, locationOffset()); LayoutUnit paintInvalidationLogicalTop = 0; LayoutUnit paintInvalidationLogicalBottom = 0; layoutInlineChildren(true, paintInvalidationLogicalTop, paintInvalidationLogicalBottom, afterEdge); if (m_needsReordering) m_needsReordering = false; // If we don't have any line boxes, then make sure the frame rect is still cleared. if (!firstLineBox()) setFrameRect(LayoutRect()); m_overflow.clear(); addVisualEffectOverflow(); if (!updateCachedBoundariesInParents) updateCachedBoundariesInParents = oldBoundaries != objectBoundingBox(); // Invalidate all resources of this client if our layout changed. if (everHadLayout() && selfNeedsLayout()) SVGResourcesCache::clientLayoutChanged(this); // If our bounds changed, notify the parents. if (updateCachedBoundariesInParents) LayoutSVGBlock::setNeedsBoundariesUpdate(); clearNeedsLayout(); }
void RenderSVGText::layout() { ASSERT(needsLayout()); LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); bool updateCachedBoundariesInParents = false; if (m_needsTransformUpdate) { SVGTextElement* text = static_cast<SVGTextElement*>(node()); m_localTransform = text->animatedLocalTransform(); m_needsTransformUpdate = false; updateCachedBoundariesInParents = true; } // If the root layout size changed (eg. window size changes) or the positioning values change // or the transform to the root context has changed then recompute the on-screen font size. if (m_needsTextMetricsUpdate || SVGRenderSupport::findTreeRootObject(this)->isLayoutSizeChanged()) { recursiveUpdateScaledFont(this); rebuildLayoutAttributes(true); updateCachedBoundariesInParents = true; m_needsTextMetricsUpdate = false; } if (m_needsPositioningValuesUpdate) { // Perform SVG text layout phase one (see SVGTextLayoutAttributesBuilder for details). m_layoutAttributesBuilder.buildLayoutAttributesForWholeTree(this); m_needsReordering = true; m_needsPositioningValuesUpdate = false; updateCachedBoundariesInParents = true; } // Reduced version of RenderBlock::layoutBlock(), which only takes care of SVG text. // All if branches that could cause early exit in RenderBlocks layoutBlock() method are turned into assertions. ASSERT(!isInline()); ASSERT(!simplifiedLayout()); ASSERT(!scrollsOverflow()); ASSERT(!hasControlClip()); ASSERT(!hasColumns()); ASSERT(!positionedObjects()); ASSERT(!m_overflow); ASSERT(!isAnonymousBlock()); if (!firstChild()) setChildrenInline(true); // FIXME: We need to find a way to only layout the child boxes, if needed. FloatRect oldBoundaries = objectBoundingBox(); ASSERT(childrenInline()); forceLayoutInlineChildren(); if (m_needsReordering) m_needsReordering = false; if (!updateCachedBoundariesInParents) updateCachedBoundariesInParents = oldBoundaries != objectBoundingBox(); // Invalidate all resources of this client if our layout changed. if (everHadLayout() && selfNeedsLayout()) SVGResourcesCache::clientLayoutChanged(this); // If our bounds changed, notify the parents. if (updateCachedBoundariesInParents) RenderSVGBlock::setNeedsBoundariesUpdate(); repainter.repaintAfterLayout(); setNeedsLayout(false); }
void RenderSVGText::layout() { StackStats::LayoutCheckPoint layoutCheckPoint; ASSERT(needsLayout()); LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(*this)); bool updateCachedBoundariesInParents = false; if (m_needsTransformUpdate) { m_localTransform = textElement().animatedLocalTransform(); m_needsTransformUpdate = false; updateCachedBoundariesInParents = true; } if (!everHadLayout()) { // When laying out initially, collect all layout attributes, build the character data map, // and propogate resulting SVGLayoutAttributes to all RenderSVGInlineText children in the subtree. ASSERT(m_layoutAttributes.isEmpty()); collectLayoutAttributes(this, m_layoutAttributes); updateFontInAllDescendants(this); m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(*this); m_needsReordering = true; m_needsTextMetricsUpdate = false; m_needsPositioningValuesUpdate = false; updateCachedBoundariesInParents = true; } else if (m_needsPositioningValuesUpdate) { // When the x/y/dx/dy/rotate lists change, recompute the layout attributes, and eventually // update the on-screen font objects as well in all descendants. if (m_needsTextMetricsUpdate) { updateFontInAllDescendants(this); m_needsTextMetricsUpdate = false; } m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(*this); m_needsReordering = true; m_needsPositioningValuesUpdate = false; updateCachedBoundariesInParents = true; } else if (m_needsTextMetricsUpdate || SVGRenderSupport::findTreeRootObject(*this).isLayoutSizeChanged()) { // If the root layout size changed (eg. window size changes) or the transform to the root // context has changed then recompute the on-screen font size. updateFontInAllDescendants(this, &m_layoutAttributesBuilder); ASSERT(!m_needsReordering); ASSERT(!m_needsPositioningValuesUpdate); m_needsTextMetricsUpdate = false; updateCachedBoundariesInParents = true; } checkLayoutAttributesConsistency(this, m_layoutAttributes); // Reduced version of RenderBlock::layoutBlock(), which only takes care of SVG text. // All if branches that could cause early exit in RenderBlocks layoutBlock() method are turned into assertions. ASSERT(!isInline()); ASSERT(!simplifiedLayout()); ASSERT(!scrollsOverflow()); ASSERT(!hasControlClip()); ASSERT(!multiColumnFlowThread()); ASSERT(!positionedObjects()); ASSERT(!m_overflow); ASSERT(!isAnonymousBlock()); if (!firstChild()) setChildrenInline(true); // FIXME: We need to find a way to only layout the child boxes, if needed. FloatRect oldBoundaries = objectBoundingBox(); ASSERT(childrenInline()); LayoutUnit repaintLogicalTop = 0; LayoutUnit repaintLogicalBottom = 0; rebuildFloatingObjectSetFromIntrudingFloats(); layoutInlineChildren(true, repaintLogicalTop, repaintLogicalBottom); if (m_needsReordering) m_needsReordering = false; if (!updateCachedBoundariesInParents) updateCachedBoundariesInParents = oldBoundaries != objectBoundingBox(); // Invalidate all resources of this client if our layout changed. if (everHadLayout() && selfNeedsLayout()) SVGResourcesCache::clientLayoutChanged(*this); // If our bounds changed, notify the parents. if (updateCachedBoundariesInParents) RenderSVGBlock::setNeedsBoundariesUpdate(); repainter.repaintAfterLayout(); clearNeedsLayout(); }