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; }
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; }
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; }
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; } }
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; }
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); }