Code

excise never-used code and stale comments
[inkscape.git] / src / libnrtype / Layout-TNG-Input.cpp
1 /*
2  * Inkscape::Text::Layout - text layout engine input functions
3  *
4  * Authors:
5  *   Richard Hughes <cyreve@users.sf.net>
6  *
7  * Copyright (C) 2005 Richard Hughes
8  *
9  * Released under GNU GPL, read the file 'COPYING' for more information
10  */
11 #include "Layout-TNG.h"
12 #include "style.h"
13 #include "svg/svg-length.h"
14 #include "sp-object.h"
15 #include "FontFactory.h"
17 namespace Inkscape {
18 namespace Text {
20 void Layout::_clearInputObjects()
21 {
22     for(std::vector<InputStreamItem*>::iterator it = _input_stream.begin() ; it != _input_stream.end() ; it++)
23         delete *it;
24     _input_stream.clear();
25     _input_wrap_shapes.clear();
26 }
28 // this function does nothing more than store all its parameters for future reference
29 void Layout::appendText(Glib::ustring const &text, SPStyle *style, void *source_cookie, OptionalTextTagAttrs const *optional_attributes, unsigned optional_attributes_offset, Glib::ustring::const_iterator text_begin, Glib::ustring::const_iterator text_end)
30 {
31     if (style == NULL) return;
33     InputStreamTextSource *new_source = new InputStreamTextSource;
35     new_source->source_cookie = source_cookie;
36     new_source->text = &text;
37     new_source->text_begin = text_begin;
38     new_source->text_end = text_end;
39     new_source->style = style;
40     sp_style_ref(style);
42     new_source->text_length = 0;
43     for ( ; text_begin != text_end && text_begin != text.end() ; text_begin++)
44         new_source->text_length++;        // save this because calculating the length of a UTF-8 string is expensive
46     if (optional_attributes) {
47         // we need to fill in x and y even if the text is empty so that empty paragraphs can be positioned correctly
48         _copyInputVector(optional_attributes->x, optional_attributes_offset, &new_source->x, std::max(1, new_source->text_length));
49         _copyInputVector(optional_attributes->y, optional_attributes_offset, &new_source->y, std::max(1, new_source->text_length));
50         _copyInputVector(optional_attributes->dx, optional_attributes_offset, &new_source->dx, new_source->text_length);
51         _copyInputVector(optional_attributes->dy, optional_attributes_offset, &new_source->dy, new_source->text_length);
52         _copyInputVector(optional_attributes->rotate, optional_attributes_offset, &new_source->rotate, new_source->text_length);
53     }
54     
55     _input_stream.push_back(new_source);
56 }
58 void Layout::_copyInputVector(std::vector<SVGLength> const &input_vector, unsigned input_offset, std::vector<SVGLength> *output_vector, size_t max_length)
59 {
60     output_vector->clear();
61     if (input_offset >= input_vector.size()) return;
62     output_vector->reserve(std::min(max_length, input_vector.size() - input_offset));
63     while (input_offset < input_vector.size() && max_length != 0) {
64         if (!input_vector[input_offset]._set)
65             break;
66         output_vector->push_back(input_vector[input_offset]);
67         input_offset++;
68         max_length--;
69     }
70 }
72 // just save what we've been given, really
73 void Layout::appendControlCode(TextControlCode code, void *source_cookie, double width, double ascent, double descent)
74 {
75     InputStreamControlCode *new_code = new InputStreamControlCode;
77     new_code->source_cookie = source_cookie;
78     new_code->code = code;
79     new_code->width = width;
80     new_code->ascent = ascent;
81     new_code->descent = descent;
82     
83     _input_stream.push_back(new_code);
84 }
86 // more saving of the parameters
87 void Layout::appendWrapShape(Shape const *shape, DisplayAlign display_align)
88 {
89     _input_wrap_shapes.push_back(InputWrapShape());
90     _input_wrap_shapes.back().shape = shape;
91     _input_wrap_shapes.back().display_align = display_align;
92 }
94 int Layout::_enum_converter(int input, EnumConversionItem const *conversion_table, unsigned conversion_table_size)
95 {
96     for (unsigned i = 0 ; i < conversion_table_size ; i++)
97         if (conversion_table[i].input == input)
98             return conversion_table[i].output;
99     return conversion_table[0].output;
102 // ***** the style format interface
103 // this doesn't include all accesses to SPStyle, only the ones that are non-trivial
105 static const float medium_font_size = 12.0;     // more of a default if all else fails than anything else
106 float Layout::InputStreamTextSource::styleComputeFontSize() const
108     return style->font_size.computed;
110     // in case the computed value's not good enough, here's some manual code held in reserve:
111     SPStyle const *this_style = style;
112     float inherit_multiplier = 1.0;
114     for ( ; ; ) {
115         if (this_style->font_size.set && !this_style->font_size.inherit) {
116             switch (this_style->font_size.type) {
117                 case SP_FONT_SIZE_LITERAL: {
118                     switch(this_style->font_size.value) {   // these multipliers are straight out of the CSS spec
119                             case SP_CSS_FONT_SIZE_XX_SMALL: return medium_font_size * inherit_multiplier * (3.0/5.0);
120                             case SP_CSS_FONT_SIZE_X_SMALL:  return medium_font_size * inherit_multiplier * (3.0/4.0);
121                             case SP_CSS_FONT_SIZE_SMALL:    return medium_font_size * inherit_multiplier * (8.0/9.0);
122                         default:
123                             case SP_CSS_FONT_SIZE_MEDIUM:   return medium_font_size * inherit_multiplier;
124                             case SP_CSS_FONT_SIZE_LARGE:    return medium_font_size * inherit_multiplier * (6.0/5.0);
125                             case SP_CSS_FONT_SIZE_X_LARGE:  return medium_font_size * inherit_multiplier * (3.0/2.0);
126                             case SP_CSS_FONT_SIZE_XX_LARGE: return medium_font_size * inherit_multiplier * 2.0;
127                             case SP_CSS_FONT_SIZE_SMALLER: inherit_multiplier *= 0.84; break;   //not exactly according to spec
128                             case SP_CSS_FONT_SIZE_LARGER:  inherit_multiplier *= 1.26; break;   //not exactly according to spec
129                     }
130                     break;
131                 }
132                 case SP_FONT_SIZE_PERCENTAGE: {    // 'em' units should be in here, but aren't. Fix in style.cpp.
133                     inherit_multiplier *= this_style->font_size.value;
134                     break;
135                 }
136                 case SP_FONT_SIZE_LENGTH: {
137                     return this_style->font_size.value * inherit_multiplier;
138                 }
139             }
140         }
141         if (this_style->object->parent == NULL) break;
142         this_style = this_style->object->parent->style;
143         if (this_style == NULL) break;
144     }
145     return medium_font_size * inherit_multiplier;
148 static const Layout::EnumConversionItem enum_convert_spstyle_block_progression_to_direction[] = {
149     {SP_CSS_BLOCK_PROGRESSION_TB, Layout::TOP_TO_BOTTOM},
150     {SP_CSS_BLOCK_PROGRESSION_LR, Layout::LEFT_TO_RIGHT},
151     {SP_CSS_BLOCK_PROGRESSION_RL, Layout::RIGHT_TO_LEFT}};
153 static const Layout::EnumConversionItem enum_convert_spstyle_writing_mode_to_direction[] = {
154     {SP_CSS_WRITING_MODE_LR_TB, Layout::TOP_TO_BOTTOM},
155     {SP_CSS_WRITING_MODE_RL_TB, Layout::TOP_TO_BOTTOM},
156     {SP_CSS_WRITING_MODE_TB_RL, Layout::RIGHT_TO_LEFT},
157     {SP_CSS_WRITING_MODE_TB_LR, Layout::LEFT_TO_RIGHT}};
159 Layout::Direction Layout::InputStreamTextSource::styleGetBlockProgression() const
161     // this function shouldn't be necessary, but since style.cpp doesn't support
162     // shorthand properties yet, it is.
163     SPStyle const *this_style = style;
165     for ( ; ; ) {
166         if (this_style->block_progression.set)
167             return (Layout::Direction)_enum_converter(this_style->block_progression.computed, enum_convert_spstyle_block_progression_to_direction, sizeof(enum_convert_spstyle_block_progression_to_direction)/sizeof(enum_convert_spstyle_block_progression_to_direction[0]));
168         if (this_style->writing_mode.set)
169             return (Layout::Direction)_enum_converter(this_style->writing_mode.computed, enum_convert_spstyle_writing_mode_to_direction, sizeof(enum_convert_spstyle_writing_mode_to_direction)/sizeof(enum_convert_spstyle_writing_mode_to_direction[0]));
170         if (this_style->object->parent == NULL) break;
171         this_style = this_style->object->parent->style;
172         if (this_style == NULL) break;
173     }
174     return TOP_TO_BOTTOM;
178 static Layout::Alignment text_anchor_to_alignment(unsigned anchor, Layout::Direction para_direction)
180     switch (anchor) {
181         default:
182         case SP_CSS_TEXT_ANCHOR_START:  return para_direction == Layout::LEFT_TO_RIGHT ? Layout::LEFT : Layout::RIGHT;
183         case SP_CSS_TEXT_ANCHOR_MIDDLE: return Layout::CENTER;
184         case SP_CSS_TEXT_ANCHOR_END:    return para_direction == Layout::LEFT_TO_RIGHT ? Layout::RIGHT : Layout::LEFT;
185     }
188 Layout::Alignment Layout::InputStreamTextSource::styleGetAlignment(Layout::Direction para_direction, bool try_text_align) const
190     if (!try_text_align)
191         return text_anchor_to_alignment(style->text_anchor.computed, para_direction);
193     // there's no way to tell the difference between text-anchor set higher up the cascade to the default and
194     // text-anchor never set anywhere in the cascade, so in order to detect which of text-anchor or text-align
195     // to use we'll have to run up the style tree ourselves.
196     SPStyle const *this_style = style;
198     for ( ; ; ) {
199         // If both text-align and text-anchor are set at the same level, text-align takes
200         // precedence because it is the most expressive.
201         if (this_style->text_align.set) {
202             switch (style->text_align.computed) {
203                 default:
204                 case SP_CSS_TEXT_ALIGN_START:   return para_direction == LEFT_TO_RIGHT ? LEFT : RIGHT;
205                 case SP_CSS_TEXT_ALIGN_END:     return para_direction == LEFT_TO_RIGHT ? RIGHT : LEFT;
206                 case SP_CSS_TEXT_ALIGN_LEFT:    return LEFT;
207                 case SP_CSS_TEXT_ALIGN_RIGHT:   return RIGHT;
208                 case SP_CSS_TEXT_ALIGN_CENTER:  return CENTER;
209                 case SP_CSS_TEXT_ALIGN_JUSTIFY: return FULL;
210             }
211         }
212         if (this_style->text_anchor.set)
213             return text_anchor_to_alignment(this_style->text_anchor.computed, para_direction);
214         if (this_style->object->parent == NULL) break;
215         this_style = this_style->object->parent->style;
216         if (this_style == NULL) break;
217     }
218     return para_direction == LEFT_TO_RIGHT ? LEFT : RIGHT;
221 static const Layout::EnumConversionItem enum_convert_spstyle_style_to_pango_style[] = {
222     {SP_CSS_FONT_STYLE_NORMAL,  PANGO_STYLE_NORMAL},
223     {SP_CSS_FONT_STYLE_ITALIC,  PANGO_STYLE_ITALIC},
224     {SP_CSS_FONT_STYLE_OBLIQUE, PANGO_STYLE_OBLIQUE}};
226 static const Layout::EnumConversionItem enum_convert_spstyle_weight_to_pango_weight[] = {
227     {SP_CSS_FONT_WEIGHT_NORMAL, PANGO_WEIGHT_NORMAL},
228     {SP_CSS_FONT_WEIGHT_100, PANGO_WEIGHT_ULTRALIGHT},
229     {SP_CSS_FONT_WEIGHT_200, PANGO_WEIGHT_ULTRALIGHT},
230     {SP_CSS_FONT_WEIGHT_300, PANGO_WEIGHT_LIGHT},
231     {SP_CSS_FONT_WEIGHT_400, PANGO_WEIGHT_NORMAL},
232     {SP_CSS_FONT_WEIGHT_500, PANGO_WEIGHT_SEMIBOLD},
233     {SP_CSS_FONT_WEIGHT_600, PANGO_WEIGHT_BOLD},
234     {SP_CSS_FONT_WEIGHT_BOLD,PANGO_WEIGHT_BOLD},
235     {SP_CSS_FONT_WEIGHT_700, PANGO_WEIGHT_BOLD},
236     {SP_CSS_FONT_WEIGHT_800, PANGO_WEIGHT_ULTRABOLD},
237     {SP_CSS_FONT_WEIGHT_900, PANGO_WEIGHT_HEAVY}};
239 static const Layout::EnumConversionItem enum_convert_spstyle_stretch_to_pango_stretch[] = {
240     {SP_CSS_FONT_STRETCH_NORMAL,          PANGO_STRETCH_NORMAL},
241     {SP_CSS_FONT_STRETCH_ULTRA_CONDENSED, PANGO_STRETCH_ULTRA_CONDENSED},
242     {SP_CSS_FONT_STRETCH_EXTRA_CONDENSED, PANGO_STRETCH_EXTRA_CONDENSED},
243     {SP_CSS_FONT_STRETCH_CONDENSED,       PANGO_STRETCH_CONDENSED},
244     {SP_CSS_FONT_STRETCH_SEMI_CONDENSED,  PANGO_STRETCH_SEMI_CONDENSED},
245     {SP_CSS_FONT_STRETCH_SEMI_EXPANDED,   PANGO_STRETCH_SEMI_EXPANDED},
246     {SP_CSS_FONT_STRETCH_EXPANDED,        PANGO_STRETCH_EXPANDED},
247     {SP_CSS_FONT_STRETCH_EXTRA_EXPANDED,  PANGO_STRETCH_EXTRA_EXPANDED},
248     {SP_CSS_FONT_STRETCH_ULTRA_EXPANDED,  PANGO_STRETCH_ULTRA_EXPANDED}};
250 static const Layout::EnumConversionItem enum_convert_spstyle_variant_to_pango_variant[] = {
251     {SP_CSS_FONT_VARIANT_NORMAL,     PANGO_VARIANT_NORMAL},
252     {SP_CSS_FONT_VARIANT_SMALL_CAPS, PANGO_VARIANT_SMALL_CAPS}};
254 font_instance *Layout::InputStreamTextSource::styleGetFontInstance() const
256     if (style->text == NULL) return NULL;
257     return (font_factory::Default())->Face(style->text->font_family.value,
258                                            _enum_converter(style->font_variant.computed, enum_convert_spstyle_variant_to_pango_variant, sizeof(enum_convert_spstyle_variant_to_pango_variant)/sizeof(enum_convert_spstyle_variant_to_pango_variant[0])),
259                                            _enum_converter(style->font_style.computed,   enum_convert_spstyle_style_to_pango_style,     sizeof(enum_convert_spstyle_style_to_pango_style)/sizeof(enum_convert_spstyle_style_to_pango_style[0])),
260                                            _enum_converter(style->font_weight.computed,  enum_convert_spstyle_weight_to_pango_weight,   sizeof(enum_convert_spstyle_weight_to_pango_weight)/sizeof(enum_convert_spstyle_weight_to_pango_weight[0])),
261                                            _enum_converter(style->font_stretch.computed, enum_convert_spstyle_stretch_to_pango_stretch, sizeof(enum_convert_spstyle_stretch_to_pango_stretch)/sizeof(enum_convert_spstyle_stretch_to_pango_stretch[0])));
264 Layout::InputStreamTextSource::~InputStreamTextSource()
266     sp_style_unref(style);
269 }//namespace Text
270 }//namespace Inkscape