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