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