1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license thaT can be 3 // found in the LICENSE file. 4 5 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_TEXT_WRITING_MODE_UTILS_H_ 6 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_TEXT_WRITING_MODE_UTILS_H_ 7 8 #include "third_party/blink/renderer/platform/text/text_direction.h" 9 #include "third_party/blink/renderer/platform/text/writing_mode.h" 10 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" 11 12 namespace blink { 13 14 // Templates to map values between logical orientations and physical 15 // orientations. See https://www.w3.org/TR/css-writing-modes-3/ and 16 // https://www.w3.org/TR/css-logical-1/ for definitions of logical orientations. 17 18 // This file provides two types of templates: 19 // 20 // - Simple value mappers (PhysicalToLogical and LogicalToPhysical): they take 21 // 4 input values in physical or logical orientations, and provide accessors 22 // to get values in logical or physical orientations. As the inputs may be 23 // evaluated even if not used (in case that the compiler is unable to remove 24 // unused evaluations, e.g. containing non-inlined function calls), for 25 // performance-senstive code, the evaluation of the inputs should be simple 26 // and/or be fully inlined. 27 // 28 // - Value mappers based on getter/setter methods (PhysicalToLogicalGetter, 29 // LogicalToPhysicalGetter, PhysicalToLogicalSetter and 30 // LogicalToPhysicalSetter): they take 4 method pointers as inputs pointing to 31 // methods accessing values in physical or logical orientations, and provide 32 // accessors to get or set values in logical or physical orientations. They 33 // are suitable for mapping of setters, or getters implemented with non- 34 // inlined functions. Evaluation of the input values are delayed when they are 35 // actually needed. 36 // 37 // See WritingModeUtilsTest.cpp, LayoutBoxModelObject.h and ComputedStyle.h for 38 // examples. 39 40 template <typename Value> 41 class PhysicalToLogical { 42 STACK_ALLOCATED(); 43 44 public: PhysicalToLogical(WritingMode writing_mode,TextDirection direction,Value top,Value right,Value bottom,Value left)45 PhysicalToLogical(WritingMode writing_mode, 46 TextDirection direction, 47 Value top, 48 Value right, 49 Value bottom, 50 Value left) 51 : writing_mode_(writing_mode), 52 direction_(direction), 53 top_(top), 54 right_(right), 55 bottom_(bottom), 56 left_(left) {} 57 InlineStart()58 Value InlineStart() const { 59 if (IsHorizontalWritingMode(writing_mode_)) 60 return IsLtr(direction_) ? left_ : right_; 61 return IsLtr(direction_) ? top_ : bottom_; 62 } 63 InlineEnd()64 Value InlineEnd() const { 65 if (IsHorizontalWritingMode(writing_mode_)) 66 return IsLtr(direction_) ? right_ : left_; 67 return IsLtr(direction_) ? bottom_ : top_; 68 } 69 BlockStart()70 Value BlockStart() const { 71 if (IsHorizontalWritingMode(writing_mode_)) 72 return top_; 73 return IsFlippedBlocksWritingMode(writing_mode_) ? right_ : left_; 74 } 75 BlockEnd()76 Value BlockEnd() const { 77 if (IsHorizontalWritingMode(writing_mode_)) 78 return bottom_; 79 return IsFlippedBlocksWritingMode(writing_mode_) ? left_ : right_; 80 } 81 Over()82 Value Over() const { 83 return IsHorizontalWritingMode(writing_mode_) ? top_ : right_; 84 } 85 Under()86 Value Under() const { 87 return IsHorizontalWritingMode(writing_mode_) ? bottom_ : left_; 88 } 89 LineLeft()90 Value LineLeft() const { 91 return IsHorizontalWritingMode(writing_mode_) ? left_ : top_; 92 } 93 LineRight()94 Value LineRight() const { 95 return IsHorizontalWritingMode(writing_mode_) ? right_ : bottom_; 96 } 97 98 // Legacy logical directions. Start()99 Value Start() const { return InlineStart(); } End()100 Value End() const { return InlineEnd(); } Before()101 Value Before() const { return BlockStart(); } After()102 Value After() const { return BlockEnd(); } 103 104 private: 105 WritingMode writing_mode_; 106 TextDirection direction_; 107 Value top_; 108 Value right_; 109 Value bottom_; 110 Value left_; 111 }; 112 113 template <typename Value> 114 class LogicalToPhysical { 115 STACK_ALLOCATED(); 116 117 public: LogicalToPhysical(WritingMode writing_mode,TextDirection direction,Value inline_start,Value inline_end,Value block_start,Value block_end)118 LogicalToPhysical(WritingMode writing_mode, 119 TextDirection direction, 120 Value inline_start, 121 Value inline_end, 122 Value block_start, 123 Value block_end) 124 : writing_mode_(writing_mode), 125 direction_(direction), 126 inline_start_(inline_start), 127 inline_end_(inline_end), 128 block_start_(block_start), 129 block_end_(block_end) {} 130 Left()131 Value Left() const { 132 if (IsHorizontalWritingMode(writing_mode_)) 133 return IsLtr(direction_) ? inline_start_ : inline_end_; 134 return IsFlippedBlocksWritingMode(writing_mode_) ? block_end_ 135 : block_start_; 136 } 137 Right()138 Value Right() const { 139 if (IsHorizontalWritingMode(writing_mode_)) 140 return IsLtr(direction_) ? inline_end_ : inline_start_; 141 return IsFlippedBlocksWritingMode(writing_mode_) ? block_start_ 142 : block_end_; 143 } 144 Top()145 Value Top() const { 146 if (IsHorizontalWritingMode(writing_mode_)) 147 return block_start_; 148 return IsLtr(direction_) ? inline_start_ : inline_end_; 149 } 150 Bottom()151 Value Bottom() const { 152 if (IsHorizontalWritingMode(writing_mode_)) 153 return block_end_; 154 return IsLtr(direction_) ? inline_end_ : inline_start_; 155 } 156 157 private: 158 WritingMode writing_mode_; 159 TextDirection direction_; 160 Value inline_start_; // a.k.a. start 161 Value inline_end_; // a.k.a. end 162 Value block_start_; // a.k.a. before 163 Value block_end_; // a.k.a. after 164 }; 165 166 template <typename Value, typename Object> 167 class LogicalToPhysicalGetter { 168 STACK_ALLOCATED(); 169 170 public: 171 using Getter = Value (Object::*)() const; LogicalToPhysicalGetter(WritingMode writing_mode,TextDirection direction,const Object & object,Getter inline_start_getter,Getter inline_end_getter,Getter block_start_getter,Getter block_end_getter)172 LogicalToPhysicalGetter(WritingMode writing_mode, 173 TextDirection direction, 174 const Object& object, 175 Getter inline_start_getter, 176 Getter inline_end_getter, 177 Getter block_start_getter, 178 Getter block_end_getter) 179 : object_(object), 180 converter_(writing_mode, 181 direction, 182 inline_start_getter, 183 inline_end_getter, 184 block_start_getter, 185 block_end_getter) {} 186 Left()187 Value Left() const { return (object_.*converter_.Left())(); } Right()188 Value Right() const { return (object_.*converter_.Right())(); } Top()189 Value Top() const { return (object_.*converter_.Top())(); } Bottom()190 Value Bottom() const { return (object_.*converter_.Bottom())(); } 191 192 private: 193 const Object& object_; 194 LogicalToPhysical<Getter> converter_; 195 }; 196 197 template <typename Value, typename Object> 198 class PhysicalToLogicalGetter { 199 STACK_ALLOCATED(); 200 201 public: 202 using Getter = Value (Object::*)() const; PhysicalToLogicalGetter(WritingMode writing_mode,TextDirection direction,const Object & object,Getter top_getter,Getter right_getter,Getter bottom_getter,Getter left_getter)203 PhysicalToLogicalGetter(WritingMode writing_mode, 204 TextDirection direction, 205 const Object& object, 206 Getter top_getter, 207 Getter right_getter, 208 Getter bottom_getter, 209 Getter left_getter) 210 : object_(object), 211 converter_(writing_mode, 212 direction, 213 top_getter, 214 right_getter, 215 bottom_getter, 216 left_getter) {} 217 InlineStart()218 Value InlineStart() const { return (object_.*converter_.InlineStart())(); } InlineEnd()219 Value InlineEnd() const { return (object_.*converter_.InlineEnd())(); } BlockStart()220 Value BlockStart() const { return (object_.*converter_.BlockStart())(); } BlockEnd()221 Value BlockEnd() const { return (object_.*converter_.BlockEnd())(); } Over()222 Value Over() const { return (object_.*converter_.Over())(); } Under()223 Value Under() const { return (object_.*converter_.Under())(); } LineLeft()224 Value LineLeft() const { return (object_.*converter_.LineLeft())(); } LineRight()225 Value LineRight() const { return (object_.*converter_.LineRight())(); } Start()226 Value Start() const { return (object_.*converter_.Start())(); } End()227 Value End() const { return (object_.*converter_.End())(); } Before()228 Value Before() const { return (object_.*converter_.Before())(); } After()229 Value After() const { return (object_.*converter_.After())(); } 230 231 private: 232 const Object& object_; 233 PhysicalToLogical<Getter> converter_; 234 }; 235 236 template <typename Value, typename Object> 237 class PhysicalToLogicalSetter { 238 STACK_ALLOCATED(); 239 240 public: 241 using Setter = void (Object::*)(Value); PhysicalToLogicalSetter(WritingMode writing_mode,TextDirection direction,Object & object,Setter inline_start_setter,Setter inline_end_setter,Setter block_start_setter,Setter block_end_setter)242 PhysicalToLogicalSetter(WritingMode writing_mode, 243 TextDirection direction, 244 Object& object, 245 Setter inline_start_setter, 246 Setter inline_end_setter, 247 Setter block_start_setter, 248 Setter block_end_setter) 249 : object_(object), 250 converter_(writing_mode, 251 direction, 252 inline_start_setter, 253 inline_end_setter, 254 block_start_setter, 255 block_end_setter) {} 256 SetLeft(Value v)257 void SetLeft(Value v) { (object_.*converter_.Left())(v); } SetRight(Value v)258 void SetRight(Value v) { (object_.*converter_.Right())(v); } SetTop(Value v)259 void SetTop(Value v) { (object_.*converter_.Top())(v); } SetBottom(Value v)260 void SetBottom(Value v) { (object_.*converter_.Bottom())(v); } 261 262 private: 263 Object& object_; 264 // This converter converts logical setters to physical setters which accept 265 // physical values and call the logical setters to set logical values. 266 LogicalToPhysical<Setter> converter_; 267 }; 268 269 template <typename Value, typename Object> 270 class LogicalToPhysicalSetter { 271 STACK_ALLOCATED(); 272 273 public: 274 using Setter = void (Object::*)(Value); LogicalToPhysicalSetter(WritingMode writing_mode,TextDirection direction,Object & object,Setter top_setter,Setter right_setter,Setter bottom_setter,Setter left_setter)275 LogicalToPhysicalSetter(WritingMode writing_mode, 276 TextDirection direction, 277 Object& object, 278 Setter top_setter, 279 Setter right_setter, 280 Setter bottom_setter, 281 Setter left_setter) 282 : object_(object), 283 converter_(writing_mode, 284 direction, 285 top_setter, 286 right_setter, 287 bottom_setter, 288 left_setter) {} 289 SetInlineStart(Value v)290 void SetInlineStart(Value v) { (object_.*converter_.InlineStart())(v); } SetInlineEnd(Value v)291 void SetInlineEnd(Value v) { (object_.*converter_.InlineEnd())(v); } SetBlockStart(Value v)292 void SetBlockStart(Value v) { (object_.*converter_.BlockStart())(v); } SetBlockEnd(Value v)293 void SetBlockEnd(Value v) { (object_.*converter_.BlockEnd())(v); } SetOver(Value v)294 void SetOver(Value v) { (object_.*converter_.Over())(v); } SetUnder(Value v)295 void SetUnder(Value v) { (object_.*converter_.Under())(v); } SetLineLeft(Value v)296 void SetLineLeft(Value v) { (object_.*converter_.LineLeft())(v); } SetLineRight(Value v)297 void SetLineRight(Value v) { (object_.*converter_.LineRight())(v); } SetStart(Value v)298 void SetStart(Value v) { (object_.*converter_.Start())(v); } SetEnd(Value v)299 void SetEnd(Value v) { (object_.*converter_.End())(v); } SetBefore(Value v)300 void SetBefore(Value v) { (object_.*converter_.Before())(v); } SetAfter(Value v)301 void SetAfter(Value v) { (object_.*converter_.After())(v); } 302 303 private: 304 Object& object_; 305 // This converter converts physical setters to logical setters which accept 306 // logical values and call the physical setters to set physical values. 307 PhysicalToLogical<Setter> converter_; 308 }; 309 310 } // namespace blink 311 312 #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_TEXT_WRITING_MODE_UTILS_H_ 313