PassRefPtr<CSSValue> CSSComputedStyleDeclaration::getSVGPropertyCSSValue(int propertyID, EUpdateLayout updateLayout) const
{
    Node* node = m_node.get();
    if (!node)
        return 0;
    
    // Make sure our layout is up to date before we allow a query on these attributes.
    if (updateLayout)
        node->document()->updateLayout();
        
    RenderStyle* style = node->computedStyle();
    if (!style)
        return 0;
    
    const SVGRenderStyle* svgStyle = style->svgStyle();
    if (!svgStyle)
        return 0;
    
    switch (static_cast<CSSPropertyID>(propertyID)) {
        case CSSPropertyClipRule:
            return CSSPrimitiveValue::create(svgStyle->clipRule());
        case CSSPropertyFloodOpacity:
            return CSSPrimitiveValue::create(svgStyle->floodOpacity(), CSSPrimitiveValue::CSS_NUMBER);
        case CSSPropertyStopOpacity:
            return CSSPrimitiveValue::create(svgStyle->stopOpacity(), CSSPrimitiveValue::CSS_NUMBER);
        case CSSPropertyColorInterpolation:
            return CSSPrimitiveValue::create(svgStyle->colorInterpolation());
        case CSSPropertyColorInterpolationFilters:
            return CSSPrimitiveValue::create(svgStyle->colorInterpolationFilters());
        case CSSPropertyFillOpacity:
            return CSSPrimitiveValue::create(svgStyle->fillOpacity(), CSSPrimitiveValue::CSS_NUMBER);
        case CSSPropertyFillRule:
            return CSSPrimitiveValue::create(svgStyle->fillRule());
        case CSSPropertyColorRendering:
            return CSSPrimitiveValue::create(svgStyle->colorRendering());
        case CSSPropertyImageRendering:
            return CSSPrimitiveValue::create(svgStyle->imageRendering());
        case CSSPropertyShapeRendering:
            return CSSPrimitiveValue::create(svgStyle->shapeRendering());
        case CSSPropertyStrokeLinecap:
            return CSSPrimitiveValue::create(svgStyle->capStyle());
        case CSSPropertyStrokeLinejoin:
            return CSSPrimitiveValue::create(svgStyle->joinStyle());
        case CSSPropertyStrokeMiterlimit:
            return CSSPrimitiveValue::create(svgStyle->strokeMiterLimit(), CSSPrimitiveValue::CSS_NUMBER);
        case CSSPropertyStrokeOpacity:
            return CSSPrimitiveValue::create(svgStyle->strokeOpacity(), CSSPrimitiveValue::CSS_NUMBER);
        case CSSPropertyAlignmentBaseline:
            return CSSPrimitiveValue::create(svgStyle->alignmentBaseline());
        case CSSPropertyDominantBaseline:
            return CSSPrimitiveValue::create(svgStyle->dominantBaseline());
        case CSSPropertyTextAnchor:
            return CSSPrimitiveValue::create(svgStyle->textAnchor());
        case CSSPropertyWritingMode:
            return CSSPrimitiveValue::create(svgStyle->writingMode());
        case CSSPropertyClipPath:
            if (!svgStyle->clipperResource().isEmpty())
                return CSSPrimitiveValue::create(svgStyle->clipperResource(), CSSPrimitiveValue::CSS_URI);
            return CSSPrimitiveValue::createIdentifier(CSSValueNone);
        case CSSPropertyMask:
            if (!svgStyle->maskerResource().isEmpty())
                return CSSPrimitiveValue::create(svgStyle->maskerResource(), CSSPrimitiveValue::CSS_URI);
            return CSSPrimitiveValue::createIdentifier(CSSValueNone);
        case CSSPropertyFilter:
            if (!svgStyle->filterResource().isEmpty())
                return CSSPrimitiveValue::create(svgStyle->filterResource(), CSSPrimitiveValue::CSS_URI);
            return CSSPrimitiveValue::createIdentifier(CSSValueNone);
        case CSSPropertyFloodColor:
            return CSSPrimitiveValue::createColor(svgStyle->floodColor().rgb());
        case CSSPropertyLightingColor:
            return CSSPrimitiveValue::createColor(svgStyle->lightingColor().rgb());
        case CSSPropertyStopColor:
            return CSSPrimitiveValue::createColor(svgStyle->stopColor().rgb());
        case CSSPropertyFill:
            return svgStyle->fillPaint();
        case CSSPropertyKerning:
            return SVGLength::toCSSPrimitiveValue(svgStyle->kerning());
        case CSSPropertyMarkerEnd:
            if (!svgStyle->markerEndResource().isEmpty())
                return CSSPrimitiveValue::create(svgStyle->markerEndResource(), CSSPrimitiveValue::CSS_URI);
            return CSSPrimitiveValue::createIdentifier(CSSValueNone);
        case CSSPropertyMarkerMid:
            if (!svgStyle->markerMidResource().isEmpty())
                return CSSPrimitiveValue::create(svgStyle->markerMidResource(), CSSPrimitiveValue::CSS_URI);
            return CSSPrimitiveValue::createIdentifier(CSSValueNone);
        case CSSPropertyMarkerStart:
            if (!svgStyle->markerStartResource().isEmpty())
                return CSSPrimitiveValue::create(svgStyle->markerStartResource(), CSSPrimitiveValue::CSS_URI);
            return CSSPrimitiveValue::createIdentifier(CSSValueNone);
        case CSSPropertyStroke:
            return svgStyle->strokePaint();
        case CSSPropertyStrokeDasharray:
            return strokeDashArrayToCSSValueList(svgStyle->strokeDashArray());
        case CSSPropertyStrokeDashoffset:
            return SVGLength::toCSSPrimitiveValue(svgStyle->strokeDashOffset());
        case CSSPropertyStrokeWidth:
            return SVGLength::toCSSPrimitiveValue(svgStyle->strokeWidth());
        case CSSPropertyBaselineShift: {
            switch (svgStyle->baselineShift()) {
                case BS_BASELINE:
                    return CSSPrimitiveValue::createIdentifier(CSSValueBaseline);
                case BS_SUPER:
                    return CSSPrimitiveValue::createIdentifier(CSSValueSuper);
                case BS_SUB:
                    return CSSPrimitiveValue::createIdentifier(CSSValueSub);
                case BS_LENGTH:
                    return SVGLength::toCSSPrimitiveValue(svgStyle->baselineShiftValue());
            }
        }
        case CSSPropertyGlyphOrientationHorizontal:
            return glyphOrientationToCSSPrimitiveValue(svgStyle->glyphOrientationHorizontal());
        case CSSPropertyGlyphOrientationVertical: {
            if (RefPtr<CSSPrimitiveValue> value = glyphOrientationToCSSPrimitiveValue(svgStyle->glyphOrientationVertical()))
                return value.release();

            if (svgStyle->glyphOrientationVertical() == GO_AUTO)
                return CSSPrimitiveValue::createIdentifier(CSSValueAuto);

            return 0;
        }
        case CSSPropertyWebkitSvgShadow:
            return valueForShadow(svgStyle->shadow(), propertyID, style);
        case CSSPropertyVectorEffect:
            return CSSPrimitiveValue::create(svgStyle->vectorEffect());
        case CSSPropertyMarker:
        case CSSPropertyEnableBackground:
        case CSSPropertyColorProfile:
            // the above properties are not yet implemented in the engine
            break;
    default:
        // If you crash here, it's because you added a css property and are not handling it
        // in either this switch statement or the one in CSSComputedStyleDelcaration::getPropertyCSSValue
        ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propertyID);
    }
    LOG_ERROR("unimplemented propertyID: %d", propertyID);
    return 0;
}
Esempio n. 2
0
void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject)
{
    // Double check that the document did in fact use generated content rules.  Otherwise we should not have been called.
    ASSERT(owner->document()->styleSheetCollection()->usesBeforeAfterRules());

    // In CSS2, before/after pseudo-content cannot nest.  Check this first.
    if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER)
        return;
    if (!s_enableUpdateBeforeAfterContent)
        return;
    
    if (!styledObject)
        styledObject = owner;

    RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
    RenderObject* child;
    switch (type) {
    case BEFORE:
        child = beforePseudoElementRenderer(owner);
        break;
    case AFTER:
        child = afterPseudoElementRenderer(owner);
        break;
    default:
        ASSERT_NOT_REACHED();
        return;
    }

    // Whether or not we currently have generated content attached.
    bool oldContentPresent = child;

    // Whether or not we now want generated content.
    bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE;

    // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate
    // :after content and not :before content.
    if (newContentWanted && type == BEFORE && owner->isElementContinuation())
        newContentWanted = false;

    // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object,
    // then we don't generate the :after content.
    if (newContentWanted && type == AFTER && owner->virtualContinuation())
        newContentWanted = false;
    
    // If we don't want generated content any longer, or if we have generated content, but it's no longer
    // identical to the new content data we want to build render objects for, then we nuke all
    // of the old generated content.
    if (oldContentPresent && (!newContentWanted || Node::diff(child->style(), pseudoElementStyle, owner->document()) == Node::Detach)) {
        // Nuke the child. 
        if (child->style()->styleType() == type) {
            oldContentPresent = false;
            child->destroy();
            child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild();
        }
    }

    // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we
    // have no generated content and can now return.
    if (!newContentWanted)
        return;

    if (owner->isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && !pseudoElementStyle->isFloating() &&
        !pseudoElementStyle->hasOutOfFlowPosition())
        // According to the CSS2 spec (the end of section 12.1), the only allowed
        // display values for the pseudo style are NONE and INLINE for inline flows.
        // FIXME: CSS2.1 lifted this restriction, but block display types will crash.
        // For now we at least relax the restriction to allow all inline types like inline-block
        // and inline-table.
        pseudoElementStyle->setDisplay(INLINE);

    if (oldContentPresent) {
        updateBeforeAfterStyle(child, type, pseudoElementStyle);
        return; // We've updated the generated content. That's all we needed to do.
    }
    
    RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0;
    if (insertBefore && insertBefore->isAnonymousBlock() && insertBefore->childrenInline() && !insertBefore->isEmpty()) {
        // We are going to add the "before" element. We have to check whether the "insertBefore" element
        // is an anonymous block with inline children. If it is, then we should insert the "before" element
        // before the first inline child of the anonymous block, otherwise we will end up with the "before"
        // element in a different block. We do this only when the anonymous block has children, otherwise
        // we end up with the before element in a wrong block.
        insertBefore = insertBefore->firstChild();
    }

    // Nothing goes before the intruded run-in, not even generated content.
    if (insertBefore && insertBefore->isRunIn() && owner->isRenderBlock()
        && toRenderBlock(owner)->runInIsPlacedIntoSiblingBlock(insertBefore))
        insertBefore = insertBefore->nextSibling();

    // Generated content consists of a single container that houses multiple children (specified
    // by the content property). This generated content container gets the pseudo-element style set on it.
    // For pseudo-elements that are regions, the container is the RenderRegion.
    RenderObject* generatedContentContainer = 0;

    if (!pseudoElementStyle->regionThread().isEmpty())
        generatedContentContainer = ensureBeforeAfterContainer(owner, type, pseudoElementStyle, styledObject->node(), insertBefore);
    else {
        // Walk our list of generated content and create render objects for each.
        for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) {
            RenderObject* renderer = content->createRenderer(owner->document(), pseudoElementStyle);

            if (!generatedContentContainer) {
                generatedContentContainer = ensureBeforeAfterContainer(owner, type, pseudoElementStyle, styledObject->node(), insertBefore);
                if (!generatedContentContainer) {
                    renderer->destroy();
                    return;
                }
            }
            if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle))
                generatedContentContainer->addChild(renderer);
            else
                renderer->destroy();
        }
    }

    if (!generatedContentContainer)
        return;

    // Handle placement of run-ins. We do the run-in placement at the end since generatedContentContainer can get destroyed.
    RenderObject* generatedContentContainerImmediateParent = generatedContentContainer->parent();
    if (generatedContentContainerImmediateParent->isRenderBlock())
        toRenderBlock(generatedContentContainerImmediateParent)->placeRunInIfNeeded(generatedContentContainer, PlaceGeneratedRunIn);
}
Esempio n. 3
0
void RenderMenuList::adjustInnerStyle()
{
    RenderStyle* innerStyle = m_innerBlock->style();
    innerStyle->setFlexGrow(1);
    innerStyle->setFlexShrink(1);
    // min-width: 0; is needed for correct shrinking.
    // FIXME: Remove this line when https://bugs.webkit.org/show_bug.cgi?id=111790 is fixed.
    innerStyle->setMinWidth(Length(0, Fixed));
    // Use margin:auto instead of align-items:center to get safe centering, i.e.
    // when the content overflows, treat it the same as align-items: flex-start.
    // But we only do that for the cases where html.css would otherwise use center.
    if (style()->alignItems() == AlignCenter) {
        innerStyle->setMarginTop(Length());
        innerStyle->setMarginBottom(Length());
        innerStyle->setAlignSelf(AlignFlexStart);
    }

    innerStyle->setPaddingLeft(Length(theme()->popupInternalPaddingLeft(style()), Fixed));
    innerStyle->setPaddingRight(Length(theme()->popupInternalPaddingRight(style()), Fixed));
    innerStyle->setPaddingTop(Length(theme()->popupInternalPaddingTop(style()), Fixed));
    innerStyle->setPaddingBottom(Length(theme()->popupInternalPaddingBottom(style()), Fixed));

    if (m_optionStyle) {
        if ((m_optionStyle->direction() != innerStyle->direction() || m_optionStyle->unicodeBidi() != innerStyle->unicodeBidi()))
            m_innerBlock->setNeedsLayoutAndPrefWidthsRecalc();
        innerStyle->setTextAlign(style()->isLeftToRightDirection() ? LEFT : RIGHT);
        innerStyle->setDirection(m_optionStyle->direction());
        innerStyle->setUnicodeBidi(m_optionStyle->unicodeBidi());
    }
}
PassRefPtrWillBeRawPtr<AnimatableValue> CSSAnimatableValueFactory::createFromColor(CSSPropertyID property, const RenderStyle& style)
{
    Color color = style.colorIncludingFallback(property, false);
    Color visitedLinkColor = style.colorIncludingFallback(property, true);
    return AnimatableColor::create(color, visitedLinkColor);
}
Esempio n. 5
0
static bool planCounter(RenderObject* object, const AtomicString& identifier, bool& isReset, int& value)
{
    ASSERT(object);

    // Real text nodes don't have their own style so they can't have counters.
    // We can't even look at their styles or we'll see extra resets and increments!
    if (object->isText())
        return false;
    Node* generatingNode = object->generatingNode();
    // We must have a generating node or else we cannot have a counter.
    if (!generatingNode)
        return false;
    RenderStyle* style = object->style();
    ASSERT(style);

    switch (style->styleType()) {
    case NOPSEUDO:
        // Sometimes nodes have more then one renderer. Only the first one gets the counter
        // LayoutTests/http/tests/css/counter-crash.html
        if (generatingNode->renderer() != object)
            return false;
        break;
    case BEFORE:
    case AFTER:
        break;
    default:
        return false; // Counters are forbidden from all other pseudo elements.
    }

    const CounterDirectives directives = style->getCounterDirectives(identifier);
    if (directives.isDefined()) {
        value = directives.combinedValue();
        isReset = directives.isReset();
        return true;
    }

    if (identifier == "list-item") {
        if (object->isListItem()) {
            if (toRenderListItem(object)->hasExplicitValue()) {
                value = toRenderListItem(object)->explicitValue();
                isReset = true;
                return true;
            }
            value = 1;
            isReset = false;
            return true;
        }
        if (Node* e = object->node()) {
            if (e->hasTagName(olTag)) {
                value = static_cast<HTMLOListElement*>(e)->start();
                isReset = true;
                return true;
            }
            if (e->hasTagName(ulTag) || e->hasTagName(menuTag) || e->hasTagName(dirTag)) {
                value = 0;
                isReset = true;
                return true;
            }
        }
    }

    return false;
}
Esempio n. 6
0
void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo)
{
    ASSERT(paintInfo.shouldPaintWithinRoot(&renderer()));
    ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
    ASSERT(truncation() == cNoTruncation);

    if (renderer().style()->visibility() != VISIBLE)
        return;

    RenderObject& parentRenderer = parent()->renderer();
    ASSERT(!parentRenderer.document().printing());

    // Determine whether or not we're selected.
    bool paintSelectedTextOnly = paintInfo.phase == PaintPhaseSelection;
    bool hasSelection = selectionState() != RenderObject::SelectionNone;
    if (!hasSelection || paintSelectedTextOnly)
        return;

    Color backgroundColor = renderer().selectionBackgroundColor();
    if (!backgroundColor.isValid() || !backgroundColor.alpha())
        return;

    if (!textShouldBePainted(toRenderSVGInlineText(this->textRenderer())))
        return;

    RenderStyle* style = parentRenderer.style();
    ASSERT(style);

    RenderStyle* selectionStyle = style;
    if (hasSelection) {
        selectionStyle = parentRenderer.getCachedPseudoStyle(SELECTION);
        if (!selectionStyle)
            selectionStyle = style;
    }

    int startPosition, endPosition;
    selectionStartEnd(startPosition, endPosition);

    int fragmentStartPosition = 0;
    int fragmentEndPosition = 0;
    AffineTransform fragmentTransform;
    unsigned textFragmentsSize = m_textFragments.size();
    for (unsigned i = 0; i < textFragmentsSize; ++i) {
        SVGTextFragment& fragment = m_textFragments.at(i);
        ASSERT(!m_paintingResource);

        fragmentStartPosition = startPosition;
        fragmentEndPosition = endPosition;
        if (!mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition))
            continue;

        GraphicsContextStateSaver stateSaver(*paintInfo.context);
        fragment.buildFragmentTransform(fragmentTransform);
        if (!fragmentTransform.isIdentity())
            paintInfo.context->concatCTM(fragmentTransform);

        paintInfo.context->setFillColor(backgroundColor, style->colorSpace());
        paintInfo.context->fillRect(selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style), backgroundColor, style->colorSpace());

        m_paintingResourceMode = ApplyToDefaultMode;
    }

    ASSERT(!m_paintingResource);
}
void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUnit, LayoutUnit)
{
    ASSERT(paintInfo.shouldPaintWithinRoot(renderer()));
    ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
    ASSERT(truncation() == cNoTruncation);

    if (renderer()->style()->visibility() != VISIBLE)
        return;

    // Note: We're explicitely not supporting composition & custom underlines and custom highlighters - unlike InlineTextBox.
    // If we ever need that for SVG, it's very easy to refactor and reuse the code.

    RenderObject* parentRenderer = parent()->renderer();
    ASSERT(parentRenderer);

    bool paintSelectedTextOnly = paintInfo.phase == PaintPhaseSelection;
    bool hasSelection = !parentRenderer->document().printing() && selectionState() != RenderObject::SelectionNone;
    if (!hasSelection && paintSelectedTextOnly)
        return;

    RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer());
    ASSERT(textRenderer);
    if (!textShouldBePainted(textRenderer))
        return;

    RenderStyle* style = parentRenderer->style();
    ASSERT(style);

    const SVGRenderStyle* svgStyle = style->svgStyle();
    ASSERT(svgStyle);

    bool hasFill = svgStyle->hasFill();
    bool hasVisibleStroke = svgStyle->hasVisibleStroke();

    RenderStyle* selectionStyle = style;
    if (hasSelection) {
        selectionStyle = parentRenderer->getCachedPseudoStyle(SELECTION);
        if (selectionStyle) {
            const SVGRenderStyle* svgSelectionStyle = selectionStyle->svgStyle();
            ASSERT(svgSelectionStyle);

            if (!hasFill)
                hasFill = svgSelectionStyle->hasFill();
            if (!hasVisibleStroke)
                hasVisibleStroke = svgSelectionStyle->hasVisibleStroke();
        } else
            selectionStyle = style;
    }

    if (textRenderer->frame() && textRenderer->frame()->view() && textRenderer->frame()->view()->paintBehavior() & PaintBehaviorRenderingSVGMask) {
        hasFill = true;
        hasVisibleStroke = false;
    }

    AffineTransform fragmentTransform;
    unsigned textFragmentsSize = m_textFragments.size();
    for (unsigned i = 0; i < textFragmentsSize; ++i) {
        SVGTextFragment& fragment = m_textFragments.at(i);
        ASSERT(!m_paintingResource);

        GraphicsContextStateSaver stateSaver(*paintInfo.context);
        fragment.buildFragmentTransform(fragmentTransform);
        if (!fragmentTransform.isIdentity())
            paintInfo.context->concatCTM(fragmentTransform);

        // Spec: All text decorations except line-through should be drawn before the text is filled and stroked; thus, the text is rendered on top of these decorations.
        int decorations = style->textDecorationsInEffect();
        if (decorations & TextDecorationUnderline)
            paintDecoration(paintInfo.context, TextDecorationUnderline, fragment);
        if (decorations & TextDecorationOverline)
            paintDecoration(paintInfo.context, TextDecorationOverline, fragment);

        for (int i = 0; i < 3; i++) {
            switch (svgStyle->paintOrderType(i)) {
            case PT_FILL:
                // Fill text
                if (hasFill) {
                    m_paintingResourceMode = ApplyToFillMode | ApplyToTextMode;
                    paintText(paintInfo.context, style, selectionStyle, fragment, hasSelection, paintSelectedTextOnly);
                }
                break;
            case PT_STROKE:
                // Stroke text
                if (hasVisibleStroke) {
                    m_paintingResourceMode = ApplyToStrokeMode | ApplyToTextMode;
                    paintText(paintInfo.context, style, selectionStyle, fragment, hasSelection, paintSelectedTextOnly);
                }
                break;
            case PT_MARKERS:
                // Markers don't apply to text
                break;
            default:
                ASSERT_NOT_REACHED();
                break;
            }
        }

        // Spec: Line-through should be drawn after the text is filled and stroked; thus, the line-through is rendered on top of the text.
        if (decorations & TextDecorationLineThrough)
            paintDecoration(paintInfo.context, TextDecorationLineThrough, fragment);

        m_paintingResourceMode = ApplyToDefaultMode;
    }

    ASSERT(!m_paintingResource);
}
bool CSSPropertyEquality::propertiesEqual(CSSPropertyID prop, const RenderStyle& a, const RenderStyle& b)
{
    switch (prop) {
    case CSSPropertyBackgroundColor:
        return a.backgroundColor().resolve(a.color()) == b.backgroundColor().resolve(b.color())
            && a.visitedLinkBackgroundColor().resolve(a.color()) == b.visitedLinkBackgroundColor().resolve(b.color());
    case CSSPropertyBackgroundImage:
        return fillLayersEqual<CSSPropertyBackgroundImage>(a.backgroundLayers(), b.backgroundLayers());
    case CSSPropertyBackgroundPositionX:
        return fillLayersEqual<CSSPropertyBackgroundPositionX>(a.backgroundLayers(), b.backgroundLayers());
    case CSSPropertyBackgroundPositionY:
        return fillLayersEqual<CSSPropertyBackgroundPositionY>(a.backgroundLayers(), b.backgroundLayers());
    case CSSPropertyBackgroundSize:
        return fillLayersEqual<CSSPropertyBackgroundSize>(a.backgroundLayers(), b.backgroundLayers());
    case CSSPropertyBaselineShift:
        return dataEquivalent(a.baselineShiftValue(), b.baselineShiftValue());
    case CSSPropertyBorderBottomColor:
        return a.borderBottomColor().resolve(a.color()) == b.borderBottomColor().resolve(b.color())
            && a.visitedLinkBorderBottomColor().resolve(a.color()) == b.visitedLinkBorderBottomColor().resolve(b.color());
    case CSSPropertyBorderBottomLeftRadius:
        return a.borderBottomLeftRadius() == b.borderBottomLeftRadius();
    case CSSPropertyBorderBottomRightRadius:
        return a.borderBottomRightRadius() == b.borderBottomRightRadius();
    case CSSPropertyBorderBottomWidth:
        return a.borderBottomWidth() == b.borderBottomWidth();
    case CSSPropertyBorderImageOutset:
        return a.borderImageOutset() == b.borderImageOutset();
    case CSSPropertyBorderImageSlice:
        return a.borderImageSlices() == b.borderImageSlices();
    case CSSPropertyBorderImageSource:
        return dataEquivalent(a.borderImageSource(), b.borderImageSource());
    case CSSPropertyBorderImageWidth:
        return a.borderImageWidth() == b.borderImageWidth();
    case CSSPropertyBorderLeftColor:
        return a.borderLeftColor().resolve(a.color()) == b.borderLeftColor().resolve(b.color())
            && a.visitedLinkBorderLeftColor().resolve(a.color()) == b.visitedLinkBorderLeftColor().resolve(b.color());
    case CSSPropertyBorderLeftWidth:
        return a.borderLeftWidth() == b.borderLeftWidth();
    case CSSPropertyBorderRightColor:
        return a.borderRightColor().resolve(a.color()) == b.borderRightColor().resolve(b.color())
            && a.visitedLinkBorderRightColor().resolve(a.color()) == b.visitedLinkBorderRightColor().resolve(b.color());
    case CSSPropertyBorderRightWidth:
        return a.borderRightWidth() == b.borderRightWidth();
    case CSSPropertyBorderTopColor:
        return a.borderTopColor().resolve(a.color()) == b.borderTopColor().resolve(b.color())
            && a.visitedLinkBorderTopColor().resolve(a.color()) == b.visitedLinkBorderTopColor().resolve(b.color());
    case CSSPropertyBorderTopLeftRadius:
        return a.borderTopLeftRadius() == b.borderTopLeftRadius();
    case CSSPropertyBorderTopRightRadius:
        return a.borderTopRightRadius() == b.borderTopRightRadius();
    case CSSPropertyBorderTopWidth:
        return a.borderTopWidth() == b.borderTopWidth();
    case CSSPropertyBottom:
        return a.bottom() == b.bottom();
    case CSSPropertyBoxShadow:
        return dataEquivalent(a.boxShadow(), b.boxShadow());
    case CSSPropertyClip:
        return a.clip() == b.clip();
    case CSSPropertyColor:
        return a.color() == b.color() && a.visitedLinkColor() == b.visitedLinkColor();
    case CSSPropertyFill: {
        const SVGRenderStyle& aSVG = *a.svgStyle();
        const SVGRenderStyle& bSVG = *b.svgStyle();
        return aSVG.fillPaintType() == bSVG.fillPaintType()
            && (aSVG.fillPaintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR || aSVG.fillPaintColor() == bSVG.fillPaintColor())
            && aSVG.visitedLinkFillPaintType() == bSVG.visitedLinkFillPaintType()
            && (aSVG.visitedLinkFillPaintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR || aSVG.visitedLinkFillPaintColor() == bSVG.visitedLinkFillPaintColor());
    }
    case CSSPropertyFillOpacity:
        return a.fillOpacity() == b.fillOpacity();
    case CSSPropertyFlexBasis:
        return a.flexBasis() == b.flexBasis();
    case CSSPropertyFlexGrow:
        return a.flexGrow() == b.flexGrow();
    case CSSPropertyFlexShrink:
        return a.flexShrink() == b.flexShrink();
    case CSSPropertyFloodColor:
        return a.floodColor() == b.floodColor();
    case CSSPropertyFloodOpacity:
        return a.floodOpacity() == b.floodOpacity();
    case CSSPropertyFontSize:
        // CSSPropertyFontSize: Must pass a specified size to setFontSize if Text Autosizing is enabled, but a computed size
        // if text zoom is enabled (if neither is enabled it's irrelevant as they're probably the same).
        // FIXME: Should we introduce an option to pass the computed font size here, allowing consumers to
        // enable text zoom rather than Text Autosizing? See http://crbug.com/227545.
        return a.specifiedFontSize() == b.specifiedFontSize();
    case CSSPropertyFontWeight:
        return a.fontWeight() == b.fontWeight();
    case CSSPropertyHeight:
        return a.height() == b.height();
    case CSSPropertyLeft:
        return a.left() == b.left();
    case CSSPropertyLetterSpacing:
        return a.letterSpacing() == b.letterSpacing();
    case CSSPropertyLightingColor:
        return a.lightingColor() == b.lightingColor();
    case CSSPropertyLineHeight:
        return a.specifiedLineHeight() == b.specifiedLineHeight();
    case CSSPropertyListStyleImage:
        return dataEquivalent(a.listStyleImage(), b.listStyleImage());
    case CSSPropertyMarginBottom:
        return a.marginBottom() == b.marginBottom();
    case CSSPropertyMarginLeft:
        return a.marginLeft() == b.marginLeft();
    case CSSPropertyMarginRight:
        return a.marginRight() == b.marginRight();
    case CSSPropertyMarginTop:
        return a.marginTop() == b.marginTop();
    case CSSPropertyMaxHeight:
        return a.maxHeight() == b.maxHeight();
    case CSSPropertyMaxWidth:
        return a.maxWidth() == b.maxWidth();
    case CSSPropertyMinHeight:
        return a.minHeight() == b.minHeight();
    case CSSPropertyMinWidth:
        return a.minWidth() == b.minWidth();
    case CSSPropertyObjectPosition:
        return a.objectPosition() == b.objectPosition();
    case CSSPropertyOpacity:
        return a.opacity() == b.opacity();
    case CSSPropertyOrphans:
        return a.orphans() == b.orphans();
    case CSSPropertyOutlineColor:
        return a.outlineColor().resolve(a.color()) == b.outlineColor().resolve(b.color())
            && a.visitedLinkOutlineColor().resolve(a.color()) == b.visitedLinkOutlineColor().resolve(b.color());
    case CSSPropertyOutlineOffset:
        return a.outlineOffset() == b.outlineOffset();
    case CSSPropertyOutlineWidth:
        return a.outlineWidth() == b.outlineWidth();
    case CSSPropertyPaddingBottom:
        return a.paddingBottom() == b.paddingBottom();
    case CSSPropertyPaddingLeft:
        return a.paddingLeft() == b.paddingLeft();
    case CSSPropertyPaddingRight:
        return a.paddingRight() == b.paddingRight();
    case CSSPropertyPaddingTop:
        return a.paddingTop() == b.paddingTop();
    case CSSPropertyRight:
        return a.right() == b.right();
    case CSSPropertyShapeImageThreshold:
        return a.shapeImageThreshold() == b.shapeImageThreshold();
    case CSSPropertyShapeMargin:
        return a.shapeMargin() == b.shapeMargin();
    case CSSPropertyShapeOutside:
        return dataEquivalent(a.shapeOutside(), b.shapeOutside());
    case CSSPropertyStopColor:
        return a.stopColor() == b.stopColor();
    case CSSPropertyStopOpacity:
        return a.stopOpacity() == b.stopOpacity();
    case CSSPropertyStroke: {
        const SVGRenderStyle& aSVG = *a.svgStyle();
        const SVGRenderStyle& bSVG = *b.svgStyle();
        return aSVG.strokePaintType() == bSVG.strokePaintType()
            && (aSVG.strokePaintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR || aSVG.strokePaintColor() == bSVG.strokePaintColor())
            && aSVG.visitedLinkStrokePaintType() == bSVG.visitedLinkStrokePaintType()
            && (aSVG.visitedLinkStrokePaintType() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR || aSVG.visitedLinkStrokePaintColor() == bSVG.visitedLinkStrokePaintColor());
    }
    case CSSPropertyStrokeDasharray:
        return dataEquivalent(a.strokeDashArray(), b.strokeDashArray());
    case CSSPropertyStrokeDashoffset:
        return dataEquivalent(a.strokeDashOffset(), b.strokeDashOffset());
    case CSSPropertyStrokeMiterlimit:
        return a.strokeMiterLimit() == b.strokeMiterLimit();
    case CSSPropertyStrokeOpacity:
        return a.strokeOpacity() == b.strokeOpacity();
    case CSSPropertyStrokeWidth:
        return dataEquivalent(a.strokeWidth(), b.strokeWidth());
    case CSSPropertyTextDecorationColor:
        return a.textDecorationColor().resolve(a.color()) == b.textDecorationColor().resolve(b.color())
            && a.visitedLinkTextDecorationColor().resolve(a.color()) == b.visitedLinkTextDecorationColor().resolve(b.color());
    case CSSPropertyTextIndent:
        return a.textIndent() == b.textIndent();
    case CSSPropertyTextShadow:
        return dataEquivalent(a.textShadow(), b.textShadow());
    case CSSPropertyTop:
        return a.top() == b.top();
    case CSSPropertyVerticalAlign:
        return a.verticalAlign() == b.verticalAlign()
            && (a.verticalAlign() != LENGTH || a.verticalAlignLength() == b.verticalAlignLength());
    case CSSPropertyVisibility:
        return a.visibility() == b.visibility();
    case CSSPropertyWebkitBackgroundSize:
        return fillLayersEqual<CSSPropertyWebkitBackgroundSize>(a.backgroundLayers(), b.backgroundLayers());
    case CSSPropertyWebkitBorderHorizontalSpacing:
        return a.horizontalBorderSpacing() == b.horizontalBorderSpacing();
    case CSSPropertyWebkitBorderVerticalSpacing:
        return a.verticalBorderSpacing() == b.verticalBorderSpacing();
    case CSSPropertyWebkitBoxShadow:
        return dataEquivalent(a.boxShadow(), b.boxShadow());
    case CSSPropertyWebkitClipPath:
        return dataEquivalent(a.clipPath(), b.clipPath());
    case CSSPropertyWebkitColumnCount:
        return a.columnCount() == b.columnCount();
    case CSSPropertyWebkitColumnGap:
        return a.columnGap() == b.columnGap();
    case CSSPropertyWebkitColumnRuleColor:
        return a.columnRuleColor().resolve(a.color()) == b.columnRuleColor().resolve(b.color())
            && a.visitedLinkColumnRuleColor().resolve(a.color()) == b.visitedLinkColumnRuleColor().resolve(b.color());
    case CSSPropertyWebkitColumnRuleWidth:
        return a.columnRuleWidth() == b.columnRuleWidth();
    case CSSPropertyWebkitColumnWidth:
        return a.columnWidth() == b.columnWidth();
    case CSSPropertyWebkitFilter:
        return a.filter() == b.filter();
    case CSSPropertyWebkitMaskBoxImageOutset:
        return a.maskBoxImageOutset() == b.maskBoxImageOutset();
    case CSSPropertyWebkitMaskBoxImageSlice:
        return a.maskBoxImageSlices() == b.maskBoxImageSlices();
    case CSSPropertyWebkitMaskBoxImageSource:
        return dataEquivalent(a.maskBoxImageSource(), b.maskBoxImageSource());
    case CSSPropertyWebkitMaskBoxImageWidth:
        return a.maskBoxImageWidth() == b.maskBoxImageWidth();
    case CSSPropertyWebkitMaskImage:
        return dataEquivalent(a.maskImage(), b.maskImage());
    case CSSPropertyWebkitMaskPositionX:
        return fillLayersEqual<CSSPropertyWebkitMaskPositionX>(a.maskLayers(), b.maskLayers());
    case CSSPropertyWebkitMaskPositionY:
        return fillLayersEqual<CSSPropertyWebkitMaskPositionY>(a.maskLayers(), b.maskLayers());
    case CSSPropertyWebkitMaskSize:
        return fillLayersEqual<CSSPropertyWebkitMaskSize>(a.maskLayers(), b.maskLayers());
    case CSSPropertyPerspective:
        return a.perspective() == b.perspective();
    case CSSPropertyPerspectiveOrigin:
        return a.perspectiveOriginX() == b.perspectiveOriginX() && a.perspectiveOriginY() == b.perspectiveOriginY();
    case CSSPropertyWebkitPerspectiveOriginX:
        return a.perspectiveOriginX() == b.perspectiveOriginX();
    case CSSPropertyWebkitPerspectiveOriginY:
        return a.perspectiveOriginY() == b.perspectiveOriginY();
    case CSSPropertyWebkitTextStrokeColor:
        return a.textStrokeColor().resolve(a.color()) == b.textStrokeColor().resolve(b.color())
            && a.visitedLinkTextStrokeColor().resolve(a.color()) == b.visitedLinkTextStrokeColor().resolve(b.color());
    case CSSPropertyTransform:
        return a.transform() == b.transform();
    case CSSPropertyTransformOrigin:
        return a.transformOriginX() == b.transformOriginX() && a.transformOriginY() == b.transformOriginY() && a.transformOriginZ() == b.transformOriginZ();
    case CSSPropertyWebkitTransformOriginX:
        return a.transformOriginX() == b.transformOriginX();
    case CSSPropertyWebkitTransformOriginY:
        return a.transformOriginY() == b.transformOriginY();
    case CSSPropertyWebkitTransformOriginZ:
        return a.transformOriginZ() == b.transformOriginZ();
    case CSSPropertyWidows:
        return a.widows() == b.widows();
    case CSSPropertyWidth:
        return a.width() == b.width();
    case CSSPropertyWordSpacing:
        return a.wordSpacing() == b.wordSpacing();
    case CSSPropertyZIndex:
        return a.zIndex() == b.zIndex();
    case CSSPropertyZoom:
        return a.zoom() == b.zoom();
    default:
        ASSERT_NOT_REACHED();
        return true;
    }
}
bool SVGPaintServerPattern::setup(GraphicsContext*& context, const RenderObject* object, SVGPaintTargetType type, bool isPaintingText) const
{
    CGContextRef contextRef = context->platformContext();

    // Build pattern tile, passing destination object bounding box
    FloatRect targetRect;
    if (isPaintingText) {
        IntRect textBoundary = const_cast<RenderObject*>(object)->absoluteBoundingBoxRect();
        targetRect = object->absoluteTransform().inverse().mapRect(textBoundary);
    } else
        targetRect = CGContextGetPathBoundingBox(contextRef);

    m_ownerElement->buildPattern(targetRect);

    if (!tile())
        return false;

    CGSize cellSize = CGSize(tile()->size());
    CGFloat alpha = 1; // canvasStyle->opacity(); //which?

    context->save();

    // Repesct local pattern transformations
    CGContextConcatCTM(contextRef, patternTransform());

    // Pattern space seems to start in the lower-left, so we flip the Y here. 
    CGSize phase = CGSizeMake(patternBoundaries().x(), -patternBoundaries().y());
    CGContextSetPatternPhase(contextRef, phase);

    RenderStyle* style = object->style();
    CGContextSetAlpha(contextRef, style->opacity()); // or do I set the alpha above?

    ASSERT(!m_pattern);
    CGPatternCallbacks callbacks = {0, patternCallback, NULL};
    m_pattern = CGPatternCreate(tile(),
                                CGRectMake(0, 0, cellSize.width, cellSize.height),
                                CGContextGetCTM(contextRef),
                                patternBoundaries().width(),
                                patternBoundaries().height(),
                                kCGPatternTilingConstantSpacing, // FIXME: should ask CG guys.
                                true, // has color
                                &callbacks);

    if (!m_patternSpace)
        m_patternSpace = CGColorSpaceCreatePattern(0);

    if ((type & ApplyToFillTargetType) && style->svgStyle()->hasFill()) {
        CGContextSetFillColorSpace(contextRef, m_patternSpace);
        CGContextSetFillPattern(contextRef, m_pattern, &alpha);
 
        if (isPaintingText) 
            context->setTextDrawingMode(cTextFill);
    }

    if ((type & ApplyToStrokeTargetType) && style->svgStyle()->hasStroke()) {
        CGContextSetStrokeColorSpace(contextRef, m_patternSpace);
        CGContextSetStrokePattern(contextRef, m_pattern, &alpha);
        applyStrokeStyleToContext(contextRef, style, object);

        if (isPaintingText) 
            context->setTextDrawingMode(cTextStroke);
    }

    return true;
}
Esempio n. 10
0
IntRect EllipsisBox::selectionRect()
{
    RenderStyle* style = renderer().style(isFirstLineStyle());
    const Font& font = style->font();
    return enclosingIntRect(font.selectionRectForText(RenderBlockFlow::constructTextRun(&renderer(), font, m_str, style, TextRun::AllowTrailingExpansion), IntPoint(logicalLeft(), logicalTop() + root().selectionTopAdjustedForPrecedingBlock()), root().selectionHeightAdjustedForPrecedingBlock()));
}
Esempio n. 11
0
void ElementImpl::recalcStyle(StyleChange change)
{
    // ### should go away and be done in renderobject
    RenderStyle *_style = m_render ? m_render->style() : 0;
    bool hasParentRenderer = parent() ? parent()->attached() : false;

#if 0
    const char* debug;
    switch(change) {
    case NoChange: debug = "NoChange";
        break;
    case NoInherit: debug= "NoInherit";
        break;
    case Inherit: debug = "Inherit";
        break;
    case Force: debug = "Force";
        break;
    }
    qDebug("recalcStyle(%d: %s, changed: %d)[%p: %s]", change, debug, changed(), this, tagName().string().latin1());
#endif
    if(hasParentRenderer && (change >= Inherit || changed()))
    {
        RenderStyle *newStyle = getDocument()->styleSelector()->styleForElement(this);
        newStyle->ref();
        StyleChange ch = diff(_style, newStyle);
        if(ch == Detach)
        {
            if(attached())
                detach();
            // ### Suboptimal. Style gets calculated again.
            attach();
            // attach recalulates the style for all children. No need to do it twice.
            setChanged(false);
            setHasChangedChild(false);
            newStyle->deref();
            return;
        }
        else if(ch != NoChange)
        {
            if(m_render && newStyle)
            {
                m_render->setStyle(newStyle);
            }
        }
        newStyle->deref();

        if(change != Force)
            change = ch;
    }
    // If a changed attribute has ancestor dependencies, restyle all children
    if(changedAscendentAttribute())
    {
        change = Force;
        setChangedAscendentAttribute(false);
    }

    NodeImpl *n;
    for(n = _first; n; n = n->nextSibling())
    {
        if(change >= Inherit || n->isTextNode() || n->hasChangedChild() || n->changed())
        {
            // qDebug("    (%p) calling recalcStyle on child %p/%s, change=%d", this, n, n->isElementNode() ? ((ElementImpl
            // *)n)->tagName().string().latin1() : n->isTextNode() ? "text" : "unknown", change );
            n->recalcStyle(change);
        }
    }

    setChanged(false);
    setHasChangedChild(false);
}
Esempio n. 12
0
static void registerElementForFlowThreadIfNeeded(Element& element, const RenderStyle& style)
{
    if (!element.shouldMoveToFlowThread(style))
        return;
    FlowThreadController& flowThreadController = element.document().renderView()->flowThreadController();
    flowThreadController.registerNamedFlowContentElement(element, flowThreadController.ensureRenderFlowThreadWithName(style.flowThread()));
}
bool RenderSVGResourceClipper::pathOnlyClipping(GraphicsContext* context, const AffineTransform& animatedLocalTransform, const FloatRect& objectBoundingBox)
{
    // If the current clip-path gets clipped itself, we have to fallback to masking.
    if (!style()->svgStyle()->clipperResource().isEmpty())
        return false;
    WindRule clipRule = RULE_NONZERO;
    Path clipPath = Path();

    for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) {
        RenderObject* renderer = childNode->renderer();
        if (!renderer)
            continue;
        // Only shapes or paths are supported for direct clipping. We need to fallback to masking for texts.
        if (renderer->isSVGText())
            return false;
        if (!childNode->isSVGElement() || !toSVGElement(childNode)->isSVGGraphicsElement())
            continue;
        SVGGraphicsElement* styled = toSVGGraphicsElement(childNode);
        RenderStyle* style = renderer->style();
        if (!style || style->display() == NONE || style->visibility() != VISIBLE)
             continue;
        const SVGRenderStyle* svgStyle = style->svgStyle();
        // Current shape in clip-path gets clipped too. Fallback to masking.
        if (!svgStyle->clipperResource().isEmpty())
            return false;

        if (clipPath.isEmpty()) {
            // First clip shape.
            styled->toClipPath(clipPath);
            clipRule = svgStyle->clipRule();
            clipPath.setWindRule(clipRule);
            continue;
        }

        if (RuntimeEnabledFeatures::pathOpsSVGClippingEnabled()) {
            // Attempt to generate a combined clip path, fall back to masking if not possible.
            Path subPath;
            styled->toClipPath(subPath);
            subPath.setWindRule(svgStyle->clipRule());
            if (!clipPath.unionPath(subPath))
                return false;
        } else {
            return false;
        }
    }
    // Only one visible shape/path was found. Directly continue clipping and transform the content to userspace if necessary.
    if (static_cast<SVGClipPathElement*>(node())->clipPathUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
        AffineTransform transform;
        transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
        transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
        clipPath.transform(transform);
    }

    // Transform path by animatedLocalTransform.
    clipPath.transform(animatedLocalTransform);

    // The SVG specification wants us to clip everything, if clip-path doesn't have a child.
    if (clipPath.isEmpty())
        clipPath.addRect(FloatRect());
    context->clipPath(clipPath, clipRule);
    return true;
}
bool RenderSVGResourceClipper::drawContentIntoMaskImage(ClipperData* clipperData, const FloatRect& objectBoundingBox)
{
    ASSERT(frame());
    ASSERT(clipperData);
    ASSERT(clipperData->clipMaskImage);

    GraphicsContext* maskContext = clipperData->clipMaskImage->context();
    ASSERT(maskContext);

    AffineTransform maskContentTransformation;
    SVGClipPathElement* clipPath = static_cast<SVGClipPathElement*>(node());
    if (clipPath->clipPathUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
        maskContentTransformation.translate(objectBoundingBox.x(), objectBoundingBox.y());
        maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
        maskContext->concatCTM(maskContentTransformation);
    }

    // Switch to a paint behavior where all children of this <clipPath> will be rendered using special constraints:
    // - fill-opacity/stroke-opacity/opacity set to 1
    // - masker/filter not applied when rendering the children
    // - fill is set to the initial fill paint server (solid, black)
    // - stroke is set to the initial stroke paint server (none)
    PaintBehavior oldBehavior = frame()->view()->paintBehavior();
    frame()->view()->setPaintBehavior(oldBehavior | PaintBehaviorRenderingSVGMask);

    // Draw all clipPath children into a global mask.
    for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) {
        RenderObject* renderer = childNode->renderer();
        if (!childNode->isSVGElement() || !renderer)
            continue;
        if (renderer->needsLayout()) {
            frame()->view()->setPaintBehavior(oldBehavior);
            return false;
        }
        RenderStyle* style = renderer->style();
        if (!style || style->display() == NONE || style->visibility() != VISIBLE)
            continue;

        WindRule newClipRule = style->svgStyle()->clipRule();
        bool isUseElement = childNode->hasTagName(SVGNames::useTag);
        if (isUseElement) {
            SVGUseElement* useElement = toSVGUseElement(childNode);
            renderer = useElement->rendererClipChild();
            if (!renderer)
                continue;
            if (!useElement->hasAttribute(SVGNames::clip_ruleAttr))
                newClipRule = renderer->style()->svgStyle()->clipRule();
        }

        // Only shapes, paths and texts are allowed for clipping.
        if (!renderer->isSVGShape() && !renderer->isSVGText())
            continue;

        maskContext->setFillRule(newClipRule);

        // In the case of a <use> element, we obtained its renderere above, to retrieve its clipRule.
        // We have to pass the <use> renderer itself to renderSubtreeToImageBuffer() to apply it's x/y/transform/etc. values when rendering.
        // So if isUseElement is true, refetch the childNode->renderer(), as renderer got overriden above.
        SVGRenderingContext::renderSubtreeToImageBuffer(clipperData->clipMaskImage.get(), isUseElement ? childNode->renderer() : renderer, maskContentTransformation);
    }

    frame()->view()->setPaintBehavior(oldBehavior);
    return true;
}
Esempio n. 15
0
void RenderTheme::paintSliderTicks(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect)
{
    Node* node = o->node();
    if (!node)
        return;

    HTMLInputElement* input = node->toInputElement();
    if (!input)
        return;

    HTMLDataListElement* dataList = static_cast<HTMLDataListElement*>(input->list());
    if (!dataList)
        return;

    double min = input->minimum();
    double max = input->maximum();
    ControlPart part = o->style()->appearance();
    // We don't support ticks on alternate sliders like MediaVolumeSliders.
    if (part !=  SliderHorizontalPart && part != SliderVerticalPart)
        return;
    bool isHorizontal = part ==  SliderHorizontalPart;

    IntSize thumbSize;
    RenderObject* thumbRenderer = input->sliderThumbElement()->renderer();
    if (thumbRenderer) {
        RenderStyle* thumbStyle = thumbRenderer->style();
        int thumbWidth = thumbStyle->width().intValue();
        int thumbHeight = thumbStyle->height().intValue();
        thumbSize.setWidth(isHorizontal ? thumbWidth : thumbHeight);
        thumbSize.setHeight(isHorizontal ? thumbHeight : thumbWidth);
    }

    IntSize tickSize = sliderTickSize();
    float zoomFactor = o->style()->effectiveZoom();
    FloatRect tickRect;
    int tickRegionSideMargin = 0;
    int tickRegionWidth = 0;
    IntRect trackBounds;
    RenderObject* trackRenderer = input->sliderTrackElement()->renderer();
    // We can ignoring transforms because transform is handled by the graphics context.
    if (trackRenderer)
        trackBounds = trackRenderer->absoluteBoundingBoxRectIgnoringTransforms();
    IntRect sliderBounds = o->absoluteBoundingBoxRectIgnoringTransforms();

    // Make position relative to the transformed ancestor element.
    trackBounds.setX(trackBounds.x() - sliderBounds.x() + rect.x());
    trackBounds.setY(trackBounds.y() - sliderBounds.y() + rect.y());

    if (isHorizontal) {
        tickRect.setWidth(floor(tickSize.width() * zoomFactor));
        tickRect.setHeight(floor(tickSize.height() * zoomFactor));
        tickRect.setY(floor(rect.y() + rect.height() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor));
        tickRegionSideMargin = trackBounds.x() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0;
        tickRegionWidth = trackBounds.width() - thumbSize.width();
    } else {
        tickRect.setWidth(floor(tickSize.height() * zoomFactor));
        tickRect.setHeight(floor(tickSize.width() * zoomFactor));
        tickRect.setX(floor(rect.x() + rect.width() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor));
        tickRegionSideMargin = trackBounds.y() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0;
        tickRegionWidth = trackBounds.height() - thumbSize.width();
    }
    RefPtr<HTMLCollection> options = dataList->options();
    GraphicsContextStateSaver stateSaver(*paintInfo.context);
    paintInfo.context->setFillColor(o->style()->visitedDependentColor(CSSPropertyColor), ColorSpaceDeviceRGB);
    for (unsigned i = 0; Node* node = options->item(i); i++) {
        ASSERT(isHTMLOptionElement(node));
        HTMLOptionElement* optionElement = toHTMLOptionElement(node);
        String value = optionElement->value();
        if (!input->isValidValue(value))
            continue;
        double parsedValue = parseToDoubleForNumberType(input->sanitizeValue(value));
        double tickFraction = (parsedValue - min) / (max - min);
        double tickRatio = isHorizontal && o->style()->isLeftToRightDirection() ? tickFraction : 1.0 - tickFraction;
        double tickPosition = round(tickRegionSideMargin + tickRegionWidth * tickRatio);
        if (isHorizontal)
            tickRect.setX(tickPosition);
        else
            tickRect.setY(tickPosition);
        paintInfo.context->fillRect(tickRect);
    }
}
static bool isDeletableElement(const Node* node)
{
    if (!node || !node->isHTMLElement() || !node->inDocument() || !node->rendererIsEditable())
        return false;

    // In general we want to only draw the UI around object of a certain area, but we still keep the min width/height to
    // make sure we don't end up with very thin or very short elements getting the UI.
    const int minimumArea = 2500;
    const int minimumWidth = 48;
    const int minimumHeight = 16;
    const unsigned minimumVisibleBorders = 1;

    RenderObject* renderer = node->renderer();
    if (!renderer || !renderer->isBox())
        return false;

    // Disallow the body element since it isn't practical to delete, and the deletion UI would be clipped.
    if (node->hasTagName(bodyTag))
        return false;

    // Disallow elements with any overflow clip, since the deletion UI would be clipped as well. <rdar://problem/6840161>
    if (renderer->hasOverflowClip())
        return false;

    // Disallow Mail blockquotes since the deletion UI would get in the way of editing for these.
    if (isMailBlockquote(node))
        return false;

    RenderBox* box = toRenderBox(renderer);
    IntRect borderBoundingBox = box->borderBoundingBox();
    if (borderBoundingBox.width() < minimumWidth || borderBoundingBox.height() < minimumHeight)
        return false;

    if ((borderBoundingBox.width() * borderBoundingBox.height()) < minimumArea)
        return false;

    if (renderer->isTable())
        return true;

    if (node->hasTagName(ulTag) || node->hasTagName(olTag) || node->hasTagName(iframeTag))
        return true;

    if (renderer->isOutOfFlowPositioned())
        return true;

    if (renderer->isRenderBlock() && !renderer->isTableCell()) {
        RenderStyle* style = renderer->style();
        if (!style)
            return false;

        // Allow blocks that have background images
        if (style->hasBackgroundImage()) {
            for (const FillLayer* background = style->backgroundLayers(); background; background = background->next()) {
                if (background->image() && background->image()->canRender(renderer, 1))
                    return true;
            }
        }

        // Allow blocks with a minimum number of non-transparent borders
        unsigned visibleBorders = style->borderTop().isVisible() + style->borderBottom().isVisible() + style->borderLeft().isVisible() + style->borderRight().isVisible();
        if (visibleBorders >= minimumVisibleBorders)
            return true;

        // Allow blocks that have a different background from it's parent
        ContainerNode* parentNode = node->parentNode();
        if (!parentNode)
            return false;

        RenderObject* parentRenderer = parentNode->renderer();
        if (!parentRenderer)
            return false;

        RenderStyle* parentStyle = parentRenderer->style();
        if (!parentStyle)
            return false;

        if (renderer->hasBackground() && (!parentRenderer->hasBackground() || style->visitedDependentColor(CSSPropertyBackgroundColor) != parentStyle->visitedDependentColor(CSSPropertyBackgroundColor)))
            return true;
    }

    return false;
}
Esempio n. 17
0
void EllipsisBox::paint(PaintInfo& paintInfo, int tx, int ty)
{
    GraphicsContext* context = paintInfo.context;
    RenderStyle* style = m_renderer->style(m_firstLine);
    Color textColor = style->visitedDependentColor(CSSPropertyColor);
    if (textColor != context->fillColor())
        context->setFillColor(textColor, style->colorSpace());
    bool setShadow = false;
    if (style->textShadow()) {
        context->setShadow(IntSize(style->textShadow()->x(), style->textShadow()->y()),
                           style->textShadow()->blur(), style->textShadow()->color(), style->colorSpace());
        setShadow = true;
    }

    if (selectionState() != RenderObject::SelectionNone) {
        paintSelection(context, tx, ty, style, style->font());

        // Select the correct color for painting the text.
        Color foreground = paintInfo.forceBlackText ? Color::black : renderer()->selectionForegroundColor();
        if (foreground.isValid() && foreground != textColor)
            context->setFillColor(foreground, style->colorSpace());
    }

    const String& str = m_str;
    context->drawText(style->font(), TextRun(str.characters(), str.length(), false, 0, 0, false, style->visuallyOrdered()), IntPoint(m_x + tx, m_y + ty + style->font().ascent()));

    // Restore the regular fill color.
    if (textColor != context->fillColor())
        context->setFillColor(textColor, style->colorSpace());

    if (setShadow)
        context->clearShadow();

    if (m_markupBox) {
        // Paint the markup box
        tx += m_x + m_width - m_markupBox->x();
        ty += m_y + style->font().ascent() - (m_markupBox->y() + m_markupBox->renderer()->style(m_firstLine)->font().ascent());
        m_markupBox->paint(paintInfo, tx, ty);
    }
}
bool AccessibilityTable::isTableExposableThroughAccessibility()
{
    // the following is a heuristic used to determine if a
    // <table> should be exposed as an AXTable. The goal
    // is to only show "data" tables
    
    if (!m_renderer || !m_renderer->isTable())
        return false;
    
    // if the developer assigned an aria role to this, then we shouldn't 
    // expose it as a table, unless, of course, the aria role is a table
    AccessibilityRole ariaRole = ariaRoleAttribute();
    if (ariaRole == TableRole)
        return true;
    if (ariaRole != UnknownRole)
        return false;
    
    RenderTable* table = static_cast<RenderTable*>(m_renderer);
    
    // this employs a heuristic to determine if this table should appear. 
    // Only "data" tables should be exposed as tables. 
    // Unfortunately, there is no good way to determine the difference
    // between a "layout" table and a "data" table
    
    Node* tableNode = table->element();
    if (!tableNode || !tableNode->hasTagName(tableTag))
        return false;
    
    // if there is a caption element, summary, THEAD, or TFOOT section, it's most certainly a data table
    HTMLTableElement* tableElement = static_cast<HTMLTableElement*>(tableNode);
    if (!tableElement->summary().isEmpty() || tableElement->tHead() || tableElement->tFoot() || tableElement->caption())
        return true;
    
    // if someone used "rules" attribute than the table should appear
    if (!tableElement->rules().isEmpty())
        return true;    
    
    // go through the cell's and check for tell-tale signs of "data" table status
    // cells have borders, or use attributes like headers, abbr, scope or axis
    RenderTableSection* firstBody = table->firstBody();
    if (!firstBody)
        return false;
    
    int numCols = firstBody->numColumns();
    int numRows = firstBody->numRows();
    
    // if there's only one cell, it's not a good AXTable candidate
    if (numRows == 1 && numCols == 1)
        return false;
    
    // store the background color of the table to check against cell's background colors
    RenderStyle* tableStyle = table->style();
    if (!tableStyle)
        return false;
    Color tableBGColor = tableStyle->backgroundColor();
    
    // check enough of the cells to find if the table matches our criteria
    // Criteria: 
    //   1) must have at least one valid cell (and)
    //   2) at least half of cells have borders (or)
    //   3) at least half of cells have different bg colors than the table, and there is cell spacing
    unsigned validCellCount = 0;
    unsigned borderedCellCount = 0;
    unsigned backgroundDifferenceCellCount = 0;
    
    for (int row = 0; row < numRows; ++row) {
        for (int col = 0; col < numCols; ++col) {    
            RenderTableCell* cell = firstBody->cellAt(row, col).cell;
            if (!cell)
                continue;
            Node* cellNode = cell->element();
            if (!cellNode)
                continue;
            
            if (cell->width() < 1 || cell->height() < 1)
                continue;
            
            validCellCount++;
            
            HTMLTableCellElement* cellElement = static_cast<HTMLTableCellElement*>(cellNode);
            
            // in this case, the developer explicitly assigned a "data" table attribute
            if (!cellElement->headers().isEmpty() || !cellElement->abbr().isEmpty() || 
                !cellElement->axis().isEmpty() || !cellElement->scope().isEmpty())
                return true;
            
            RenderStyle* renderStyle = cell->style();
            if (!renderStyle)
                continue;

            // a cell needs to have matching bordered sides, before it can be considered a bordered cell.
            if ((cell->borderTop() > 0 && cell->borderBottom() > 0) ||
                (cell->borderLeft() > 0 && cell->borderRight() > 0))
                borderedCellCount++;
            
            // if the cell has a different color from the table and there is cell spacing,
            // then it is probably a data table cell (spacing and colors take the place of borders)
            Color cellColor = renderStyle->backgroundColor();
            if (table->hBorderSpacing() > 0 && table->vBorderSpacing() > 0 && 
                tableBGColor != cellColor && cellColor.alpha() != 1)
                backgroundDifferenceCellCount++;
            
            // if we've found 10 "good" cells, we don't need to keep searching
            if (borderedCellCount >= 10 || backgroundDifferenceCellCount >= 10)
                return true;
        }
    }

    // if there is less than two valid cells, it's not a data table
    if (validCellCount <= 1)
        return false;
    
    // half of the cells had borders, it's a data table
    unsigned neededCellCount = validCellCount / 2;
    if (borderedCellCount >= neededCellCount)
        return true;
    
    // half had different background colors, it's a data table
    if (backgroundDifferenceCellCount >= neededCellCount)
        return true;

    return false;
}
Esempio n. 19
0
void RenderMenuList::adjustInnerStyle()
{
    RenderStyle* innerStyle = m_innerBlock->style();
    innerStyle->setFlexGrow(1);
    innerStyle->setFlexShrink(1);
    // min-width: 0; is needed for correct shrinking.
    // FIXME: Remove this line when https://bugs.webkit.org/show_bug.cgi?id=111790 is fixed.
    innerStyle->setMinWidth(Length(0, Fixed));
    // Use margin:auto instead of align-items:center to get safe centering, i.e.
    // when the content overflows, treat it the same as align-items: flex-start.
    // But we only do that for the cases where html.css would otherwise use center.
    if (style()->alignItems() == AlignCenter) {
        innerStyle->setMarginTop(Length());
        innerStyle->setMarginBottom(Length());
        innerStyle->setAlignSelf(AlignFlexStart);
    }

    innerStyle->setPaddingLeft(Length(theme()->popupInternalPaddingLeft(style()), Fixed));
    innerStyle->setPaddingRight(Length(theme()->popupInternalPaddingRight(style()), Fixed));
    innerStyle->setPaddingTop(Length(theme()->popupInternalPaddingTop(style()), Fixed));
    innerStyle->setPaddingBottom(Length(theme()->popupInternalPaddingBottom(style()), Fixed));

    if (document().page()->chrome().selectItemWritingDirectionIsNatural()) {
        // Items in the popup will not respect the CSS text-align and direction properties,
        // so we must adjust our own style to match.
        innerStyle->setTextAlign(LEFT);
        TextDirection direction = (m_buttonText && m_buttonText->text()->defaultWritingDirection() == WTF::Unicode::RightToLeft) ? RTL : LTR;
        innerStyle->setDirection(direction);
    } else if (m_optionStyle && document().page()->chrome().selectItemAlignmentFollowsMenuWritingDirection()) {
        if ((m_optionStyle->direction() != innerStyle->direction() || m_optionStyle->unicodeBidi() != innerStyle->unicodeBidi()))
            m_innerBlock->setNeedsLayoutAndPrefWidthsRecalc();
        innerStyle->setTextAlign(style()->isLeftToRightDirection() ? LEFT : RIGHT);
        innerStyle->setDirection(m_optionStyle->direction());
        innerStyle->setUnicodeBidi(m_optionStyle->unicodeBidi());
    }
}
Esempio n. 20
0
bool AccessibilityTable::isDataTable() const
{
    if (!m_renderer)
        return false;

    // Do not consider it a data table is it has an ARIA role.
    if (hasARIARole())
        return false;

    // When a section of the document is contentEditable, all tables should be
    // treated as data tables, otherwise users may not be able to work with rich
    // text editors that allow creating and editing tables.
    if (node() && node()->rendererIsEditable())
        return true;

    // This employs a heuristic to determine if this table should appear.
    // Only "data" tables should be exposed as tables.
    // Unfortunately, there is no good way to determine the difference
    // between a "layout" table and a "data" table.
    
    RenderTable* table = toRenderTable(m_renderer);
    Node* tableNode = table->node();
    if (!tableNode || !tableNode->hasTagName(tableTag))
        return false;

    // if there is a caption element, summary, THEAD, or TFOOT section, it's most certainly a data table
    HTMLTableElement* tableElement = static_cast<HTMLTableElement*>(tableNode);
    if (!tableElement->summary().isEmpty() || tableElement->tHead() || tableElement->tFoot() || tableElement->caption())
        return true;
    
    // if someone used "rules" attribute than the table should appear
    if (!tableElement->rules().isEmpty())
        return true;    

    // if there's a colgroup or col element, it's probably a data table.
    for (Node* child = tableElement->firstChild(); child; child = child->nextSibling()) {
        if (child->hasTagName(colTag) || child->hasTagName(colgroupTag))
            return true;
    }
    
    // go through the cell's and check for tell-tale signs of "data" table status
    // cells have borders, or use attributes like headers, abbr, scope or axis
    table->recalcSectionsIfNeeded();
    RenderTableSection* firstBody = table->firstBody();
    if (!firstBody)
        return false;
    
    int numCols = firstBody->numColumns();
    int numRows = firstBody->numRows();
    
    // If there's only one cell, it's not a good AXTable candidate.
    if (numRows == 1 && numCols == 1)
        return false;

    // If there are at least 20 rows, we'll call it a data table.
    if (numRows >= 20)
        return true;
    
    // Store the background color of the table to check against cell's background colors.
    RenderStyle* tableStyle = table->style();
    if (!tableStyle)
        return false;
    Color tableBGColor = tableStyle->visitedDependentColor(CSSPropertyBackgroundColor);
    
    // check enough of the cells to find if the table matches our criteria
    // Criteria: 
    //   1) must have at least one valid cell (and)
    //   2) at least half of cells have borders (or)
    //   3) at least half of cells have different bg colors than the table, and there is cell spacing
    unsigned validCellCount = 0;
    unsigned borderedCellCount = 0;
    unsigned backgroundDifferenceCellCount = 0;
    unsigned cellsWithTopBorder = 0;
    unsigned cellsWithBottomBorder = 0;
    unsigned cellsWithLeftBorder = 0;
    unsigned cellsWithRightBorder = 0;
    
    Color alternatingRowColors[5];
    int alternatingRowColorCount = 0;
    
    int headersInFirstColumnCount = 0;
    for (int row = 0; row < numRows; ++row) {
    
        int headersInFirstRowCount = 0;
        for (int col = 0; col < numCols; ++col) {    
            RenderTableCell* cell = firstBody->primaryCellAt(row, col);
            if (!cell)
                continue;
            Node* cellNode = cell->node();
            if (!cellNode)
                continue;
            
            if (cell->width() < 1 || cell->height() < 1)
                continue;
            
            validCellCount++;
            
            HTMLTableCellElement* cellElement = static_cast<HTMLTableCellElement*>(cellNode);
            
            bool isTHCell = cellElement->hasTagName(thTag);
            // If the first row is comprised of all <th> tags, assume it is a data table.
            if (!row && isTHCell)
                headersInFirstRowCount++;

            // If the first column is comprised of all <th> tags, assume it is a data table.
            if (!col && isTHCell)
                headersInFirstColumnCount++;
            
            // in this case, the developer explicitly assigned a "data" table attribute
            if (!cellElement->headers().isEmpty() || !cellElement->abbr().isEmpty()
                || !cellElement->axis().isEmpty() || !cellElement->scope().isEmpty())
                return true;
            
            RenderStyle* renderStyle = cell->style();
            if (!renderStyle)
                continue;

            // If the empty-cells style is set, we'll call it a data table.
            if (renderStyle->emptyCells() == HIDE)
                return true;

            // If a cell has matching bordered sides, call it a (fully) bordered cell.
            if ((cell->borderTop() > 0 && cell->borderBottom() > 0)
                || (cell->borderLeft() > 0 && cell->borderRight() > 0))
                borderedCellCount++;

            // Also keep track of each individual border, so we can catch tables where most
            // cells have a bottom border, for example.
            if (cell->borderTop() > 0)
                cellsWithTopBorder++;
            if (cell->borderBottom() > 0)
                cellsWithBottomBorder++;
            if (cell->borderLeft() > 0)
                cellsWithLeftBorder++;
            if (cell->borderRight() > 0)
                cellsWithRightBorder++;
            
            // If the cell has a different color from the table and there is cell spacing,
            // then it is probably a data table cell (spacing and colors take the place of borders).
            Color cellColor = renderStyle->visitedDependentColor(CSSPropertyBackgroundColor);
            if (table->hBorderSpacing() > 0 && table->vBorderSpacing() > 0
                && tableBGColor != cellColor && cellColor.alpha() != 1)
                backgroundDifferenceCellCount++;
            
            // If we've found 10 "good" cells, we don't need to keep searching.
            if (borderedCellCount >= 10 || backgroundDifferenceCellCount >= 10)
                return true;
            
            // For the first 5 rows, cache the background color so we can check if this table has zebra-striped rows.
            if (row < 5 && row == alternatingRowColorCount) {
                RenderObject* renderRow = cell->parent();
                if (!renderRow || !renderRow->isBoxModelObject() || !toRenderBoxModelObject(renderRow)->isTableRow())
                    continue;
                RenderStyle* rowRenderStyle = renderRow->style();
                if (!rowRenderStyle)
                    continue;
                Color rowColor = rowRenderStyle->visitedDependentColor(CSSPropertyBackgroundColor);
                alternatingRowColors[alternatingRowColorCount] = rowColor;
                alternatingRowColorCount++;
            }
        }
        
        if (!row && headersInFirstRowCount == numCols && numCols > 1)
            return true;
    }

    if (headersInFirstColumnCount == numRows && numRows > 1)
        return true;
    
    // if there is less than two valid cells, it's not a data table
    if (validCellCount <= 1)
        return false;
    
    // half of the cells had borders, it's a data table
    unsigned neededCellCount = validCellCount / 2;
    if (borderedCellCount >= neededCellCount
        || cellsWithTopBorder >= neededCellCount
        || cellsWithBottomBorder >= neededCellCount
        || cellsWithLeftBorder >= neededCellCount
        || cellsWithRightBorder >= neededCellCount)
        return true;
    
    // half had different background colors, it's a data table
    if (backgroundDifferenceCellCount >= neededCellCount)
        return true;

    // Check if there is an alternating row background color indicating a zebra striped style pattern.
    if (alternatingRowColorCount > 2) {
        Color firstColor = alternatingRowColors[0];
        for (int k = 1; k < alternatingRowColorCount; k++) {
            // If an odd row was the same color as the first row, its not alternating.
            if (k % 2 == 1 && alternatingRowColors[k] == firstColor)
                return false;
            // If an even row is not the same as the first row, its not alternating.
            if (!(k % 2) && alternatingRowColors[k] != firstColor)
                return false;
        }
        return true;
    }
    
    return false;
}
Esempio n. 21
0
void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, RenderObject* styledObject)
{
    // Double check that the document did in fact use generated content rules.  Otherwise we should not have been called.
    ASSERT(owner->document()->usesBeforeAfterRules());

    // In CSS2, before/after pseudo-content cannot nest.  Check this first.
    if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER)
        return;
    
    if (!styledObject)
        styledObject = owner;

    RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
    RenderObject* child = beforeAfterContainer(owner, type);

    // Whether or not we currently have generated content attached.
    bool oldContentPresent = child;

    // Whether or not we now want generated content.
    bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE;

    // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate
    // :after content and not :before content.
    if (newContentWanted && type == BEFORE && owner->isRenderInline() && toRenderInline(owner)->isInlineContinuation())
        newContentWanted = false;

    // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object,
    // then we don't generate the :after content.
    if (newContentWanted && type == AFTER && owner->isRenderInline() && toRenderInline(owner)->continuation())
        newContentWanted = false;
    
    // If we don't want generated content any longer, or if we have generated content, but it's no longer
    // identical to the new content data we want to build render objects for, then we nuke all
    // of the old generated content.
    if (oldContentPresent && (!newContentWanted || Node::diff(child->style(), pseudoElementStyle) == Node::Detach)) {
        // Nuke the child. 
        if (child->style()->styleType() == type) {
            oldContentPresent = false;
            child->destroy();
            child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild();
        }
    }

    // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we
    // have no generated content and can now return.
    if (!newContentWanted)
        return;

    if (owner->isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && pseudoElementStyle->floating() == FNONE &&
        !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition))
        // According to the CSS2 spec (the end of section 12.1), the only allowed
        // display values for the pseudo style are NONE and INLINE for inline flows.
        // FIXME: CSS2.1 lifted this restriction, but block display types will crash.
        // For now we at least relax the restriction to allow all inline types like inline-block
        // and inline-table.
        pseudoElementStyle->setDisplay(INLINE);

    if (oldContentPresent) {
        if (child && child->style()->styleType() == type) {
            // We have generated content present still.  We want to walk this content and update our
            // style information with the new pseudo-element style.
            child->setStyle(pseudoElementStyle);

            RenderObject* beforeAfterParent = findBeforeAfterParent(child);
            if (!beforeAfterParent)
                return;

            // Note that if we ever support additional types of generated content (which should be way off
            // in the future), this code will need to be patched.
            for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) {
                if (genChild->isText())
                    // Generated text content is a child whose style also needs to be set to the pseudo-element style.
                    genChild->setStyle(pseudoElementStyle);
                else if (genChild->isImage()) {
                    // Images get an empty style that inherits from the pseudo.
                    RefPtr<RenderStyle> style = RenderStyle::create();
                    style->inheritFrom(pseudoElementStyle);
                    genChild->setStyle(style.release());
                } else {
                    // RenderListItem may insert a list marker here. We do not need to care about this case.
                    // Otherwise, genChild must be a first-letter container. updateFirstLetter() will take care of it.
                    ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER);
                }
            }
        }
        return; // We've updated the generated content. That's all we needed to do.
    }
    
    RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0;

    // Generated content consists of a single container that houses multiple children (specified
    // by the content property).  This generated content container gets the pseudo-element style set on it.
    RenderObject* generatedContentContainer = 0;
    
    // Walk our list of generated content and create render objects for each.
    for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) {
        RenderObject* renderer = 0;
        switch (content->type()) {
            case CONTENT_NONE:
                break;
            case CONTENT_TEXT:
                renderer = new (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, content->text());
                renderer->setStyle(pseudoElementStyle);
                break;
            case CONTENT_OBJECT: {
                RenderImageGeneratedContent* image = new (owner->renderArena()) RenderImageGeneratedContent(owner->document()); // anonymous object
                RefPtr<RenderStyle> style = RenderStyle::create();
                style->inheritFrom(pseudoElementStyle);
                image->setStyle(style.release());
                if (StyleImage* styleImage = content->image())
                    image->setStyleImage(styleImage);
                renderer = image;
                break;
            }
            case CONTENT_COUNTER:
                renderer = new (owner->renderArena()) RenderCounter(owner->document(), *content->counter());
                renderer->setStyle(pseudoElementStyle);
                break;
        }

        if (renderer) {
            if (!generatedContentContainer) {
                // Make a generated box that might be any display type now that we are able to drill down into children
                // to find the original content properly.
                generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle);
                generatedContentContainer->setStyle(pseudoElementStyle);
                owner->addChild(generatedContentContainer, insertBefore);
            }
            if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle))
                generatedContentContainer->addChild(renderer);
            else
                renderer->destroy();
        }
    }
}
Esempio n. 22
0
void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject)
{
    // Double check that the document did in fact use generated content rules.  Otherwise we should not have been called.
    ASSERT(owner->document()->usesBeforeAfterRules());

    // In CSS2, before/after pseudo-content cannot nest.  Check this first.
    if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER)
        return;
    
    if (!styledObject)
        styledObject = owner;

    RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
    RenderObject* child;
    switch (type) {
    case BEFORE:
        child = beforePseudoElementRenderer(owner);
        break;
    case AFTER:
        child = afterPseudoElementRenderer(owner);
        break;
    default:
        ASSERT_NOT_REACHED();
        return;
    }

    // Whether or not we currently have generated content attached.
    bool oldContentPresent = child;

    // Whether or not we now want generated content.
    bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE;

    // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate
    // :after content and not :before content.
    if (newContentWanted && type == BEFORE && owner->isElementContinuation())
        newContentWanted = false;

    // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object,
    // then we don't generate the :after content.
    if (newContentWanted && type == AFTER && owner->virtualContinuation())
        newContentWanted = false;
    
    // If we don't want generated content any longer, or if we have generated content, but it's no longer
    // identical to the new content data we want to build render objects for, then we nuke all
    // of the old generated content.
    if (oldContentPresent && (!newContentWanted || Node::diff(child->style(), pseudoElementStyle, owner->document()) == Node::Detach)) {
        // Nuke the child. 
        if (child->style()->styleType() == type) {
            oldContentPresent = false;
            child->destroy();
            child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild();
        }
    }

    // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we
    // have no generated content and can now return.
    if (!newContentWanted)
        return;

    if (owner->isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && !pseudoElementStyle->isFloating() &&
        !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition))
        // According to the CSS2 spec (the end of section 12.1), the only allowed
        // display values for the pseudo style are NONE and INLINE for inline flows.
        // FIXME: CSS2.1 lifted this restriction, but block display types will crash.
        // For now we at least relax the restriction to allow all inline types like inline-block
        // and inline-table.
        pseudoElementStyle->setDisplay(INLINE);

    if (oldContentPresent) {
        updateBeforeAfterStyle(child, type, pseudoElementStyle);
        return; // We've updated the generated content. That's all we needed to do.
    }
    
    RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0;
    if (insertBefore && insertBefore->isAnonymousBlock() && insertBefore->childrenInline() && !insertBefore->isEmpty()) {
        // We are going to add the "before" element. We have to check whether the "insertBefore" element
        // is an anonymous block with inline children. If it is, then we should insert the "before" element
        // before the first inline child of the anonymous block, otherwise we will end up with the "before"
        // element in a different block. We do this only when the anonymous block has children, otherwise
        // we end up with the before element in a wrong block.
        insertBefore = insertBefore->firstChild();
    }

    // Generated content consists of a single container that houses multiple children (specified
    // by the content property).  This generated content container gets the pseudo-element style set on it.
    RenderObject* generatedContentContainer = 0;

    // Walk our list of generated content and create render objects for each.
    for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) {
        RenderObject* renderer =  createRenderForBeforeAfterContent(owner, content, pseudoElementStyle);

        if (renderer) {
            if (!generatedContentContainer) {
                // Make a generated box that might be any display type now that we are able to drill down into children
                // to find the original content properly.
                generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle);
                ASSERT(styledObject->node()); // The styled object cannot be anonymous or else it could not have ':before' or ':after' pseudo elements.
                generatedContentContainer->setNode(styledObject->node()); // This allows access to the generatingNode.
                generatedContentContainer->setStyle(pseudoElementStyle);
                if (!owner->isChildAllowed(generatedContentContainer, pseudoElementStyle)) {
                    // The generated content container is not allowed here -> abort.
                    generatedContentContainer->destroy();
                    renderer->destroy();
                    return;
                }

                // When we don't have a first child and are part of a continuation chain,
                // insertBefore is incorrectly set to zero above, which causes the :before
                // child to end up at the end of continuation chain.
                // See https://bugs.webkit.org/show_bug.cgi?id=78380.
                if (!insertBefore && type == BEFORE && owner->virtualContinuation())
                    owner->addChildIgnoringContinuation(generatedContentContainer, 0);
                else
                    owner->addChild(generatedContentContainer, insertBefore);
            }
            if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle))
                generatedContentContainer->addChild(renderer);
            else
                renderer->destroy();
        }
    }
}
// FIXME: Generate this function.
PassRefPtrWillBeRawPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID property, const RenderStyle& style)
{
    ASSERT(CSSPropertyMetadata::isAnimatableProperty(property));
    switch (property) {
    case CSSPropertyBackgroundColor:
        return createFromColor(property, style);
    case CSSPropertyBackgroundImage:
        return createFromFillLayers<CSSPropertyBackgroundImage>(style.backgroundLayers(), style);
    case CSSPropertyBackgroundPositionX:
        return createFromFillLayers<CSSPropertyBackgroundPositionX>(style.backgroundLayers(), style);
    case CSSPropertyBackgroundPositionY:
        return createFromFillLayers<CSSPropertyBackgroundPositionY>(style.backgroundLayers(), style);
    case CSSPropertyBackgroundSize:
    case CSSPropertyWebkitBackgroundSize:
        return createFromFillLayers<CSSPropertyBackgroundSize>(style.backgroundLayers(), style);
    case CSSPropertyBaselineShift:
        return AnimatableSVGLength::create(style.baselineShiftValue());
    case CSSPropertyBorderBottomColor:
        return createFromColor(property, style);
    case CSSPropertyBorderBottomLeftRadius:
        return createFromLengthSize(style.borderBottomLeftRadius(), style);
    case CSSPropertyBorderBottomRightRadius:
        return createFromLengthSize(style.borderBottomRightRadius(), style);
    case CSSPropertyBorderBottomWidth:
        return createFromDouble(style.borderBottomWidth());
    case CSSPropertyBorderImageOutset:
        return createFromBorderImageLengthBox(style.borderImageOutset(), style);
    case CSSPropertyBorderImageSlice:
        return createFromLengthBox(style.borderImageSlices(), style);
    case CSSPropertyBorderImageSource:
        return createFromStyleImage(style.borderImageSource());
    case CSSPropertyBorderImageWidth:
        return createFromBorderImageLengthBox(style.borderImageWidth(), style);
    case CSSPropertyBorderLeftColor:
        return createFromColor(property, style);
    case CSSPropertyBorderLeftWidth:
        return createFromDouble(style.borderLeftWidth());
    case CSSPropertyBorderRightColor:
        return createFromColor(property, style);
    case CSSPropertyBorderRightWidth:
        return createFromDouble(style.borderRightWidth());
    case CSSPropertyBorderTopColor:
        return createFromColor(property, style);
    case CSSPropertyBorderTopLeftRadius:
        return createFromLengthSize(style.borderTopLeftRadius(), style);
    case CSSPropertyBorderTopRightRadius:
        return createFromLengthSize(style.borderTopRightRadius(), style);
    case CSSPropertyBorderTopWidth:
        return createFromDouble(style.borderTopWidth());
    case CSSPropertyBottom:
        return createFromLength(style.bottom(), style);
    case CSSPropertyBoxShadow:
    case CSSPropertyWebkitBoxShadow:
        return AnimatableShadow::create(style.boxShadow());
    case CSSPropertyClip:
        if (style.hasAutoClip())
            return AnimatableUnknown::create(CSSPrimitiveValue::create(CSSValueAuto));
        return createFromLengthBox(style.clip(), style);
    case CSSPropertyColor:
        return createFromColor(property, style);
    case CSSPropertyFillOpacity:
        return createFromDouble(style.fillOpacity());
    case CSSPropertyFill:
        return AnimatableSVGPaint::create(
            normalizeSVGPaintType(style.svgStyle().fillPaintType()), normalizeSVGPaintType(style.svgStyle().visitedLinkFillPaintType()),
            style.svgStyle().fillPaintColor(), style.svgStyle().visitedLinkFillPaintColor(),
            style.svgStyle().fillPaintUri(), style.svgStyle().visitedLinkFillPaintUri());
    case CSSPropertyFlexGrow:
        return createFromDouble(style.flexGrow(), AnimatableDouble::InterpolationIsNonContinuousWithZero);
    case CSSPropertyFlexShrink:
        return createFromDouble(style.flexShrink(), AnimatableDouble::InterpolationIsNonContinuousWithZero);
    case CSSPropertyFlexBasis:
        return createFromLength(style.flexBasis(), style);
    case CSSPropertyFloodColor:
        return createFromColor(property, style);
    case CSSPropertyFloodOpacity:
        return createFromDouble(style.floodOpacity());
    case CSSPropertyFontSize:
        // Must pass a specified size to setFontSize if Text Autosizing is enabled, but a computed size
        // if text zoom is enabled (if neither is enabled it's irrelevant as they're probably the same).
        // FIXME: Should we introduce an option to pass the computed font size here, allowing consumers to
        // enable text zoom rather than Text Autosizing? See http://crbug.com/227545.
        return createFromDouble(style.specifiedFontSize());
    case CSSPropertyFontStretch:
        return createFromFontStretch(style.fontStretch());
    case CSSPropertyFontWeight:
        return createFromFontWeight(style.fontWeight());
    case CSSPropertyHeight:
        return createFromLength(style.height(), style);
    case CSSPropertyLightingColor:
        return createFromColor(property, style);
    case CSSPropertyListStyleImage:
        return createFromStyleImage(style.listStyleImage());
    case CSSPropertyLeft:
        return createFromLength(style.left(), style);
    case CSSPropertyLetterSpacing:
        return createFromDouble(style.letterSpacing());
    case CSSPropertyLineHeight:
        return createFromLineHeight(style.specifiedLineHeight(), style);
    case CSSPropertyMarginBottom:
        return createFromLength(style.marginBottom(), style);
    case CSSPropertyMarginLeft:
        return createFromLength(style.marginLeft(), style);
    case CSSPropertyMarginRight:
        return createFromLength(style.marginRight(), style);
    case CSSPropertyMarginTop:
        return createFromLength(style.marginTop(), style);
    case CSSPropertyMaxHeight:
        return createFromLength(style.maxHeight(), style);
    case CSSPropertyMaxWidth:
        return createFromLength(style.maxWidth(), style);
    case CSSPropertyMinHeight:
        return createFromLength(style.minHeight(), style);
    case CSSPropertyMinWidth:
        return createFromLength(style.minWidth(), style);
    case CSSPropertyObjectPosition:
        return createFromLengthPoint(style.objectPosition(), style);
    case CSSPropertyOpacity:
        return createFromDouble(style.opacity());
    case CSSPropertyOrphans:
        return createFromDouble(style.orphans());
    case CSSPropertyOutlineColor:
        return createFromColor(property, style);
    case CSSPropertyOutlineOffset:
        return createFromDouble(style.outlineOffset());
    case CSSPropertyOutlineWidth:
        return createFromDouble(style.outlineWidth());
    case CSSPropertyPaddingBottom:
        return createFromLength(style.paddingBottom(), style);
    case CSSPropertyPaddingLeft:
        return createFromLength(style.paddingLeft(), style);
    case CSSPropertyPaddingRight:
        return createFromLength(style.paddingRight(), style);
    case CSSPropertyPaddingTop:
        return createFromLength(style.paddingTop(), style);
    case CSSPropertyRight:
        return createFromLength(style.right(), style);
    case CSSPropertyStrokeWidth:
        return AnimatableSVGLength::create(style.strokeWidth());
    case CSSPropertyStopColor:
        return createFromColor(property, style);
    case CSSPropertyStopOpacity:
        return createFromDouble(style.stopOpacity());
    case CSSPropertyStrokeDasharray:
        return AnimatableStrokeDasharrayList::create(style.strokeDashArray());
    case CSSPropertyStrokeDashoffset:
        return AnimatableSVGLength::create(style.strokeDashOffset());
    case CSSPropertyStrokeMiterlimit:
        return createFromDouble(style.strokeMiterLimit());
    case CSSPropertyStrokeOpacity:
        return createFromDouble(style.strokeOpacity());
    case CSSPropertyStroke:
        return AnimatableSVGPaint::create(
            normalizeSVGPaintType(style.svgStyle().strokePaintType()), normalizeSVGPaintType(style.svgStyle().visitedLinkStrokePaintType()),
            style.svgStyle().strokePaintColor(), style.svgStyle().visitedLinkStrokePaintColor(),
            style.svgStyle().strokePaintUri(), style.svgStyle().visitedLinkStrokePaintUri());
    case CSSPropertyTextDecorationColor:
        return createFromColor(property, style);
    case CSSPropertyTextIndent:
        return createFromLength(style.textIndent(), style);
    case CSSPropertyTextShadow:
        return AnimatableShadow::create(style.textShadow());
    case CSSPropertyTop:
        return createFromLength(style.top(), style);
    case CSSPropertyWebkitBorderHorizontalSpacing:
        return createFromDouble(style.horizontalBorderSpacing());
    case CSSPropertyWebkitBorderVerticalSpacing:
        return createFromDouble(style.verticalBorderSpacing());
    case CSSPropertyWebkitClipPath:
        if (ClipPathOperation* operation = style.clipPath())
            return AnimatableClipPathOperation::create(operation);
        return AnimatableUnknown::create(CSSValueNone);
    case CSSPropertyWebkitColumnCount:
        return createFromDouble(style.columnCount());
    case CSSPropertyWebkitColumnGap:
        return createFromDouble(style.columnGap());
    case CSSPropertyWebkitColumnRuleColor:
        return createFromColor(property, style);
    case CSSPropertyWebkitColumnRuleWidth:
        return createFromDouble(style.columnRuleWidth());
    case CSSPropertyWebkitColumnWidth:
        return createFromDouble(style.columnWidth());
    case CSSPropertyWebkitFilter:
        return AnimatableFilterOperations::create(style.filter());
    case CSSPropertyWebkitMaskBoxImageOutset:
        return createFromBorderImageLengthBox(style.maskBoxImageOutset(), style);
    case CSSPropertyWebkitMaskBoxImageSlice:
        return createFromLengthBoxAndBool(style.maskBoxImageSlices(), style.maskBoxImageSlicesFill(), style);
    case CSSPropertyWebkitMaskBoxImageSource:
        return createFromStyleImage(style.maskBoxImageSource());
    case CSSPropertyWebkitMaskBoxImageWidth:
        return createFromBorderImageLengthBox(style.maskBoxImageWidth(), style);
    case CSSPropertyWebkitMaskImage:
        return createFromFillLayers<CSSPropertyWebkitMaskImage>(style.maskLayers(), style);
    case CSSPropertyWebkitMaskPositionX:
        return createFromFillLayers<CSSPropertyWebkitMaskPositionX>(style.maskLayers(), style);
    case CSSPropertyWebkitMaskPositionY:
        return createFromFillLayers<CSSPropertyWebkitMaskPositionY>(style.maskLayers(), style);
    case CSSPropertyWebkitMaskSize:
        return createFromFillLayers<CSSPropertyWebkitMaskSize>(style.maskLayers(), style);
    case CSSPropertyPerspective:
        return createFromDouble(style.perspective());
    case CSSPropertyPerspectiveOrigin:
        return createFromLengthPoint(style.perspectiveOrigin(), style);
    case CSSPropertyShapeOutside:
        return createFromShapeValue(style.shapeOutside());
    case CSSPropertyShapeMargin:
        return createFromLength(style.shapeMargin(), style);
    case CSSPropertyShapeImageThreshold:
        return createFromDouble(style.shapeImageThreshold());
    case CSSPropertyWebkitTextStrokeColor:
        return createFromColor(property, style);
    case CSSPropertyTransform:
        return AnimatableTransform::create(style.transform());
    case CSSPropertyTransformOrigin:
        return createFromTransformOrigin(style.transformOrigin(), style);
    case CSSPropertyMotionPosition:
        return createFromLength(style.motionPosition(), style);
    case CSSPropertyMotionRotation:
        return createFromDoubleAndBool(style.motionRotation(), style.motionRotationType() == MotionRotationAuto, style);
    case CSSPropertyWidows:
        return createFromDouble(style.widows());
    case CSSPropertyWidth:
        return createFromLength(style.width(), style);
    case CSSPropertyWordSpacing:
        return createFromDouble(style.wordSpacing());
    case CSSPropertyVerticalAlign:
        if (style.verticalAlign() == LENGTH)
            return createFromLength(style.verticalAlignLength(), style);
        return AnimatableUnknown::create(CSSPrimitiveValue::create(style.verticalAlign()));
    case CSSPropertyVisibility:
        return AnimatableVisibility::create(style.visibility());
    case CSSPropertyZIndex:
        return createFromDouble(style.zIndex());
    case CSSPropertyZoom:
        return createFromDouble(style.zoom());
    default:
        ASSERT_NOT_REACHED();
        // This return value is to avoid a release crash if possible.
        return AnimatableUnknown::create(nullptr);
    }
}
void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom)
{
    GraphicsContext* context = paintInfo.context;
    RenderStyle* style = m_renderer->style(isFirstLineStyle());
    Color textColor = style->visitedDependentColor(CSSPropertyWebkitTextFillColor);
    if (textColor != context->fillColor())
        context->setFillColor(textColor, style->colorSpace());
    bool setShadow = false;
    if (style->textShadow()) {
        context->setShadow(LayoutSize(style->textShadow()->x(), style->textShadow()->y()),
                           style->textShadow()->radius(), style->textShadow()->color(), style->colorSpace());
        setShadow = true;
    }

    const Font& font = style->font();
    if (selectionState() != RenderObject::SelectionNone) {
        paintSelection(context, paintOffset, style, font);

        // Select the correct color for painting the text.
        Color foreground = paintInfo.forceBlackText() ? Color::black : renderer()->selectionForegroundColor();
        if (foreground.isValid() && foreground != textColor)
            context->setFillColor(foreground, style->colorSpace());
    }

    // FIXME: Why is this always LTR? Fix by passing correct text run flags below.
    context->drawText(font, RenderBlock::constructTextRun(renderer(), font, m_str, style, TextRun::AllowTrailingExpansion), LayoutPoint(x() + paintOffset.x(), y() + paintOffset.y() + style->fontMetrics().ascent()));

    // Restore the regular fill color.
    if (textColor != context->fillColor())
        context->setFillColor(textColor, style->colorSpace());

    if (setShadow)
        context->clearShadow();

    paintMarkupBox(paintInfo, paintOffset, lineTop, lineBottom, style);
}
Esempio n. 25
0
bool RenderStyle::diffNeedsFullLayout(const RenderStyle& other) const
{
    // FIXME: Not all cases in this method need both full layout and paint invalidation.
    // Should move cases into diffNeedsFullLayout() if
    // - don't need paint invalidation at all;
    // - or the renderer knows how to exactly invalidate paints caused by the layout change
    //   instead of forced full paint invalidation.

    if (surround.get() != other.surround.get()) {
        // If our border widths change, then we need to layout. Other changes to borders only necessitate a paint invalidation.
        if (borderLeftWidth() != other.borderLeftWidth()
            || borderTopWidth() != other.borderTopWidth()
            || borderBottomWidth() != other.borderBottomWidth()
            || borderRightWidth() != other.borderRightWidth())
            return true;
    }

    if (rareNonInheritedData.get() != other.rareNonInheritedData.get()) {
        if (rareNonInheritedData->textOverflow != other.rareNonInheritedData->textOverflow
            || rareNonInheritedData->m_wrapFlow != other.rareNonInheritedData->m_wrapFlow
            || rareNonInheritedData->m_wrapThrough != other.rareNonInheritedData->m_wrapThrough
            || rareNonInheritedData->m_order != other.rareNonInheritedData->m_order
            || rareNonInheritedData->m_alignContent != other.rareNonInheritedData->m_alignContent
            || rareNonInheritedData->m_alignItems != other.rareNonInheritedData->m_alignItems
            || rareNonInheritedData->m_alignSelf != other.rareNonInheritedData->m_alignSelf
            || rareNonInheritedData->m_justifyContent != other.rareNonInheritedData->m_justifyContent)
            return true;

        if (rareNonInheritedData->m_flexibleBox.get() != other.rareNonInheritedData->m_flexibleBox.get()
            && *rareNonInheritedData->m_flexibleBox.get() != *other.rareNonInheritedData->m_flexibleBox.get())
            return true;

        // FIXME: We should add an optimized form of layout that just recomputes visual overflow.
        if (!rareNonInheritedData->shadowDataEquivalent(*other.rareNonInheritedData.get()))
            return true;

        // If the counter directives change, trigger a relayout to re-calculate counter values and rebuild the counter node tree.
        const CounterDirectiveMap* mapA = rareNonInheritedData->m_counterDirectives.get();
        const CounterDirectiveMap* mapB = other.rareNonInheritedData->m_counterDirectives.get();
        if (!(mapA == mapB || (mapA && mapB && *mapA == *mapB)))
            return true;

        // We only need do layout for opacity changes if adding or losing opacity could trigger a change
        // in us being a stacking context.
        if (hasAutoZIndex() != other.hasAutoZIndex() && rareNonInheritedData->hasOpacity() != other.rareNonInheritedData->hasOpacity()) {
            // FIXME: We would like to use SimplifiedLayout here, but we can't quite do that yet.
            // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need
            // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line).
            // In addition we need to solve the floating object issue when layers come and go. Right now
            // a full layout is necessary to keep floating object lists sane.
            return true;
        }
    }

    if (rareInheritedData.get() != other.rareInheritedData.get()) {
        if (rareInheritedData->highlight != other.rareInheritedData->highlight
            || rareInheritedData->indent != other.rareInheritedData->indent
            || rareInheritedData->m_textAlignLast != other.rareInheritedData->m_textAlignLast
            || rareInheritedData->m_textIndentLine != other.rareInheritedData->m_textIndentLine
            || rareInheritedData->wordBreak != other.rareInheritedData->wordBreak
            || rareInheritedData->overflowWrap != other.rareInheritedData->overflowWrap
            || rareInheritedData->lineBreak != other.rareInheritedData->lineBreak
            || rareInheritedData->hyphens != other.rareInheritedData->hyphens
            || rareInheritedData->hyphenationLimitBefore != other.rareInheritedData->hyphenationLimitBefore
            || rareInheritedData->hyphenationLimitAfter != other.rareInheritedData->hyphenationLimitAfter
            || rareInheritedData->hyphenationString != other.rareInheritedData->hyphenationString
            || rareInheritedData->locale != other.rareInheritedData->locale
            || rareInheritedData->textEmphasisMark != other.rareInheritedData->textEmphasisMark
            || rareInheritedData->textEmphasisPosition != other.rareInheritedData->textEmphasisPosition
            || rareInheritedData->textEmphasisCustomMark != other.rareInheritedData->textEmphasisCustomMark
            || rareInheritedData->m_textJustify != other.rareInheritedData->m_textJustify
            || rareInheritedData->m_textOrientation != other.rareInheritedData->m_textOrientation
            || rareInheritedData->m_tabSize != other.rareInheritedData->m_tabSize
            || rareInheritedData->m_lineBoxContain != other.rareInheritedData->m_lineBoxContain
            || rareInheritedData->textStrokeWidth != other.rareInheritedData->textStrokeWidth)
            return true;

        if (!rareInheritedData->shadowDataEquivalent(*other.rareInheritedData.get()))
            return true;
    }

    if (inherited.get() != other.inherited.get()) {
        if (inherited->line_height != other.inherited->line_height
            || inherited->font != other.inherited->font
            || inherited->horizontal_border_spacing != other.inherited->horizontal_border_spacing
            || inherited->vertical_border_spacing != other.inherited->vertical_border_spacing)
            return true;
    }

    if (inherited_flags.m_rtlOrdering != other.inherited_flags.m_rtlOrdering
        || inherited_flags._text_align != other.inherited_flags._text_align
        || inherited_flags._direction != other.inherited_flags._direction
        || inherited_flags._white_space != other.inherited_flags._white_space)
        return true;

    if (noninherited_flags.overflowX != other.noninherited_flags.overflowX
        || noninherited_flags.overflowY != other.noninherited_flags.overflowY
        || noninherited_flags.unicodeBidi != other.noninherited_flags.unicodeBidi
        || noninherited_flags.position != other.noninherited_flags.position
        || noninherited_flags.originalDisplay != other.noninherited_flags.originalDisplay)
        return true;

    if (!m_background->outline().visuallyEqual(other.m_background->outline())) {
        // FIXME: We only really need to recompute the overflow but we don't have an optimized layout for it.
        return true;
    }

    if (m_box.get() != other.m_box.get()) {
        if (m_box->width() != other.m_box->width()
            || m_box->minWidth() != other.m_box->minWidth()
            || m_box->maxWidth() != other.m_box->maxWidth()
            || m_box->height() != other.m_box->height()
            || m_box->minHeight() != other.m_box->minHeight()
            || m_box->maxHeight() != other.m_box->maxHeight())
            return true;

        if (m_box->verticalAlign() != other.m_box->verticalAlign())
            return true;

        if (m_box->boxSizing() != other.m_box->boxSizing())
            return true;
    }

    if (noninherited_flags.verticalAlign != other.noninherited_flags.verticalAlign)
        return true;

    if (surround.get() != other.surround.get()) {
        if (surround->margin != other.surround->margin)
            return true;

        if (surround->padding != other.surround->padding)
            return true;
    }

    // Movement of non-static-positioned object is special cased in RenderStyle::visualInvalidationDiff().

    return false;
}
Esempio n. 26
0
void RenderLayerModelObject::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
{
    s_wasFloating = isFloating();
    s_hadLayer = hasLayer();
    s_hadTransform = hasTransform();
    if (s_hadLayer)
        s_layerWasSelfPainting = layer()->isSelfPaintingLayer();

    // If our z-index changes value or our visibility changes,
    // we need to dirty our stacking context's z-order list.
    RenderStyle* oldStyle = style();
    if (oldStyle && newStyle) {
        if (parent()) {
            // Do a repaint with the old style first, e.g., for example if we go from
            // having an outline to not having an outline.
            if (diff == StyleDifferenceRepaintLayer) {
                layer()->repaintIncludingDescendants();
                if (!(oldStyle->clip() == newStyle->clip()))
                    layer()->clearClipRectsIncludingDescendants();
            } else if (diff == StyleDifferenceRepaint || newStyle->outlineSize() < oldStyle->outlineSize())
                repaint();
        }

        if (diff == StyleDifferenceLayout || diff == StyleDifferenceSimplifiedLayout) {
            // When a layout hint happens, we go ahead and do a repaint of the layer, since the layer could
            // end up being destroyed.
            if (hasLayer()) {
                if (oldStyle->position() != newStyle->position()
                    || oldStyle->zIndex() != newStyle->zIndex()
                    || oldStyle->hasAutoZIndex() != newStyle->hasAutoZIndex()
                    || !(oldStyle->clip() == newStyle->clip())
                    || oldStyle->hasClip() != newStyle->hasClip()
                    || oldStyle->opacity() != newStyle->opacity()
                    || oldStyle->transform() != newStyle->transform()
                    || oldStyle->filter() != newStyle->filter()
                    )
                layer()->repaintIncludingDescendants();
            } else if (newStyle->hasTransform() || newStyle->opacity() < 1 || newStyle->hasFilter()) {
                // If we don't have a layer yet, but we are going to get one because of transform or opacity,
                //  then we need to repaint the old position of the object.
                repaint();
            }
        }
    }

    RenderObject::styleWillChange(diff, newStyle);
}
Esempio n. 27
0
PopupMenuStyle RenderMenuList::menuStyle() const
{
    RenderStyle* s = m_innerBlock ? m_innerBlock->style() : style();
    return PopupMenuStyle(s->visitedDependentColor(CSSPropertyColor), s->visitedDependentColor(CSSPropertyBackgroundColor), s->font(), s->visibility() == VISIBLE,
        s->display() == NONE, s->textIndent(), style()->direction(), isOverride(style()->unicodeBidi()));
}
bool RenderEmbeddedObject::isReplacementObscured() const
{
    // Return whether or not the replacement content for blocked plugins is accessible to the user.

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

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

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

    return false;
}
bool HTMLOptGroupElement::isDisplayNone() const
{
    RenderStyle* style = nonRendererStyle();
    return style && style->display() == NONE;
}
Esempio n. 30
0
bool HTMLFrameSetElement::rendererIsNeeded(const RenderStyle& style)
{
    // For compatibility, frames render even when display: none is set.
    // However, we delay creating a renderer until stylesheets have loaded. 
    return style.isStyleAvailable();
}