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