static PassRefPtrWillBeRawPtr<AnimatableValue> createFromLength(const Length& length, const RenderStyle& style)
{
    switch (length.type()) {
    case Fixed:
    case Percent:
    case Calculated:
        return AnimatableLength::create(length, style.effectiveZoom());
    case Auto:
    case Intrinsic:
    case MinIntrinsic:
    case MinContent:
    case MaxContent:
    case FillAvailable:
    case FitContent:
        return AnimatableUnknown::create(CSSPrimitiveValue::create(length, 1));
    case MaxSizeNone:
        return AnimatableUnknown::create(CSSValueNone);
    case ExtendToZoom: // Does not apply to elements.
    case DeviceWidth:
    case DeviceHeight:
        ASSERT_NOT_REACHED();
        return nullptr;
    }
    ASSERT_NOT_REACHED();
    return nullptr;
}
AffineTransform SVGGraphicsElement::animatedLocalTransform() const
{
    AffineTransform matrix;
    RenderStyle* style = renderer() ? &renderer()->style() : nullptr;

    // If CSS property was set, use that, otherwise fallback to attribute (if set).
    if (style && style->hasTransform()) {
        // Note: objectBoundingBox is an emptyRect for elements like pattern or clipPath.
        // See the "Object bounding box units" section of http://dev.w3.org/csswg/css3-transforms/
        TransformationMatrix transform;
        style->applyTransform(transform, renderer()->objectBoundingBox());

        // Flatten any 3D transform.
        matrix = transform.toAffineTransform();
        // CSS bakes the zoom factor into lengths, including translation components.
        // In order to align CSS & SVG transforms, we need to invert this operation.
        float zoom = style->effectiveZoom();
        if (zoom != 1) {
            matrix.setE(matrix.e() / zoom);
            matrix.setF(matrix.f() / zoom);
        }

    } else
        transform().concatenate(matrix);

    if (m_supplementalTransform)
        return *m_supplementalTransform * matrix;
    return matrix;
}
Example #3
0
AffineTransform SVGGraphicsElement::calculateAnimatedLocalTransform() const
{
    AffineTransform matrix;
    RenderStyle* style = renderer() ? renderer()->style() : 0;

    // If CSS property was set, use that, otherwise fallback to attribute (if set).
    if (style && style->hasTransform()) {
        TransformationMatrix transform;
        float zoom = style->effectiveZoom();

        // SVGTextElements need special handling for the text positioning code.
        if (isSVGTextElement(this)) {
            // Do not take into account SVG's zoom rules, transform-origin, or percentage values.
            style->applyTransform(transform, IntSize(0, 0), RenderStyle::ExcludeTransformOrigin);
        } else {
            // CSS transforms operate with pre-scaled lengths. To make this work with SVG
            // (which applies the zoom factor globally, at the root level) we
            //
            //   * pre-scale the bounding box (to bring it into the same space as the other CSS values)
            //   * invert the zoom factor (to effectively compute the CSS transform under a 1.0 zoom)
            //
            // Note: objectBoundingBox is an emptyRect for elements like pattern or clipPath.
            // See the "Object bounding box units" section of http://dev.w3.org/csswg/css3-transforms/
            if (zoom != 1) {
                FloatRect scaledBBox = renderer()->objectBoundingBox();
                scaledBBox.scale(zoom);
                transform.scale(1 / zoom);
                style->applyTransform(transform, scaledBBox);
                transform.scale(zoom);
            } else {
                style->applyTransform(transform, renderer()->objectBoundingBox());
            }
        }

        // Flatten any 3D transform.
        matrix = transform.toAffineTransform();
    } else {
        m_transform->currentValue()->concatenate(matrix);
    }

    if (hasSVGRareData())
        return *svgRareData()->animateMotionTransform() * matrix;
    return matrix;
}
Example #4
0
void RenderMediaControls::adjustMediaSliderThumbSize(RenderStyle& style)
{
    int part;
    switch (style.appearance()) {
    case MediaSliderThumbPart:
        part = MediaSliderThumb;
        break;
    case MediaVolumeSliderThumbPart:
        part = MediaVolumeSliderThumb;
        break;
    case MediaFullScreenVolumeSliderThumbPart:
        part = MediaFullScreenVolumeSliderThumb;
        break;
    default:
        return;
    }

    CGSize size;
    wkMeasureMediaUIPart(part, 0, &size);

    float zoomLevel = style.effectiveZoom();
    style.setWidth(Length(static_cast<int>(size.width * zoomLevel), Fixed));
    style.setHeight(Length(static_cast<int>(size.height * zoomLevel), Fixed));
}
static bool paintMediaVolumeSlider(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
{
    HTMLMediaElement* mediaElement = toParentMediaElement(object);
    if (!mediaElement)
        return false;

    GraphicsContext* context = paintInfo.context;
    RenderStyle* style = object->style();

    paintRoundedSliderBackground(rect, style, context);

    // Calculate volume position for white background rectangle.
    float volume = mediaElement->volume();
    if (std::isnan(volume) || volume < 0)
        return true;
    if (volume > 1)
        volume = 1;
    if (!hasSource(mediaElement) || !mediaElement->hasAudio() || mediaElement->muted())
        volume = 0;

    // Calculate the position relative to the center of the thumb.
    float fillWidth = 0;
    if (volume > 0) {
        float thumbCenter = mediaVolumeSliderThumbWidth / 2;
        float zoomLevel = style->effectiveZoom();
        float positionWidth = volume * (rect.width() - (zoomLevel * thumbCenter));
        fillWidth = positionWidth + (zoomLevel * thumbCenter / 2);
    }

    Color startColor = Color(195, 195, 195);
    Color endColor = Color(217, 217, 217);

    paintSliderRangeHighlight(rect, style, context, 0.0, fillWidth, startColor, endColor);

    return true;
}
Example #6
0
void RenderTheme::adjustStyle(StyleResolver& styleResolver, RenderStyle& style, Element* element, bool UAHasAppearance, const BorderData& border, const FillLayer& background, const Color& backgroundColor)
{
    // Force inline and table display styles to be inline-block (except for table- which is block)
    ControlPart part = style.appearance();
    if (style.display() == INLINE || style.display() == INLINE_TABLE || style.display() == TABLE_ROW_GROUP
        || style.display() == TABLE_HEADER_GROUP || style.display() == TABLE_FOOTER_GROUP
        || style.display() == TABLE_ROW || style.display() == TABLE_COLUMN_GROUP || style.display() == TABLE_COLUMN
        || style.display() == TABLE_CELL || style.display() == TABLE_CAPTION)
        style.setDisplay(INLINE_BLOCK);
    else if (style.display() == COMPACT || style.display() == LIST_ITEM || style.display() == TABLE)
        style.setDisplay(BLOCK);

    if (UAHasAppearance && isControlStyled(style, border, background, backgroundColor)) {
        if (part == MenulistPart) {
            style.setAppearance(MenulistButtonPart);
            part = MenulistButtonPart;
        } else
            style.setAppearance(NoControlPart);
    }

    if (!style.hasAppearance())
        return;

    // Never support box-shadow on native controls.
    style.setBoxShadow(nullptr);
    
#if USE(NEW_THEME)
    switch (part) {
    case CheckboxPart:
    case InnerSpinButtonPart:
    case RadioPart:
    case PushButtonPart:
    case SquareButtonPart:
    case DefaultButtonPart:
    case ButtonPart: {
        // Border
        LengthBox borderBox(style.borderTopWidth(), style.borderRightWidth(), style.borderBottomWidth(), style.borderLeftWidth());
        borderBox = m_theme->controlBorder(part, style.fontCascade(), borderBox, style.effectiveZoom());
        if (borderBox.top().value() != static_cast<int>(style.borderTopWidth())) {
            if (borderBox.top().value())
                style.setBorderTopWidth(borderBox.top().value());
            else
                style.resetBorderTop();
        }
        if (borderBox.right().value() != static_cast<int>(style.borderRightWidth())) {
            if (borderBox.right().value())
                style.setBorderRightWidth(borderBox.right().value());
            else
                style.resetBorderRight();
        }
        if (borderBox.bottom().value() != static_cast<int>(style.borderBottomWidth())) {
            style.setBorderBottomWidth(borderBox.bottom().value());
            if (borderBox.bottom().value())
                style.setBorderBottomWidth(borderBox.bottom().value());
            else
                style.resetBorderBottom();
        }
        if (borderBox.left().value() != static_cast<int>(style.borderLeftWidth())) {
            style.setBorderLeftWidth(borderBox.left().value());
            if (borderBox.left().value())
                style.setBorderLeftWidth(borderBox.left().value());
            else
                style.resetBorderLeft();
        }

        // Padding
        LengthBox paddingBox = m_theme->controlPadding(part, style.fontCascade(), style.paddingBox(), style.effectiveZoom());
        if (paddingBox != style.paddingBox())
            style.setPaddingBox(paddingBox);

        // Whitespace
        if (m_theme->controlRequiresPreWhiteSpace(part))
            style.setWhiteSpace(PRE);
            
        // Width / Height
        // The width and height here are affected by the zoom.
        // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
        LengthSize controlSize = m_theme->controlSize(part, style.fontCascade(), LengthSize(style.width(), style.height()), style.effectiveZoom());
        if (controlSize.width() != style.width())
            style.setWidth(controlSize.width());
        if (controlSize.height() != style.height())
            style.setHeight(controlSize.height());
                
        // Min-Width / Min-Height
        LengthSize minControlSize = m_theme->minimumControlSize(part, style.fontCascade(), style.effectiveZoom());
        if (minControlSize.width() != style.minWidth())
            style.setMinWidth(minControlSize.width());
        if (minControlSize.height() != style.minHeight())
            style.setMinHeight(minControlSize.height());
                
        // Font
        if (auto themeFont = m_theme->controlFont(part, style.fontCascade(), style.effectiveZoom())) {
            // If overriding the specified font with the theme font, also override the line height with the standard line height.
            style.setLineHeight(RenderStyle::initialLineHeight());
            if (style.setFontDescription(themeFont.value()))
                style.fontCascade().update(nullptr);
        }

        // Special style that tells enabled default buttons in active windows to use the ActiveButtonText color.
        // The active window part of the test has to be done at paint time since it's not triggered by a style change.
        style.setInsideDefaultButton(part == DefaultButtonPart && element && !element->isDisabledFormControl());
        break;
    }
    default:
        break;
    }
#endif

    // Call the appropriate style adjustment method based off the appearance value.
    switch (style.appearance()) {
#if !USE(NEW_THEME)
    case CheckboxPart:
        return adjustCheckboxStyle(styleResolver, style, element);
    case RadioPart:
        return adjustRadioStyle(styleResolver, style, element);
    case PushButtonPart:
    case SquareButtonPart:
    case DefaultButtonPart:
    case ButtonPart:
        return adjustButtonStyle(styleResolver, style, element);
    case InnerSpinButtonPart:
        return adjustInnerSpinButtonStyle(styleResolver, style, element);
#endif
    case TextFieldPart:
        return adjustTextFieldStyle(styleResolver, style, element);
    case TextAreaPart:
        return adjustTextAreaStyle(styleResolver, style, element);
    case MenulistPart:
        return adjustMenuListStyle(styleResolver, style, element);
    case MenulistButtonPart:
        return adjustMenuListButtonStyle(styleResolver, style, element);
    case MediaPlayButtonPart:
    case MediaCurrentTimePart:
    case MediaTimeRemainingPart:
    case MediaEnterFullscreenButtonPart:
    case MediaExitFullscreenButtonPart:
    case MediaMuteButtonPart:
    case MediaVolumeSliderContainerPart:
        return adjustMediaControlStyle(styleResolver, style, element);
    case MediaSliderPart:
    case MediaVolumeSliderPart:
    case MediaFullScreenVolumeSliderPart:
    case SliderHorizontalPart:
    case SliderVerticalPart:
        return adjustSliderTrackStyle(styleResolver, style, element);
    case SliderThumbHorizontalPart:
    case SliderThumbVerticalPart:
        return adjustSliderThumbStyle(styleResolver, style, element);
    case SearchFieldPart:
        return adjustSearchFieldStyle(styleResolver, style, element);
    case SearchFieldCancelButtonPart:
        return adjustSearchFieldCancelButtonStyle(styleResolver, style, element);
    case SearchFieldDecorationPart:
        return adjustSearchFieldDecorationPartStyle(styleResolver, style, element);
    case SearchFieldResultsDecorationPart:
        return adjustSearchFieldResultsDecorationPartStyle(styleResolver, style, element);
    case SearchFieldResultsButtonPart:
        return adjustSearchFieldResultsButtonStyle(styleResolver, style, element);
    case ProgressBarPart:
        return adjustProgressBarStyle(styleResolver, style, element);
#if ENABLE(METER_ELEMENT)
    case MeterPart:
    case RelevancyLevelIndicatorPart:
    case ContinuousCapacityLevelIndicatorPart:
    case DiscreteCapacityLevelIndicatorPart:
    case RatingLevelIndicatorPart:
        return adjustMeterStyle(styleResolver, style, element);
#endif
#if ENABLE(SERVICE_CONTROLS)
    case ImageControlsButtonPart:
        break;
#endif
    case CapsLockIndicatorPart:
        return adjustCapsLockIndicatorStyle(styleResolver, style, element);
#if ENABLE(ATTACHMENT_ELEMENT)
    case AttachmentPart:
        return adjustAttachmentStyle(styleResolver, style, element);
#endif
    default:
        break;
    }
}
Example #7
0
PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSValuePool::createValue(const Length& value, const RenderStyle& style)
{
    return CSSPrimitiveValue::create(value, style.effectiveZoom());
}
static PassRefPtr<AnimatableValue> createFromLength(const Length& length, const RenderStyle& style)
{
    switch (length.type()) {
    case Fixed:
        return AnimatableLength::create(adjustFloatForAbsoluteZoom(length.value(), style), AnimatableLength::UnitTypePixels);
    case Percent:
        return AnimatableLength::create(length.value(), AnimatableLength::UnitTypePercentage);
    case ViewportPercentageWidth:
        return AnimatableLength::create(length.value(), AnimatableLength::UnitTypeViewportWidth);
    case ViewportPercentageHeight:
        return AnimatableLength::create(length.value(), AnimatableLength::UnitTypeViewportHeight);
    case ViewportPercentageMin:
        return AnimatableLength::create(length.value(), AnimatableLength::UnitTypeViewportMin);
    case ViewportPercentageMax:
        return AnimatableLength::create(length.value(), AnimatableLength::UnitTypeViewportMax);
    case Calculated:
        return AnimatableLength::create(CSSCalcValue::createExpressionNode(length.calculationValue()->expression(), style.effectiveZoom()));
    case Auto:
    case Intrinsic:
    case MinIntrinsic:
    case MinContent:
    case MaxContent:
    case FillAvailable:
    case FitContent:
        return AnimatableUnknown::create(CSSPrimitiveValue::create(length));
    case Undefined:
        return AnimatableUnknown::create(CSSValueNone);
    case ExtendToZoom: // Does not apply to elements.
    case Relative: // Does not get used by interpolable properties.
        ASSERT_NOT_REACHED();
        return 0;
    }
    ASSERT_NOT_REACHED();
    return 0;
}
Example #9
0
void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, const RenderSVGInlineText& text, const RenderStyle& style)
{
    if (m_inPathLayout && !m_textPathCalculator)
        return;

    SVGElement* lengthContext = toSVGElement(text.parent()->node());

    RenderObject* textParent = text.parent();
    bool definesTextLength = textParent ? parentDefinesTextLength(textParent) : false;

    const SVGRenderStyle& svgStyle = style.svgStyle();

    m_visualMetricsListOffset = 0;
    m_visualCharacterOffset = 0;

    const Vector<SVGTextMetrics>& visualMetricsValues = text.layoutAttributes()->textMetricsValues();
    ASSERT(!visualMetricsValues.isEmpty());

    const Font& font = style.font();

    SVGTextLayoutEngineSpacing spacingLayout(font, style.effectiveZoom());
    SVGTextLayoutEngineBaseline baselineLayout(font);

    bool didStartTextFragment = false;
    bool applySpacingToNextCharacter = false;

    float lastAngle = 0;
    float baselineShift = baselineLayout.calculateBaselineShift(svgStyle, lengthContext);
    baselineShift -= baselineLayout.calculateAlignmentBaselineShift(m_isVerticalText, &text);

    // Main layout algorithm.
    while (true) {
        // Find the start of the current text box in this list, respecting ligatures.
        SVGTextMetrics visualMetrics(SVGTextMetrics::SkippedSpaceMetrics);
        if (!currentVisualCharacterMetrics(textBox, visualMetricsValues, visualMetrics))
            break;

        if (visualMetrics.isEmpty()) {
            advanceToNextVisualCharacter(visualMetrics);
            continue;
        }

        SVGTextLayoutAttributes* logicalAttributes = 0;
        if (!currentLogicalCharacterAttributes(logicalAttributes))
            break;

        ASSERT(logicalAttributes);
        SVGTextMetrics logicalMetrics(SVGTextMetrics::SkippedSpaceMetrics);
        if (!currentLogicalCharacterMetrics(logicalAttributes, logicalMetrics))
            break;

        SVGCharacterDataMap& characterDataMap = logicalAttributes->characterDataMap();
        SVGCharacterData data;
        SVGCharacterDataMap::iterator it = characterDataMap.find(m_logicalCharacterOffset + 1);
        if (it != characterDataMap.end())
            data = it->value;

        float x = data.x;
        float y = data.y;

        // When we've advanced to the box start offset, determine using the original x/y values,
        // whether this character starts a new text chunk, before doing any further processing.
        if (m_visualCharacterOffset == textBox->start())
            textBox->setStartsNewTextChunk(logicalAttributes->context()->characterStartsNewTextChunk(m_logicalCharacterOffset));

        float angle = data.rotate == SVGTextLayoutAttributes::emptyValue() ? 0 : data.rotate;

        // Calculate glyph orientation angle.
        UChar currentCharacter = text.characterAt(m_visualCharacterOffset);
        float orientationAngle = baselineLayout.calculateGlyphOrientationAngle(m_isVerticalText, svgStyle, currentCharacter);

        // Calculate glyph advance & x/y orientation shifts.
        float xOrientationShift = 0;
        float yOrientationShift = 0;
        float glyphAdvance = baselineLayout.calculateGlyphAdvanceAndOrientation(m_isVerticalText, visualMetrics, orientationAngle, xOrientationShift, yOrientationShift);

        // Assign current text position to x/y values, if needed.
        updateCharacterPositionIfNeeded(x, y);

        // Apply dx/dy value adjustments to current text position, if needed.
        updateRelativePositionAdjustmentsIfNeeded(data.dx, data.dy);

        // Calculate CSS 'letter-spacing' and 'word-spacing' for next character, if needed.
        float spacing = spacingLayout.calculateCSSSpacing(currentCharacter);

        float textPathOffset = 0;
        if (m_inPathLayout) {
            float scaledGlyphAdvance = glyphAdvance * m_textPathScaling;
            if (m_isVerticalText) {
                // If there's an absolute y position available, it marks the beginning of a new position along the path.
                if (y != SVGTextLayoutAttributes::emptyValue())
                    m_textPathCurrentOffset = y + m_textPathStartOffset;

                m_textPathCurrentOffset += m_dy;
                m_dy = 0;

                // Apply dx/dy correction and setup translations that move to the glyph midpoint.
                xOrientationShift += m_dx + baselineShift;
                yOrientationShift -= scaledGlyphAdvance / 2;
            } else {
                // If there's an absolute x position available, it marks the beginning of a new position along the path.
                if (x != SVGTextLayoutAttributes::emptyValue())
                    m_textPathCurrentOffset = x + m_textPathStartOffset;

                m_textPathCurrentOffset += m_dx;
                m_dx = 0;

                // Apply dx/dy correction and setup translations that move to the glyph midpoint.
                xOrientationShift -= scaledGlyphAdvance / 2;
                yOrientationShift += m_dy - baselineShift;
            }

            // Calculate current offset along path.
            textPathOffset = m_textPathCurrentOffset + scaledGlyphAdvance / 2;

            // Move to next character.
            m_textPathCurrentOffset += scaledGlyphAdvance + m_textPathSpacing + spacing * m_textPathScaling;

            // Skip character, if we're before the path.
            if (textPathOffset < 0) {
                advanceToNextLogicalCharacter(logicalMetrics);
                advanceToNextVisualCharacter(visualMetrics);
                continue;
            }

            // Stop processing, if the next character lies behind the path.
            if (textPathOffset > m_textPathLength)
                break;

            FloatPoint point;
            bool ok = m_textPathCalculator->pointAndNormalAtLength(textPathOffset, point, angle);
            ASSERT_UNUSED(ok, ok);
            x = point.x();
            y = point.y();

            // For vertical text on path, the actual angle has to be rotated 90 degrees anti-clockwise, not the orientation angle!
            if (m_isVerticalText)
                angle -= 90;
        } else {
            // Apply all previously calculated shift values.
            if (m_isVerticalText)
                x += baselineShift;
            else
                y -= baselineShift;

            x += m_dx;
            y += m_dy;
        }

        // Determine whether we have to start a new fragment.
        bool shouldStartNewFragment = m_dx || m_dy || m_isVerticalText || m_inPathLayout || angle || angle != lastAngle
            || orientationAngle || applySpacingToNextCharacter || definesTextLength;

        // If we already started a fragment, close it now.
        if (didStartTextFragment && shouldStartNewFragment) {
            applySpacingToNextCharacter = false;
            recordTextFragment(textBox, visualMetricsValues);
        }

        // Eventually start a new fragment, if not yet done.
        if (!didStartTextFragment || shouldStartNewFragment) {
            ASSERT(!m_currentTextFragment.characterOffset);
            ASSERT(!m_currentTextFragment.length);

            didStartTextFragment = true;
            m_currentTextFragment.characterOffset = m_visualCharacterOffset;
            m_currentTextFragment.metricsListOffset = m_visualMetricsListOffset;
            m_currentTextFragment.x = x;
            m_currentTextFragment.y = y;

            // Build fragment transformation.
            if (angle)
                m_currentTextFragment.transform.rotate(angle);

            if (xOrientationShift || yOrientationShift)
                m_currentTextFragment.transform.translate(xOrientationShift, yOrientationShift);

            if (orientationAngle)
                m_currentTextFragment.transform.rotate(orientationAngle);

            m_currentTextFragment.isTextOnPath = m_inPathLayout && m_textPathScaling != 1;
            if (m_currentTextFragment.isTextOnPath) {
                if (m_isVerticalText)
                    m_currentTextFragment.lengthAdjustTransform.scaleNonUniform(1, m_textPathScaling);
                else
                    m_currentTextFragment.lengthAdjustTransform.scaleNonUniform(m_textPathScaling, 1);
            }
        }

        // Update current text position, after processing of the current character finished.
        if (m_inPathLayout)
            updateCurrentTextPosition(x, y, glyphAdvance);
        else {
            // Apply CSS 'kerning', 'letter-spacing' and 'word-spacing' to next character, if needed.
            if (spacing)
                applySpacingToNextCharacter = true;

            float xNew = x - m_dx;
            float yNew = y - m_dy;

            if (m_isVerticalText)
                xNew -= baselineShift;
            else
                yNew += baselineShift;

            updateCurrentTextPosition(xNew, yNew, glyphAdvance + spacing);
        }

        advanceToNextLogicalCharacter(logicalMetrics);
        advanceToNextVisualCharacter(visualMetrics);
        lastAngle = angle;
    }

    if (!didStartTextFragment)
        return;

    // Close last open fragment, if needed.
    recordTextFragment(textBox, visualMetricsValues);
}