1*c667dd47SPedro Giffuni#!/usr/bin/env perl -w
27e90fac2SAndrew Rist#**************************************************************
37e90fac2SAndrew Rist#
47e90fac2SAndrew Rist#  Licensed to the Apache Software Foundation (ASF) under one
57e90fac2SAndrew Rist#  or more contributor license agreements.  See the NOTICE file
67e90fac2SAndrew Rist#  distributed with this work for additional information
77e90fac2SAndrew Rist#  regarding copyright ownership.  The ASF licenses this file
87e90fac2SAndrew Rist#  to you under the Apache License, Version 2.0 (the
97e90fac2SAndrew Rist#  "License"); you may not use this file except in compliance
107e90fac2SAndrew Rist#  with the License.  You may obtain a copy of the License at
117e90fac2SAndrew Rist#
127e90fac2SAndrew Rist#    http://www.apache.org/licenses/LICENSE-2.0
137e90fac2SAndrew Rist#
147e90fac2SAndrew Rist#  Unless required by applicable law or agreed to in writing,
157e90fac2SAndrew Rist#  software distributed under the License is distributed on an
167e90fac2SAndrew Rist#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
177e90fac2SAndrew Rist#  KIND, either express or implied.  See the License for the
187e90fac2SAndrew Rist#  specific language governing permissions and limitations
197e90fac2SAndrew Rist#  under the License.
207e90fac2SAndrew Rist#
217e90fac2SAndrew Rist#**************************************************************
227e90fac2SAndrew Rist
237e90fac2SAndrew Rist
24cdf0e10cSrcweir
25cdf0e10cSrcweiruse warnings;
26cdf0e10cSrcweir
27cdf0e10cSrcweirsub usage() {
28cdf0e10cSrcweir    print STDERR <<EOF;
29cdf0e10cSrcweirUsage: preset-definitions-to-shape-types.pl <shapes> <text>
30cdf0e10cSrcweir
31cdf0e10cSrcweirConverts presetShapeDefinitions.xml and presetTextWarpDefinitions.xml to a
32cdf0e10cSrcweir.cxx that contains VML with the definitions of the shapes.  The result is
33cdf0e10cSrcweirwritten to stdout.
34cdf0e10cSrcweir
35cdf0e10cSrcweir<shapes> presetShapeDefinitions.xml (including the path to it)
36cdf0e10cSrcweir<text>   presetTextWarpDefinitions.xml (including the path to it)
37cdf0e10cSrcweirEOF
38cdf0e10cSrcweir    exit 1;
39cdf0e10cSrcweir}
40cdf0e10cSrcweir
41cdf0e10cSrcweirsub show_call_stack
42cdf0e10cSrcweir{
43cdf0e10cSrcweir    my ( $path, $line, $subr );
44cdf0e10cSrcweir    my $max_depth = 30;
45cdf0e10cSrcweir    my $i = 1;
46cdf0e10cSrcweir    print STDERR "--- Begin stack trace ---\n";
47cdf0e10cSrcweir    while ( (my @call_details = (caller($i++))) && ($i<$max_depth) ) {
48cdf0e10cSrcweir        print STDERR "$call_details[1] line $call_details[2] in function $call_details[3]\n";
49cdf0e10cSrcweir    }
50cdf0e10cSrcweir    print STDERR "--- End stack trace ---\n";
51cdf0e10cSrcweir}
52cdf0e10cSrcweir
53cdf0e10cSrcweir$src_shapes = shift;
54cdf0e10cSrcweir$src_text = shift;
55cdf0e10cSrcweir
56cdf0e10cSrcweirusage() if ( !defined( $src_shapes ) || !defined( $src_text ) ||
57cdf0e10cSrcweir             $src_shapes eq "-h" || $src_shapes eq "--help" ||
58cdf0e10cSrcweir             !-f $src_shapes || !-f $src_text );
59cdf0e10cSrcweir
60cdf0e10cSrcweir# Global variables
61cdf0e10cSrcweir@levels = ();
62cdf0e10cSrcweir$shape_name = "";
63cdf0e10cSrcweir$state = "";
64cdf0e10cSrcweir$path = "";
65cdf0e10cSrcweir$adjust = "";
66cdf0e10cSrcweir$max_adj_no = 0;
67cdf0e10cSrcweir@formulas = ();
68cdf0e10cSrcweir%variables = ();
69cdf0e10cSrcweir$ignore_this_shape = 0;
70cdf0e10cSrcweir$handles = "";
71cdf0e10cSrcweir$textboxrect = "";
72cdf0e10cSrcweir$last_pos_x = "";
73cdf0e10cSrcweir$last_pos_y = "";
74cdf0e10cSrcweir$no_stroke = 0;
75cdf0e10cSrcweir$no_fill = 0;
76cdf0e10cSrcweir$path_w = 1;
77cdf0e10cSrcweir$path_h = 1;
78cdf0e10cSrcweir@quadratic_bezier = ();
79cdf0e10cSrcweir
80cdf0e10cSrcweir%result_shapes = ();
81cdf0e10cSrcweir
82cdf0e10cSrcweir%shapes_ids = (
83cdf0e10cSrcweir    0 => 'notPrimitive',
84cdf0e10cSrcweir    1 => 'rectangle',
85cdf0e10cSrcweir    2 => 'roundRectangle',
86cdf0e10cSrcweir    3 => 'ellipse',
87cdf0e10cSrcweir    4 => 'diamond',
88cdf0e10cSrcweir    5 => 'triangle',
89cdf0e10cSrcweir    6 => 'rtTriangle',
90cdf0e10cSrcweir    7 => 'parallelogram',
91cdf0e10cSrcweir    8 => 'trapezoid',
92cdf0e10cSrcweir    9 => 'hexagon',
93cdf0e10cSrcweir    10 => 'octagon',
94cdf0e10cSrcweir    11 => 'plus',
95cdf0e10cSrcweir    12 => 'star5',
96cdf0e10cSrcweir    13 => 'rightArrow',
97cdf0e10cSrcweir    14 => 'thickArrow', # should not be used
98cdf0e10cSrcweir    15 => 'homePlate',
99cdf0e10cSrcweir    16 => 'cube',
100cdf0e10cSrcweir    17 => 'wedgeRoundRectCallout', # balloon
101cdf0e10cSrcweir    18 => 'star16', # seal
102cdf0e10cSrcweir    19 => 'arc',
103cdf0e10cSrcweir    20 => 'line',
104cdf0e10cSrcweir    21 => 'plaque',
105cdf0e10cSrcweir    22 => 'can',
106cdf0e10cSrcweir    23 => 'donut',
107cdf0e10cSrcweir    24 => 'textPlain', # textSimple - FIXME MS Office 2007 converts these to textboxes with unstyled text, so is it actually correct to map it to a real style?
108cdf0e10cSrcweir    25 => 'textStop', # textOctagon FIXME see 24
109cdf0e10cSrcweir    26 => 'textTriangle', # textHexagon FIXMME see 24
110cdf0e10cSrcweir    27 => 'textCanDown', # textCurve FIXMME see 24
111cdf0e10cSrcweir    28 => 'textWave1', # textWave FIXMME see 24
112cdf0e10cSrcweir    29 => 'textArchUpPour', # textRing FIXMME see 24
113cdf0e10cSrcweir    30 => 'textCanDown', # textOnCurve FIXMME see 24
114cdf0e10cSrcweir    31 => 'textArchUp', # textOnRing FIXMME see 24
115cdf0e10cSrcweir    32 => 'straightConnector1',
116cdf0e10cSrcweir    33 => 'bentConnector2',
117cdf0e10cSrcweir    34 => 'bentConnector3',
118cdf0e10cSrcweir    35 => 'bentConnector4',
119cdf0e10cSrcweir    36 => 'bentConnector5',
120cdf0e10cSrcweir    37 => 'curvedConnector2',
121cdf0e10cSrcweir    38 => 'curvedConnector3',
122cdf0e10cSrcweir    39 => 'curvedConnector4',
123cdf0e10cSrcweir    40 => 'curvedConnector5',
124cdf0e10cSrcweir    41 => 'callout1',
125cdf0e10cSrcweir    42 => 'callout2',
126cdf0e10cSrcweir    43 => 'callout3',
127cdf0e10cSrcweir    44 => 'accentCallout1',
128cdf0e10cSrcweir    45 => 'accentCallout2',
129cdf0e10cSrcweir    46 => 'accentCallout3',
130cdf0e10cSrcweir    47 => 'borderCallout1',
131cdf0e10cSrcweir    48 => 'borderCallout2',
132cdf0e10cSrcweir    49 => 'borderCallout3',
133cdf0e10cSrcweir    50 => 'accentBorderCallout1',
134cdf0e10cSrcweir    51 => 'accentBorderCallout2',
135cdf0e10cSrcweir    52 => 'accentBorderCallout3',
136cdf0e10cSrcweir    53 => 'ribbon',
137cdf0e10cSrcweir    54 => 'ribbon2',
138cdf0e10cSrcweir    55 => 'chevron',
139cdf0e10cSrcweir    56 => 'pentagon',
140cdf0e10cSrcweir    57 => 'noSmoking',
141cdf0e10cSrcweir    58 => 'star8', # seal8
142cdf0e10cSrcweir    59 => 'star16', # seal16
143cdf0e10cSrcweir    60 => 'star32', # seal32
144cdf0e10cSrcweir    61 => 'wedgeRectCallout',
145cdf0e10cSrcweir    62 => 'wedgeRoundRectCallout', # wedgeRRectCallout
146cdf0e10cSrcweir    63 => 'wedgeEllipseCallout',
147cdf0e10cSrcweir    64 => 'wave',
148cdf0e10cSrcweir    65 => 'foldedCorner',
149cdf0e10cSrcweir    66 => 'leftArrow',
150cdf0e10cSrcweir    67 => 'downArrow',
151cdf0e10cSrcweir    68 => 'upArrow',
152cdf0e10cSrcweir    69 => 'leftRightArrow',
153cdf0e10cSrcweir    70 => 'upDownArrow',
154cdf0e10cSrcweir    71 => 'irregularSeal1',
155cdf0e10cSrcweir    72 => 'irregularSeal2',
156cdf0e10cSrcweir    73 => 'lightningBolt',
157cdf0e10cSrcweir    74 => 'heart',
158cdf0e10cSrcweir    75 => 'frame', # pictureFrame
159cdf0e10cSrcweir    76 => 'quadArrow',
160cdf0e10cSrcweir    77 => 'leftArrowCallout',
161cdf0e10cSrcweir    78 => 'rightArrowCallout',
162cdf0e10cSrcweir    79 => 'upArrowCallout',
163cdf0e10cSrcweir    80 => 'downArrowCallout',
164cdf0e10cSrcweir    81 => 'leftRightArrowCallout',
165cdf0e10cSrcweir    82 => 'upDownArrowCallout',
166cdf0e10cSrcweir    83 => 'quadArrowCallout',
167cdf0e10cSrcweir    84 => 'bevel',
168cdf0e10cSrcweir    85 => 'leftBracket',
169cdf0e10cSrcweir    86 => 'rightBracket',
170cdf0e10cSrcweir    87 => 'leftBrace',
171cdf0e10cSrcweir    88 => 'rightBrace',
172cdf0e10cSrcweir    89 => 'leftUpArrow',
173cdf0e10cSrcweir    90 => 'bentUpArrow',
174cdf0e10cSrcweir    91 => 'bentArrow',
175cdf0e10cSrcweir    92 => 'star24', # seal24
176cdf0e10cSrcweir    93 => 'stripedRightArrow',
177cdf0e10cSrcweir    94 => 'notchedRightArrow',
178cdf0e10cSrcweir    95 => 'blockArc',
179cdf0e10cSrcweir    96 => 'smileyFace',
180cdf0e10cSrcweir    97 => 'verticalScroll',
181cdf0e10cSrcweir    98 => 'horizontalScroll',
182cdf0e10cSrcweir    99 => 'circularArrow',
183cdf0e10cSrcweir    100 => 'notchedCircularArrow', # should not be used
184cdf0e10cSrcweir    101 => 'uturnArrow',
185cdf0e10cSrcweir    102 => 'curvedRightArrow',
186cdf0e10cSrcweir    103 => 'curvedLeftArrow',
187cdf0e10cSrcweir    104 => 'curvedUpArrow',
188cdf0e10cSrcweir    105 => 'curvedDownArrow',
189cdf0e10cSrcweir    106 => 'cloudCallout',
190cdf0e10cSrcweir    107 => 'ellipseRibbon',
191cdf0e10cSrcweir    108 => 'ellipseRibbon2',
192cdf0e10cSrcweir    109 => 'flowChartProcess',
193cdf0e10cSrcweir    110 => 'flowChartDecision',
194cdf0e10cSrcweir    111 => 'flowChartInputOutput',
195cdf0e10cSrcweir    112 => 'flowChartPredefinedProcess',
196cdf0e10cSrcweir    113 => 'flowChartInternalStorage',
197cdf0e10cSrcweir    114 => 'flowChartDocument',
198cdf0e10cSrcweir    115 => 'flowChartMultidocument',
199cdf0e10cSrcweir    116 => 'flowChartTerminator',
200cdf0e10cSrcweir    117 => 'flowChartPreparation',
201cdf0e10cSrcweir    118 => 'flowChartManualInput',
202cdf0e10cSrcweir    119 => 'flowChartManualOperation',
203cdf0e10cSrcweir    120 => 'flowChartConnector',
204cdf0e10cSrcweir    121 => 'flowChartPunchedCard',
205cdf0e10cSrcweir    122 => 'flowChartPunchedTape',
206cdf0e10cSrcweir    123 => 'flowChartSummingJunction',
207cdf0e10cSrcweir    124 => 'flowChartOr',
208cdf0e10cSrcweir    125 => 'flowChartCollate',
209cdf0e10cSrcweir    126 => 'flowChartSort',
210cdf0e10cSrcweir    127 => 'flowChartExtract',
211cdf0e10cSrcweir    128 => 'flowChartMerge',
212cdf0e10cSrcweir    129 => 'flowChartOfflineStorage',
213cdf0e10cSrcweir    130 => 'flowChartOnlineStorage',
214cdf0e10cSrcweir    131 => 'flowChartMagneticTape',
215cdf0e10cSrcweir    132 => 'flowChartMagneticDisk',
216cdf0e10cSrcweir    133 => 'flowChartMagneticDrum',
217cdf0e10cSrcweir    134 => 'flowChartDisplay',
218cdf0e10cSrcweir    135 => 'flowChartDelay',
219cdf0e10cSrcweir    136 => 'textPlain', # textPlainText
220cdf0e10cSrcweir    137 => 'textStop',
221cdf0e10cSrcweir    138 => 'textTriangle',
222cdf0e10cSrcweir    139 => 'textTriangleInverted',
223cdf0e10cSrcweir    140 => 'textChevron',
224cdf0e10cSrcweir    141 => 'textChevronInverted',
225cdf0e10cSrcweir    142 => 'textRingInside',
226cdf0e10cSrcweir    143 => 'textRingOutside',
227cdf0e10cSrcweir    144 => 'textArchUp', # textArchUpCurve
228cdf0e10cSrcweir    145 => 'textArchDown', # textArchDownCurve
229cdf0e10cSrcweir    146 => 'textCircle', # textCircleCurve
230cdf0e10cSrcweir    147 => 'textButton', # textButtonCurve
231cdf0e10cSrcweir    148 => 'textArchUpPour',
232cdf0e10cSrcweir    149 => 'textArchDownPour',
233cdf0e10cSrcweir    150 => 'textCirclePour',
234cdf0e10cSrcweir    151 => 'textButtonPour',
235cdf0e10cSrcweir    152 => 'textCurveUp',
236cdf0e10cSrcweir    153 => 'textCurveDown',
237cdf0e10cSrcweir    154 => 'textCascadeUp',
238cdf0e10cSrcweir    155 => 'textCascadeDown',
239cdf0e10cSrcweir    156 => 'textWave1',
240cdf0e10cSrcweir    157 => 'textWave2',
241cdf0e10cSrcweir    158 => 'textWave3',
242cdf0e10cSrcweir    159 => 'textWave4',
243cdf0e10cSrcweir    160 => 'textInflate',
244cdf0e10cSrcweir    161 => 'textDeflate',
245cdf0e10cSrcweir    162 => 'textInflateBottom',
246cdf0e10cSrcweir    163 => 'textDeflateBottom',
247cdf0e10cSrcweir    164 => 'textInflateTop',
248cdf0e10cSrcweir    165 => 'textDeflateTop',
249cdf0e10cSrcweir    166 => 'textDeflateInflate',
250cdf0e10cSrcweir    167 => 'textDeflateInflateDeflate',
251cdf0e10cSrcweir    168 => 'textFadeRight',
252cdf0e10cSrcweir    169 => 'textFadeLeft',
253cdf0e10cSrcweir    170 => 'textFadeUp',
254cdf0e10cSrcweir    171 => 'textFadeDown',
255cdf0e10cSrcweir    172 => 'textSlantUp',
256cdf0e10cSrcweir    173 => 'textSlantDown',
257cdf0e10cSrcweir    174 => 'textCanUp',
258cdf0e10cSrcweir    175 => 'textCanDown',
259cdf0e10cSrcweir    176 => 'flowChartAlternateProcess',
260cdf0e10cSrcweir    177 => 'flowChartOffpageConnector',
261cdf0e10cSrcweir    178 => 'callout1', # callout90
262cdf0e10cSrcweir    179 => 'accentCallout1', # accentCallout90
263cdf0e10cSrcweir    180 => 'borderCallout1', # borderCallout90
264cdf0e10cSrcweir    181 => 'accentBorderCallout1', # accentBorderCallout90
265cdf0e10cSrcweir    182 => 'leftRightUpArrow',
266cdf0e10cSrcweir    183 => 'sun',
267cdf0e10cSrcweir    184 => 'moon',
268cdf0e10cSrcweir    185 => 'bracketPair',
269cdf0e10cSrcweir    186 => 'bracePair',
270cdf0e10cSrcweir    187 => 'star4', # seal4
271cdf0e10cSrcweir    188 => 'doubleWave',
272cdf0e10cSrcweir    189 => 'actionButtonBlank',
273cdf0e10cSrcweir    190 => 'actionButtonHome',
274cdf0e10cSrcweir    191 => 'actionButtonHelp',
275cdf0e10cSrcweir    192 => 'actionButtonInformation',
276cdf0e10cSrcweir    193 => 'actionButtonForwardNext',
277cdf0e10cSrcweir    194 => 'actionButtonBackPrevious',
278cdf0e10cSrcweir    195 => 'actionButtonEnd',
279cdf0e10cSrcweir    196 => 'actionButtonBeginning',
280cdf0e10cSrcweir    197 => 'actionButtonReturn',
281cdf0e10cSrcweir    198 => 'actionButtonDocument',
282cdf0e10cSrcweir    199 => 'actionButtonSound',
283cdf0e10cSrcweir    200 => 'actionButtonMovie',
284cdf0e10cSrcweir    201 => 'hostControl', # should not be used
285cdf0e10cSrcweir    202 => 'textBox'
286cdf0e10cSrcweir);
287a893be29SPedro Giffuni# An error occurred, we have to ignore this shape
288cdf0e10cSrcweirsub error( $ )
289cdf0e10cSrcweir{
290cdf0e10cSrcweir    my ( $msg ) = @_;
291cdf0e10cSrcweir
292cdf0e10cSrcweir    $ignore_this_shape = 1;
293cdf0e10cSrcweir    print STDERR "ERROR (in $shape_name ): $msg\n";
294cdf0e10cSrcweir}
295cdf0e10cSrcweir
296cdf0e10cSrcweir# Check that we are in the correct level
297cdf0e10cSrcweirsub is_level( $$ )
298cdf0e10cSrcweir{
299cdf0e10cSrcweir    my ( $level, $value ) = @_;
300cdf0e10cSrcweir
301cdf0e10cSrcweir    if ( $level > 0 ) {
302cdf0e10cSrcweir        error( "Error in is_level(), \$level should be <= 0." );
303cdf0e10cSrcweir    }
304cdf0e10cSrcweir    return ( $#levels + $level > 0 ) && ( $levels[$#levels + $level] eq $value );
305cdf0e10cSrcweir}
306cdf0e10cSrcweir
307cdf0e10cSrcweir# Setup the %variables map with predefined values
308cdf0e10cSrcweirsub setup_variables()
309cdf0e10cSrcweir{
310cdf0e10cSrcweir    %variables = (
311cdf0e10cSrcweir        'l'        => 0,
312cdf0e10cSrcweir        't'        => 0,
313cdf0e10cSrcweir        'r'        => 21600,
314cdf0e10cSrcweir        'b'        => 21600,
315cdf0e10cSrcweir
316cdf0e10cSrcweir        'w'        => 21600,
317cdf0e10cSrcweir        'h'        => 21600,
318cdf0e10cSrcweir        'ss'       => 21600,
319cdf0e10cSrcweir        'ls'       => 21600,
320cdf0e10cSrcweir
321cdf0e10cSrcweir        'ssd2'     => 10800, # 1/2
322cdf0e10cSrcweir        'ssd4'     => 5400,  # 1/4
323cdf0e10cSrcweir        'ssd6'     => 3600,  # 1/6
324cdf0e10cSrcweir        'ssd8'     => 2700,  # 1/8
325cdf0e10cSrcweir        'ssd16'    => 1350,  # 1/16
326cdf0e10cSrcweir        'ssd32'    => 675,   # 1/32
327cdf0e10cSrcweir
328cdf0e10cSrcweir        'hc'       => 10800, # horizontal center
329cdf0e10cSrcweir        'vc'       => 10800, # vertical center
330cdf0e10cSrcweir
331cdf0e10cSrcweir        'wd2'      => 10800, # 1/2
332cdf0e10cSrcweir        'wd3'      => 7200,  # 1/3
333cdf0e10cSrcweir        'wd4'      => 5400,  # 1/4
334cdf0e10cSrcweir        'wd5'      => 4320,  # 1/5
335cdf0e10cSrcweir        'wd6'      => 3600,  # 1/6
336cdf0e10cSrcweir        'wd8'      => 2700,  # 1/8
337cdf0e10cSrcweir        'wd10'     => 2160,  # 1/10
338cdf0e10cSrcweir        'wd12'     => 1800,  # 1/12
339cdf0e10cSrcweir        'wd32'     => 675,   # 1/32
340cdf0e10cSrcweir
341cdf0e10cSrcweir        'hd2'      => 10800, # 1/2
342cdf0e10cSrcweir        'hd3'      => 7200,  # 1/3
343cdf0e10cSrcweir        'hd4'      => 5400,  # 1/4
344cdf0e10cSrcweir        'hd5'      => 4320,  # 1/5
345cdf0e10cSrcweir        'hd6'      => 3600,  # 1/6
346cdf0e10cSrcweir        'hd8'      => 2700,  # 1/8
347cdf0e10cSrcweir        'hd10'     => 2160,  # 1/10
348cdf0e10cSrcweir        'hd12'     => 1800,  # 1/12
349cdf0e10cSrcweir        'hd32'     => 675,   # 1/32
350cdf0e10cSrcweir
351cdf0e10cSrcweir        '25000'    => 5400,
352cdf0e10cSrcweir        '12500'    => 2700,
353cdf0e10cSrcweir
354cdf0e10cSrcweir        'cd4'      => 90,    # 1/4 of a circle
355cdf0e10cSrcweir        'cd2'      => 180,   # 1/2 of a circle
356cdf0e10cSrcweir        '3cd4'     => 270,   # 3/4 of a circle
357cdf0e10cSrcweir
358cdf0e10cSrcweir        'cd8'      => 45,    # 1/8 of a circle
359cdf0e10cSrcweir        '3cd8'     => 135,   # 3/8 of a circle
360cdf0e10cSrcweir        '5cd8'     => 225,   # 5/8 of a circle
361cdf0e10cSrcweir        '7cd8'     => 315,   # 7/8 of a circle
362cdf0e10cSrcweir
363cdf0e10cSrcweir        '-5400000' => -90,
364cdf0e10cSrcweir        '-10800000'=> -180,
365cdf0e10cSrcweir        '-16200000'=> -270,
366cdf0e10cSrcweir        '-21600000'=> -360,
367cdf0e10cSrcweir        '-21599999'=> -360,
368cdf0e10cSrcweir
369cdf0e10cSrcweir        '5400000'  => 90,
370cdf0e10cSrcweir        '10800000' => 180,
371cdf0e10cSrcweir        '16200000' => 270,
372cdf0e10cSrcweir        '21600000' => 360,
373cdf0e10cSrcweir        '21599999' => 360
374cdf0e10cSrcweir#
375cdf0e10cSrcweir#        '21600000' => 360,   # angle conversions
376cdf0e10cSrcweir#        '27000000' => 450,
377cdf0e10cSrcweir#        '32400000' => 540,
378cdf0e10cSrcweir#        '37800000' => 630
379cdf0e10cSrcweir    );
380cdf0e10cSrcweir}
381cdf0e10cSrcweir
382cdf0e10cSrcweir# Convert the (predefiend) value to a number
383cdf0e10cSrcweirsub value( $ )
384cdf0e10cSrcweir{
385cdf0e10cSrcweir    my ( $val ) = @_;
386cdf0e10cSrcweir
387cdf0e10cSrcweir    my $result = $variables{$val};
388cdf0e10cSrcweir    return $result if ( defined( $result ) );
389cdf0e10cSrcweir
390cdf0e10cSrcweir    return $val if ( $val =~ /^[0-9-]+$/ );
391cdf0e10cSrcweir
392cdf0e10cSrcweir    error( "Unknown variable '$val'." );
393cdf0e10cSrcweir
394cdf0e10cSrcweir    show_call_stack();
395cdf0e10cSrcweir    return $val;
396cdf0e10cSrcweir}
397cdf0e10cSrcweir
398cdf0e10cSrcweir# Convert the DrawingML formula to a VML one
399cdf0e10cSrcweir%command_variables = (
400cdf0e10cSrcweir    'w' => 'width',
401cdf0e10cSrcweir    'h' => 'height',
402cdf0e10cSrcweir    'r' => 'width',
403cdf0e10cSrcweir    'b' => 'height'
404cdf0e10cSrcweir);
405cdf0e10cSrcweir
406cdf0e10cSrcweir# The same as value(), but some of the hardcoded values can have a name
407cdf0e10cSrcweirsub command_value( $ )
408cdf0e10cSrcweir{
409cdf0e10cSrcweir    my ( $value ) = @_;
410cdf0e10cSrcweir
411cdf0e10cSrcweir    return "" if ( $value eq "" );
412cdf0e10cSrcweir
413cdf0e10cSrcweir    return $value if ( $value =~ /^@/ );
414cdf0e10cSrcweir
415cdf0e10cSrcweir    my $command_val = $command_variables{$value};
416cdf0e10cSrcweir    if ( defined( $command_val ) ) {
417cdf0e10cSrcweir        return $command_val;
418cdf0e10cSrcweir    }
419cdf0e10cSrcweir
420cdf0e10cSrcweir    return value( $value );
421cdf0e10cSrcweir}
422cdf0e10cSrcweir
423cdf0e10cSrcweir# Insert the new formula to the list of formulas
424cdf0e10cSrcweir# Creates the name if it's empty...
425cdf0e10cSrcweirsub insert_formula( $$ )
426cdf0e10cSrcweir{
427cdf0e10cSrcweir    my ( $name, $fmla ) = @_;
428cdf0e10cSrcweir
429cdf0e10cSrcweir    my $i = 0;
430cdf0e10cSrcweir    foreach $f ( @formulas ) {
431cdf0e10cSrcweir        if ( $f eq $fmla ) {
432cdf0e10cSrcweir            if ( $name ne "" ) {
433cdf0e10cSrcweir                $variables{$name} = "@" . $i;
434cdf0e10cSrcweir            }
435cdf0e10cSrcweir            return "@" . $i;
436cdf0e10cSrcweir        }
437cdf0e10cSrcweir        ++$i;
438cdf0e10cSrcweir    }
439cdf0e10cSrcweir
440cdf0e10cSrcweir    if ( $name eq "" ) {
441cdf0e10cSrcweir        $name = "@" . ( $#formulas + 1 );
442cdf0e10cSrcweir    }
443cdf0e10cSrcweir
444cdf0e10cSrcweir    $variables{$name} = "@" . ( $#formulas + 1 );
445cdf0e10cSrcweir    push @formulas, $fmla;
446cdf0e10cSrcweir
447cdf0e10cSrcweir    if ( $#formulas > 127 ) {
448cdf0e10cSrcweir        error( "Reached the maximum amount of formulas, have to ignore the shape '$shape_name'" );
449cdf0e10cSrcweir    }
450cdf0e10cSrcweir
451cdf0e10cSrcweir    return $variables{$name};
452cdf0e10cSrcweir}
453cdf0e10cSrcweir
454cdf0e10cSrcweir# The same as insert_formula(), but converts the params
455cdf0e10cSrcweirsub insert_formula_params( $$$$$ )
456cdf0e10cSrcweir{
457cdf0e10cSrcweir    my ( $name, $command, $p1, $p2, $p3 ) = @_;
458cdf0e10cSrcweir
459cdf0e10cSrcweir    my $result = $command;
460cdf0e10cSrcweir    if ( $p1 ne "" ) {
461cdf0e10cSrcweir        $result .= " " . command_value( $p1 );
462cdf0e10cSrcweir        if ( $p2 ne "" ) {
463cdf0e10cSrcweir            $result .= " " . command_value( $p2 );
464cdf0e10cSrcweir            if ( $p3 ne "" ) {
465cdf0e10cSrcweir                $result .= " " . command_value( $p3 );
466cdf0e10cSrcweir            }
467cdf0e10cSrcweir        }
468cdf0e10cSrcweir    }
469cdf0e10cSrcweir
470cdf0e10cSrcweir    return insert_formula( $name, $result );
471cdf0e10cSrcweir}
472cdf0e10cSrcweir
473cdf0e10cSrcweir# Convert the formula from DrawingML to VML
474cdf0e10cSrcweirsub convert_formula( $$ )
475cdf0e10cSrcweir{
476cdf0e10cSrcweir    my ( $name, $fmla ) = @_;
477cdf0e10cSrcweir
478cdf0e10cSrcweir    if ( $fmla =~ /^([^ ]+)/ ) {
479cdf0e10cSrcweir        my $command = $1;
480cdf0e10cSrcweir
481cdf0e10cSrcweir        # parse the parameters
482cdf0e10cSrcweir        ( my $values = $fmla ) =~ s/^([^ ]+) *//;
483cdf0e10cSrcweir        my $p1 = "", $p2 = "", $p3 = "";
484cdf0e10cSrcweir        if ( $values =~ /^([^ ]+)/ ) {
485cdf0e10cSrcweir            $p1 = $1;
486cdf0e10cSrcweir            $values =~ s/^([^ ]+) *//;
487cdf0e10cSrcweir            if ( $values =~ /^([^ ]+)/ ) {
488cdf0e10cSrcweir                $p2 = $1;
489cdf0e10cSrcweir                $values =~ s/^([^ ]+) *//;
490cdf0e10cSrcweir                if ( $values =~ /^([^ ]+)/ ) {
491cdf0e10cSrcweir                    $p3 = $1;
492cdf0e10cSrcweir                }
493cdf0e10cSrcweir            }
494cdf0e10cSrcweir        }
495cdf0e10cSrcweir
496cdf0e10cSrcweir        # now convert the formula
497cdf0e10cSrcweir        if ( $command eq "+-" ) {
498cdf0e10cSrcweir            if ( $p1 eq "100000" ) {
499cdf0e10cSrcweir                $p1 = value( 'w' );
500cdf0e10cSrcweir            }
501cdf0e10cSrcweir            insert_formula_params( $name, "sum", $p1, $p2, $p3 );
502cdf0e10cSrcweir            return;
503cdf0e10cSrcweir        }
504cdf0e10cSrcweir        elsif ( $command eq "*/" ) {
505cdf0e10cSrcweir            if ( ( $p2 =~ /^(w|h|ss|hd2|wd2|vc)$/ ) && defined( $variables{$p1} ) ) {
506cdf0e10cSrcweir                # switch it ;-) - presetTextWarpDefinitions.xml has it in other order
507cdf0e10cSrcweir                my $tmp = $p1;
508cdf0e10cSrcweir                $p1 = $p2;
509cdf0e10cSrcweir                $p2 = $tmp;
510cdf0e10cSrcweir            }
511cdf0e10cSrcweir
512cdf0e10cSrcweir            if ( ( $p1 =~ /^(w|h|ss|hd2|wd2|vc)$/ ) && defined( $variables{$p2} ) ) {
513cdf0e10cSrcweir                my $val3 = $p3;
514cdf0e10cSrcweir                if ( $val3 =~ /^[0-9-]+$/ ) {
515cdf0e10cSrcweir                    $val3 *= ( value( 'w' ) / value( $p1 ) );
516cdf0e10cSrcweir
517cdf0e10cSrcweir                    # Oh yes, I'm too lazy to implement the full GCD here ;-)
518cdf0e10cSrcweir                    if ( ( $val3 % 100000 ) == 0 ) {
519cdf0e10cSrcweir                        $p1 = 1;
520cdf0e10cSrcweir                        $p3 = sprintf( "%.0f", ( $val3 / 100000 ) );
521cdf0e10cSrcweir                    }
522cdf0e10cSrcweir                    elsif ( $val3 < 100000 ) {
523cdf0e10cSrcweir                        $p3 = 1;
524cdf0e10cSrcweir                        while ( ( ( $p3 * 100000 ) % $val3 ) != 0 ) {
525cdf0e10cSrcweir                            ++$p3
526cdf0e10cSrcweir                        }
527cdf0e10cSrcweir                        $p1 = ( $p3 * 100000 ) / $val3;
528cdf0e10cSrcweir                    }
529cdf0e10cSrcweir                    else {
530cdf0e10cSrcweir                        error( "Need to count the greatest common divisor." );
531cdf0e10cSrcweir                    }
532cdf0e10cSrcweir                }
533cdf0e10cSrcweir            }
534cdf0e10cSrcweir            elsif ( $p3 eq "100000" && $p2 =~ /^[0-9-]+$/ ) {
535cdf0e10cSrcweir                # prevent overflows in some shapes
536cdf0e10cSrcweir                $p2 = sprintf( "%.0f", ( $p2 / 10 ) );
537cdf0e10cSrcweir                $p3 /= 10;
538cdf0e10cSrcweir            }
539cdf0e10cSrcweir            elsif ( $p3 eq "32768" && $p2 =~ /^[0-9-]+$/ ) {
540cdf0e10cSrcweir                # prevent overflows in some shapes
541cdf0e10cSrcweir                $p2 = sprintf( "%.0f", ( $p2 / 8 ) );
542cdf0e10cSrcweir                $p3 /= 8;
543cdf0e10cSrcweir            }
544cdf0e10cSrcweir            elsif ( $p3 eq "50000" ) {
545cdf0e10cSrcweir                $p3 = 10800;
546cdf0e10cSrcweir            }
547cdf0e10cSrcweir            elsif ( $name =~ /^maxAdj/ ) {
548cdf0e10cSrcweir                my $val = value( $p1 );
549cdf0e10cSrcweir                if ( $val =~ /^[0-9-]+$/ ) {
550cdf0e10cSrcweir                    $p1 = sprintf( "%.0f", ( value( 'w' ) * $val / 100000 ) );
551cdf0e10cSrcweir                }
552cdf0e10cSrcweir            }
553cdf0e10cSrcweir
554cdf0e10cSrcweir            if ( ( value( $p1 ) eq value( $p3 ) ) || ( value( $p2 ) eq value( $p3 ) ) ) {
555cdf0e10cSrcweir                my $val = value( ( value( $p1 ) eq value( $p3 ) )? $p2: $p1 );
556cdf0e10cSrcweir                if ( $val =~ /^@([0-9]+)$/ ) {
557cdf0e10cSrcweir                    insert_formula( $name, $formulas[$1] );
558cdf0e10cSrcweir                }
559cdf0e10cSrcweir                else {
560cdf0e10cSrcweir                    insert_formula( $name, "val $val" );
561cdf0e10cSrcweir                }
562cdf0e10cSrcweir            }
563cdf0e10cSrcweir            else {
564cdf0e10cSrcweir                insert_formula_params( $name, "prod", $p1, $p2, $p3 );
565cdf0e10cSrcweir            }
566cdf0e10cSrcweir            return;
567cdf0e10cSrcweir        }
568cdf0e10cSrcweir        elsif ( $command eq "+/" ) {
569cdf0e10cSrcweir            # we have to split this into 2 formulas - 'sum' and 'prod'
570cdf0e10cSrcweir            my $constructed = insert_formula_params( "", "sum", $p1, $p2, "0" );
571cdf0e10cSrcweir            insert_formula_params( $name, "prod", 1, $constructed, $p3); # references the 'sum' formula
572cdf0e10cSrcweir            return;
573cdf0e10cSrcweir        }
574cdf0e10cSrcweir        elsif ( $command eq "?:" ) {
575cdf0e10cSrcweir            insert_formula_params( $name, "if", $p1, $p2, $p3 );
576cdf0e10cSrcweir            return;
577cdf0e10cSrcweir        }
578cdf0e10cSrcweir        elsif ( $command eq "sin" || $command eq "cos" ) {
579cdf0e10cSrcweir            if ( $p2 =~ /^[0-9-]+$/ && ( ( $p2 % 60000 ) == 0 ) ) {
580cdf0e10cSrcweir                $p2 /= 60000;
581cdf0e10cSrcweir            }
582cdf0e10cSrcweir            else {
583cdf0e10cSrcweir                $p2 = insert_formula_params( "", "prod", "1", $p2, "60000" );
584cdf0e10cSrcweir            }
585cdf0e10cSrcweir            # we have to use 'sumangle' even for the case when $p2 is const
586cdf0e10cSrcweir            # and theoretically could be written as such; but Word does not
587cdf0e10cSrcweir            # accept it :-(
588cdf0e10cSrcweir            my $conv = insert_formula_params( "", "sumangle", "0", $p2, "0" );
589cdf0e10cSrcweir
590cdf0e10cSrcweir            $p2 = $conv;
591cdf0e10cSrcweir
592cdf0e10cSrcweir            insert_formula_params( $name, $command, $p1, $p2, "" );
593cdf0e10cSrcweir            return;
594cdf0e10cSrcweir        }
595cdf0e10cSrcweir        elsif ( $command eq "abs" ) {
596cdf0e10cSrcweir            insert_formula_params( $name, $command, $p1, "", "" );
597cdf0e10cSrcweir            return;
598cdf0e10cSrcweir        }
599cdf0e10cSrcweir        elsif ( $command eq "max" || $command eq "min" ) {
600cdf0e10cSrcweir            insert_formula_params( $name, $command, $p1, $p2, "" );
601cdf0e10cSrcweir            return;
602cdf0e10cSrcweir        }
603cdf0e10cSrcweir        elsif ( $command eq "at2" ) {
604cdf0e10cSrcweir            insert_formula_params( $name, "atan2", $p1, $p2, "" );
605cdf0e10cSrcweir            return;
606cdf0e10cSrcweir        }
607cdf0e10cSrcweir        elsif ( $command eq "cat2" ) {
608cdf0e10cSrcweir            insert_formula_params( $name, "cosatan2", $p1, $p2, $p3 );
609cdf0e10cSrcweir            return;
610cdf0e10cSrcweir        }
611cdf0e10cSrcweir        elsif ( $command eq "sat2" ) {
612cdf0e10cSrcweir            insert_formula_params( $name, "sinatan2", $p1, $p2, $p3 );
613cdf0e10cSrcweir            return;
614cdf0e10cSrcweir        }
615cdf0e10cSrcweir        elsif ( $command eq "sqrt" ) {
616cdf0e10cSrcweir            insert_formula_params( $name, "sqrt", $p1, "", "" );
617cdf0e10cSrcweir            return;
618cdf0e10cSrcweir        }
619cdf0e10cSrcweir        elsif ( $command eq "mod" ) {
620cdf0e10cSrcweir            insert_formula_params( $name, "mod", $p1, $p2, $p3 );
621cdf0e10cSrcweir            return;
622cdf0e10cSrcweir        }
623cdf0e10cSrcweir        elsif ( $command eq "val" ) {
624cdf0e10cSrcweir            insert_formula_params( $name, "val", value( $p1 ), "", "" );
625cdf0e10cSrcweir            return;
626cdf0e10cSrcweir        }
627cdf0e10cSrcweir        else {
628cdf0e10cSrcweir            error( "Unknown formula '$name', '$fmla'." );
629cdf0e10cSrcweir        }
630cdf0e10cSrcweir    }
631cdf0e10cSrcweir    else {
632cdf0e10cSrcweir        error( "Cannot convert formula's command '$name', '$fmla'." );
633cdf0e10cSrcweir    }
634cdf0e10cSrcweir}
635cdf0e10cSrcweir
636cdf0e10cSrcweir# There's no exact equivalent of 'arcTo' in VML, we have to do some special casing...
637cdf0e10cSrcweir%convert_arcTo = (
638cdf0e10cSrcweir    '0' => {
639cdf0e10cSrcweir        '90' => {
640cdf0e10cSrcweir            'path' => 'qy',
641cdf0e10cSrcweir            'op' => [ 'sum 0 __last_x__ __wR__', 'sum __hR__ __last_y__ 0' ],
642cdf0e10cSrcweir        },
643cdf0e10cSrcweir        '-90' => {
644cdf0e10cSrcweir            'path' => 'qy',
645cdf0e10cSrcweir            'op' => [ 'sum 0 __last_x__ __wR__', 'sum 0 __last_y__ __hR__' ],
646cdf0e10cSrcweir        },
647cdf0e10cSrcweir    },
648cdf0e10cSrcweir    '90' => {
649cdf0e10cSrcweir        '90' => {
650cdf0e10cSrcweir            'path' => 'qx',
651cdf0e10cSrcweir            'op' => [ 'sum 0 __last_x__ __wR__', 'sum 0 __last_y__ __hR__' ],
652cdf0e10cSrcweir        },
653cdf0e10cSrcweir        '-90' => {
654cdf0e10cSrcweir            'path' => 'qx',
655cdf0e10cSrcweir            'op' => [ 'sum __wR__ __last_x__ 0', 'sum 0 __last_y__ __hR__' ],
656cdf0e10cSrcweir        },
657cdf0e10cSrcweir    },
658cdf0e10cSrcweir    '180' => {
659cdf0e10cSrcweir        '90' => {
660cdf0e10cSrcweir            'path' => 'qy',
661cdf0e10cSrcweir            'op' => [ 'sum __wR__ __last_x__ 0', 'sum 0 __last_y__ __hR__' ],
662cdf0e10cSrcweir        },
663cdf0e10cSrcweir        '-90' => {
664cdf0e10cSrcweir            'path' => 'qy',
665cdf0e10cSrcweir            'op' => [ 'sum __wR__ __last_x__ 0', 'sum __hR__ __last_y__ 0' ],
666cdf0e10cSrcweir        },
667cdf0e10cSrcweir    },
668cdf0e10cSrcweir    '270' => {
669cdf0e10cSrcweir        '90' => {
670cdf0e10cSrcweir            'path' => 'qx',
671cdf0e10cSrcweir            'op' => [ 'sum __wR__ __last_x__ 0', 'sum __hR__ __last_y__ 0' ],
672cdf0e10cSrcweir        },
673cdf0e10cSrcweir        '-90' => {
674cdf0e10cSrcweir            'path' => 'qx',
675cdf0e10cSrcweir            'op' => [ 'sum 0 __last_x__ __wR__', 'sum __hR__ __last_y__ 0' ],
676cdf0e10cSrcweir        },
677cdf0e10cSrcweir    },
678cdf0e10cSrcweir);
679cdf0e10cSrcweir
680cdf0e10cSrcweir# Elliptic quadrant
681cdf0e10cSrcweir# FIXME optimize so that we compute the const values when possible
682cdf0e10cSrcweirsub elliptic_quadrant( $$$$ )
683cdf0e10cSrcweir{
684cdf0e10cSrcweir    my ( $wR, $hR, $stAng, $swAng ) = @_;
685cdf0e10cSrcweir
686cdf0e10cSrcweir    if ( defined( $convert_arcTo{$stAng} ) && defined( $convert_arcTo{$stAng}{$swAng} ) ) {
687cdf0e10cSrcweir        my $conv_path = $convert_arcTo{$stAng}{$swAng}{'path'};
688cdf0e10cSrcweir        my $conv_op_ref = $convert_arcTo{$stAng}{$swAng}{'op'};
689cdf0e10cSrcweir
690cdf0e10cSrcweir        $path .= "$conv_path";
691cdf0e10cSrcweir
692cdf0e10cSrcweir        my $pos_x = $last_pos_x;
693cdf0e10cSrcweir        my $pos_y = $last_pos_y;
694cdf0e10cSrcweir        for ( my $i = 0; $i <= $#{$conv_op_ref}; ++$i ) {
695cdf0e10cSrcweir            my $op = $conv_op_ref->[$i];
696cdf0e10cSrcweir
697cdf0e10cSrcweir            $op =~ s/__last_x__/$last_pos_x/g;
698cdf0e10cSrcweir            $op =~ s/__last_y__/$last_pos_y/g;
699cdf0e10cSrcweir            $op =~ s/__wR__/$wR/g;
700cdf0e10cSrcweir            $op =~ s/__hR__/$hR/g;
701cdf0e10cSrcweir
702cdf0e10cSrcweir            my $fmla = insert_formula( "", $op );
703cdf0e10cSrcweir
704cdf0e10cSrcweir            $path .= $fmla;
705cdf0e10cSrcweir
706cdf0e10cSrcweir            # so far it's sufficient just to rotate the positions
707cdf0e10cSrcweir            # FIXME if not ;-)
708cdf0e10cSrcweir            $pos_x = $pos_y;
709cdf0e10cSrcweir            $pos_y = $fmla;
710cdf0e10cSrcweir        }
711cdf0e10cSrcweir        $last_pos_x = $pos_x;
712cdf0e10cSrcweir        $last_pos_y = $pos_y;
713cdf0e10cSrcweir    }
714cdf0e10cSrcweir    else {
715cdf0e10cSrcweir        error( "Unhandled elliptic_quadrant(), input is ($wR, $hR, $stAng, $swAng)." );
716cdf0e10cSrcweir    }
717cdf0e10cSrcweir}
718cdf0e10cSrcweir
719cdf0e10cSrcweir# Convert the quadratic bezier to cubic (exact)
720cdf0e10cSrcweir# No idea why, but the 'qb' did not work for me :-(
721cdf0e10cSrcweirsub quadratic_to_cubic_bezier( $ )
722cdf0e10cSrcweir{
723cdf0e10cSrcweir    my ( $axis ) = @_;
724cdf0e10cSrcweir
725cdf0e10cSrcweir    my $a0 = $quadratic_bezier[0]->{$axis};
726cdf0e10cSrcweir    my $a1 = $quadratic_bezier[1]->{$axis};
727cdf0e10cSrcweir    my $a2 = $quadratic_bezier[2]->{$axis};
728cdf0e10cSrcweir
729cdf0e10cSrcweir    my $b0 = $a0;
730cdf0e10cSrcweir
731cdf0e10cSrcweir    # $b1 = $a0 + 2/3 * ( $a1 - $a0 ), but in VML
732cdf0e10cSrcweir    # FIXME optimize for constants - compute directly
733cdf0e10cSrcweir    my $b1_1 = insert_formula_params( "", "sum", "0", $a1, $a0 );
734cdf0e10cSrcweir    my $b1_2 = insert_formula_params( "", "prod", "2", $b1_1, "3" );
735cdf0e10cSrcweir    my $b1   = insert_formula_params( "", "sum", $a0, $b1_2, "0" );
736cdf0e10cSrcweir
737cdf0e10cSrcweir    # $b2 = $b1 + 1/3 * ( $a2 - $a0 );
738cdf0e10cSrcweir    # FIXME optimize for constants - compute directly
739cdf0e10cSrcweir    my $b2_1 = insert_formula_params( "", "sum", "0", $a2, $a0 );
740cdf0e10cSrcweir    my $b2_2 = insert_formula_params( "", "prod", "1", $b2_1, "3" );
741cdf0e10cSrcweir    my $b2   = insert_formula_params( "", "sum", $b1, $b2_2, "0" );
742cdf0e10cSrcweir
743cdf0e10cSrcweir    my $b3 = $a2;
744cdf0e10cSrcweir
745cdf0e10cSrcweir    return ( $b0, $b1, $b2, $b3 );
746cdf0e10cSrcweir}
747cdf0e10cSrcweir
748cdf0e10cSrcweir# Extend $path by one more point
749cdf0e10cSrcweirsub add_point_to_path( $$ )
750cdf0e10cSrcweir{
751cdf0e10cSrcweir    my ( $x, $y ) = @_;
752cdf0e10cSrcweir
753cdf0e10cSrcweir    if ( $path =~ /[0-9]$/ && $x =~ /^[0-9-]/ ) {
754cdf0e10cSrcweir        $path .= ",";
755cdf0e10cSrcweir    }
756cdf0e10cSrcweir    $path .= $x;
757cdf0e10cSrcweir
758cdf0e10cSrcweir    if ( $path =~ /[0-9]$/ && $y =~ /^[0-9-]/ ) {
759cdf0e10cSrcweir        $path .= ",";
760cdf0e10cSrcweir    }
761cdf0e10cSrcweir    $path .= $y;
762cdf0e10cSrcweir}
763cdf0e10cSrcweir
764cdf0e10cSrcweir# Start of an element
765cdf0e10cSrcweirsub start_element( $% )
766cdf0e10cSrcweir{
767cdf0e10cSrcweir    my ( $element, %attr ) = @_;
768cdf0e10cSrcweir
769cdf0e10cSrcweir    push @levels, $element;
770cdf0e10cSrcweir
771cdf0e10cSrcweir    #print "element: $element\n";
772cdf0e10cSrcweir
773cdf0e10cSrcweir    if ( is_level( -1, "presetShapeDefinitons" ) || is_level( -1, "presetTextWarpDefinitions" ) ) {
774cdf0e10cSrcweir        $shape_name = $element;
775cdf0e10cSrcweir
776cdf0e10cSrcweir        $state = "";
777cdf0e10cSrcweir        $ignore_this_shape = 0;
778cdf0e10cSrcweir        $path = "";
779cdf0e10cSrcweir        $adjust = "";
780cdf0e10cSrcweir        $max_adj_no = 0;
781cdf0e10cSrcweir        @formulas = ();
782cdf0e10cSrcweir        $handles = "";
783cdf0e10cSrcweir        $textboxrect = "";
784cdf0e10cSrcweir        $last_pos_x = "";
785cdf0e10cSrcweir        $last_pos_y = "";
786cdf0e10cSrcweir        $no_stroke = 0;
787cdf0e10cSrcweir        $no_fill = 0;
788cdf0e10cSrcweir        @quadratic_bezier = ();
789cdf0e10cSrcweir
790cdf0e10cSrcweir        setup_variables();
791cdf0e10cSrcweir
792cdf0e10cSrcweir        if ( $shape_name eq "sun" ) {
793cdf0e10cSrcweir            # hack for this shape
794cdf0e10cSrcweir            $variables{'100000'} = "21600";
795cdf0e10cSrcweir            $variables{'50000'} = "10800";
796cdf0e10cSrcweir            $variables{'25000'} = "5400";
797cdf0e10cSrcweir            $variables{'12500'} = "2700";
798cdf0e10cSrcweir            $variables{'3662'} = "791";
799cdf0e10cSrcweir        }
800cdf0e10cSrcweir
801cdf0e10cSrcweir        my $found = 0;
802cdf0e10cSrcweir        foreach my $name ( values( %shapes_ids ) ) {
803cdf0e10cSrcweir            if ( $name eq $shape_name ) {
804cdf0e10cSrcweir                $found = 1;
805cdf0e10cSrcweir                last;
806cdf0e10cSrcweir            }
807cdf0e10cSrcweir        }
808cdf0e10cSrcweir        if ( !$found ) {
809cdf0e10cSrcweir            error( "Unknown shape '$shape_name'." );
810cdf0e10cSrcweir        }
811cdf0e10cSrcweir    }
812cdf0e10cSrcweir    elsif ( $element eq "pathLst" ) {
813cdf0e10cSrcweir        $state = "path";
814cdf0e10cSrcweir    }
815cdf0e10cSrcweir    elsif ( $element eq "avLst" ) {
816cdf0e10cSrcweir        $state = "adjust";
817cdf0e10cSrcweir    }
818cdf0e10cSrcweir    elsif ( $element eq "gdLst" ) {
819cdf0e10cSrcweir        $state = "formulas";
820cdf0e10cSrcweir    }
821cdf0e10cSrcweir    elsif ( $element eq "ahLst" ) {
822cdf0e10cSrcweir        $state = "handles";
823cdf0e10cSrcweir    }
824cdf0e10cSrcweir    elsif ( $element eq "rect" ) {
825cdf0e10cSrcweir        $textboxrect = value( $attr{'l'} ) . "," . value( $attr{'t'} ) . "," .
826cdf0e10cSrcweir                       value( $attr{'r'} ) . "," . value( $attr{'b'} );
827cdf0e10cSrcweir    }
828cdf0e10cSrcweir    elsif ( $state eq "path" ) {
829cdf0e10cSrcweir        if ( $element eq "path" ) {
830cdf0e10cSrcweir            $no_stroke = ( defined( $attr{'stroke'} ) && $attr{'stroke'} eq 'false' );
831cdf0e10cSrcweir            $no_fill = ( defined( $attr{'fill'} ) && $attr{'fill'} eq 'none' );
832cdf0e10cSrcweir            $path_w = $attr{'w'};
833cdf0e10cSrcweir            $path_h = $attr{'h'};
834cdf0e10cSrcweir        }
835cdf0e10cSrcweir        elsif ( $element eq "moveTo" ) {
836cdf0e10cSrcweir            $path .= "m";
837cdf0e10cSrcweir        }
838cdf0e10cSrcweir        elsif ( $element eq "lnTo" ) {
839cdf0e10cSrcweir            $path .= "l";
840cdf0e10cSrcweir        }
841cdf0e10cSrcweir        elsif ( $element eq "cubicBezTo" ) {
842cdf0e10cSrcweir            $path .= "c";
843cdf0e10cSrcweir        }
844cdf0e10cSrcweir        elsif ( $element eq "quadBezTo" ) {
845cdf0e10cSrcweir            my %points = ( 'x' => $last_pos_x, 'y' => $last_pos_y );
846cdf0e10cSrcweir            @quadratic_bezier = ( \%points );
847cdf0e10cSrcweir        }
848cdf0e10cSrcweir        elsif ( $element eq "close" ) {
849cdf0e10cSrcweir            $path .= "x";
850cdf0e10cSrcweir        }
851cdf0e10cSrcweir        elsif ( $element eq "pt" ) {
852cdf0e10cSrcweir            # rememeber the last position for the arcTo
853cdf0e10cSrcweir            $last_pos_x = value( $attr{'x'} );
854cdf0e10cSrcweir            $last_pos_y = value( $attr{'y'} );
855cdf0e10cSrcweir
856cdf0e10cSrcweir            $last_pos_x *= ( value( 'w' ) / $path_w ) if ( defined( $path_w ) );
857cdf0e10cSrcweir            $last_pos_y *= ( value( 'h' ) / $path_h ) if ( defined( $path_h ) );
858cdf0e10cSrcweir
859cdf0e10cSrcweir            if ( $#quadratic_bezier >= 0 ) {
860cdf0e10cSrcweir                my %points = ( 'x' => $last_pos_x, 'y' => $last_pos_y );
861cdf0e10cSrcweir                push( @quadratic_bezier, \%points );
862cdf0e10cSrcweir            }
863cdf0e10cSrcweir            else {
864cdf0e10cSrcweir                add_point_to_path( $last_pos_x, $last_pos_y );
865cdf0e10cSrcweir            }
866cdf0e10cSrcweir        }
867cdf0e10cSrcweir        elsif ( ( $element eq "arcTo" ) && ( $last_pos_x ne "" ) && ( $last_pos_y ne "" ) ) {
868cdf0e10cSrcweir            # there's no exact equivalent of arcTo in VML, so we have to
869cdf0e10cSrcweir            # compute here a bit...
870cdf0e10cSrcweir            my $stAng = value( $attr{'stAng'} );
871cdf0e10cSrcweir            my $swAng = value( $attr{'swAng'} );
872cdf0e10cSrcweir            my $wR = value( $attr{'wR'} );
873cdf0e10cSrcweir            my $hR = value( $attr{'hR'} );
874cdf0e10cSrcweir
875cdf0e10cSrcweir            $wR *= ( value( 'w' ) / $path_w ) if ( defined( $path_w ) );
876cdf0e10cSrcweir            $hR *= ( value( 'h' ) / $path_h ) if ( defined( $path_h ) );
877cdf0e10cSrcweir
878cdf0e10cSrcweir            if ( ( $stAng =~ /^[0-9-]+$/ ) && ( $swAng =~ /^[0-9-]+$/ ) ) {
879cdf0e10cSrcweir                if ( ( ( $stAng % 90 ) == 0 ) && ( ( $swAng % 90 ) == 0 ) && ( $swAng != 0 ) ) {
880cdf0e10cSrcweir                    my $end = $stAng + $swAng;
881cdf0e10cSrcweir                    my $step = ( $swAng > 0 )? 90: -90;
882cdf0e10cSrcweir
883cdf0e10cSrcweir                    for ( my $cur = $stAng; $cur != $end; $cur += $step ) {
884cdf0e10cSrcweir                        elliptic_quadrant( $wR, $hR, ( $cur % 360 ), $step );
885cdf0e10cSrcweir                    }
886cdf0e10cSrcweir                }
887cdf0e10cSrcweir                else {
888cdf0e10cSrcweir                    error( "Unsupported numeric 'arcTo' ($attr{'wR'}, $attr{'hR'}, $stAng, $swAng)." );
889cdf0e10cSrcweir                }
890cdf0e10cSrcweir            }
891cdf0e10cSrcweir            else {
892cdf0e10cSrcweir                error( "Unsupported 'arcTo' conversion ($attr{'wR'}, $attr{'hR'}, $stAng, $swAng)." );
893cdf0e10cSrcweir            }
894cdf0e10cSrcweir        }
895cdf0e10cSrcweir        else {
896cdf0e10cSrcweir            error( "Unhandled path element '$element'." );
897cdf0e10cSrcweir        }
898cdf0e10cSrcweir    }
899cdf0e10cSrcweir    elsif ( $state eq "adjust" ) {
900cdf0e10cSrcweir        if ( $element eq "gd" ) {
901cdf0e10cSrcweir            my $adj_no = $attr{'name'};
902cdf0e10cSrcweir            my $is_const = 0;
903cdf0e10cSrcweir
904cdf0e10cSrcweir            $adj_no =~ s/^adj//;
905cdf0e10cSrcweir            if ( $adj_no eq "" ) {
906cdf0e10cSrcweir                $max_adj_no = 0;
907cdf0e10cSrcweir            }
908cdf0e10cSrcweir            elsif ( !( $adj_no =~ /^[0-9]*$/ ) ) {
909cdf0e10cSrcweir                ++$max_adj_no;
910cdf0e10cSrcweir                $is_const = 1;
911cdf0e10cSrcweir            }
912cdf0e10cSrcweir            elsif ( $adj_no != $max_adj_no + 1 ) {
913cdf0e10cSrcweir                error( "Wrong order of adj values." );
914cdf0e10cSrcweir                ++$max_adj_no;
915cdf0e10cSrcweir            }
916cdf0e10cSrcweir            else {
917cdf0e10cSrcweir                $max_adj_no = $adj_no;
918cdf0e10cSrcweir            }
919cdf0e10cSrcweir
920cdf0e10cSrcweir            if ( $attr{'fmla'} =~ /^val ([0-9-]*)$/ ) {
921cdf0e10cSrcweir                my $val = sprintf( "%.0f", ( 21600 * $1 ) / 100000 );
922cdf0e10cSrcweir                if ( $is_const ) {
923cdf0e10cSrcweir                    $variables{$adj_no} = $val;
924cdf0e10cSrcweir                }
925cdf0e10cSrcweir                elsif ( $adjust eq "" ) {
926cdf0e10cSrcweir                    $adjust = $val;
927cdf0e10cSrcweir                }
928cdf0e10cSrcweir                else {
929cdf0e10cSrcweir                    $adjust = "$val,$adjust";
930cdf0e10cSrcweir                }
931cdf0e10cSrcweir            }
932cdf0e10cSrcweir            else {
933cdf0e10cSrcweir                error( "Wrong fmla '$attr{'fmla'}'." );
934cdf0e10cSrcweir            }
935cdf0e10cSrcweir        }
936cdf0e10cSrcweir        else {
937cdf0e10cSrcweir            error( "Unhandled adjust element '$element'." );
938cdf0e10cSrcweir        }
939cdf0e10cSrcweir    }
940cdf0e10cSrcweir    elsif ( $state eq "formulas" ) {
941cdf0e10cSrcweir        if ( $element eq "gd" ) {
942cdf0e10cSrcweir            if ( $attr{'fmla'} =~ /^\*\/ (h|w|ss) adj([0-9]+) 100000$/ ) {
943cdf0e10cSrcweir                insert_formula( $attr{'name'}, "val #" . ( $max_adj_no - $2 ) );
944cdf0e10cSrcweir            }
945cdf0e10cSrcweir            elsif ( $attr{'fmla'} =~ /^pin [^ ]+ ([^ ]+) / ) {
946cdf0e10cSrcweir                print STDERR "TODO Map 'pin' to VML as xrange for handles.\n";
947cdf0e10cSrcweir                my $pin_val = $1;
948cdf0e10cSrcweir                if ( $pin_val eq "adj" ) {
949cdf0e10cSrcweir                    insert_formula( $attr{'name'}, "val #0" );
950cdf0e10cSrcweir                }
951cdf0e10cSrcweir                elsif ( $pin_val =~ /^adj([0-9]+)/ ) {
952cdf0e10cSrcweir                    insert_formula( $attr{'name'}, "val #" . ( $max_adj_no - $1 ) );
953cdf0e10cSrcweir                }
954cdf0e10cSrcweir                else {
955cdf0e10cSrcweir                    insert_formula( $attr{'name'}, "val " . value( $pin_val ) );
956cdf0e10cSrcweir                }
957cdf0e10cSrcweir            }
958cdf0e10cSrcweir            elsif ( $attr{'fmla'} =~ /adj/ ) {
959cdf0e10cSrcweir                error( "Non-standard usage of adj in '$attr{'fmla'}'." );
960cdf0e10cSrcweir            }
961cdf0e10cSrcweir            else {
962cdf0e10cSrcweir                convert_formula( $attr{'name'}, $attr{'fmla'} );
963cdf0e10cSrcweir            }
964cdf0e10cSrcweir        }
965cdf0e10cSrcweir    }
966cdf0e10cSrcweir    elsif ( $state eq "handles" ) {
967cdf0e10cSrcweir        if ( $element eq "pos" ) {
968cdf0e10cSrcweir            $handles .= "<v:h position=\"" . value( $attr{'x'} ) . "," . value( $attr{'y'} ) . "\"/>\n";
969cdf0e10cSrcweir        }
970cdf0e10cSrcweir    }
971cdf0e10cSrcweir}
972cdf0e10cSrcweir
973cdf0e10cSrcweir# End of an element
974cdf0e10cSrcweirsub end_element( $ )
975cdf0e10cSrcweir{
976cdf0e10cSrcweir    my ( $element ) = @_;
977cdf0e10cSrcweir
978cdf0e10cSrcweir    pop @levels;
979cdf0e10cSrcweir
980cdf0e10cSrcweir    if ( $element eq $shape_name ) {
981cdf0e10cSrcweir        if ( !$ignore_this_shape ) {
982cdf0e10cSrcweir            # we have all the info, generate the shape now
983cdf0e10cSrcweir            $state = "";
984cdf0e10cSrcweir
985cdf0e10cSrcweir            # shape path
986cdf0e10cSrcweir            my $out = "<v:shapetype id=\"shapetype___ID__\" coordsize=\"21600,21600\" o:spt=\"__ID__\" ";
987cdf0e10cSrcweir            if ( $adjust ne "" ) {
988cdf0e10cSrcweir                $out .= "adj=\"$adjust\" ";
989cdf0e10cSrcweir            }
990cdf0e10cSrcweir
991cdf0e10cSrcweir            # optimize it [yes, we need this twice ;-)]
992cdf0e10cSrcweir            $path =~ s/([^0-9-@])0([^0-9-@])/$1$2/g;
993cdf0e10cSrcweir            $path =~ s/([^0-9-@])0([^0-9-@])/$1$2/g;
994cdf0e10cSrcweir
995cdf0e10cSrcweir            $out .= "path=\"$path\">\n";
996cdf0e10cSrcweir
997cdf0e10cSrcweir            # stroke
998cdf0e10cSrcweir            $out .= "<v:stroke joinstyle=\"miter\"/>\n";
999cdf0e10cSrcweir
1000cdf0e10cSrcweir            # formulas
1001cdf0e10cSrcweir            if ( $#formulas >= 0 )
1002cdf0e10cSrcweir            {
1003cdf0e10cSrcweir                $out .= "<v:formulas>\n";
1004cdf0e10cSrcweir                foreach $fmla ( @formulas ) {
1005cdf0e10cSrcweir                    $out .= "<v:f eqn=\"$fmla\"/>\n"
1006cdf0e10cSrcweir                }
1007cdf0e10cSrcweir                $out .= "</v:formulas>\n";
1008cdf0e10cSrcweir            }
1009cdf0e10cSrcweir
1010cdf0e10cSrcweir            # path
1011cdf0e10cSrcweir            if ( $textboxrect ne "" ) { # TODO connectlocs, connectangles
1012cdf0e10cSrcweir                $out .= "<v:path gradientshapeok=\"t\" o:connecttype=\"rect\" textboxrect=\"$textboxrect\"/>\n";
1013cdf0e10cSrcweir            }
1014cdf0e10cSrcweir
1015cdf0e10cSrcweir            # handles
1016cdf0e10cSrcweir            if ( $handles ne "" ) {
1017cdf0e10cSrcweir                $out .= "<v:handles>\n$handles</v:handles>\n";
1018cdf0e10cSrcweir            }
1019cdf0e10cSrcweir
1020cdf0e10cSrcweir            $out .="</v:shapetype>";
1021cdf0e10cSrcweir
1022cdf0e10cSrcweir            # hooray! :-)
1023cdf0e10cSrcweir            $result_shapes{$shape_name} = $out;
1024cdf0e10cSrcweir        }
1025cdf0e10cSrcweir        else {
1026cdf0e10cSrcweir            print STDERR "Shape '$shape_name' ignored; see the above error(s) for the reason.\n";
1027cdf0e10cSrcweir        }
1028cdf0e10cSrcweir        $shape_name = "";
1029cdf0e10cSrcweir    }
1030cdf0e10cSrcweir    elsif ( $state eq "path" ) {
1031cdf0e10cSrcweir        if ( $element eq "path" ) {
1032cdf0e10cSrcweir            $path .= "ns" if ( $no_stroke );
1033cdf0e10cSrcweir            $path .= "nf" if ( $no_fill );
1034cdf0e10cSrcweir            $path .= "e";
1035cdf0e10cSrcweir        }
1036cdf0e10cSrcweir        elsif ( $element eq "quadBezTo" ) {
1037cdf0e10cSrcweir            # we have to convert the quadratic bezier to cubic
1038cdf0e10cSrcweir            if ( $#quadratic_bezier == 2 ) {
1039cdf0e10cSrcweir                my @points_x = quadratic_to_cubic_bezier( 'x' );
1040cdf0e10cSrcweir                my @points_y = quadratic_to_cubic_bezier( 'y' );
1041cdf0e10cSrcweir
1042cdf0e10cSrcweir                $path .= "c";
1043cdf0e10cSrcweir                # ignore the starting point
1044cdf0e10cSrcweir                for ( my $i = 1; $i < 4; ++$i ) {
1045cdf0e10cSrcweir                    add_point_to_path( $points_x[$i], $points_y[$i] );
1046cdf0e10cSrcweir                }
1047cdf0e10cSrcweir            }
1048cdf0e10cSrcweir            else {
1049cdf0e10cSrcweir                error( "Wrong number of points of the quadratic bezier." );
1050cdf0e10cSrcweir            }
1051cdf0e10cSrcweir            @quadratic_bezier = ();
1052cdf0e10cSrcweir        }
1053cdf0e10cSrcweir    }
1054cdf0e10cSrcweir    elsif ( $element eq "avLst" ) {
1055cdf0e10cSrcweir        $state = "";
1056cdf0e10cSrcweir    }
1057cdf0e10cSrcweir    elsif ( $element eq "gdLst" ) {
1058cdf0e10cSrcweir        $state = "";
1059cdf0e10cSrcweir    }
1060cdf0e10cSrcweir    elsif ( $element eq "ahLst" ) {
1061cdf0e10cSrcweir        $state = "";
1062cdf0e10cSrcweir    }
1063cdf0e10cSrcweir}
1064cdf0e10cSrcweir
1065cdf0e10cSrcweir# Text inside an element
1066cdf0e10cSrcweirsub characters( $ )
1067cdf0e10cSrcweir{
1068cdf0e10cSrcweir    #my ( $text ) = @_;
1069cdf0e10cSrcweir}
1070cdf0e10cSrcweir
1071cdf0e10cSrcweir#################### A trivial XML parser ####################
1072cdf0e10cSrcweir
1073cdf0e10cSrcweir# Parse the attributes
1074cdf0e10cSrcweirsub parse_start_element( $ )
1075cdf0e10cSrcweir{
1076cdf0e10cSrcweir    # split the string containing both the elements and attributes
1077cdf0e10cSrcweir    my ( $element_tmp ) = @_;
1078cdf0e10cSrcweir
1079cdf0e10cSrcweir    $element_tmp =~ s/\s*$//;
1080cdf0e10cSrcweir    $element_tmp =~ s/^\s*//;
1081cdf0e10cSrcweir
1082cdf0e10cSrcweir    ( my $element = $element_tmp ) =~ s/\s.*$//;
1083cdf0e10cSrcweir    if ( $element_tmp =~ /\s/ ) {
1084cdf0e10cSrcweir        $element_tmp =~ s/^[^\s]*\s//;
1085cdf0e10cSrcweir    }
1086cdf0e10cSrcweir    else {
1087cdf0e10cSrcweir        $element_tmp = "";
1088cdf0e10cSrcweir    }
1089cdf0e10cSrcweir
1090cdf0e10cSrcweir    # we have the element, now the attributes
1091cdf0e10cSrcweir    my %attr;
1092cdf0e10cSrcweir    my $is_key = 1;
1093cdf0e10cSrcweir    my $key = "";
1094cdf0e10cSrcweir    foreach my $tmp ( split( /"/, $element_tmp ) ) {
1095cdf0e10cSrcweir        if ( $is_key ) {
1096cdf0e10cSrcweir            $key = $tmp;
1097cdf0e10cSrcweir            $key =~ s/^\s*//;
1098cdf0e10cSrcweir            $key =~ s/\s*=\s*$//;
1099cdf0e10cSrcweir        }
1100cdf0e10cSrcweir        else {
1101cdf0e10cSrcweir            $attr{$key} = $tmp;
1102cdf0e10cSrcweir        }
1103cdf0e10cSrcweir        $is_key = !$is_key;
1104cdf0e10cSrcweir    }
1105cdf0e10cSrcweir
1106cdf0e10cSrcweir    if ( $element ne "" ) {
1107cdf0e10cSrcweir        start_element( $element, %attr );
1108cdf0e10cSrcweir    }
1109cdf0e10cSrcweir}
1110cdf0e10cSrcweir
1111cdf0e10cSrcweir# Parse the file
1112cdf0e10cSrcweirsub parse( $ )
1113cdf0e10cSrcweir{
1114cdf0e10cSrcweir    my ( $file ) = @_;
1115cdf0e10cSrcweir
1116cdf0e10cSrcweir    my $in_comment = 0;
1117cdf0e10cSrcweir    my $line = "";
1118cdf0e10cSrcweir    while (<$file>) {
1119cdf0e10cSrcweir        # ignore comments
1120cdf0e10cSrcweir        s/<\?[^>]*\?>//g;
1121cdf0e10cSrcweir        s/<!--[^>]*-->//g;
1122cdf0e10cSrcweir        if ( /<!--/ ) {
1123cdf0e10cSrcweir            $in_comment = 1;
1124cdf0e10cSrcweir            s/<!--.*//;
1125cdf0e10cSrcweir        }
1126cdf0e10cSrcweir        elsif ( /-->/ && $in_comment ) {
1127cdf0e10cSrcweir            $in_comment = 0;
1128cdf0e10cSrcweir            s/.*-->//;
1129cdf0e10cSrcweir        }
1130cdf0e10cSrcweir        elsif ( $in_comment ) {
1131cdf0e10cSrcweir            next;
1132cdf0e10cSrcweir        }
1133cdf0e10cSrcweir        # ignore empty lines
1134cdf0e10cSrcweir        chomp;
1135cdf0e10cSrcweir        s/^\s*//;
1136cdf0e10cSrcweir        s/\s*$//;
1137cdf0e10cSrcweir        next if ( $_ eq "" );
1138cdf0e10cSrcweir
1139cdf0e10cSrcweir        # take care of lines where element continues
1140cdf0e10cSrcweir        if ( $line ne "" ) {
1141cdf0e10cSrcweir            $line .= " " . $_;
1142cdf0e10cSrcweir        }
1143cdf0e10cSrcweir        else {
1144cdf0e10cSrcweir            $line = $_;
1145cdf0e10cSrcweir        }
1146cdf0e10cSrcweir        next if ( !/>$/ );
1147cdf0e10cSrcweir
1148cdf0e10cSrcweir        # the actual parsing
1149cdf0e10cSrcweir        my @starts = split( /</, $line );
1150cdf0e10cSrcweir        $line = "";
1151cdf0e10cSrcweir        foreach $start ( @starts ) {
1152cdf0e10cSrcweir            next if ( $start eq "" );
1153cdf0e10cSrcweir
1154cdf0e10cSrcweir            @ends = split( />/, $start );
1155cdf0e10cSrcweir            my $element = $ends[0];
1156cdf0e10cSrcweir            my $data = $ends[1];
1157cdf0e10cSrcweir
1158cdf0e10cSrcweir            # start or end element
1159cdf0e10cSrcweir            if ( $element =~ /^\/(.*)/ ) {
1160cdf0e10cSrcweir                end_element( $1 );
1161cdf0e10cSrcweir            }
1162cdf0e10cSrcweir            elsif ( $element =~ /^(.*)\/$/ ) {
1163cdf0e10cSrcweir                parse_start_element( $1 );
1164cdf0e10cSrcweir                ( my $end = $1 ) =~ s/\s.*$//;
1165cdf0e10cSrcweir                end_element( $end );
1166cdf0e10cSrcweir            }
1167cdf0e10cSrcweir            else {
1168cdf0e10cSrcweir                parse_start_element( $element );
1169cdf0e10cSrcweir            }
1170cdf0e10cSrcweir
1171cdf0e10cSrcweir            # the data
1172cdf0e10cSrcweir            characters( $data ) if ( defined( $data ) && $data ne "" );
1173cdf0e10cSrcweir        }
1174cdf0e10cSrcweir    }
1175cdf0e10cSrcweir}
1176cdf0e10cSrcweir
1177cdf0e10cSrcweir# Do the real work
1178cdf0e10cSrcweiropen( IN, "<$src_shapes" ) || die "Cannot open $src_shapes.";
1179cdf0e10cSrcweirparse( IN );
1180cdf0e10cSrcweirclose( IN );
1181cdf0e10cSrcweir
1182cdf0e10cSrcweiropen( IN, "<$src_text" ) || die "Cannot open $src_text.";
1183cdf0e10cSrcweirparse( IN );
1184cdf0e10cSrcweirclose( IN );
1185cdf0e10cSrcweir
1186cdf0e10cSrcweirif ( !defined( $result_shapes{'textBox'} ) ) {
1187cdf0e10cSrcweir    $result_shapes{'textBox'} =
1188cdf0e10cSrcweir        "<v:shapetype id=\"shapetype___ID__\" coordsize=\"21600,21600\" " .
1189cdf0e10cSrcweir        "o:spt=\"__ID__\" path=\"m,l,21600l21600,21600l21600,xe\">\n" .
1190cdf0e10cSrcweir        "<v:stroke joinstyle=\"miter\"/>\n" .
1191cdf0e10cSrcweir        "<v:path gradientshapeok=\"t\" o:connecttype=\"rect\"/>\n" .
1192cdf0e10cSrcweir        "</v:shapetype>";
1193cdf0e10cSrcweir}
1194cdf0e10cSrcweir
1195cdf0e10cSrcweir# Generate the code
1196cdf0e10cSrcweirprint <<EOF;
1197cdf0e10cSrcweir// Shape types generated from
1198cdf0e10cSrcweir//   '$src_shapes'
1199cdf0e10cSrcweir// and
1200cdf0e10cSrcweir//   '$src_text'
1201cdf0e10cSrcweir// which are part of the OOXML documentation
1202cdf0e10cSrcweir
1203cdf0e10cSrcweir#include <svx/escherex.hxx>
1204cdf0e10cSrcweir
1205cdf0e10cSrcweirconst char* pShapeTypes[ ESCHER_ShpInst_COUNT ] =
1206cdf0e10cSrcweir{
1207cdf0e10cSrcweirEOF
1208cdf0e10cSrcweir
1209cdf0e10cSrcweirfor ( $i = 0; $i < 203; ++$i ) {
1210cdf0e10cSrcweir    if ( $i < 4 ) {
1211cdf0e10cSrcweir        print "    /* $i - $shapes_ids{$i} - handled separately */\n    NULL,\n";
1212cdf0e10cSrcweir    }
1213cdf0e10cSrcweir    else {
1214cdf0e10cSrcweir        print "    /* $i - $shapes_ids{$i} */\n";
1215cdf0e10cSrcweir        my $out = $result_shapes{$shapes_ids{$i}};
1216cdf0e10cSrcweir        if ( defined( $out ) ) {
1217cdf0e10cSrcweir            # set the id
1218cdf0e10cSrcweir            $out =~ s/__ID__/$i/g;
1219cdf0e10cSrcweir
1220cdf0e10cSrcweir            # escape the '"'s
1221cdf0e10cSrcweir            $out =~ s/"/\\"/g;
1222cdf0e10cSrcweir
1223cdf0e10cSrcweir            # output as string
1224cdf0e10cSrcweir            $out =~ s/^/    "/;
1225cdf0e10cSrcweir            $out =~ s/\n/"\n    "/g;
1226cdf0e10cSrcweir            $out =~ s/$/"/;
1227cdf0e10cSrcweir
1228cdf0e10cSrcweir            print "$out,\n";
1229cdf0e10cSrcweir        }
1230cdf0e10cSrcweir        else {
1231cdf0e10cSrcweir            print "    NULL,\n";
1232cdf0e10cSrcweir        }
1233cdf0e10cSrcweir    }
1234cdf0e10cSrcweir}
1235cdf0e10cSrcweir
1236cdf0e10cSrcweirprint <<EOF;
1237cdf0e10cSrcweir};
1238cdf0e10cSrcweirEOF
1239