From cf8408ead320988435b4605abf1e79049807268b Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Sat, 17 Jan 2015 15:22:51 +1100 Subject: [PATCH] Bug 1083134 - Part 3.1: Cascade block-axis logical properties with their physical equivalents. r=dbaron --- layout/style/nsCSSDataBlock.cpp | 70 ++++++++------------ layout/style/test/property_database.js | 88 +++++++++++++++++++++----- 2 files changed, 98 insertions(+), 60 deletions(-) diff --git a/layout/style/nsCSSDataBlock.cpp b/layout/style/nsCSSDataBlock.cpp index 0fdb935da24d..493716f6c5cd 100644 --- a/layout/style/nsCSSDataBlock.cpp +++ b/layout/style/nsCSSDataBlock.cpp @@ -16,6 +16,7 @@ #include "nsStyleSet.h" #include "nsStyleContext.h" #include "nsIDocument.h" +#include "WritingModes.h" using namespace mozilla; @@ -171,51 +172,34 @@ MapSinglePropertyInto(nsCSSProperty aProp, static inline void EnsurePhysicalProperty(nsCSSProperty& aProperty, nsRuleData* aRuleData) { - uint8_t direction = aRuleData->mStyleContext->StyleVisibility()->mDirection; - bool ltr = direction == NS_STYLE_DIRECTION_LTR; + bool isBlock = + nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_LOGICAL_BLOCK_AXIS); + bool isEnd = + nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_LOGICAL_END_EDGE); - switch (aProperty) { - case eCSSProperty_margin_end: - aProperty = ltr ? eCSSProperty_margin_right : eCSSProperty_margin_left; - break; - case eCSSProperty_margin_start: - aProperty = ltr ? eCSSProperty_margin_left : eCSSProperty_margin_right; - break; - case eCSSProperty_padding_end: - aProperty = ltr ? eCSSProperty_padding_right : eCSSProperty_padding_left; - break; - case eCSSProperty_padding_start: - aProperty = ltr ? eCSSProperty_padding_left : eCSSProperty_padding_right; - break; - case eCSSProperty_border_end_color: - aProperty = ltr ? eCSSProperty_border_right_color : - eCSSProperty_border_left_color; - break; - case eCSSProperty_border_end_style: - aProperty = ltr ? eCSSProperty_border_right_style : - eCSSProperty_border_left_style; - break; - case eCSSProperty_border_end_width: - aProperty = ltr ? eCSSProperty_border_right_width : - eCSSProperty_border_left_width; - break; - case eCSSProperty_border_start_color: - aProperty = ltr ? eCSSProperty_border_left_color : - eCSSProperty_border_right_color; - break; - case eCSSProperty_border_start_style: - aProperty = ltr ? eCSSProperty_border_left_style : - eCSSProperty_border_right_style; - break; - case eCSSProperty_border_start_width: - aProperty = ltr ? eCSSProperty_border_left_width : - eCSSProperty_border_right_width; - break; - default: - NS_ABORT_IF_FALSE(nsCSSProps::PropHasFlags(aProperty, - CSS_PROPERTY_LOGICAL), - "unhandled logical property"); + LogicalEdge edge = isEnd ? eLogicalEdgeEnd : eLogicalEdgeStart; + + // We handle block axis logical properties separately to save a bit of + // work that the WritingMode constructor does that is unnecessary + // unless we have an inline axis property. + mozilla::css::Side side; + if (isBlock) { + uint8_t wm = aRuleData->mStyleContext->StyleVisibility()->mWritingMode; + side = WritingMode::PhysicalSideForBlockAxis(wm, edge); + } else { + WritingMode wm(aRuleData->mStyleContext); + side = wm.PhysicalSideForInlineAxis(edge); } + + nsCSSProperty shorthand = nsCSSProps::BoxShorthandFor(aProperty); + const nsCSSProperty* subprops = nsCSSProps::SubpropertyEntryFor(shorthand); + MOZ_ASSERT(subprops[0] != eCSSProperty_UNKNOWN && + subprops[1] != eCSSProperty_UNKNOWN && + subprops[2] != eCSSProperty_UNKNOWN && + subprops[3] != eCSSProperty_UNKNOWN && + subprops[4] == eCSSProperty_UNKNOWN, + "expected four-element subproperty table"); + aProperty = subprops[side]; } void diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index 3f3fc9ea6124..a51613b5b8ed 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -4542,24 +4542,78 @@ var gCSSProperties = { function logical_box_prop_get_computed(cs, property) { - var ltr = cs.getPropertyValue("direction") == "ltr"; + // http://dev.w3.org/csswg/css-writing-modes-3/#logical-to-physical + + // Use defaults for these two properties in case the vertical text + // pref (which they live behind) is turned off. + var writingMode = cs.getPropertyValue("writing-mode") || "horizontal-tb"; + var textOrientation = cs.getPropertyValue("text-orientation") || "mixed"; + + var direction = cs.getPropertyValue("direction"); + + // We only need to distinguish between text-orientation values of + // sideways-left and {mixed,upright,sideways-right} (which we will + // call "others"). + + if (textOrientation == "sideways") { + // text-orientation does not contribute to the logical to physical + // mapping when writing-mode is horizontal-tb, so it doesn't matter + // that we convert it to sideways-left in that case. + textOrientation = writingMode == "vertical-rl" ? "others" : "sideways-left"; + } else if (textOrientation != "sideways-left") { + textOrientation = "others"; + } + + // keys in blockMappings are writing-mode values + var blockMappings = { + "horizontal-tb": { "start": "top", "end": "bottom" }, + "vertical-rl": { "start": "right", "end": "left" }, + "vertical-lr": { "start": "left", "end": "right" }, + }; + + // keys in inlineMappings are regular expressions that match against + // a {writing-mode,text-orientation,direction} triple as a space- + // separated string + var inlineMappings = { + "horizontal-tb \\S+ ltr": { "start": "left", "end": "right" }, + "horizontal-tb \\S+ rtl": { "start": "right", "end": "left" }, + "vertical-.. sideways-left ltr": { "start": "bottom", "end": "top" }, + "vertical-.. sideways-left rtl": { "start": "top", "end": "bottom" }, + "vertical-.. others ltr": { "start": "top", "end": "bottom" }, + "vertical-.. others rtl": { "start": "bottom", "end": "top" }, + }; + + var blockMapping = blockMappings[writingMode]; + var inlineMapping; + + // test each regular expression in inlineMappings against the + // {writing-mode,text-orientation,direction} triple + var key = `${writingMode} ${textOrientation} ${direction}`; + for (var k in inlineMappings) { + if (new RegExp(k).test(key)) { + inlineMapping = inlineMappings[k]; + break; + } + } + + if (!blockMapping || !inlineMapping) { + throw "Unexpected writing mode property values"; + } + + function physicalize(aProperty, aMapping, aLogicalPrefix) { + for (var logicalSide in aMapping) { + var physicalSide = aMapping[logicalSide]; + logicalSide = aLogicalPrefix + logicalSide; + aProperty = aProperty.replace(logicalSide, physicalSide); + } + return aProperty; + } + if (/^-moz-/.test(property)) { - property = property.substring(5); - if (ltr) { - property = property.replace("-start", "-left") - .replace("-end", "-right"); - } else { - property = property.replace("-start", "-right") - .replace("-end", "-left"); - } - } else if (/-inline-(start|end)/.test(property)) { - if (ltr) { - property = property.replace("-inline-start", "-left") - .replace("-inline-end", "-right"); - } else { - property = property.replace("-inline-start", "-right") - .replace("-inline-end", "-left"); - } + property = physicalize(property.substring(5), inlineMapping, ""); + } else if (/-(block|inline)-(start|end)/.test(property)) { + property = physicalize(property, blockMapping, "block-"); + property = physicalize(property, inlineMapping, "inline-"); } else { throw "Unexpected property"; }