3 # This file is part of the LibreOffice project.
5 # This Source Code Form is subject to the terms of the Mozilla Public
6 # License, v. 2.0. If a copy of the MPL was not distributed with this
7 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 # This file incorporates work covered by the following license notice:
11 # Licensed to the Apache Software Foundation (ASF) under one or more
12 # contributor license agreements. See the NOTICE file distributed
13 # with this work for additional information regarding copyright
14 # ownership. The ASF licenses this file to you under the Apache
15 # License, Version 2.0 (the "License"); you may not use this file
16 # except in compliance with the License. You may obtain a copy of
17 # the License at http://www.apache.org/licenses/LICENSE-2.0 .
25 Usage: preset-definitions-to-shape-types.pl [ --drawingml-adj-names-data | --vml-shape-types-data ] <shapes> <text>
27 Converts presetShapeDefinitions.xml and presetTextWarpDefinitions.xml to a
28 .cxx that contains VML with the definitions of the shapes. The result is
31 <shapes> presetShapeDefinitions.xml (including the path to it)
32 <text> presetTextWarpDefinitions.xml (including the path to it)
39 my ( $path, $line, $subr );
42 print STDERR
"--- Begin stack trace ---\n";
43 while ( (my @call_details = (caller($i++))) && ($i<$max_depth) ) {
44 print STDERR
"$call_details[1] line $call_details[2] in function $call_details[3]\n";
46 print STDERR
"--- End stack trace ---\n";
49 my $drawingml_adj_names_data = 0;
50 my $vml_shape_types_data = 0;
51 my $src_shapes = shift;
52 if ($src_shapes eq "--drawingml-adj-names-data") {
53 $drawingml_adj_names_data = 1;
55 } elsif ($src_shapes eq "--vml-shape-types-data") {
56 $vml_shape_types_data = 1;
61 usage
() if ( !defined( $src_shapes ) || !defined( $src_text ) ||
62 $src_shapes eq "-h" || $src_shapes eq "--help" ||
63 !-f
$src_shapes || !-f
$src_text );
75 my $ignore_this_shape = 0;
84 my @quadratic_bezier = ();
86 my %result_shapes = ();
91 2 => 'roundRectangle',
103 14 => 'thickArrow', # should not be used
106 17 => 'wedgeRoundRectCallout', # balloon
107 18 => 'star16', # seal
113 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?
114 25 => 'textStop', # textOctagon FIXME see 24
115 26 => 'textTriangle', # textHexagon FIXMME see 24
116 27 => 'textCanDown', # textCurve FIXMME see 24
117 28 => 'textWave1', # textWave FIXMME see 24
118 29 => 'textArchUpPour', # textRing FIXMME see 24
119 30 => 'textCanDown', # textOnCurve FIXMME see 24
120 31 => 'textArchUp', # textOnRing FIXMME see 24
121 32 => 'straightConnector1',
122 33 => 'bentConnector2',
123 34 => 'bentConnector3',
124 35 => 'bentConnector4',
125 36 => 'bentConnector5',
126 37 => 'curvedConnector2',
127 38 => 'curvedConnector3',
128 39 => 'curvedConnector4',
129 40 => 'curvedConnector5',
133 44 => 'accentCallout1',
134 45 => 'accentCallout2',
135 46 => 'accentCallout3',
136 47 => 'borderCallout1',
137 48 => 'borderCallout2',
138 49 => 'borderCallout3',
139 50 => 'accentBorderCallout1',
140 51 => 'accentBorderCallout2',
141 52 => 'accentBorderCallout3',
147 58 => 'star8', # seal8
148 59 => 'star16', # seal16
149 60 => 'star32', # seal32
150 61 => 'wedgeRectCallout',
151 62 => 'wedgeRoundRectCallout', # wedgeRRectCallout
152 63 => 'wedgeEllipseCallout',
154 65 => 'foldedCorner',
158 69 => 'leftRightArrow',
160 71 => 'irregularSeal1',
161 72 => 'irregularSeal2',
162 73 => 'lightningBolt',
164 75 => 'pictureFrame',
166 77 => 'leftArrowCallout',
167 78 => 'rightArrowCallout',
168 79 => 'upArrowCallout',
169 80 => 'downArrowCallout',
170 81 => 'leftRightArrowCallout',
171 82 => 'upDownArrowCallout',
172 83 => 'quadArrowCallout',
175 86 => 'rightBracket',
181 92 => 'star24', # seal24
182 93 => 'stripedRightArrow',
183 94 => 'notchedRightArrow',
186 97 => 'verticalScroll',
187 98 => 'horizontalScroll',
188 99 => 'circularArrow',
189 100 => 'notchedCircularArrow', # should not be used
191 102 => 'curvedRightArrow',
192 103 => 'curvedLeftArrow',
193 104 => 'curvedUpArrow',
194 105 => 'curvedDownArrow',
195 106 => 'cloudCallout',
196 107 => 'ellipseRibbon',
197 108 => 'ellipseRibbon2',
198 109 => 'flowChartProcess',
199 110 => 'flowChartDecision',
200 111 => 'flowChartInputOutput',
201 112 => 'flowChartPredefinedProcess',
202 113 => 'flowChartInternalStorage',
203 114 => 'flowChartDocument',
204 115 => 'flowChartMultidocument',
205 116 => 'flowChartTerminator',
206 117 => 'flowChartPreparation',
207 118 => 'flowChartManualInput',
208 119 => 'flowChartManualOperation',
209 120 => 'flowChartConnector',
210 121 => 'flowChartPunchedCard',
211 122 => 'flowChartPunchedTape',
212 123 => 'flowChartSummingJunction',
213 124 => 'flowChartOr',
214 125 => 'flowChartCollate',
215 126 => 'flowChartSort',
216 127 => 'flowChartExtract',
217 128 => 'flowChartMerge',
218 129 => 'flowChartOfflineStorage',
219 130 => 'flowChartOnlineStorage',
220 131 => 'flowChartMagneticTape',
221 132 => 'flowChartMagneticDisk',
222 133 => 'flowChartMagneticDrum',
223 134 => 'flowChartDisplay',
224 135 => 'flowChartDelay',
225 136 => 'textPlain', # textPlainText
227 138 => 'textTriangle',
228 139 => 'textTriangleInverted',
229 140 => 'textChevron',
230 141 => 'textChevronInverted',
231 142 => 'textRingInside',
232 143 => 'textRingOutside',
233 144 => 'textArchUp', # textArchUpCurve
234 145 => 'textArchDown', # textArchDownCurve
235 146 => 'textCircle', # textCircleCurve
236 147 => 'textButton', # textButtonCurve
237 148 => 'textArchUpPour',
238 149 => 'textArchDownPour',
239 150 => 'textCirclePour',
240 151 => 'textButtonPour',
241 152 => 'textCurveUp',
242 153 => 'textCurveDown',
243 154 => 'textCascadeUp',
244 155 => 'textCascadeDown',
249 160 => 'textInflate',
250 161 => 'textDeflate',
251 162 => 'textInflateBottom',
252 163 => 'textDeflateBottom',
253 164 => 'textInflateTop',
254 165 => 'textDeflateTop',
255 166 => 'textDeflateInflate',
256 167 => 'textDeflateInflateDeflate',
257 168 => 'textFadeRight',
258 169 => 'textFadeLeft',
260 171 => 'textFadeDown',
261 172 => 'textSlantUp',
262 173 => 'textSlantDown',
264 175 => 'textCanDown',
265 176 => 'flowChartAlternateProcess',
266 177 => 'flowChartOffpageConnector',
267 178 => 'callout1', # callout90
268 179 => 'accentCallout1', # accentCallout90
269 180 => 'borderCallout1', # borderCallout90
270 181 => 'accentBorderCallout1', # accentBorderCallout90
271 182 => 'leftRightUpArrow',
274 185 => 'bracketPair',
276 187 => 'star4', # seal4
278 189 => 'actionButtonBlank',
279 190 => 'actionButtonHome',
280 191 => 'actionButtonHelp',
281 192 => 'actionButtonInformation',
282 193 => 'actionButtonForwardNext',
283 194 => 'actionButtonBackPrevious',
284 195 => 'actionButtonEnd',
285 196 => 'actionButtonBeginning',
286 197 => 'actionButtonReturn',
287 198 => 'actionButtonDocument',
288 199 => 'actionButtonSound',
289 200 => 'actionButtonMovie',
290 201 => 'hostControl',
293 # An error occurred, we have to ignore this shape
298 $ignore_this_shape = 1;
299 print STDERR
"ERROR (in $shape_name ): $msg\n";
302 # Setup the %variables map with predefined values
303 sub setup_variables
()
316 'ssd2' => 10800, # 1/2
317 'ssd4' => 5400, # 1/4
318 'ssd6' => 3600, # 1/6
319 'ssd8' => 2700, # 1/8
320 'ssd16' => 1350, # 1/16
321 'ssd32' => 675, # 1/32
323 'hc' => 10800, # horizontal center
324 'vc' => 10800, # vertical center
326 'wd2' => 10800, # 1/2
332 'wd10' => 2160, # 1/10
333 'wd12' => 1800, # 1/12
334 'wd32' => 675, # 1/32
336 'hd2' => 10800, # 1/2
342 'hd10' => 2160, # 1/10
343 'hd12' => 1800, # 1/12
344 'hd32' => 675, # 1/32
349 'cd4' => 90, # 1/4 of a circle
350 'cd2' => 180, # 1/2 of a circle
351 '3cd4' => 270, # 3/4 of a circle
353 'cd8' => 45, # 1/8 of a circle
354 '3cd8' => 135, # 3/8 of a circle
355 '5cd8' => 225, # 5/8 of a circle
356 '7cd8' => 315, # 7/8 of a circle
370 # '21600000' => 360, # angle conversions
377 # Convert the (predefined) value to a number
382 my $result = $variables{$val};
383 return $result if ( defined( $result ) );
385 return $val if ( $val =~ /^[0-9-]+$/ );
387 error
( "Unknown variable '$val'." );
393 # Convert the DrawingML formula to a VML one
394 my %command_variables = (
401 # The same as value(), but some of the hardcoded values can have a name
402 sub command_value
( $ )
406 return "" if ( $value eq "" );
408 return $value if ( $value =~ /^@/ );
410 my $command_val = $command_variables{$value};
411 if ( defined( $command_val ) ) {
415 return value
( $value );
418 # Insert the new formula to the list of formulas
419 # Creates the name if it's empty...
420 sub insert_formula
( $$ )
422 my ( $name, $fmla ) = @_;
425 foreach my $f ( @formulas ) {
428 $variables{$name} = "@" . $i;
436 $name = "@" . ( $#formulas + 1 );
439 $variables{$name} = "@" . ( $#formulas + 1 );
440 push @formulas, $fmla;
442 if ( $#formulas > 127 ) {
443 error
( "Reached the maximum amount of formulas, have to ignore the shape '$shape_name'" );
446 return $variables{$name};
449 # The same as insert_formula(), but converts the params
450 sub insert_formula_params
( $$$$$ )
452 my ( $name, $command, $p1, $p2, $p3 ) = @_;
454 my $result = $command;
456 $result .= " " . command_value
( $p1 );
458 $result .= " " . command_value
( $p2 );
460 $result .= " " . command_value
( $p3 );
465 return insert_formula
( $name, $result );
468 # Convert the formula from DrawingML to VML
469 sub convert_formula
( $$ )
471 my ( $name, $fmla ) = @_;
473 if ( $fmla =~ /^([^ ]+)/ ) {
476 # parse the parameters
477 ( my $values = $fmla ) =~ s/^([^ ]+) *//;
481 if ( $values =~ /^([^ ]+)/ ) {
483 $values =~ s/^([^ ]+) *//;
484 if ( $values =~ /^([^ ]+)/ ) {
486 $values =~ s/^([^ ]+) *//;
487 if ( $values =~ /^([^ ]+)/ ) {
493 # now convert the formula
494 if ( $command eq "+-" ) {
495 if ( $p1 eq "100000" ) {
498 insert_formula_params
( $name, "sum", $p1, $p2, $p3 );
501 elsif ( $command eq "*/" ) {
502 if ( ( $p2 =~ /^(w|h|ss|hd2|wd2|vc)$/ ) && defined( $variables{$p1} ) ) {
503 # switch it ;-) - presetTextWarpDefinitions.xml has it in other order
509 if ( ( $p1 =~ /^(w|h|ss|hd2|wd2|vc)$/ ) && defined( $variables{$p2} ) ) {
511 if ( $val3 =~ /^[0-9-]+$/ ) {
512 $val3 *= ( value
( 'w' ) / value
( $p1 ) );
514 # Oh yes, I'm too lazy to implement the full GCD here ;-)
515 if ( ( $val3 % 100000 ) == 0 ) {
517 $p3 = sprintf( "%.0f", ( $val3 / 100000 ) );
519 elsif ( $val3 < 100000 ) {
521 while ( ( ( $p3 * 100000 ) % $val3 ) != 0 ) {
524 $p1 = ( $p3 * 100000 ) / $val3;
527 error
( "Need to count the greatest common divisor." );
531 elsif ( $p3 eq "100000" && $p2 =~ /^[0-9-]+$/ ) {
532 # prevent overflows in some shapes
533 $p2 = sprintf( "%.0f", ( $p2 / 10 ) );
536 elsif ( $p3 eq "32768" && $p2 =~ /^[0-9-]+$/ ) {
537 # prevent overflows in some shapes
538 $p2 = sprintf( "%.0f", ( $p2 / 8 ) );
541 elsif ( $p3 eq "50000" ) {
544 elsif ( $name =~ /^maxAdj/ ) {
545 my $val = value
( $p1 );
546 if ( $val =~ /^[0-9-]+$/ ) {
547 $p1 = sprintf( "%.0f", ( value
( 'w' ) * $val / 100000 ) );
551 if ( ( value
( $p1 ) eq value
( $p3 ) ) || ( value
( $p2 ) eq value
( $p3 ) ) ) {
552 my $val = value
( ( value
( $p1 ) eq value
( $p3 ) )?
$p2: $p1 );
553 if ( $val =~ /^@([0-9]+)$/ ) {
554 insert_formula
( $name, $formulas[$1] );
557 insert_formula
( $name, "val $val" );
561 insert_formula_params
( $name, "prod", $p1, $p2, $p3 );
565 elsif ( $command eq "+/" ) {
566 # we have to split this into 2 formulas - 'sum' and 'prod'
567 my $constructed = insert_formula_params
( "", "sum", $p1, $p2, "0" );
568 insert_formula_params
( $name, "prod", 1, $constructed, $p3); # references the 'sum' formula
571 elsif ( $command eq "?:" ) {
572 insert_formula_params
( $name, "if", $p1, $p2, $p3 );
575 elsif ( $command eq "sin" || $command eq "cos" ) {
576 if ( $p2 =~ /^[0-9-]+$/ && ( ( $p2 % 60000 ) == 0 ) ) {
580 $p2 = insert_formula_params
( "", "prod", "1", $p2, "60000" );
582 # we have to use 'sumangle' even for the case when $p2 is const
583 # and theoretically could be written as such; but Word does not
585 my $conv = insert_formula_params
( "", "sumangle", "0", $p2, "0" );
589 insert_formula_params
( $name, $command, $p1, $p2, "" );
592 elsif ( $command eq "abs" ) {
593 insert_formula_params
( $name, $command, $p1, "", "" );
596 elsif ( $command eq "max" || $command eq "min" ) {
597 insert_formula_params
( $name, $command, $p1, $p2, "" );
600 elsif ( $command eq "at2" ) {
601 insert_formula_params
( $name, "atan2", $p1, $p2, "" );
604 elsif ( $command eq "cat2" ) {
605 insert_formula_params
( $name, "cosatan2", $p1, $p2, $p3 );
608 elsif ( $command eq "sat2" ) {
609 insert_formula_params
( $name, "sinatan2", $p1, $p2, $p3 );
612 elsif ( $command eq "sqrt" ) {
613 insert_formula_params
( $name, "sqrt", $p1, "", "" );
616 elsif ( $command eq "mod" ) {
617 insert_formula_params
( $name, "mod", $p1, $p2, $p3 );
620 elsif ( $command eq "val" ) {
621 insert_formula_params
( $name, "val", value
( $p1 ), "", "" );
625 error
( "Unknown formula '$name', '$fmla'." );
629 error
( "Cannot convert formula's command '$name', '$fmla'." );
633 # There's no exact equivalent of 'arcTo' in VML, we have to do some special casing...
634 my %convert_arcTo = (
638 'op' => [ 'sum 0 __last_x__ __wR__', 'sum __hR__ __last_y__ 0' ],
642 'op' => [ 'sum 0 __last_x__ __wR__', 'sum 0 __last_y__ __hR__' ],
648 'op' => [ 'sum 0 __last_x__ __wR__', 'sum 0 __last_y__ __hR__' ],
652 'op' => [ 'sum __wR__ __last_x__ 0', 'sum 0 __last_y__ __hR__' ],
658 'op' => [ 'sum __wR__ __last_x__ 0', 'sum 0 __last_y__ __hR__' ],
662 'op' => [ 'sum __wR__ __last_x__ 0', 'sum __hR__ __last_y__ 0' ],
668 'op' => [ 'sum __wR__ __last_x__ 0', 'sum __hR__ __last_y__ 0' ],
672 'op' => [ 'sum 0 __last_x__ __wR__', 'sum __hR__ __last_y__ 0' ],
678 # FIXME optimize so that we compute the const values when possible
679 sub elliptic_quadrant
( $$$$ )
681 my ( $wR, $hR, $stAng, $swAng ) = @_;
683 if ( defined( $convert_arcTo{$stAng} ) && defined( $convert_arcTo{$stAng}{$swAng} ) ) {
684 my $conv_path = $convert_arcTo{$stAng}{$swAng}{'path'};
685 my $conv_op_ref = $convert_arcTo{$stAng}{$swAng}{'op'};
687 $path .= "$conv_path";
689 my $pos_x = $last_pos_x;
690 my $pos_y = $last_pos_y;
691 for ( my $i = 0; $i <= $#{$conv_op_ref}; ++$i ) {
692 my $op = $conv_op_ref->[$i];
694 $op =~ s/__last_x__/$last_pos_x/g;
695 $op =~ s/__last_y__/$last_pos_y/g;
696 $op =~ s/__wR__/$wR/g;
697 $op =~ s/__hR__/$hR/g;
699 my $fmla = insert_formula
( "", $op );
703 # so far it's sufficient just to rotate the positions
708 $last_pos_x = $pos_x;
709 $last_pos_y = $pos_y;
712 error
( "Unhandled elliptic_quadrant(), input is ($wR, $hR, $stAng, $swAng)." );
716 # Convert the quadratic bezier to cubic (exact)
717 # No idea why, but the 'qb' did not work for me :-(
718 sub quadratic_to_cubic_bezier
( $ )
722 my $a0 = $quadratic_bezier[0]->{$axis};
723 my $a1 = $quadratic_bezier[1]->{$axis};
724 my $a2 = $quadratic_bezier[2]->{$axis};
728 # $b1 = $a0 + 2/3 * ( $a1 - $a0 ), but in VML
729 # FIXME optimize for constants - compute directly
730 my $b1_1 = insert_formula_params
( "", "sum", "0", $a1, $a0 );
731 my $b1_2 = insert_formula_params
( "", "prod", "2", $b1_1, "3" );
732 my $b1 = insert_formula_params
( "", "sum", $a0, $b1_2, "0" );
734 # $b2 = $b1 + 1/3 * ( $a2 - $a0 );
735 # FIXME optimize for constants - compute directly
736 my $b2_1 = insert_formula_params
( "", "sum", "0", $a2, $a0 );
737 my $b2_2 = insert_formula_params
( "", "prod", "1", $b2_1, "3" );
738 my $b2 = insert_formula_params
( "", "sum", $b1, $b2_2, "0" );
742 return ( $b0, $b1, $b2, $b3 );
745 # Extend $path by one more point
746 sub add_point_to_path
( $$ )
750 if ( $path =~ /[0-9]$/ && $x =~ /^[0-9-]/ ) {
755 if ( $path =~ /[0-9]$/ && $y =~ /^[0-9-]/ ) {
761 # Start of an element
762 sub start_element
( $% )
764 my ( $element, %attr ) = @_;
766 push @levels, $element;
768 #print "element: $element\n";
770 if ( @levels > 1 && ( $levels[-2] eq "presetShapeDefinitons" ||
771 $levels[-2] eq "presetTextWarpDefinitions" ) ) {
772 $shape_name = $element;
775 $ignore_this_shape = 0;
786 @quadratic_bezier = ();
790 if ( $shape_name eq "sun" ) {
791 # hack for this shape
792 $variables{'100000'} = "21600";
793 $variables{'50000'} = "10800";
794 $variables{'25000'} = "5400";
795 $variables{'12500'} = "2700";
796 $variables{'3662'} = "791";
800 foreach my $name ( values( %shapes_ids ) ) {
801 if ( $name eq $shape_name ) {
807 error
( "Unknown shape '$shape_name'." );
810 elsif ( $element eq "pathLst" ) {
813 elsif ( $element eq "avLst" ) {
816 elsif ( $element eq "gdLst" ) {
819 elsif ( $element eq "ahLst" ) {
822 elsif ( $element eq "rect" ) {
823 $textboxrect = value
( $attr{'l'} ) . "," . value
( $attr{'t'} ) . "," .
824 value
( $attr{'r'} ) . "," . value
( $attr{'b'} );
826 elsif ( $state eq "path" ) {
827 if ( $element eq "path" ) {
828 $no_stroke = ( defined( $attr{'stroke'} ) && $attr{'stroke'} eq 'false' );
829 $no_fill = ( defined( $attr{'fill'} ) && $attr{'fill'} eq 'none' );
830 $path_w = $attr{'w'};
831 $path_h = $attr{'h'};
833 elsif ( $element eq "moveTo" ) {
836 elsif ( $element eq "lnTo" ) {
839 elsif ( $element eq "cubicBezTo" ) {
842 elsif ( $element eq "quadBezTo" ) {
843 my %points = ( 'x' => $last_pos_x, 'y' => $last_pos_y );
844 @quadratic_bezier = ( \
%points );
846 elsif ( $element eq "close" ) {
849 elsif ( $element eq "pt" ) {
850 # remember the last position for the arcTo
851 $last_pos_x = value
( $attr{'x'} );
852 $last_pos_y = value
( $attr{'y'} );
854 $last_pos_x *= ( value
( 'w' ) / $path_w ) if ( defined( $path_w ) );
855 $last_pos_y *= ( value
( 'h' ) / $path_h ) if ( defined( $path_h ) );
857 if ( $#quadratic_bezier >= 0 ) {
858 my %points = ( 'x' => $last_pos_x, 'y' => $last_pos_y );
859 push( @quadratic_bezier, \
%points );
862 add_point_to_path
( $last_pos_x, $last_pos_y );
865 elsif ( ( $element eq "arcTo" ) && ( $last_pos_x ne "" ) && ( $last_pos_y ne "" ) ) {
866 # there's no exact equivalent of arcTo in VML, so we have to
867 # compute here a bit...
868 my $stAng = value
( $attr{'stAng'} );
869 my $swAng = value
( $attr{'swAng'} );
870 my $wR = value
( $attr{'wR'} );
871 my $hR = value
( $attr{'hR'} );
873 $wR *= ( value
( 'w' ) / $path_w ) if ( defined( $path_w ) );
874 $hR *= ( value
( 'h' ) / $path_h ) if ( defined( $path_h ) );
876 if ( ( $stAng =~ /^[0-9-]+$/ ) && ( $swAng =~ /^[0-9-]+$/ ) ) {
877 if ( ( ( $stAng % 90 ) == 0 ) && ( ( $swAng % 90 ) == 0 ) && ( $swAng != 0 ) ) {
878 my $end = $stAng + $swAng;
879 my $step = ( $swAng > 0 )?
90: -90;
881 for ( my $cur = $stAng; $cur != $end; $cur += $step ) {
882 elliptic_quadrant
( $wR, $hR, ( $cur % 360 ), $step );
886 error
( "Unsupported numeric 'arcTo' ($attr{'wR'}, $attr{'hR'}, $stAng, $swAng)." );
890 error
( "Unsupported 'arcTo' conversion ($attr{'wR'}, $attr{'hR'}, $stAng, $swAng)." );
894 error
( "Unhandled path element '$element'." );
897 elsif ( $state eq "adjust" ) {
898 if ( $element eq "gd" ) {
899 my $adj_no = $attr{'name'};
901 # Save this adj number for this type for later use.
902 push(@
{$adj_names{$shape_name}}, $adj_no);
907 if ( $adj_no eq "" ) {
910 elsif ( !( $adj_no =~ /^[0-9]*$/ ) ) {
914 elsif ( $adj_no != $max_adj_no + 1 ) {
915 error
( "Wrong order of adj values." );
919 $max_adj_no = $adj_no;
922 if ( $attr{'fmla'} =~ /^val ([0-9-]*)$/ ) {
923 my $val = sprintf( "%.0f", ( 21600 * $1 ) / 100000 );
925 $variables{$adj_no} = $val;
927 elsif ( $adjust eq "" ) {
931 $adjust = "$val,$adjust";
935 error
( "Wrong fmla '$attr{'fmla'}'." );
939 error
( "Unhandled adjust element '$element'." );
942 elsif ( $state eq "formulas" ) {
943 if ( $element eq "gd" ) {
944 if ( $attr{'fmla'} =~ /^\*\/ (h
|w
|ss
) adj
([0-9]+) 100000$/ ) {
945 insert_formula
( $attr{'name'}, "val #" . ( $max_adj_no - $2 ) );
947 elsif ( $attr{'fmla'} =~ /^pin [^ ]+ ([^ ]+) / ) {
948 print STDERR
"TODO Map 'pin' to VML as xrange for handles.\n";
950 if ( $pin_val eq "adj" ) {
951 insert_formula
( $attr{'name'}, "val #0" );
953 elsif ( $pin_val =~ /^adj([0-9]+)/ ) {
954 insert_formula
( $attr{'name'}, "val #" . ( $max_adj_no - $1 ) );
957 insert_formula
( $attr{'name'}, "val " . value
( $pin_val ) );
960 elsif ( $attr{'fmla'} =~ /adj/ ) {
961 error
( "Non-standard usage of adj in '$attr{'fmla'}'." );
964 convert_formula
( $attr{'name'}, $attr{'fmla'} );
968 elsif ( $state eq "handles" ) {
969 if ( $element eq "pos" ) {
970 $handles .= "<v:h position=\"" . value
( $attr{'x'} ) . "," . value
( $attr{'y'} ) . "\"/>\n";
978 my ( $element ) = @_;
982 if ( $element eq $shape_name ) {
983 if ( !$ignore_this_shape ) {
984 # we have all the info, generate the shape now
988 my $out = "<v:shapetype id=\"_x0000_t__ID__\" coordsize=\"21600,21600\" o:spt=\"__ID__\" ";
989 if ( $adjust ne "" ) {
990 $out .= "adj=\"$adjust\" ";
993 # optimize it [yes, we need this twice ;-)]
994 $path =~ s/([^0-9-@])0([^0-9-@])/$1$2/g;
995 $path =~ s/([^0-9-@])0([^0-9-@])/$1$2/g;
997 $out .= "path=\"$path\">\n";
1000 $out .= "<v:stroke joinstyle=\"miter\"/>\n";
1003 if ( $#formulas >= 0 )
1005 $out .= "<v:formulas>\n";
1006 foreach my $fmla ( @formulas ) {
1007 $out .= "<v:f eqn=\"$fmla\"/>\n"
1009 $out .= "</v:formulas>\n";
1013 if ( $textboxrect ne "" ) { # TODO connectlocs, connectangles
1014 $out .= "<v:path gradientshapeok=\"t\" o:connecttype=\"rect\" textboxrect=\"$textboxrect\"/>\n";
1018 if ( $handles ne "" ) {
1019 $out .= "<v:handles>\n$handles</v:handles>\n";
1022 $out .="</v:shapetype>";
1025 $result_shapes{$shape_name} = $out;
1028 print STDERR
"Shape '$shape_name' ignored; see the above error(s) for the reason.\n";
1032 elsif ( $state eq "path" ) {
1033 if ( $element eq "path" ) {
1034 $path .= "ns" if ( $no_stroke );
1035 $path .= "nf" if ( $no_fill );
1038 elsif ( $element eq "quadBezTo" ) {
1039 # we have to convert the quadratic bezier to cubic
1040 if ( $#quadratic_bezier == 2 ) {
1041 my @points_x = quadratic_to_cubic_bezier
( 'x' );
1042 my @points_y = quadratic_to_cubic_bezier
( 'y' );
1045 # ignore the starting point
1046 for ( my $i = 1; $i < 4; ++$i ) {
1047 add_point_to_path
( $points_x[$i], $points_y[$i] );
1051 error
( "Wrong number of points of the quadratic bezier." );
1053 @quadratic_bezier = ();
1056 elsif ( $element eq "avLst" ) {
1059 elsif ( $element eq "gdLst" ) {
1062 elsif ( $element eq "ahLst" ) {
1067 # Text inside an element
1073 #################### A trivial XML parser ####################
1075 # Parse the attributes
1076 sub parse_start_element
( $ )
1078 # split the string containing both the elements and attributes
1079 my ( $element_tmp ) = @_;
1081 $element_tmp =~ s/\s*$//;
1082 $element_tmp =~ s/^\s*//;
1084 ( my $element = $element_tmp ) =~ s/\s.*$//;
1085 if ( $element_tmp =~ /\s/ ) {
1086 $element_tmp =~ s/^[^\s]*\s//;
1092 # we have the element, now the attributes
1096 foreach my $tmp ( split( /"/, $element_tmp ) ) {
1100 $key =~ s/\s*=\s*$//;
1108 if ( $element ne "" ) {
1109 start_element
( $element, %attr );
1128 elsif ( /-->/ && $in_comment ) {
1132 elsif ( $in_comment ) {
1135 # ignore empty lines
1139 next if ( $_ eq "" );
1141 # take care of lines where element continues
1142 if ( $line ne "" ) {
1150 # the actual parsing
1151 my @starts = split( /</, $line );
1153 foreach my $start ( @starts ) {
1154 next if ( $start eq "" );
1156 my @ends = split( />/, $start );
1157 my $element = $ends[0];
1158 my $data = $ends[1];
1160 # start or end element
1161 if ( $element =~ /^\/(.*)/ ) {
1164 elsif ( $element =~ /^(.*)\/$/ ) {
1165 parse_start_element
( $1 );
1166 ( my $end = $1 ) =~ s/\s.*$//;
1167 end_element
( $end );
1170 parse_start_element
( $element );
1174 characters
( $data ) if ( defined( $data ) && $data ne "" );
1181 open( $file, "<$src_shapes" ) || die "Cannot open $src_shapes: $!";
1185 open( $file, "<$src_text" ) || die "Cannot open $src_text: $!";
1189 if ( !defined( $result_shapes{'textBox'} ) ) {
1190 # tdf#114842 shapetype id of the textbox, must be the same as defined
1191 $result_shapes{'textBox'} =
1192 "<v:shapetype id=\"_x0000_t__ID__\" coordsize=\"21600,21600\" " .
1193 "o:spt=\"__ID__\" path=\"m,l,21600l21600,21600l21600,xe\">\n" .
1194 "<v:stroke joinstyle=\"miter\"/>\n" .
1195 "<v:path gradientshapeok=\"t\" o:connecttype=\"rect\"/>\n" .
1200 if ($drawingml_adj_names_data eq 1) {
1201 foreach my $adj_name (sort(keys %adj_names))
1203 foreach my $adj (@
{$adj_names{$adj_name}})
1205 print "$adj_name\t$adj\n";
1209 } elsif ($vml_shape_types_data eq 1) {
1210 for ( my $i = 0; $i < 203; ++$i ) {
1212 print "/* $i - $shapes_ids{$i} - handled separately */\nNULL\n";
1215 print "/* $i - $shapes_ids{$i} */\n";
1216 my $out = $result_shapes{$shapes_ids{$i}};
1217 if ( defined( $out ) ) {
1219 $out =~ s/__ID__/$i/g;
1237 # vim:set ft=perl shiftwidth=4 softtabstop=4 expandtab: #