bool SVGGraphicsElement::hasAnimatedLocalTransform() const { const ComputedStyle* style = layoutObject() ? layoutObject()->style() : nullptr; // Each of these is used in SVGGraphicsElement::calculateAnimatedLocalTransform to create an animated local transform. return (style && style->hasTransform()) || !m_transform->currentValue()->isEmpty() || hasSVGRareData(); }
void InlineBox::adjustPosition(FloatWillBeLayoutUnit dx, FloatWillBeLayoutUnit dy) { m_topLeft.move(dx, dy); if (layoutObject().isReplaced()) toLayoutBox(layoutObject()).move(dx, dy); }
bool SVGInlineTextBox::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit, LayoutUnit) { // FIXME: integrate with InlineTextBox::nodeAtPoint better. ASSERT(!isLineBreak()); PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, result.hitTestRequest(), layoutObject().style()->pointerEvents()); bool isVisible = layoutObject().style()->visibility() == VISIBLE; if (isVisible || !hitRules.requireVisible) { if (hitRules.canHitBoundingBox || (hitRules.canHitStroke && (layoutObject().style()->svgStyle().hasStroke() || !hitRules.requireStroke)) || (hitRules.canHitFill && (layoutObject().style()->svgStyle().hasFill() || !hitRules.requireFill))) { FloatPointWillBeLayoutPoint boxOrigin(x(), y()); boxOrigin.moveBy(accumulatedOffset); FloatRectWillBeLayoutRect rect(boxOrigin, size()); // FIXME: both calls to rawValue() below is temporary and should be removed once the transition // to LayoutUnit-based types is complete (crbug.com/321237) if (locationInContainer.intersects(rect.rawValue())) { layoutObject().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); if (!result.addNodeToListBasedTestResult(layoutObject().node(), locationInContainer, rect.rawValue())) return true; } } } return false; }
void SVGPathElement::svgAttributeChanged(const QualifiedName& attrName) { if (attrName == SVGNames::dAttr) { SVGElement::InvalidationGuard invalidationGuard(this); invalidateSVGPresentationAttributeStyle(); setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::fromAttribute(attrName)); if (LayoutSVGShape* layoutPath = toLayoutSVGShape(this->layoutObject())) layoutPath->setNeedsShapeUpdate(); invalidateMPathDependencies(); if (layoutObject()) markForLayoutAndParentResourceInvalidation(layoutObject()); return; } if (attrName == SVGNames::pathLengthAttr) { SVGElement::InvalidationGuard invalidationGuard(this); if (layoutObject()) markForLayoutAndParentResourceInvalidation(layoutObject()); return; } SVGGeometryElement::svgAttributeChanged(attrName); }
RawPtr<Text> Text::splitText(unsigned offset, ExceptionState& exceptionState) { // IndexSizeError: Raised if the specified offset is negative or greater than // the number of 16-bit units in data. if (offset > length()) { exceptionState.throwDOMException(IndexSizeError, "The offset " + String::number(offset) + " is larger than the Text node's length."); return nullptr; } EventQueueScope scope; String oldStr = data(); RawPtr<Text> newText = cloneWithData(oldStr.substring(offset)); setDataWithoutUpdate(oldStr.substring(0, offset)); didModifyData(oldStr, CharacterData::UpdateFromNonParser); if (parentNode()) parentNode()->insertBefore(newText.get(), nextSibling(), exceptionState); if (exceptionState.hadException()) return nullptr; if (layoutObject()) layoutObject()->setTextWithOffset(dataImpl(), 0, oldStr.length()); if (parentNode()) document().didSplitTextNode(*this); return newText.release(); }
void SVGGeometryElement::toClipPath(Path& path) const { path = asPath(); path.transform(calculateAnimatedLocalTransform()); ASSERT(layoutObject()); ASSERT(layoutObject()->style()); path.setWindRule(layoutObject()->style()->svgStyle().clipRule()); }
void SliderThumbElement::setPositionFromValue() { // Since the code to calculate position is in the LayoutSliderThumb layout // path, we don't actually update the value here. Instead, we poke at the // renderer directly to trigger layout. if (layoutObject()) layoutObject()->setNeedsLayoutAndFullPaintInvalidation(LayoutInvalidationReason::SliderValueChanged); }
void HTMLTextAreaElement::defaultEventHandler(Event* event) { if (layoutObject() && (event->isMouseEvent() || event->isDragEvent() || event->hasInterface(EventNames::WheelEvent) || event->type() == EventTypeNames::blur)) forwardEvent(event); else if (layoutObject() && event->isBeforeTextInsertedEvent()) handleBeforeTextInsertedEvent(static_cast<BeforeTextInsertedEvent*>(event)); HTMLTextFormControlElement::defaultEventHandler(event); }
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); }
bool HTMLTextFormControlElement::placeholderShouldBeVisible() const { return supportsPlaceholder() && isEmptyValue() && isEmptySuggestedValue() && !isPlaceholderEmpty() && (document().focusedElement() != this || (LayoutTheme::theme().shouldShowPlaceholderWhenFocused())) && (!layoutObject() || layoutObject()->style()->visibility() == VISIBLE); }
void HTMLTextAreaElement::parseAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& value) { if (name == rowsAttr) { unsigned rows = 0; if (value.isEmpty() || !parseHTMLNonNegativeInteger(value, rows) || rows <= 0) rows = defaultRows; if (m_rows != rows) { m_rows = rows; if (layoutObject()) layoutObject() ->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation( LayoutInvalidationReason::AttributeChanged); } } else if (name == colsAttr) { unsigned cols = 0; if (value.isEmpty() || !parseHTMLNonNegativeInteger(value, cols) || cols <= 0) cols = defaultCols; if (m_cols != cols) { m_cols = cols; if (LayoutObject* layoutObject = this->layoutObject()) layoutObject->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation( LayoutInvalidationReason::AttributeChanged); } } else if (name == wrapAttr) { // The virtual/physical values were a Netscape extension of HTML 3.0, now // deprecated. The soft/hard /off values are a recommendation for HTML 4 // extension by IE and NS 4. WrapMethod wrap; if (equalIgnoringCase(value, "physical") || equalIgnoringCase(value, "hard") || equalIgnoringCase(value, "on")) wrap = HardWrap; else if (equalIgnoringCase(value, "off")) wrap = NoWrap; else wrap = SoftWrap; if (wrap != m_wrap) { m_wrap = wrap; if (LayoutObject* layoutObject = this->layoutObject()) layoutObject->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation( LayoutInvalidationReason::AttributeChanged); } } else if (name == accesskeyAttr) { // ignore for the moment } else if (name == maxlengthAttr) { UseCounter::count(document(), UseCounter::TextAreaMaxLength); setNeedsValidityCheck(); } else if (name == minlengthAttr) { UseCounter::count(document(), UseCounter::TextAreaMinLength); setNeedsValidityCheck(); } else { HTMLTextFormControlElement::parseAttribute(name, oldValue, value); } }
FloatRect SVGGraphicsElement::getBBox() { document().updateStyleAndLayoutIgnorePendingStylesheets(); // FIXME: Eventually we should support getBBox for detached elements. if (!layoutObject()) return FloatRect(); return layoutObject()->objectBoundingBox(); }
void InlineBox::showBox(int printedCharacters) const { printedCharacters += fprintf(stderr, "%s %p", boxName(), this); for (; printedCharacters < showTreeCharacterOffset; printedCharacters++) fputc(' ', stderr); fprintf(stderr, "\t%s %p {pos=%g,%g size=%g,%g} baseline=%i/%i\n", layoutObject().decoratedName().ascii().data(), &layoutObject(), x().toFloat(), y().toFloat(), width().toFloat(), height().toFloat(), baselinePosition(AlphabeticBaseline), baselinePosition(IdeographicBaseline)); }
inline void HTMLLIElement::parseValue(const AtomicString& value) { DCHECK(layoutObject()); DCHECK(layoutObject()->isListItem()); bool valueOK; int requestedValue = value.toInt(&valueOK); if (valueOK) toLayoutListItem(layoutObject())->setExplicitValue(requestedValue); else toLayoutListItem(layoutObject())->clearExplicitValue(); }
void SliderThumbElement::stopDragging() { if (!m_inDragMode) return; if (LocalFrame* frame = document().frame()) frame->eventHandler().setCapturingMouseEventsNode(nullptr); m_inDragMode = false; if (layoutObject()) layoutObject()->setNeedsLayoutAndFullPaintInvalidation(LayoutInvalidationReason::SliderValueChanged); if (hostInput()) hostInput()->dispatchFormControlChangeEvent(); }
FloatSize SVGSVGElement::currentViewportSize() const { if (!layoutObject()) return FloatSize(); if (layoutObject()->isSVGRoot()) { LayoutRect contentBoxRect = toLayoutSVGRoot(layoutObject())->contentBoxRect(); return FloatSize(contentBoxRect.width() / layoutObject()->style()->effectiveZoom(), contentBoxRect.height() / layoutObject()->style()->effectiveZoom()); } FloatRect viewportRect = toLayoutSVGViewportContainer(layoutObject())->viewport(); return FloatSize(viewportRect.width(), viewportRect.height()); }
bool SVGGeometryElement::isPointInStroke(PassRefPtrWillBeRawPtr<SVGPointTearOff> point) const { document().updateLayoutIgnorePendingStylesheets(); // FIXME: Eventually we should support isPointInStroke for display:none elements. if (!layoutObject() || !layoutObject()->isSVGShape()) return false; HitTestRequest request(HitTestRequest::ReadOnly); PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_GEOMETRY_HITTESTING, request, layoutObject()->style()->pointerEvents()); hitRules.canHitFill = false; return toLayoutSVGShape(layoutObject())->nodeAtFloatPointInternal(request, point->target()->value(), hitRules); }
void HTMLElement::adjustDirectionalityIfNeededAfterChildAttributeChanged(Element* child) { ASSERT(selfOrAncestorHasDirAutoAttribute()); TextDirection textDirection = directionality(); if (layoutObject() && layoutObject()->style() && layoutObject()->style()->direction() != textDirection) { Element* elementToAdjust = this; for (; elementToAdjust; elementToAdjust = ComposedTreeTraversal::parentElement(*elementToAdjust)) { if (elementAffectsDirectionality(elementToAdjust)) { elementToAdjust->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::WritingModeChange)); return; } } } }
void HTMLFrameElement::parseAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& value) { if (name == frameborderAttr) { m_frameBorder = value.toInt(); m_frameBorderSet = !value.isNull(); // FIXME: If we are already attached, this has no effect. } else if (name == noresizeAttr) { if (layoutObject()) layoutObject()->updateFromElement(); } else { HTMLFrameElementBase::parseAttribute(name, oldValue, value); } }
void SVGSVGElement::svgAttributeChanged(const QualifiedName& attrName) { bool updateRelativeLengthsOrViewBox = false; bool widthChanged = attrName == SVGNames::widthAttr; bool heightChanged = attrName == SVGNames::heightAttr; if (widthChanged || heightChanged || attrName == SVGNames::xAttr || attrName == SVGNames::yAttr) { updateRelativeLengthsOrViewBox = true; updateRelativeLengthsInformation(); invalidateRelativeLengthClients(); // At the SVG/HTML boundary (aka LayoutSVGRoot), the width and // height attributes can affect the replaced size so we need // to mark it for updating. // // FIXME: For width/height animated as XML attributes on SVG // roots, there is an attribute synchronization missing. See // http://crbug.com/364807 if (widthChanged || heightChanged) { LayoutObject* layoutObject = this->layoutObject(); if (layoutObject && layoutObject->isSVGRoot()) { invalidateSVGPresentationAttributeStyle(); setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::SVGContainerSizeChange)); } } else { invalidateSVGPresentationAttributeStyle(); setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::fromAttribute(attrName)); } } if (SVGFitToViewBox::isKnownAttribute(attrName)) { updateRelativeLengthsOrViewBox = true; invalidateRelativeLengthClients(); if (LayoutObject* object = layoutObject()) object->setNeedsTransformUpdate(); } if (updateRelativeLengthsOrViewBox || SVGZoomAndPan::isKnownAttribute(attrName)) { SVGElement::InvalidationGuard invalidationGuard(this); if (layoutObject()) markForLayoutAndParentResourceInvalidation(layoutObject()); return; } SVGGraphicsElement::svgAttributeChanged(attrName); }
void HTMLTextAreaElement::handleBeforeTextInsertedEvent( BeforeTextInsertedEvent* event) const { DCHECK(event); DCHECK(layoutObject()); int signedMaxLength = maxLength(); if (signedMaxLength < 0) return; unsigned unsignedMaxLength = static_cast<unsigned>(signedMaxLength); const String& currentValue = innerEditorValue(); unsigned currentLength = computeLengthForAPIValue(currentValue); if (currentLength + computeLengthForAPIValue(event->text()) < unsignedMaxLength) return; // selectionLength represents the selection length of this text field to be // removed by this insertion. // If the text field has no focus, we don't need to take account of the // selection length. The selection is the source of text drag-and-drop in // that case, and nothing in the text field will be removed. unsigned selectionLength = 0; if (isFocused()) { // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets // needs to be audited. See http://crbug.com/590369 for more details. document().updateStyleAndLayoutIgnorePendingStylesheets(); selectionLength = computeLengthForAPIValue( document().frame()->selection().selectedText()); } DCHECK_GE(currentLength, selectionLength); unsigned baseLength = currentLength - selectionLength; unsigned appendableLength = unsignedMaxLength > baseLength ? unsignedMaxLength - baseLength : 0; event->setText(sanitizeUserInputValue(event->text(), appendableLength)); }
void PseudoElement::attach(const AttachContext& context) { ASSERT(!layoutObject()); Element::attach(context); LayoutObject* renderer = this->layoutObject(); if (!renderer) return; ComputedStyle& style = renderer->mutableStyleRef(); if (style.styleType() != BEFORE && style.styleType() != AFTER) return; ASSERT(style.contentData()); for (const ContentData* content = style.contentData(); content; content = content->next()) { LayoutObject* child = content->createLayoutObject(document(), style); if (renderer->isChildAllowed(child, style)) { renderer->addChild(child); if (child->isQuote()) toLayoutQuote(child)->attachQuote(); } else child->destroy(); } }
PassOwnPtr<FloatingObject> FloatingObject::unsafeClone() const { OwnPtr<FloatingObject> cloneObject = adoptPtr(new FloatingObject(layoutObject(), type(), m_frameRect, static_cast<Ownership>(m_ownership), false)); cloneObject->m_paginationStrut = m_paginationStrut; cloneObject->m_isPlaced = m_isPlaced; return cloneObject.release(); }
void InlineBox::move(const LayoutSize& delta) { m_topLeft.move(delta); if (lineLayoutItem().isReplaced()) toLayoutBox(layoutObject()).move(delta.width(), delta.height()); }
void NodeRareData::finalizeGarbageCollectedObject() { RELEASE_ASSERT(!layoutObject()); if (m_isElementRareData) static_cast<ElementRareData*>(this)->~ElementRareData(); else this->~NodeRareData(); }
void Text::reattachIfNeeded(const AttachContext& context) { bool layoutObjectIsNeeded = false; ContainerNode* layoutParent = LayoutTreeBuilderTraversal::parent(*this); if (layoutParent) { if (LayoutObject* parentLayoutObject = layoutParent->layoutObject()) { if (textLayoutObjectIsNeeded(*parentLayoutObject->style(), *parentLayoutObject)) layoutObjectIsNeeded = true; } } if (layoutObjectIsNeeded == !!layoutObject()) return; // The following is almost the same as Node::reattach() except that we create a layoutObject only if needed. // Not calling reattach() to avoid repeated calls to Text::textLayoutObjectIsNeeded(). AttachContext reattachContext(context); reattachContext.performingReattach = true; if (getStyleChangeType() < NeedsReattachStyleChange) detach(reattachContext); if (layoutObjectIsNeeded) LayoutTreeBuilderForText(*this, layoutParent->layoutObject()).createLayoutObject(); CharacterData::attach(reattachContext); }
std::unique_ptr<FloatingObject> FloatingObject::unsafeClone() const { std::unique_ptr<FloatingObject> cloneObject = WTF::wrapUnique(new FloatingObject(layoutObject(), getType(), m_frameRect, m_shouldPaint, m_isDescendant, false)); cloneObject->m_isPlaced = m_isPlaced; return cloneObject; }
void HTMLTextFormControlElement::setInnerEditorValue(const String& value) { ASSERT(!openShadowRoot()); if (!isTextFormControl() || openShadowRoot()) return; bool textIsChanged = value != innerEditorValue(); HTMLElement* innerEditor = innerEditorElement(); if (!textIsChanged && innerEditor->hasChildren()) return; // If the last child is a trailing <br> that's appended below, remove it // first so as to enable setInnerText() fast path of updating a text node. if (isHTMLBRElement(innerEditor->lastChild())) innerEditor->removeChild(innerEditor->lastChild(), ASSERT_NO_EXCEPTION); // We don't use setTextContent. It triggers unnecessary paint. if (value.isEmpty()) innerEditor->removeChildren(); else replaceChildrenWithText(innerEditor, value, ASSERT_NO_EXCEPTION); // Add <br> so that we can put the caret at the next line of the last // newline. addPlaceholderBreakElementIfNecessary(); if (textIsChanged && layoutObject()) { if (AXObjectCache* cache = document().existingAXObjectCache()) cache->handleTextFormControlChanged(this); } }
TextRun SVGInlineTextBox::constructTextRun(const ComputedStyle& style, const SVGTextFragment& fragment) const { LayoutText* text = &layoutObject(); // FIXME(crbug.com/264211): This should not be necessary but can occur if we // layout during layout. Remove this when 264211 is fixed. RELEASE_ASSERT(!text->needsLayout()); TextRun run(static_cast<const LChar*>(0) // characters, will be set below if non-zero. , 0 // length, will be set below if non-zero. , 0 // xPos, only relevant with allowTabs=true , 0 // padding, only relevant for justified text, not relevant for SVG , TextRun::AllowTrailingExpansion , direction() , dirOverride() || style.rtlOrdering() == VisualOrder /* directionalOverride */); if (fragment.length) { if (text->is8Bit()) run.setText(text->characters8() + fragment.characterOffset, fragment.length); else run.setText(text->characters16() + fragment.characterOffset, fragment.length); } // We handle letter & word spacing ourselves. run.disableSpacing(); // Propagate the maximum length of the characters buffer to the TextRun, even when we're only processing a substring. run.setCharactersLength(text->textLength() - fragment.characterOffset); ASSERT(run.charactersLength() >= run.length()); return run; }
// If a whitespace node had no layoutObject and goes through a recalcStyle it may // need to create one if the parent style now has white-space: pre. bool Text::needsWhitespaceLayoutObject() { ASSERT(!layoutObject()); if (const ComputedStyle* style = parentComputedStyle()) return style->preserveNewline(); return false; }