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