mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Support logical properties
This commit is contained in:
parent
f1c3e97fb4
commit
e34eb13d65
6 changed files with 146 additions and 40 deletions
|
@ -103,6 +103,31 @@ partial interface CSSStyleDeclaration {
|
||||||
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString borderTopWidth;
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString borderTopWidth;
|
||||||
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString border-top-width;
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString border-top-width;
|
||||||
|
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString border-block-start-color;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString borderBlockStartColor;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString border-block-start-width;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString borderBlockStartWidth;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString border-block-start-style;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString borderBlockStartStyle;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString border-block-end-color;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString borderBlockEndColor;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString border-block-end-width;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString borderBlockEndWidth;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString border-block-end-style;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString borderBlockEndStyle;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString border-inline-start-color;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString borderInlineStartColor;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString border-inline-start-width;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString borderInlineStartWidth;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString border-inline-start-style;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString borderInlineStartStyle;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString border-inline-end-color;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString borderInlineEndColor;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString border-inline-end-width;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString borderInlineEndWidth;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString border-inline-end-style;
|
||||||
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString borderInlineEndStyle;
|
||||||
|
|
||||||
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString content;
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString content;
|
||||||
|
|
||||||
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString color;
|
[SetterThrows, TreatNullAs=EmptyString] attribute DOMString color;
|
||||||
|
|
|
@ -4,6 +4,11 @@
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
PHYSICAL_SIDES = ["top", "left", "bottom", "right"]
|
||||||
|
LOGICAL_SIDES = ["block-start", "block-end", "inline-start", "inline-end"]
|
||||||
|
# bool is True when logical
|
||||||
|
ALL_SIDES = [(side, False) for side in PHYSICAL_SIDES] + [(side, True) for side in LOGICAL_SIDES]
|
||||||
|
|
||||||
|
|
||||||
def to_rust_ident(name):
|
def to_rust_ident(name):
|
||||||
name = name.replace("-", "_")
|
name = name.replace("-", "_")
|
||||||
|
@ -63,12 +68,19 @@ class Keyword(object):
|
||||||
return "as " + type_str if self.needs_cast() else ""
|
return "as " + type_str if self.needs_cast() else ""
|
||||||
|
|
||||||
|
|
||||||
|
def arg_to_bool(arg):
|
||||||
|
if isinstance(arg, bool):
|
||||||
|
return arg
|
||||||
|
assert arg in ["True", "False"]
|
||||||
|
return arg == "True"
|
||||||
|
|
||||||
|
|
||||||
class Longhand(object):
|
class Longhand(object):
|
||||||
def __init__(self, style_struct, name, animatable=None, derived_from=None, keyword=None,
|
def __init__(self, style_struct, name, animatable=None, derived_from=None, keyword=None,
|
||||||
predefined_type=None, custom_cascade=False, experimental=False, internal=False,
|
predefined_type=None, custom_cascade=False, experimental=False, internal=False,
|
||||||
need_clone=False, need_index=False, gecko_ffi_name=None, depend_on_viewport_size=False,
|
need_clone=False, need_index=False, gecko_ffi_name=None, depend_on_viewport_size=False,
|
||||||
allowed_in_keyframe_block=True, complex_color=False, cast_type='u8',
|
allowed_in_keyframe_block=True, complex_color=False, cast_type='u8',
|
||||||
has_uncacheable_values=False):
|
has_uncacheable_values=False, logical=False):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.keyword = keyword
|
self.keyword = keyword
|
||||||
self.predefined_type = predefined_type
|
self.predefined_type = predefined_type
|
||||||
|
@ -85,6 +97,7 @@ class Longhand(object):
|
||||||
self.derived_from = (derived_from or "").split()
|
self.derived_from = (derived_from or "").split()
|
||||||
self.complex_color = complex_color
|
self.complex_color = complex_color
|
||||||
self.cast_type = cast_type
|
self.cast_type = cast_type
|
||||||
|
self.logical = arg_to_bool(logical)
|
||||||
|
|
||||||
# https://drafts.csswg.org/css-animations/#keyframes
|
# https://drafts.csswg.org/css-animations/#keyframes
|
||||||
# > The <declaration-list> inside of <keyframe-block> accepts any CSS property
|
# > The <declaration-list> inside of <keyframe-block> accepts any CSS property
|
||||||
|
@ -97,12 +110,10 @@ class Longhand(object):
|
||||||
# really random.
|
# really random.
|
||||||
if animatable is None:
|
if animatable is None:
|
||||||
raise TypeError("animatable should be specified for " + name + ")")
|
raise TypeError("animatable should be specified for " + name + ")")
|
||||||
if isinstance(animatable, bool):
|
self.animatable = arg_to_bool(animatable)
|
||||||
self.animatable = animatable
|
if self.logical:
|
||||||
else:
|
# Logical properties don't animate separately
|
||||||
assert animatable == "True" or animatable == "False"
|
self.animatable = False
|
||||||
self.animatable = animatable == "True"
|
|
||||||
|
|
||||||
# NB: Animatable implies clone because a property animation requires a
|
# NB: Animatable implies clone because a property animation requires a
|
||||||
# copy of the computed value.
|
# copy of the computed value.
|
||||||
#
|
#
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
from data import to_rust_ident
|
from data import to_rust_ident
|
||||||
from data import Keyword
|
from data import Keyword
|
||||||
%>
|
%>
|
||||||
|
<%namespace name="helpers" file="/helpers.mako.rs" />
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use custom_properties::ComputedValuesMap;
|
use custom_properties::ComputedValuesMap;
|
||||||
|
@ -400,6 +401,10 @@ def set_gecko_property(ffi_name, expr):
|
||||||
% endif
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
<%def name="impl_logical(name, need_clone=False, **kwargs)">
|
||||||
|
${helpers.logical_setter(name, need_clone)}
|
||||||
|
</%def>
|
||||||
|
|
||||||
<%def name="impl_style_struct(style_struct)">
|
<%def name="impl_style_struct(style_struct)">
|
||||||
impl ${style_struct.gecko_struct_name} {
|
impl ${style_struct.gecko_struct_name} {
|
||||||
#[allow(dead_code, unused_variables)]
|
#[allow(dead_code, unused_variables)]
|
||||||
|
@ -495,7 +500,10 @@ impl Debug for ${style_struct.gecko_struct_name} {
|
||||||
need_clone=longhand.need_clone)
|
need_clone=longhand.need_clone)
|
||||||
|
|
||||||
# get the method and pass additional keyword or type-specific arguments
|
# get the method and pass additional keyword or type-specific arguments
|
||||||
if longhand.keyword:
|
if longhand.logical:
|
||||||
|
method = impl_logical
|
||||||
|
args.update(name=longhand.name)
|
||||||
|
elif longhand.keyword:
|
||||||
method = impl_keyword
|
method = impl_keyword
|
||||||
args.update(keyword=longhand.keyword)
|
args.update(keyword=longhand.keyword)
|
||||||
if "font" in longhand.ident:
|
if "font" in longhand.ident:
|
||||||
|
@ -509,7 +517,7 @@ impl Debug for ${style_struct.gecko_struct_name} {
|
||||||
|
|
||||||
picked_longhands, stub_longhands = [], []
|
picked_longhands, stub_longhands = [], []
|
||||||
for x in longhands:
|
for x in longhands:
|
||||||
if (x.keyword or x.predefined_type in predefined_types) and x.name not in force_stub:
|
if (x.keyword or x.predefined_type in predefined_types or x.logical) and x.name not in force_stub:
|
||||||
picked_longhands.append(x)
|
picked_longhands.append(x)
|
||||||
else:
|
else:
|
||||||
stub_longhands.append(x)
|
stub_longhands.append(x)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
<%! from data import Keyword, to_rust_ident, to_camel_case %>
|
<%! from data import Keyword, to_rust_ident, to_camel_case, LOGICAL_SIDES, PHYSICAL_SIDES %>
|
||||||
|
|
||||||
<%def name="longhand(name, **kwargs)">
|
<%def name="longhand(name, **kwargs)">
|
||||||
<%call expr="raw_longhand(name, **kwargs)">
|
<%call expr="raw_longhand(name, **kwargs)">
|
||||||
|
@ -221,15 +221,19 @@
|
||||||
cascade_info.on_cascade_property(&declaration,
|
cascade_info.on_cascade_property(&declaration,
|
||||||
&value);
|
&value);
|
||||||
}
|
}
|
||||||
|
% if property.logical:
|
||||||
|
let wm = context.style.writing_mode;
|
||||||
|
% endif
|
||||||
|
<% maybe_wm = ", wm" if property.logical else "" %>
|
||||||
match *value {
|
match *value {
|
||||||
DeclaredValue::Value(ref specified_value) => {
|
DeclaredValue::Value(ref specified_value) => {
|
||||||
let computed = specified_value.to_computed_value(context);
|
let computed = specified_value.to_computed_value(context);
|
||||||
% if property.has_uncacheable_values:
|
% if property.has_uncacheable_values:
|
||||||
context.mutate_style().mutate_${data.current_style_struct.name_lower}()
|
context.mutate_style().mutate_${data.current_style_struct.name_lower}()
|
||||||
.set_${property.ident}(computed, cacheable);
|
.set_${property.ident}(computed, cacheable ${maybe_wm});
|
||||||
% else:
|
% else:
|
||||||
context.mutate_style().mutate_${data.current_style_struct.name_lower}()
|
context.mutate_style().mutate_${data.current_style_struct.name_lower}()
|
||||||
.set_${property.ident}(computed);
|
.set_${property.ident}(computed ${maybe_wm});
|
||||||
% endif
|
% endif
|
||||||
}
|
}
|
||||||
DeclaredValue::WithVariables { .. } => unreachable!(),
|
DeclaredValue::WithVariables { .. } => unreachable!(),
|
||||||
|
@ -239,7 +243,7 @@
|
||||||
let initial_struct = ComputedValues::initial_values()
|
let initial_struct = ComputedValues::initial_values()
|
||||||
.get_${data.current_style_struct.name_lower}();
|
.get_${data.current_style_struct.name_lower}();
|
||||||
context.mutate_style().mutate_${data.current_style_struct.name_lower}()
|
context.mutate_style().mutate_${data.current_style_struct.name_lower}()
|
||||||
.copy_${property.ident}_from(initial_struct);
|
.copy_${property.ident}_from(initial_struct ${maybe_wm});
|
||||||
},
|
},
|
||||||
DeclaredValue::Inherit => {
|
DeclaredValue::Inherit => {
|
||||||
// This is a bit slow, but this is rare so it shouldn't
|
// This is a bit slow, but this is rare so it shouldn't
|
||||||
|
@ -250,7 +254,7 @@
|
||||||
let inherited_struct =
|
let inherited_struct =
|
||||||
inherited_style.get_${data.current_style_struct.name_lower}();
|
inherited_style.get_${data.current_style_struct.name_lower}();
|
||||||
context.mutate_style().mutate_${data.current_style_struct.name_lower}()
|
context.mutate_style().mutate_${data.current_style_struct.name_lower}()
|
||||||
.copy_${property.ident}_from(inherited_struct);
|
.copy_${property.ident}_from(inherited_struct ${maybe_wm});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, error_reporter);
|
}, error_reporter);
|
||||||
|
@ -607,3 +611,53 @@
|
||||||
}
|
}
|
||||||
</%self:shorthand>
|
</%self:shorthand>
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
<%def name="logical_setter_helper(name)">
|
||||||
|
<%
|
||||||
|
side = None
|
||||||
|
maybe_side = [side for side in LOGICAL_SIDES if side in name]
|
||||||
|
if len(maybe_side) == 1:
|
||||||
|
side = maybe_side[0]
|
||||||
|
%>
|
||||||
|
% if side is not None:
|
||||||
|
use logical_geometry::PhysicalSide;
|
||||||
|
match wm.${to_rust_ident(side)}_physical_side() {
|
||||||
|
% for phy_side in PHYSICAL_SIDES:
|
||||||
|
PhysicalSide::${phy_side.title()} => {
|
||||||
|
${caller.inner(side_ident=to_rust_ident(name.replace(side, phy_side)))}
|
||||||
|
}
|
||||||
|
% endfor
|
||||||
|
}
|
||||||
|
% else:
|
||||||
|
<% raise Exception("Don't know what to do with logical property %s" % name) %>
|
||||||
|
% endif
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="logical_setter(name, need_clone=False)">
|
||||||
|
pub fn set_${to_rust_ident(name)}(&mut self,
|
||||||
|
v: longhands::${to_rust_ident(name)}::computed_value::T,
|
||||||
|
wm: WritingMode) {
|
||||||
|
<%self:logical_setter_helper name="${name}">
|
||||||
|
<%def name="inner(side_ident)">
|
||||||
|
self.set_${side_ident}(v)
|
||||||
|
</%def>
|
||||||
|
</%self:logical_setter_helper>
|
||||||
|
}
|
||||||
|
pub fn copy_${to_rust_ident(name)}_from(&mut self, other: &Self, wm: WritingMode) {
|
||||||
|
<%self:logical_setter_helper name="${name}">
|
||||||
|
<%def name="inner(side_ident)">
|
||||||
|
self.copy_${side_ident}_from(other)
|
||||||
|
</%def>
|
||||||
|
</%self:logical_setter_helper>
|
||||||
|
}
|
||||||
|
% if need_clone:
|
||||||
|
pub fn clone_${to_rust_ident(name)}(&self, wm: WritingMode)
|
||||||
|
-> longhands::${to_rust_ident(name)}::computed_value::T {
|
||||||
|
<%self:logical_setter_helper name="${name}">
|
||||||
|
<%def name="inner(side_ident)">
|
||||||
|
self.clone_${side_ident}()
|
||||||
|
</%def>
|
||||||
|
</%self:logical_setter_helper>
|
||||||
|
}
|
||||||
|
% endif
|
||||||
|
</%def>
|
||||||
|
|
|
@ -3,26 +3,26 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
<%namespace name="helpers" file="/helpers.mako.rs" />
|
<%namespace name="helpers" file="/helpers.mako.rs" />
|
||||||
<% from data import Method %>
|
<% from data import Method, PHYSICAL_SIDES, ALL_SIDES %>
|
||||||
|
|
||||||
<% data.new_style_struct("Border", inherited=False,
|
<% data.new_style_struct("Border", inherited=False,
|
||||||
additional_methods=[Method("border_" + side + "_has_nonzero_width",
|
additional_methods=[Method("border_" + side + "_has_nonzero_width",
|
||||||
"bool") for side in ["top", "right", "bottom", "left"]]) %>
|
"bool") for side in ["top", "right", "bottom", "left"]]) %>
|
||||||
|
|
||||||
% for side in ["top", "right", "bottom", "left"]:
|
% for side in ALL_SIDES:
|
||||||
${helpers.predefined_type("border-%s-color" % side, "CSSColor",
|
${helpers.predefined_type("border-%s-color" % side[0], "CSSColor",
|
||||||
"::cssparser::Color::CurrentColor",
|
"::cssparser::Color::CurrentColor",
|
||||||
animatable=True)}
|
animatable=True, logical = side[1])}
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
% for side in ["top", "right", "bottom", "left"]:
|
% for side in ALL_SIDES:
|
||||||
${helpers.predefined_type("border-%s-style" % side, "BorderStyle",
|
${helpers.predefined_type("border-%s-style" % side[0], "BorderStyle",
|
||||||
"specified::BorderStyle::none",
|
"specified::BorderStyle::none",
|
||||||
need_clone=True, animatable=False)}
|
need_clone=True, animatable=False, logical = side[1])}
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
% for side in ["top", "right", "bottom", "left"]:
|
% for side in ALL_SIDES:
|
||||||
<%helpers:longhand name="border-${side}-width" animatable="True">
|
<%helpers:longhand name="border-${side[0]}-width" animatable="True" logical="${side[1]}">
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
|
|
|
@ -893,6 +893,7 @@ pub mod style_structs {
|
||||||
use fnv::FnvHasher;
|
use fnv::FnvHasher;
|
||||||
use super::longhands;
|
use super::longhands;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
use logical_geometry::WritingMode;
|
||||||
|
|
||||||
% for style_struct in data.active_style_structs():
|
% for style_struct in data.active_style_structs():
|
||||||
% if style_struct.name == "Font":
|
% if style_struct.name == "Font":
|
||||||
|
@ -923,24 +924,27 @@ pub mod style_structs {
|
||||||
|
|
||||||
impl ${style_struct.name} {
|
impl ${style_struct.name} {
|
||||||
% for longhand in style_struct.longhands:
|
% for longhand in style_struct.longhands:
|
||||||
#[allow(non_snake_case)]
|
% if longhand.logical:
|
||||||
#[inline]
|
${helpers.logical_setter(name=longhand.name)}
|
||||||
pub fn set_${longhand.ident}(&mut self, v: longhands::${longhand.ident}::computed_value::T) {
|
% else:
|
||||||
self.${longhand.ident} = v;
|
|
||||||
}
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
#[inline]
|
|
||||||
pub fn copy_${longhand.ident}_from(&mut self, other: &Self) {
|
|
||||||
self.${longhand.ident} = other.${longhand.ident}.clone();
|
|
||||||
}
|
|
||||||
% if longhand.need_clone:
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn clone_${longhand.ident}(&self) -> longhands::${longhand.ident}::computed_value::T {
|
pub fn set_${longhand.ident}(&mut self, v: longhands::${longhand.ident}::computed_value::T) {
|
||||||
self.${longhand.ident}.clone()
|
self.${longhand.ident} = v;
|
||||||
}
|
}
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[inline]
|
||||||
|
pub fn copy_${longhand.ident}_from(&mut self, other: &Self) {
|
||||||
|
self.${longhand.ident} = other.${longhand.ident}.clone();
|
||||||
|
}
|
||||||
|
% if longhand.need_clone:
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[inline]
|
||||||
|
pub fn clone_${longhand.ident}(&self) -> longhands::${longhand.ident}::computed_value::T {
|
||||||
|
self.${longhand.ident}.clone()
|
||||||
|
}
|
||||||
|
% endif
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
% if longhand.need_index:
|
% if longhand.need_index:
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn ${longhand.ident}_count(&self) -> usize {
|
pub fn ${longhand.ident}_count(&self) -> usize {
|
||||||
|
@ -1560,7 +1564,9 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
|
||||||
PropertyDeclaration::Position(_) |
|
PropertyDeclaration::Position(_) |
|
||||||
PropertyDeclaration::Float(_) |
|
PropertyDeclaration::Float(_) |
|
||||||
PropertyDeclaration::TextDecoration${'' if product == 'servo' else 'Line'}(_) |
|
PropertyDeclaration::TextDecoration${'' if product == 'servo' else 'Line'}(_) |
|
||||||
PropertyDeclaration::WritingMode(_)
|
PropertyDeclaration::WritingMode(_) |
|
||||||
|
PropertyDeclaration::Direction(_) |
|
||||||
|
PropertyDeclaration::TextOrientation(_)
|
||||||
);
|
);
|
||||||
if
|
if
|
||||||
% if category_to_cascade_now == "early":
|
% if category_to_cascade_now == "early":
|
||||||
|
@ -1580,6 +1586,10 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
|
||||||
&mut cascade_info,
|
&mut cascade_info,
|
||||||
&mut error_reporter);
|
&mut error_reporter);
|
||||||
}
|
}
|
||||||
|
% if category_to_cascade_now == "early":
|
||||||
|
let mode = get_writing_mode(context.style.get_inheritedbox());
|
||||||
|
context.style.set_writing_mode(mode);
|
||||||
|
% endif
|
||||||
% endfor
|
% endfor
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1686,8 +1696,6 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
|
||||||
style.mutate_font().compute_font_hash();
|
style.mutate_font().compute_font_hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mode = get_writing_mode(style.get_inheritedbox());
|
|
||||||
style.set_writing_mode(mode);
|
|
||||||
style
|
style
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue