1 /** \file lvstyles.h
2 
3     \brief CSS Styles and node format
4 
5     (c) Vadim Lopatin, 2000-2006
6 
7     This source code is distributed under the terms of
8     GNU General Public License.
9 
10     See LICENSE file for details.
11 
12 */
13 
14 #if !defined(__LV_STYLES_H_INCLUDED__)
15 #define __LV_STYLES_H_INCLUDED__
16 
17 #include "cssdef.h"
18 #include "lvmemman.h"
19 #include "lvrefcache.h"
20 #include "lvtextfm.h"
21 #include "lvfntman.h"
22 #include "lvstring8collection.h"
23 
24 class SerialBuf;
25 
26 /* bit position (in 'lUInt32[] important' and 'lUInt32[] importance' bitmaps)
27  * of each css_style_rec_tag properties to flag its '!important' status */
28 enum css_style_rec_important_bit {
29     imp_bit_display = 0,
30     imp_bit_white_space,
31     imp_bit_text_align,
32     imp_bit_text_align_last,
33     imp_bit_text_decoration,
34     imp_bit_text_transform,
35     imp_bit_vertical_align,
36     imp_bit_font_family,
37     imp_bit_font_name,
38     imp_bit_font_size,
39     imp_bit_font_style,
40     imp_bit_font_weight,
41     imp_bit_font_features,
42     imp_bit_text_indent,
43     imp_bit_line_height,
44     imp_bit_width,
45     imp_bit_height,
46     imp_bit_margin_left,
47     imp_bit_margin_right,
48     imp_bit_margin_top,
49     imp_bit_margin_bottom,
50     imp_bit_padding_left,
51     imp_bit_padding_right,
52     imp_bit_padding_top,
53     imp_bit_padding_bottom,
54     imp_bit_color,
55     imp_bit_background_color,
56     imp_bit_letter_spacing,
57     imp_bit_page_break_before,
58     imp_bit_page_break_after,
59     imp_bit_page_break_inside,
60     imp_bit_hyphenate,
61     imp_bit_list_style_type,
62     imp_bit_list_style_position,
63     imp_bit_border_style_top,
64     imp_bit_border_style_bottom,
65     imp_bit_border_style_right,
66     imp_bit_border_style_left,
67     imp_bit_border_width_top,
68     imp_bit_border_width_right,
69     imp_bit_border_width_bottom,
70     imp_bit_border_width_left,
71     imp_bit_border_color_top,
72     imp_bit_border_color_right,
73     imp_bit_border_color_bottom,
74     imp_bit_border_color_left,
75     imp_bit_background_image,
76     imp_bit_background_repeat,
77     imp_bit_background_position,
78     imp_bit_background_size_h,
79     imp_bit_background_size_v,
80     imp_bit_border_collapse,
81     imp_bit_border_spacing_h,
82     imp_bit_border_spacing_v,
83     imp_bit_orphans,
84     imp_bit_widows,
85     imp_bit_float,
86     imp_bit_clear,
87     imp_bit_direction,
88     imp_bit_content,
89     imp_bit_cr_hint
90 };
91 #define NB_IMP_BITS 61 // The number of lines in the enum above: KEEP IT UPDATED.
92 
93 #define NB_IMP_SLOTS    ((NB_IMP_BITS-1)>>5)+1
94 // In lvstyles.cpp, we have hardcoded important[0] ... importance[1]
95 // So once NB_IMP_SLOTS becomes 3 when IMP_BIT_MAX > 64, add in lvstyles.cpp
96 // the needed important[2] and importance[2]. Let us know if we forget that:
97 #if (NB_IMP_SLOTS != 2)
98     #error "NB_IMP_SLOTS != 2, some updates in lvstyles.cpp (and then here) are needed"
99 #endif
100 
101 // Style handling flags
102 #define STYLE_REC_FLAG_MATCHED  0x01 // This style has had some stylesheet declaration matched and applied.
103                                      // Currently only used for a pseudo element style,
104                                      // see LVCssSelector::apply() if more generic usage needed.
105 
106 /**
107     \brief Element style record.
108 
109     Contains set of style properties.
110 */
111 typedef struct css_style_rec_tag css_style_rec_t;
112 struct css_style_rec_tag {
113     int                  refCount; // for reference counting
114     lUInt32              hash; // cache calculated hash value here
115     lUInt32              important[NB_IMP_SLOTS];  // bitmap for !important (used only by LVCssDeclaration)
116     lUInt32              importance[NB_IMP_SLOTS]; // bitmap for important bit's importance/origin
117                                                    // (allows for 2 level of !important importance)
118     css_display_t        display;
119     css_white_space_t    white_space;
120     css_text_align_t     text_align;
121     css_text_align_t     text_align_last;
122     css_text_decoration_t text_decoration;
123     css_text_transform_t text_transform;
124     css_length_t         vertical_align;
125     css_font_family_t    font_family;
126     lString8             font_name;
127     css_length_t         font_size;
128     css_font_style_t     font_style;
129     css_font_weight_t    font_weight;
130     css_length_t         font_features;
131     css_length_t         text_indent;
132     css_length_t         line_height;
133     css_length_t         width;
134     css_length_t         height;
135     css_length_t         margin[4]; ///< margin-left, -right, -top, -bottom
136     css_length_t         padding[4]; ///< padding-left, -right, -top, -bottom
137     css_length_t         color;
138     css_length_t         background_color;
139     css_length_t         letter_spacing;
140     css_page_break_t     page_break_before;
141     css_page_break_t     page_break_after;
142     css_page_break_t     page_break_inside;
143     css_hyphenate_t        hyphenate;
144     css_list_style_type_t list_style_type;
145     css_list_style_position_t list_style_position;
146     css_border_style_type_t border_style_top;
147     css_border_style_type_t border_style_bottom;
148     css_border_style_type_t border_style_right;
149     css_border_style_type_t border_style_left;
150     css_length_t border_width[4]; ///< border-top-width, -right-, -bottom-, -left-
151     css_length_t border_color[4]; ///< border-top-color, -right-, -bottom-, -left-
152     lString8 background_image;
153     css_background_repeat_value_t background_repeat;
154     css_background_position_value_t background_position;
155     css_length_t background_size[2];//first width and second height
156     css_border_collapse_value_t border_collapse;
157     css_length_t border_spacing[2];//first horizontal and the second vertical spacing
158     css_orphans_widows_value_t orphans;
159     css_orphans_widows_value_t widows;
160     css_float_t            float_; // "float" is a C++ keyword...
161     css_clear_t            clear;
162     css_direction_t        direction;
163     lString32              content;
164     css_length_t           cr_hint;
165     // The following should only be used when applying stylesheets while in lvend.cpp setNodeStyle(),
166     // and cleaned up there, before the style is cached and shared. They are not serialized.
167     lInt8                flags; // bitmap of STYLE_REC_FLAG_*
168     css_style_rec_t *    pseudo_elem_before_style;
169     css_style_rec_t *    pseudo_elem_after_style;
170 
css_style_rec_tagcss_style_rec_tag171     css_style_rec_tag()
172     : refCount(0)
173     , hash(0)
174     , important{} // zero-initialization of all array slots
175     , importance{}
176     , display( css_d_inline )
177     , white_space(css_ws_inherit)
178     , text_align(css_ta_inherit)
179     , text_align_last(css_ta_inherit)
180     , text_decoration (css_td_inherit)
181     , text_transform (css_tt_inherit)
182     , vertical_align(css_val_unspecified, css_va_baseline)
183     , font_family(css_ff_inherit)
184     , font_size(css_val_inherited, 0)
185     , font_style(css_fs_inherit)
186     , font_weight(css_fw_inherit)
187     , font_features(css_val_inherited, 0)
188     , text_indent(css_val_inherited, 0)
189     , line_height(css_val_inherited, 0)
190     , width(css_val_unspecified, 0)
191     , height(css_val_unspecified, 0)
192     , color(css_val_inherited, 0)
193     , background_color(css_val_unspecified, 0)
194     , letter_spacing(css_val_inherited, 0)
195     , page_break_before(css_pb_auto)
196     , page_break_after(css_pb_auto)
197     , page_break_inside(css_pb_auto)
198     , hyphenate(css_hyph_inherit)
199     , list_style_type(css_lst_inherit)
200     , list_style_position(css_lsp_inherit)
201     , border_style_top(css_border_none)
202     , border_style_bottom(css_border_none)
203     , border_style_right(css_border_none)
204     , border_style_left(css_border_none)
205     , background_repeat(css_background_r_none)
206     , background_position(css_background_p_none)
207     , border_collapse(css_border_seperate)
208     , orphans(css_orphans_widows_inherit)
209     , widows(css_orphans_widows_inherit)
210     , float_(css_f_none)
211     , clear(css_c_none)
212     , direction(css_dir_inherit)
213     , cr_hint(css_val_inherited, 0)
214     , flags(0)
215     , pseudo_elem_before_style(NULL)
216     , pseudo_elem_after_style(NULL)
217     {
218         // css_length_t fields are initialized by css_length_tag()
219         // to (css_val_screen_px, 0)
220         // These should not: a not specified border width will
221         // use DEFAULT_BORDER_WIDTH (=2)
222         border_width[0] = css_length_t(css_val_unspecified, 0);
223         border_width[1] = css_length_t(css_val_unspecified, 0);
224         border_width[2] = css_length_t(css_val_unspecified, 0);
225         border_width[3] = css_length_t(css_val_unspecified, 0);
226         background_size[0] = css_length_t(css_val_unspecified, 0);
227         background_size[1] = css_length_t(css_val_unspecified, 0);
228     }
AddRefcss_style_rec_tag229     void AddRef() { refCount++; }
Releasecss_style_rec_tag230     int Release() { return --refCount; }
getRefCountcss_style_rec_tag231     int getRefCount() { return refCount; }
232     bool serialize( SerialBuf & buf );
233     bool deserialize( SerialBuf & buf );
234     //  important bitmap management
isImportantcss_style_rec_tag235     bool isImportant( css_style_rec_important_bit bit ) { return important[bit>>5] & (1<<(bit&0x1f)); }
setImportantcss_style_rec_tag236     void setImportant( css_style_rec_important_bit bit ) { important[bit>>5] |= (1<<(bit&0x1f)); }
237     // apply value to field if important bit not yet set, then set it if is_important
Applycss_style_rec_tag238     template <typename T> inline void Apply( T value, T *field, css_style_rec_important_bit bit, lUInt8 is_important ) {
239         int slot = bit>>5;        // 32 bits per LUint32 slot
240         int sbit = 1<<(bit&0x1f); // bitmask for this single bit in its slot
241         // is_important is 2 bits: (high_importance, is_important) (see lvstsheet.cpp)
242         if (     !(important[slot] & sbit)     // important flag not previously set
243               || (is_important == 0x3)  // coming value has '!important' and comes from some CSS parsed with higher_importance=true
244               || (is_important == 0x1 && !(importance[slot] & sbit) ) // coming value has '!important' and comes from some CSS parsed
245                                                                // with higher_importance=false, but previous value was not set from
246                                                                // a !important that came from CSS parsed with higher_importance=true
247            ) {
248             *field = value; // apply
249             if (is_important & 0x1) important[slot] |= sbit;   // update important flag
250             if (is_important == 0x3) importance[slot] |= sbit; // update importance flag (!important comes from higher_importance CSS)
251         }
252     }
253     // Similar to previous one, but logical-OR'ing values, for bitmaps (currently, only style->font_features and style->cr_hint)
ApplyAsBitmapOrcss_style_rec_tag254     inline void ApplyAsBitmapOr( css_length_t value, css_length_t *field, css_style_rec_important_bit bit, lUInt8 is_important ) {
255         int slot = bit>>5;        // 32 bits per LUint32 slot
256         int sbit = 1<<(bit&0x1f); // bitmask for this bit in its slot
257         if (     !(important[slot] & sbit)
258               || (is_important == 0x3)
259               || (is_important == 0x1 && !(importance[slot] & sbit) )
260            ) {
261             field->value |= value.value; // logical-or values
262             field->type = value.type;    // use the one from value (always css_val_unspecified for font_features)
263             if (is_important & 0x1) important[slot] |= sbit;
264             if (is_important == 0x3) importance[slot] |= sbit;
265         }
266     }
267 };
268 
269 /// style record reference type
270 typedef LVFastRef< css_style_rec_t > css_style_ref_t;
271 /// font reference type
272 typedef LVFontRef font_ref_t;
273 
274 /// to compare two styles
275 bool operator == (const css_style_rec_t & r1, const css_style_rec_t & r2);
276 
277 /// style hash table size
278 #define LV_STYLE_HASH_SIZE 0x100
279 
280 /// style cache: allows to avoid duplicate style object allocation
281 class lvdomStyleCache : public LVRefCache< css_style_ref_t >
282 {
283 public:
284     lvdomStyleCache( int size = LV_STYLE_HASH_SIZE ) : LVRefCache< css_style_ref_t >( size ) {}
285 };
286 
287 /// element rendering methods
288 enum lvdom_element_render_method
289 {
290     erm_invisible = 0, ///< invisible: don't render
291     erm_killed,        ///< reset to this when there is no room to render element
292     erm_block,         ///< render as block element (render as containing other elements)
293     erm_final,         ///< final element: render the whole it's content as single render block
294     erm_inline,        ///< inline element
295     erm_table,         ///< table element: render as table
296     erm_table_row_group,    ///< table row group
297     erm_table_header_group, ///< table header group
298     erm_table_footer_group, ///< table footer group
299     erm_table_row,          ///< table row
300     erm_table_column_group, ///< table column group
301     erm_table_column,       ///< table column
302     // Note that table cells always become either erm_block or erm_final depending on their content
303     // and that table captions are set erm_final.
304 };
305 
306 /// node format record
307 class lvdomElementFormatRec {
308 protected:
309     // Values on the x-axis can be stored in a 16bit int, values
310     // on the y-axis should better be stored in a 32bit int.
311     // Some of these fields were added to support floats and
312     // optimize some computations (we increased the size of
313     // this object from 4 to 16 32bits-int - this make cache
314     // files grow only by ~1%, probably because they compress
315     // well when not filled and left to be 0).
316 
317     // Position and size of a (block or final) element, relative to
318     // it's parent block container top left, not including margins,
319     // but including borders and paddings.
320     int    _y;
321     int    _height;
322     short  _x;
323     short  _width;
324     // For erm_final block, inner width and position (so, excluding
325     // paddings and border) of the LFormattedText inside that element.
326     short  _inner_width; // = _width - left and right borders and paddings
327     short  _inner_x;     // = left border + padding
328     short  _inner_y;     // = top border + padding
329                          // (no need for any _inner_height currently)
330 
331     short  _baseline;    // reference baseline y (only set for inline-block box)
332         // (Note: it's limited to 32767px here, but images and inline-box height
333         // is also limited to that for being carried in lInt16 slots when
334         // formatting text in lvtextfm.cpp.)
335 
336     short _usable_left_overflow;   // Usable overflow for hanging punctuation
337     short _usable_right_overflow;  // and glyphs negative side bearings
338 
339     // Children blocks should be fully contained in their parent block,
340     // and sibling nodes blocks should not overlap with other siblings,
341     // except when float are involved and we allow them to continue
342     // over next outer elements.
343     // Record these overflows, mostly to just be able to draw floats
344     // correctly and not ignore them if their container block is out
345     // of screen. Also help selecting text in overflowing floats.
346     int _top_overflow;    // Overflow (positive value) below _y
347     int _bottom_overflow; // Overflow (positive value) after _y+_height
348 
349     int _lang_node_idx;     // dataIndex of the upper node this erm_final block
350                             // should get its lang= langage from
351 
352     // Flags & extras, to have additional info related to this rect cached.
353     // - For erm_final nodes, these contain the footprint of outer floats
354     //   that we need to know when accessing this final node (for re-
355     //   formatting, when drawing, or selecting text or links...) to expect
356     //   a reproducible layout (see BlockFloatFootprint for the different
357     //   possible usages of these extra fields).
358     unsigned short  _flags;
359     unsigned short  _extra0;
360     int  _extra1;
361     int  _extra2;
362     int  _extra3;
363     int  _extra4;
364     int  _extra5;
365 
366     int _listprop_node_idx; // dataIndex of the UL/OL node this erm_final block
367                             // should get its marker from
368 
369     // We're now at 16 32-bits ints. If needing new fields, add some padding:
370     // Added for padding from 17 to 20 32-bits ints
371     // int _available1; int _available2; int _available3;
372 
373 public:
lvdomElementFormatRec()374     lvdomElementFormatRec()
375     : _x(0), _width(0), _y(0), _height(0)
376     , _inner_width(0), _inner_x(0), _inner_y(0), _baseline(0)
377     , _usable_left_overflow(0), _usable_right_overflow(0)
378     , _top_overflow(0), _bottom_overflow(0)
379     , _lang_node_idx(0) , _listprop_node_idx(0)
380     , _flags(0), _extra0(0)
381     , _extra1(0), _extra2(0), _extra3(0), _extra4(0), _extra5(0)
382     {
383     }
~lvdomElementFormatRec()384     ~lvdomElementFormatRec()
385     {
386     }
clear()387     void clear()
388     {
389         _x = _width = _y = _height = 0;
390         _inner_width = _inner_x = _inner_y = _baseline = 0;
391         _usable_left_overflow = _usable_right_overflow = 0;
392         _top_overflow = _bottom_overflow = 0;
393         _lang_node_idx = _listprop_node_idx = 0;
394         _flags = _extra0 = 0;
395         _extra1 = _extra2 = _extra3 = _extra4 = _extra5 = 0;
396     }
397     bool operator == ( lvdomElementFormatRec & v )
398     {
399         return (_height==v._height && _y==v._y && _width==v._width && _x==v._x &&
400                 _inner_width==v._inner_width && _inner_x==v._inner_x &&
401                 _inner_y==v._inner_y && _baseline==v._baseline &&
402                 _usable_left_overflow==v._usable_left_overflow && _usable_right_overflow==v._usable_right_overflow &&
403                 _top_overflow==v._top_overflow && _bottom_overflow==v._bottom_overflow &&
404                 _lang_node_idx==v._lang_node_idx && _listprop_node_idx==v._listprop_node_idx &&
405                 _flags==v._flags && _extra0==v._extra0 &&
406                 _extra1==v._extra1 && _extra2==v._extra2 && _extra3==v._extra3 &&
407                 _extra4==v._extra4 && _extra5==v._extra5
408                 );
409     }
410     bool operator != ( lvdomElementFormatRec & v )
411     {
412         return (_height!=v._height || _y!=v._y || _width!=v._width || _x!=v._x ||
413                 _inner_width!=v._inner_width || _inner_x!=v._inner_x ||
414                 _inner_y!=v._inner_y || _baseline!=v._baseline ||
415                 _usable_left_overflow!=v._usable_left_overflow || _usable_right_overflow!=v._usable_right_overflow ||
416                 _top_overflow!=v._top_overflow || _bottom_overflow!=v._bottom_overflow ||
417                 _lang_node_idx!=v._lang_node_idx || _listprop_node_idx!=v._listprop_node_idx ||
418                 _flags!=v._flags || _extra0!=v._extra0 ||
419                 _extra1!=v._extra1 || _extra2!=v._extra2 || _extra3!=v._extra3 ||
420                 _extra4!=v._extra4 || _extra5!=v._extra5
421                 );
422     }
423     // Get/Set
getX()424     int getX() const { return _x; }
getY()425     int getY() const { return _y; }
getWidth()426     int getWidth() const { return _width; }
getHeight()427     int getHeight() const { return _height; }
getRect(lvRect & rc)428     void getRect( lvRect & rc ) const
429     {
430         rc.left = _x;
431         rc.top = _y;
432         rc.right = _x + _width;
433         rc.bottom = _y + _height;
434     }
setX(int x)435     void setX( int x ) { _x = x; }
setY(int y)436     void setY( int y ) { _y = y; }
setWidth(int w)437     void setWidth( int w ) { _width = w; }
setHeight(int h)438     void setHeight( int h ) { _height = h; }
439     // No real need for setters/getters for the other fields, RenderRectAccessor
440     // extends this class and can access them freely.
441 };
442 
443 /// calculate cache record hash
444 lUInt32 calcHash(css_style_rec_t & rec);
445 /// calculate font instance record hash
446 lUInt32 calcHash(font_ref_t & rec);
447 /// calculate cache record hash
calcHash(css_style_ref_t & rec)448 inline lUInt32 calcHash(css_style_ref_t & rec) { return rec.isNull() ? 0 : calcHash( *rec.get() ); }
449 
450 /// splits string like "Arial", Times New Roman, Courier;  into list
451 // returns number of characters processed
452 int splitPropertyValueList( const char * fontNames, lString8Collection & list );
453 
454 /// joins list into string of comma separated quoted values
455 lString8 joinPropertyValueList( const lString8Collection & list );
456 
457 
458 #endif // __LV_STYLES_H_INCLUDED__
459