void AXTableColumn::headerObjectsForColumn(AXObjectVector& headers) { if (!m_parent) return; LayoutObject* layoutObject = m_parent->getLayoutObject(); if (!layoutObject) return; if (!m_parent->isAXTable()) return; if (toAXTable(m_parent)->isAriaTable()) { for (const auto& cell : children()) { if (cell->roleValue() == ColumnHeaderRole) headers.append(cell); } return; } if (!layoutObject->isTable()) return; LayoutTable* table = toLayoutTable(layoutObject); LayoutTableSection* tableSection = table->topSection(); for (; tableSection; tableSection = table->sectionBelow(tableSection, SkipEmptySections)) { unsigned numCols = tableSection->numEffectiveColumns(); if (m_columnIndex >= numCols) continue; unsigned numRows = tableSection->numRows(); for (unsigned r = 0; r < numRows; r++) { LayoutTableCell* layoutCell = tableSection->primaryCellAt(r, m_columnIndex); if (!layoutCell) continue; AXObject* cell = axObjectCache().getOrCreate(layoutCell->node()); if (!cell || !cell->isTableCell() || headers.contains(cell)) continue; if (toAXTableCell(cell)->scanToDecideHeaderRole() == ColumnHeaderRole) headers.append(cell); } } }
void PaintPropertyTreeBuilder::walk(LayoutObject& object, const PaintPropertyTreeBuilderContext& context) { PaintPropertyTreeBuilderContext localContext(context); deriveBorderBoxFromContainerContext(object, localContext); RefPtr<TransformPaintPropertyNode> newTransformNodeForPaintOffsetTranslation = createPaintOffsetTranslationIfNeeded(object, localContext); RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = createTransformIfNeeded(object, localContext); RefPtr<EffectPaintPropertyNode> newEffectNode = createEffectIfNeeded(object, localContext); RefPtr<ClipPaintPropertyNode> newClipNodeForOverflowClip = createOverflowClipIfNeeded(object, localContext); // TODO(trchen): Insert flattening transform here, as specified by // http://www.w3.org/TR/css3-transforms/#transform-style-property RefPtr<TransformPaintPropertyNode> newTransformNodeForPerspective = createPerspectiveIfNeeded(object, localContext); RefPtr<TransformPaintPropertyNode> newTransformNodeForScrollTranslation = createScrollTranslationIfNeeded(object, localContext); updateOutOfFlowContext(object, newTransformNodeForTransform, localContext); if (newTransformNodeForPaintOffsetTranslation || newTransformNodeForTransform || newEffectNode || newClipNodeForOverflowClip || newTransformNodeForPerspective || newTransformNodeForScrollTranslation) { OwnPtr<ObjectPaintProperties> updatedPaintProperties = ObjectPaintProperties::create( newTransformNodeForPaintOffsetTranslation.release(), newTransformNodeForTransform.release(), newEffectNode.release(), newClipNodeForOverflowClip.release(), newTransformNodeForPerspective.release(), newTransformNodeForScrollTranslation.release()); object.setObjectPaintProperties(updatedPaintProperties.release()); } else { object.clearObjectPaintProperties(); } for (LayoutObject* child = object.slowFirstChild(); child; child = child->nextSibling()) { if (child->isBoxModelObject() || child->isSVG()) walk(*child, localContext); } }
void PseudoElement::attach(const AttachContext& context) { ASSERT(!layoutObject()); Element::attach(context); LayoutObject* layoutObject = this->layoutObject(); if (!layoutObject) return; ComputedStyle& style = layoutObject->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 (layoutObject->isChildAllowed(child, style)) { layoutObject->addChild(child); if (child->isQuote()) toLayoutQuote(child)->attachQuote(); } else { child->destroy(); } } }
bool MediaControlsPainter::paintMediaSliderThumb(const LayoutObject& object, const PaintInfo& paintInfo, const IntRect& rect) { if (!object.node()) return false; const HTMLMediaElement* mediaElement = toParentMediaElement(object.node()->shadowHost()); if (!mediaElement) return false; if (!hasSource(mediaElement)) return true; Image* mediaSliderThumb = getMediaSliderThumb(); IntRect paintRect; const ComputedStyle& style = object.styleRef(); adjustMediaSliderThumbPaintSize(rect, style, paintRect); return paintMediaButton(paintInfo.context, paintRect, mediaSliderThumb); }
static PassRefPtr<EffectPaintPropertyNode> createEffectIfNeeded(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) { const ComputedStyle& style = object.styleRef(); if (!style.hasOpacity()) return nullptr; RefPtr<EffectPaintPropertyNode> newEffectNode = EffectPaintPropertyNode::create(style.opacity(), context.currentEffect); context.currentEffect = newEffectNode.get(); return newEffectNode.release(); }
bool LayoutTheme::isSpinUpButtonPartPressed(const LayoutObject& o) { Node* node = o.node(); if (!node || !node->active() || !node->isElementNode() || !toElement(node)->isSpinButtonElement()) return false; SpinButtonElement* element = toSpinButtonElement(node); return element->upDownState() == SpinButtonElement::Up; }
void AutoscrollController::updateAutoscrollLayoutObject() { if (!m_autoscrollLayoutObject) return; LayoutObject* layoutObject = m_autoscrollLayoutObject; #if OS(WIN) HitTestResult hitTest = layoutObject->frame()->eventHandler().hitTestResultAtPoint(m_panScrollStartPos, HitTestRequest::ReadOnly | HitTestRequest::Active); if (Node* nodeAtPoint = hitTest.innerNode()) layoutObject = nodeAtPoint->layoutObject(); #endif while (layoutObject && !(layoutObject->isBox() && toLayoutBox(layoutObject)->canAutoscroll())) layoutObject = layoutObject->parent(); m_autoscrollLayoutObject = layoutObject && layoutObject->isBox() ? toLayoutBox(layoutObject) : nullptr; }
bool LayoutTheme::controlStateChanged(LayoutObject& o, ControlState state) const { if (!o.styleRef().hasAppearance()) return false; // Default implementation assumes the controls don't respond to changes in :hover state if (state == HoverControlState && !supportsHover(o.styleRef())) return false; // Assume pressed state is only responded to if the control is enabled. if (state == PressedControlState && !isEnabled(&o)) return false; o.setShouldDoFullPaintInvalidation(); if (RuntimeEnabledFeatures::slimmingPaintEnabled()) o.invalidateDisplayItemClientForNonCompositingDescendants(); return true; }
void SVGLayoutSupport::mapLocalToAncestor(const LayoutObject* object, const LayoutBoxModelObject* ancestor, TransformState& transformState, MapCoordinatesFlags flags) { transformState.applyTransform(object->localToSVGParentTransform()); LayoutObject* parent = object->parent(); // At the SVG/HTML boundary (aka LayoutSVGRoot), we apply the // localToBorderBoxTransform to map an element from SVG viewport coordinates // to CSS box coordinates. // LayoutSVGRoot's mapLocalToAncestor method expects CSS box coordinates. if (parent->isSVGRoot()) transformState.applyTransform( toLayoutSVGRoot(parent)->localToBorderBoxTransform()); parent->mapLocalToAncestor(ancestor, transformState, flags); }
bool SVGLayoutSupport::pointInClippingArea(const LayoutObject& object, const FloatPoint& point) { ClipPathOperation* clipPathOperation = object.styleRef().clipPath(); if (!clipPathOperation) return true; if (clipPathOperation->type() == ClipPathOperation::SHAPE) { ShapeClipPathOperation& clipPath = toShapeClipPathOperation(*clipPathOperation); return clipPath.path(object.objectBoundingBox()).contains(point); } DCHECK_EQ(clipPathOperation->type(), ClipPathOperation::REFERENCE); SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(&object); if (!resources || !resources->clipper()) return true; return resources->clipper()->hitTestClipContent(object.objectBoundingBox(), point); }
static WebLayer* webLayerFromElement(Element* element) { if (!element) return 0; LayoutObject* layoutObject = element->layoutObject(); if (!layoutObject || !layoutObject->isBoxModelObject()) return 0; PaintLayer* layer = toLayoutBoxModelObject(layoutObject)->layer(); if (!layer) return 0; if (!layer->hasCompositedLayerMapping()) return 0; CompositedLayerMapping* compositedLayerMapping = layer->compositedLayerMapping(); GraphicsLayer* graphicsLayer = compositedLayerMapping->mainGraphicsLayer(); if (!graphicsLayer) return 0; return graphicsLayer->platformLayer(); }
void PaintPropertyTreeBuilder::updateScrollTranslation(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) { if (!object.isBoxModelObject() || !object.hasOverflowClip()) return; PaintLayer* layer = toLayoutBoxModelObject(object).layer(); ASSERT(layer); DoubleSize scrollOffset = layer->getScrollableArea()->scrollOffset(); if (scrollOffset.isZero() && !layer->scrollsOverflow()) return; RefPtr<TransformPaintPropertyNode> scrollTranslation = TransformPaintPropertyNode::create( TransformationMatrix().translate(-scrollOffset.width(), -scrollOffset.height()), FloatPoint3D(), context.currentTransform); context.currentTransform = scrollTranslation.get(); object.getMutableForPainting().ensureObjectPaintProperties().setScrollTranslation(scrollTranslation.release()); }
// TODO(trchen): Remove this once we bake the paint offset into frameRect. void PaintPropertyTreeBuilder::updateScrollbarPaintOffset(const LayoutObject& object, const PaintPropertyTreeBuilderContext& context) { IntPoint roundedPaintOffset = roundedIntPoint(context.paintOffset); if (roundedPaintOffset == IntPoint()) return; if (!object.isBoxModelObject()) return; PaintLayerScrollableArea* scrollableArea = toLayoutBoxModelObject(object).getScrollableArea(); if (!scrollableArea) return; if (!scrollableArea->horizontalScrollbar() && !scrollableArea->verticalScrollbar()) return; auto paintOffset = TransformationMatrix().translate(roundedPaintOffset.x(), roundedPaintOffset.y()); object.getMutableForPainting().ensureObjectPaintProperties().setScrollbarPaintOffset( TransformPaintPropertyNode::create(paintOffset, FloatPoint3D(), context.currentTransform)); }
void PaintPropertyTreeBuilder::updateCssClip(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) { if (!object.hasClip()) return; ASSERT(object.canContainAbsolutePositionObjects()); // Create clip node for descendants that are not fixed position. // We don't have to setup context.clipForAbsolutePosition here because this object must be // a container for absolute position descendants, and will copy from in-flow context later // at updateOutOfFlowContext() step. LayoutRect clipRect = toLayoutBox(object).clipRect(context.paintOffset); RefPtr<ClipPaintPropertyNode> clipNode = ClipPaintPropertyNode::create( context.currentTransform, FloatRoundedRect(FloatRect(clipRect)), context.currentClip); context.currentClip = clipNode.get(); object.getMutableForPainting().ensureObjectPaintProperties().setCssClip(clipNode.release()); }
void SVGSVGElement::svgAttributeChanged(const QualifiedName& attrName) { bool updateRelativeLengthsOrViewBox = false; bool widthOrHeightChanged = attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr; if (widthOrHeightChanged || 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. if (widthOrHeightChanged) { 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 LayoutCounter::layoutObjectStyleChanged(LayoutObject& layoutObject, const ComputedStyle* oldStyle, const ComputedStyle& newStyle) { Node* node = layoutObject.generatingNode(); if (!node || node->needsAttach()) return; // cannot have generated content or if it can have, it will be handled during attaching const CounterDirectiveMap* oldCounterDirectives = oldStyle ? oldStyle->counterDirectives() : 0; const CounterDirectiveMap* newCounterDirectives = newStyle.counterDirectives(); if (oldCounterDirectives) { if (newCounterDirectives) { CounterDirectiveMap::const_iterator newMapEnd = newCounterDirectives->end(); CounterDirectiveMap::const_iterator oldMapEnd = oldCounterDirectives->end(); for (CounterDirectiveMap::const_iterator it = newCounterDirectives->begin(); it != newMapEnd; ++it) { CounterDirectiveMap::const_iterator oldMapIt = oldCounterDirectives->find(it->key); if (oldMapIt != oldMapEnd) { if (oldMapIt->value == it->value) continue; LayoutCounter::destroyCounterNode(layoutObject, it->key); } // We must create this node here, because the changed node may be a node with no display such as // as those created by the increment or reset directives and the re-layout that will happen will // not catch the change if the node had no children. makeCounterNode(layoutObject, it->key, false); } // Destroying old counters that do not exist in the new counterDirective map. for (CounterDirectiveMap::const_iterator it = oldCounterDirectives->begin(); it !=oldMapEnd; ++it) { if (!newCounterDirectives->contains(it->key)) LayoutCounter::destroyCounterNode(layoutObject, it->key); } } else { if (layoutObject.hasCounterNodeMap()) LayoutCounter::destroyCounterNodes(layoutObject); } } else if (newCounterDirectives) { if (layoutObject.hasCounterNodeMap()) LayoutCounter::destroyCounterNodes(layoutObject); CounterDirectiveMap::const_iterator newMapEnd = newCounterDirectives->end(); for (CounterDirectiveMap::const_iterator it = newCounterDirectives->begin(); it != newMapEnd; ++it) { // We must create this node here, because the added node may be a node with no display such as // as those created by the increment or reset directives and the re-layout that will happen will // not catch the change if the node had no children. makeCounterNode(layoutObject, it->key, false); } } }
void SVGLayoutSupport::layoutChildren(LayoutObject* start, bool selfNeedsLayout) { // When hasRelativeLengths() is false, no descendants have relative lengths // (hence no one is interested in viewport size changes). bool layoutSizeChanged = toSVGElement(start->node())->hasRelativeLengths() && layoutSizeOfNearestViewportChanged(start); bool transformChanged = transformToRootChanged(start); for (LayoutObject* child = start->slowFirstChild(); child; child = child->nextSibling()) { bool forceLayout = selfNeedsLayout; if (transformChanged) { // If the transform changed we need to update the text metrics (note: this also happens for layoutSizeChanged=true). if (child->isSVGText()) toLayoutSVGText(child)->setNeedsTextMetricsUpdate(); forceLayout = true; } if (layoutSizeChanged) { // When selfNeedsLayout is false and the layout size changed, we have to check whether this child uses relative lengths if (SVGElement* element = child->node()->isSVGElement() ? toSVGElement(child->node()) : 0) { if (element->hasRelativeLengths()) { // FIXME: this should be done on invalidation, not during layout. // When the layout size changed and when using relative values tell the LayoutSVGShape to update its shape object if (child->isSVGShape()) { toLayoutSVGShape(child)->setNeedsShapeUpdate(); } else if (child->isSVGText()) { toLayoutSVGText(child)->setNeedsTextMetricsUpdate(); toLayoutSVGText(child)->setNeedsPositioningValuesUpdate(); } forceLayout = true; } } } SubtreeLayoutScope layoutScope(*child); // Resource containers are nasty: they can invalidate clients outside the current SubtreeLayoutScope. // Since they only care about viewport size changes (to resolve their relative lengths), we trigger // their invalidation directly from SVGSVGElement::svgAttributeChange() or at a higher // SubtreeLayoutScope (in LayoutView::layout()). if (forceLayout && !child->isSVGResourceContainer()) layoutScope.setNeedsLayout(child, LayoutInvalidationReason::SvgChanged); // Lay out any referenced resources before the child. layoutResourcesIfNeeded(child); child->layoutIfNeeded(); } }
PassRefPtr<const SkPicture> LayoutSVGResourceMasker::createContentPicture(AffineTransform& contentTransformation, const FloatRect& targetBoundingBox) { SVGUnitTypes::SVGUnitType contentUnits = toSVGMaskElement(element())->maskContentUnits()->currentValue()->enumValue(); if (contentUnits == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { contentTransformation.translate(targetBoundingBox.x(), targetBoundingBox.y()); contentTransformation.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height()); } if (m_maskContentPicture) return m_maskContentPicture; SubtreeContentTransformScope contentTransformScope(contentTransformation); // Using strokeBoundingBox (instead of paintInvalidationRectInLocalCoordinates) to avoid the intersection // with local clips/mask, which may yield incorrect results when mixing objectBoundingBox and // userSpaceOnUse units (http://crbug.com/294900). FloatRect bounds = strokeBoundingBox(); OwnPtr<DisplayItemList> displayItemList; if (RuntimeEnabledFeatures::slimmingPaintEnabled()) displayItemList = DisplayItemList::create(); GraphicsContext context(nullptr, displayItemList.get()); context.beginRecording(bounds); ColorFilter maskContentFilter = style()->svgStyle().colorInterpolation() == CI_LINEARRGB ? ColorFilterSRGBToLinearRGB : ColorFilterNone; context.setColorFilter(maskContentFilter); for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) { LayoutObject* layoutObject = childElement->layoutObject(); if (!layoutObject) continue; const ComputedStyle* style = layoutObject->style(); if (!style || style->display() == NONE || style->visibility() != VISIBLE) continue; SVGPaintContext::paintSubtree(&context, layoutObject); } if (displayItemList) displayItemList->commitNewDisplayItemsAndReplay(context); m_maskContentPicture = context.endRecording(); return m_maskContentPicture; }
bool SVGClipPainter::applyClippingToContext(const LayoutObject& target, const FloatRect& targetBoundingBox, const FloatRect& paintInvalidationRect, GraphicsContext* context, ClipperState& clipperState) { ASSERT(context); ASSERT(clipperState == ClipperNotApplied); ASSERT_WITH_SECURITY_IMPLICATION(!m_clip.needsLayout()); if (paintInvalidationRect.isEmpty() || m_clip.hasCycle()) return false; SVGClipExpansionCycleHelper inClipExpansionChange(m_clip); AffineTransform animatedLocalTransform = toSVGClipPathElement(m_clip.element())->calculateAnimatedLocalTransform(); // When drawing a clip for non-SVG elements, the CTM does not include the zoom factor. // In this case, we need to apply the zoom scale explicitly - but only for clips with // userSpaceOnUse units (the zoom is accounted for objectBoundingBox-resolved lengths). if (!target.isSVG() && m_clip.clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) { ASSERT(m_clip.style()); animatedLocalTransform.scale(m_clip.style()->effectiveZoom()); } // First, try to apply the clip as a clipPath. if (m_clip.tryPathOnlyClipping(target, context, animatedLocalTransform, targetBoundingBox)) { clipperState = ClipperAppliedPath; return true; } // Fall back to masking. clipperState = ClipperAppliedMask; // Begin compositing the clip mask. CompositingRecorder::beginCompositing(*context, target, SkXfermode::kSrcOver_Mode, 1, &paintInvalidationRect); { TransformRecorder recorder(*context, target, animatedLocalTransform); // clipPath can also be clipped by another clipPath. SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(&m_clip); LayoutSVGResourceClipper* clipPathClipper = resources ? resources->clipper() : 0; ClipperState clipPathClipperState = ClipperNotApplied; if (clipPathClipper && !SVGClipPainter(*clipPathClipper).applyClippingToContext(m_clip, targetBoundingBox, paintInvalidationRect, context, clipPathClipperState)) { // End the clip mask's compositor. CompositingRecorder::endCompositing(*context, target); return false; } drawClipMaskContent(context, target, targetBoundingBox); if (clipPathClipper) SVGClipPainter(*clipPathClipper).postApplyStatefulResource(m_clip, context, clipPathClipperState); } // Masked content layer start. CompositingRecorder::beginCompositing(*context, target, SkXfermode::kSrcIn_Mode, 1, &paintInvalidationRect); return true; }
void PaintPropertyTreeBuilder::updateLocalBorderBoxContext( const LayoutObject& object, PaintPropertyTreeBuilderContext& context) { // Avoid adding an ObjectPaintProperties for non-boxes to save memory, since // we don't need them at the moment. if (!object.isBox() && !object.hasLayer()) return; std::unique_ptr<ObjectPaintProperties::PropertyTreeStateWithOffset> borderBoxContext = wrapUnique(new ObjectPaintProperties::PropertyTreeStateWithOffset( context.current.paintOffset, PropertyTreeState(context.current.transform, context.current.clip, context.currentEffect, context.current.scroll))); object.getMutableForPainting() .ensurePaintProperties() .setLocalBorderBoxProperties(std::move(borderBoxContext)); }
void HTMLElement::setInnerText(const String& text, ExceptionState& exceptionState) { if (ieForbidsInsertHTML()) { exceptionState.throwDOMException(NoModificationAllowedError, "The '" + localName() + "' element does not support text insertion."); return; } if (shouldProhibitSetInnerOuterText(*this)) { exceptionState.throwDOMException(NoModificationAllowedError, "The '" + localName() + "' element does not support text insertion."); return; } // FIXME: This doesn't take whitespace collapsing into account at all. if (!text.contains('\n') && !text.contains('\r')) { if (text.isEmpty()) { removeChildren(); return; } replaceChildrenWithText(this, text, exceptionState); return; } // FIXME: Do we need to be able to detect preserveNewline style even when there's no renderer? // FIXME: Can the renderer be out of date here? Do we need to call updateStyleIfNeeded? // For example, for the contents of textarea elements that are display:none? LayoutObject* r = layoutObject(); if (r && r->style()->preserveNewline()) { if (!text.contains('\r')) { replaceChildrenWithText(this, text, exceptionState); return; } String textWithConsistentLineBreaks = text; textWithConsistentLineBreaks.replace("\r\n", "\n"); textWithConsistentLineBreaks.replace('\r', '\n'); replaceChildrenWithText(this, textWithConsistentLineBreaks, exceptionState); return; } // Add text nodes and <br> elements. RefPtrWillBeRawPtr<DocumentFragment> fragment = textToFragment(text, exceptionState); if (!exceptionState.hadException()) replaceChildrenWithFragment(this, fragment.release(), exceptionState); }
const LayoutObject* SVGLayoutSupport::pushMappingToContainer(const LayoutObject* object, const LayoutBoxModelObject* ancestorToStopAt, LayoutGeometryMap& geometryMap) { ASSERT_UNUSED(ancestorToStopAt, ancestorToStopAt != object); LayoutObject* parent = object->parent(); // At the SVG/HTML boundary (aka LayoutSVGRoot), we apply the localToBorderBoxTransform // to map an element from SVG viewport coordinates to CSS box coordinates. // LayoutSVGRoot's mapLocalToContainer method expects CSS box coordinates. if (parent->isSVGRoot()) { TransformationMatrix matrix(object->localToParentTransform()); matrix.multiply(toLayoutSVGRoot(parent)->localToBorderBoxTransform()); geometryMap.push(object, matrix); } else { geometryMap.push(object, object->localToParentTransform()); } return parent; }
TEST_F(ScrollingCoordinatorTest, iframeScrolling) { registerMockedHttpURLLoad("iframe-scrolling.html"); registerMockedHttpURLLoad("iframe-scrolling-inner.html"); navigateTo(m_baseURL + "iframe-scrolling.html"); forceFullCompositingUpdate(); // Verify the properties of the accelerated scrolling element starting from the LayoutObject // all the way to the WebLayer. Element* scrollableFrame = frame()->document()->getElementById("scrollable"); ASSERT_TRUE(scrollableFrame); LayoutObject* layoutObject = scrollableFrame->layoutObject(); ASSERT_TRUE(layoutObject); ASSERT_TRUE(layoutObject->isLayoutPart()); LayoutPart* layoutPart = toLayoutPart(layoutObject); ASSERT_TRUE(layoutPart); ASSERT_TRUE(layoutPart->widget()); ASSERT_TRUE(layoutPart->widget()->isFrameView()); FrameView* innerFrameView = toFrameView(layoutPart->widget()); LayoutView* innerLayoutView = innerFrameView->layoutView(); ASSERT_TRUE(innerLayoutView); PaintLayerCompositor* innerCompositor = innerLayoutView->compositor(); ASSERT_TRUE(innerCompositor->inCompositingMode()); ASSERT_TRUE(innerCompositor->scrollLayer()); GraphicsLayer* scrollLayer = innerCompositor->scrollLayer(); ASSERT_EQ(innerFrameView, scrollLayer->scrollableArea()); WebLayer* webScrollLayer = scrollLayer->platformLayer(); ASSERT_TRUE(webScrollLayer->scrollable()); #if OS(ANDROID) // Now verify we've attached impl-side scrollbars onto the scrollbar layers ASSERT_TRUE(innerCompositor->layerForHorizontalScrollbar()); ASSERT_TRUE(innerCompositor->layerForHorizontalScrollbar()->hasContentsLayer()); ASSERT_TRUE(innerCompositor->layerForVerticalScrollbar()); ASSERT_TRUE(innerCompositor->layerForVerticalScrollbar()->hasContentsLayer()); #endif }
bool ThemePainterDefault::paintMenuListButton(const LayoutObject& o, const PaintInfo& i, const IntRect& rect) { if (!o.isBox()) return false; WebThemeEngine::ExtraParams extraParams; extraParams.menuList.hasBorder = false; extraParams.menuList.hasBorderRadius = o.styleRef().hasBorderRadius(); extraParams.menuList.backgroundColor = Color::transparent; extraParams.menuList.fillContentArea = false; setupMenuListArrow(toLayoutBox(o), rect, extraParams); WebCanvas* canvas = i.context.canvas(); Platform::current()->themeEngine()->paint( canvas, WebThemeEngine::PartMenuList, getWebThemeState(o), WebRect(rect), &extraParams); return false; }
static void updateOutOfFlowContext(const LayoutObject& object, bool createdNewTransform, PaintPropertyTreeBuilderContext& context) { // At the html->svg boundary (see: createPaintOffsetTranslationIfNeeded) the currentTransform is // up-to-date for all children of the svg root element. Additionally, inside SVG, all positioning // uses transforms. Therefore, we only need to check createdNewTransform and isSVGRoot() to // ensure out-of-flow and fixed positioning is correct at the svg->html boundary. if (object.isPositioned() || createdNewTransform || object.isSVGRoot()) { context.transformForOutOfFlowPositioned = context.currentTransform; context.paintOffsetForOutOfFlowPositioned = context.paintOffset; context.clipForOutOfFlowPositioned = context.currentClip; } if (createdNewTransform || object.isSVGRoot()) { context.transformForFixedPositioned = context.currentTransform; context.paintOffsetForFixedPositioned = context.paintOffset; context.clipForFixedPositioned = context.currentClip; } }
bool LayoutTheme::isHovered(const LayoutObject& o) { Node* node = o.node(); if (!node) return false; if (!node->isElementNode() || !toElement(node)->isSpinButtonElement()) return node->hovered(); SpinButtonElement* element = toSpinButtonElement(node); return element->hovered() && element->upDownState() != SpinButtonElement::Indeterminate; }
int VisiblePosition::lineDirectionPointForBlockDirectionNavigation() const { if (isNull()) return 0; LayoutObject* layoutObject; LayoutRect localRect = localCaretRect(layoutObject); if (localRect.isEmpty() || !layoutObject) return 0; // This ignores transforms on purpose, for now. Vertical navigation is done // without consulting transforms, so that 'up' in transformed text is 'up' // relative to the text, not absolute 'up'. FloatPoint caretPoint = layoutObject->localToAbsolute(FloatPoint(localRect.location())); LayoutObject* containingBlock = layoutObject->containingBlock(); if (!containingBlock) containingBlock = layoutObject; // Just use ourselves to determine the writing mode if we have no containing block. return containingBlock->isHorizontalWritingMode() ? caretPoint.x() : caretPoint.y(); }
void FrameSetPainter::paintChildren(const PaintInfo& paintInfo, const LayoutPoint& adjustedPaintOffset) { // Paint only those children that fit in the grid. // Remaining frames are "hidden". // See also LayoutFrameSet::positionFrames. LayoutObject* child = m_layoutFrameSet.firstChild(); size_t rows = m_layoutFrameSet.rows().m_sizes.size(); size_t cols = m_layoutFrameSet.columns().m_sizes.size(); for (size_t r = 0; r < rows; r++) { for (size_t c = 0; c < cols; c++) { // Self-painting layers are painted during the PaintLayer paint recursion, not LayoutObject. if (!child->isBoxModelObject() || !toLayoutBoxModelObject(child)->hasSelfPaintingLayer()) child->paint(paintInfo, adjustedPaintOffset); child = child->nextSibling(); if (!child) return; } } }
LayoutUnit LayoutListBox::itemHeight() const { HTMLSelectElement* select = selectElement(); if (!select) return 0; Element* baseItem = ElementTraversal::firstChild(*select); if (!baseItem) return defaultItemHeight(); if (isHTMLOptGroupElement(baseItem)) baseItem = &toHTMLOptGroupElement(baseItem)->optGroupLabelElement(); else if (!isHTMLOptionElement(baseItem)) return defaultItemHeight(); LayoutObject* baseItemRenderer = baseItem->layoutObject(); if (!baseItemRenderer) return defaultItemHeight(); if (!baseItemRenderer || !baseItemRenderer->isBox()) return defaultItemHeight(); return toLayoutBox(baseItemRenderer)->size().height(); }
static void walkTree(LayoutSVGText* start, LayoutSVGInlineText* stopAtLeaf, MeasureTextData* data) { LayoutObject* child = start->firstChild(); while (child) { if (child->isSVGInlineText()) { LayoutSVGInlineText* text = toLayoutSVGInlineText(child); measureTextLayoutObject(text, data, !stopAtLeaf || stopAtLeaf == text); if (stopAtLeaf && stopAtLeaf == text) return; } else if (child->isSVGInline()) { // Visit children of text content elements. if (LayoutObject* inlineChild = toLayoutSVGInline(child)->firstChild()) { child = inlineChild; continue; } } child = child->nextInPreOrderAfterChildren(start); } }