2 #*************************************************************************
4 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 # Copyright 2008 by Sun Microsystems, Inc.
8 # OpenOffice.org - a multi-platform office productivity suite
10 # This file is part of OpenOffice.org.
12 # OpenOffice.org is free software: you can redistribute it and/or modify
13 # it under the terms of the GNU Lesser General Public License version 3
14 # only, as published by the Free Software Foundation.
16 # OpenOffice.org is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU Lesser General Public License version 3 for more details
20 # (a copy is included in the LICENSE file that accompanied this code).
22 # You should have received a copy of the GNU Lesser General Public License
23 # version 3 along with OpenOffice.org. If not, see
24 # <http://www.openoffice.org/license.html>
25 # for a copy of the LGPLv3 License.
27 #*************************************************************************
33 Usage: preset-definitions-to-shape-types.pl <shapes> <text>
35 Converts presetShapeDefinitions.xml and presetTextWarpDefinitions.xml to a
36 .cxx that contains VML with the definitions of the shapes. The result is
39 <shapes> presetShapeDefinitions.xml (including the path to it)
40 <text> presetTextWarpDefinitions.xml (including the path to it)
47 my ( $path, $line, $subr );
50 print STDERR
"--- Begin stack trace ---\n";
51 while ( (my @call_details = (caller($i++))) && ($i<$max_depth) ) {
52 print STDERR
"$call_details[1] line $call_details[2] in function $call_details[3]\n";
54 print STDERR
"--- End stack trace ---\n";
60 usage
() if ( !defined( $src_shapes ) || !defined( $src_text ) ||
61 $src_shapes eq "-h" || $src_shapes eq "--help" ||
62 !-f
$src_shapes || !-f
$src_text );
73 $ignore_this_shape = 0;
82 @quadratic_bezier = ();
89 2 => 'roundRectangle',
101 14 => 'thickArrow', # should not be used
104 17 => 'wedgeRoundRectCallout', # balloon
105 18 => 'star16', # seal
111 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?
112 25 => 'textStop', # textOctagon FIXME see 24
113 26 => 'textTriangle', # textHexagon FIXMME see 24
114 27 => 'textCanDown', # textCurve FIXMME see 24
115 28 => 'textWave1', # textWave FIXMME see 24
116 29 => 'textArchUpPour', # textRing FIXMME see 24
117 30 => 'textCanDown', # textOnCurve FIXMME see 24
118 31 => 'textArchUp', # textOnRing FIXMME see 24
119 32 => 'straightConnector1',
120 33 => 'bentConnector2',
121 34 => 'bentConnector3',
122 35 => 'bentConnector4',
123 36 => 'bentConnector5',
124 37 => 'curvedConnector2',
125 38 => 'curvedConnector3',
126 39 => 'curvedConnector4',
127 40 => 'curvedConnector5',
131 44 => 'accentCallout1',
132 45 => 'accentCallout2',
133 46 => 'accentCallout3',
134 47 => 'borderCallout1',
135 48 => 'borderCallout2',
136 49 => 'borderCallout3',
137 50 => 'accentBorderCallout1',
138 51 => 'accentBorderCallout2',
139 52 => 'accentBorderCallout3',
145 58 => 'star8', # seal8
146 59 => 'star16', # seal16
147 60 => 'star32', # seal32
148 61 => 'wedgeRectCallout',
149 62 => 'wedgeRoundRectCallout', # wedgeRRectCallout
150 63 => 'wedgeEllipseCallout',
152 65 => 'foldedCorner',
156 69 => 'leftRightArrow',
158 71 => 'irregularSeal1',
159 72 => 'irregularSeal2',
160 73 => 'lightningBolt',
162 75 => 'frame', # pictureFrame
164 77 => 'leftArrowCallout',
165 78 => 'rightArrowCallout',
166 79 => 'upArrowCallout',
167 80 => 'downArrowCallout',
168 81 => 'leftRightArrowCallout',
169 82 => 'upDownArrowCallout',
170 83 => 'quadArrowCallout',
173 86 => 'rightBracket',
179 92 => 'star24', # seal24
180 93 => 'stripedRightArrow',
181 94 => 'notchedRightArrow',
184 97 => 'verticalScroll',
185 98 => 'horizontalScroll',
186 99 => 'circularArrow',
187 100 => 'notchedCircularArrow', # should not be used
189 102 => 'curvedRightArrow',
190 103 => 'curvedLeftArrow',
191 104 => 'curvedUpArrow',
192 105 => 'curvedDownArrow',
193 106 => 'cloudCallout',
194 107 => 'ellipseRibbon',
195 108 => 'ellipseRibbon2',
196 109 => 'flowChartProcess',
197 110 => 'flowChartDecision',
198 111 => 'flowChartInputOutput',
199 112 => 'flowChartPredefinedProcess',
200 113 => 'flowChartInternalStorage',
201 114 => 'flowChartDocument',
202 115 => 'flowChartMultidocument',
203 116 => 'flowChartTerminator',
204 117 => 'flowChartPreparation',
205 118 => 'flowChartManualInput',
206 119 => 'flowChartManualOperation',
207 120 => 'flowChartConnector',
208 121 => 'flowChartPunchedCard',
209 122 => 'flowChartPunchedTape',
210 123 => 'flowChartSummingJunction',
211 124 => 'flowChartOr',
212 125 => 'flowChartCollate',
213 126 => 'flowChartSort',
214 127 => 'flowChartExtract',
215 128 => 'flowChartMerge',
216 129 => 'flowChartOfflineStorage',
217 130 => 'flowChartOnlineStorage',
218 131 => 'flowChartMagneticTape',
219 132 => 'flowChartMagneticDisk',
220 133 => 'flowChartMagneticDrum',
221 134 => 'flowChartDisplay',
222 135 => 'flowChartDelay',
223 136 => 'textPlain', # textPlainText
225 138 => 'textTriangle',
226 139 => 'textTriangleInverted',
227 140 => 'textChevron',
228 141 => 'textChevronInverted',
229 142 => 'textRingInside',
230 143 => 'textRingOutside',
231 144 => 'textArchUp', # textArchUpCurve
232 145 => 'textArchDown', # textArchDownCurve
233 146 => 'textCircle', # textCircleCurve
234 147 => 'textButton', # textButtonCurve
235 148 => 'textArchUpPour',
236 149 => 'textArchDownPour',
237 150 => 'textCirclePour',
238 151 => 'textButtonPour',
239 152 => 'textCurveUp',
240 153 => 'textCurveDown',
241 154 => 'textCascadeUp',
242 155 => 'textCascadeDown',
247 160 => 'textInflate',
248 161 => 'textDeflate',
249 162 => 'textInflateBottom',
250 163 => 'textDeflateBottom',
251 164 => 'textInflateTop',
252 165 => 'textDeflateTop',
253 166 => 'textDeflateInflate',
254 167 => 'textDeflateInflateDeflate',
255 168 => 'textFadeRight',
256 169 => 'textFadeLeft',
258 171 => 'textFadeDown',
259 172 => 'textSlantUp',
260 173 => 'textSlantDown',
262 175 => 'textCanDown',
263 176 => 'flowChartAlternateProcess',
264 177 => 'flowChartOffpageConnector',
265 178 => 'callout1', # callout90
266 179 => 'accentCallout1', # accentCallout90
267 180 => 'borderCallout1', # borderCallout90
268 181 => 'accentBorderCallout1', # accentBorderCallout90
269 182 => 'leftRightUpArrow',
272 185 => 'bracketPair',
274 187 => 'star4', # seal4
276 189 => 'actionButtonBlank',
277 190 => 'actionButtonHome',
278 191 => 'actionButtonHelp',
279 192 => 'actionButtonInformation',
280 193 => 'actionButtonForwardNext',
281 194 => 'actionButtonBackPrevious',
282 195 => 'actionButtonEnd',
283 196 => 'actionButtonBeginning',
284 197 => 'actionButtonReturn',
285 198 => 'actionButtonDocument',
286 199 => 'actionButtonSound',
287 200 => 'actionButtonMovie',
288 201 => 'hostControl', # should not be used
291 # An error occured, we have to ignore this shape
296 $ignore_this_shape = 1;
297 print STDERR
"ERROR (in $shape_name ): $msg\n";
300 # Check that we are in the correct level
303 my ( $level, $value ) = @_;
306 error
( "Error in is_level(), \$level should be <= 0." );
308 return ( $#levels + $level > 0 ) && ( $levels[$#levels + $level] eq $value );
311 # Setup the %variables map with predefined values
312 sub setup_variables
()
325 'ssd2' => 10800, # 1/2
326 'ssd4' => 5400, # 1/4
327 'ssd6' => 3600, # 1/6
328 'ssd8' => 2700, # 1/8
329 'ssd16' => 1350, # 1/16
330 'ssd32' => 675, # 1/32
332 'hc' => 10800, # horizontal center
333 'vc' => 10800, # vertical center
335 'wd2' => 10800, # 1/2
341 'wd10' => 2160, # 1/10
342 'wd12' => 1800, # 1/12
343 'wd32' => 675, # 1/32
345 'hd2' => 10800, # 1/2
351 'hd10' => 2160, # 1/10
352 'hd12' => 1800, # 1/12
353 'hd32' => 675, # 1/32
358 'cd4' => 90, # 1/4 of a circle
359 'cd2' => 180, # 1/2 of a circle
360 '3cd4' => 270, # 3/4 of a circle
362 'cd8' => 45, # 1/8 of a circle
363 '3cd8' => 135, # 3/8 of a circle
364 '5cd8' => 225, # 5/8 of a circle
365 '7cd8' => 315, # 7/8 of a circle
379 # '21600000' => 360, # angle conversions
386 # Convert the (predefiend) value to a number
391 my $result = $variables{$val};
392 return $result if ( defined( $result ) );
394 return $val if ( $val =~ /^[0-9-]+$/ );
396 error
( "Unknown variable '$val'." );
402 # Convert the DrawingML formula to a VML one
403 %command_variables = (
410 # The same as value(), but some of the hardcoded values can have a name
411 sub command_value
( $ )
415 return "" if ( $value eq "" );
417 return $value if ( $value =~ /^@/ );
419 my $command_val = $command_variables{$value};
420 if ( defined( $command_val ) ) {
424 return value
( $value );
427 # Insert the new formula to the list of formulas
428 # Creates the name if it's empty...
429 sub insert_formula
( $$ )
431 my ( $name, $fmla ) = @_;
434 foreach $f ( @formulas ) {
437 $variables{$name} = "@" . $i;
445 $name = "@" . ( $#formulas + 1 );
448 $variables{$name} = "@" . ( $#formulas + 1 );
449 push @formulas, $fmla;
451 if ( $#formulas > 127 ) {
452 error
( "Reached the maximum amount of formulas, have to ignore the shape '$shape_name'" );
455 return $variables{$name};
458 # The same as insert_formula(), but converts the params
459 sub insert_formula_params
( $$$$$ )
461 my ( $name, $command, $p1, $p2, $p3 ) = @_;
463 my $result = $command;
465 $result .= " " . command_value
( $p1 );
467 $result .= " " . command_value
( $p2 );
469 $result .= " " . command_value
( $p3 );
474 return insert_formula
( $name, $result );
477 # Convert the formula from DrawingML to VML
478 sub convert_formula
( $$ )
480 my ( $name, $fmla ) = @_;
482 if ( $fmla =~ /^([^ ]+)/ ) {
485 # parse the parameters
486 ( my $values = $fmla ) =~ s/^([^ ]+) *//;
487 my $p1 = "", $p2 = "", $p3 = "";
488 if ( $values =~ /^([^ ]+)/ ) {
490 $values =~ s/^([^ ]+) *//;
491 if ( $values =~ /^([^ ]+)/ ) {
493 $values =~ s/^([^ ]+) *//;
494 if ( $values =~ /^([^ ]+)/ ) {
500 # now convert the formula
501 if ( $command eq "+-" ) {
502 if ( $p1 eq "100000" ) {
505 insert_formula_params
( $name, "sum", $p1, $p2, $p3 );
508 elsif ( $command eq "*/" ) {
509 if ( ( $p2 =~ /^(w|h|ss|hd2|wd2|vc)$/ ) && defined( $variables{$p1} ) ) {
510 # switch it ;-) - presetTextWarpDefinitions.xml has it in other order
516 if ( ( $p1 =~ /^(w|h|ss|hd2|wd2|vc)$/ ) && defined( $variables{$p2} ) ) {
518 if ( $val3 =~ /^[0-9-]+$/ ) {
519 $val3 *= ( value
( 'w' ) / value
( $p1 ) );
521 # Oh yes, I'm too lazy to implement the full GCD here ;-)
522 if ( ( $val3 % 100000 ) == 0 ) {
524 $p3 = sprintf( "%.0f", ( $val3 / 100000 ) );
526 elsif ( $val3 < 100000 ) {
528 while ( ( ( $p3 * 100000 ) % $val3 ) != 0 ) {
531 $p1 = ( $p3 * 100000 ) / $val3;
534 error
( "Need to count the greatest common divisor." );
538 elsif ( $p3 eq "100000" && $p2 =~ /^[0-9-]+$/ ) {
539 # prevent overflows in some shapes
540 $p2 = sprintf( "%.0f", ( $p2 / 10 ) );
543 elsif ( $p3 eq "32768" && $p2 =~ /^[0-9-]+$/ ) {
544 # prevent overflows in some shapes
545 $p2 = sprintf( "%.0f", ( $p2 / 8 ) );
548 elsif ( $p3 eq "50000" ) {
551 elsif ( $name =~ /^maxAdj/ ) {
552 my $val = value
( $p1 );
553 if ( $val =~ /^[0-9-]+$/ ) {
554 $p1 = sprintf( "%.0f", ( value
( 'w' ) * $val / 100000 ) );
558 if ( ( value
( $p1 ) eq value
( $p3 ) ) || ( value
( $p2 ) eq value
( $p3 ) ) ) {
559 my $val = value
( ( value
( $p1 ) eq value
( $p3 ) )?
$p2: $p1 );
560 if ( $val =~ /^@([0-9]+)$/ ) {
561 insert_formula
( $name, $formulas[$1] );
564 insert_formula
( $name, "val $val" );
568 insert_formula_params
( $name, "prod", $p1, $p2, $p3 );
572 elsif ( $command eq "+/" ) {
573 # we have to split this into 2 formulas - 'sum' and 'prod'
574 my $constructed = insert_formula_params
( "", "sum", $p1, $p2, "0" );
575 insert_formula_params
( $name, "prod", 1, $constructed, $p3); # references the 'sum' formula
578 elsif ( $command eq "?:" ) {
579 insert_formula_params
( $name, "if", $p1, $p2, $p3 );
582 elsif ( $command eq "sin" || $command eq "cos" ) {
583 if ( $p2 =~ /^[0-9-]+$/ && ( ( $p2 % 60000 ) == 0 ) ) {
587 $p2 = insert_formula_params
( "", "prod", "1", $p2, "60000" );
589 # we have to use 'sumangle' even for the case when $p2 is const
590 # and theoretically could be written as such; but Word does not
592 my $conv = insert_formula_params
( "", "sumangle", "0", $p2, "0" );
596 insert_formula_params
( $name, $command, $p1, $p2, "" );
599 elsif ( $command eq "abs" ) {
600 insert_formula_params
( $name, $command, $p1, "", "" );
603 elsif ( $command eq "max" || $command eq "min" ) {
604 insert_formula_params
( $name, $command, $p1, $p2, "" );
607 elsif ( $command eq "at2" ) {
608 insert_formula_params
( $name, "atan2", $p1, $p2, "" );
611 elsif ( $command eq "cat2" ) {
612 insert_formula_params
( $name, "cosatan2", $p1, $p2, $p3 );
615 elsif ( $command eq "sat2" ) {
616 insert_formula_params
( $name, "sinatan2", $p1, $p2, $p3 );
619 elsif ( $command eq "sqrt" ) {
620 insert_formula_params
( $name, "sqrt", $p1, "", "" );
623 elsif ( $command eq "mod" ) {
624 insert_formula_params
( $name, "mod", $p1, $p2, $p3 );
627 elsif ( $command eq "val" ) {
628 insert_formula_params
( $name, "val", value
( $p1 ), "", "" );
632 error
( "Unknown formula '$name', '$fmla'." );
636 error
( "Cannot convert formula's command '$name', '$fmla'." );
640 # There's no exact equivalent of 'arcTo' in VML, we have to do some special casing...
645 'op' => [ 'sum 0 __last_x__ __wR__', 'sum __hR__ __last_y__ 0' ],
649 'op' => [ 'sum 0 __last_x__ __wR__', 'sum 0 __last_y__ __hR__' ],
655 'op' => [ 'sum 0 __last_x__ __wR__', 'sum 0 __last_y__ __hR__' ],
659 'op' => [ 'sum __wR__ __last_x__ 0', 'sum 0 __last_y__ __hR__' ],
665 'op' => [ 'sum __wR__ __last_x__ 0', 'sum 0 __last_y__ __hR__' ],
669 'op' => [ 'sum __wR__ __last_x__ 0', 'sum __hR__ __last_y__ 0' ],
675 'op' => [ 'sum __wR__ __last_x__ 0', 'sum __hR__ __last_y__ 0' ],
679 'op' => [ 'sum 0 __last_x__ __wR__', 'sum __hR__ __last_y__ 0' ],
685 # FIXME optimize so that we compute the const values when possible
686 sub elliptic_quadrant
( $$$$ )
688 my ( $wR, $hR, $stAng, $swAng ) = @_;
690 if ( defined( $convert_arcTo{$stAng} ) && defined( $convert_arcTo{$stAng}{$swAng} ) ) {
691 my $conv_path = $convert_arcTo{$stAng}{$swAng}{'path'};
692 my $conv_op_ref = $convert_arcTo{$stAng}{$swAng}{'op'};
694 $path .= "$conv_path";
696 my $pos_x = $last_pos_x;
697 my $pos_y = $last_pos_y;
698 for ( my $i = 0; $i <= $#{$conv_op_ref}; ++$i ) {
699 my $op = $conv_op_ref->[$i];
701 $op =~ s/__last_x__/$last_pos_x/g;
702 $op =~ s/__last_y__/$last_pos_y/g;
703 $op =~ s/__wR__/$wR/g;
704 $op =~ s/__hR__/$hR/g;
706 my $fmla = insert_formula
( "", $op );
710 # so far it's sufficient just to rotate the positions
715 $last_pos_x = $pos_x;
716 $last_pos_y = $pos_y;
719 error
( "Unhandled elliptic_quadrant(), input is ($wR, $hR, $stAng, $swAng)." );
723 # Convert the quadratic bezier to cubic (exact)
724 # No idea why, but the 'qb' did not work for me :-(
725 sub quadratic_to_cubic_bezier
( $ )
729 my $a0 = $quadratic_bezier[0]->{$axis};
730 my $a1 = $quadratic_bezier[1]->{$axis};
731 my $a2 = $quadratic_bezier[2]->{$axis};
735 # $b1 = $a0 + 2/3 * ( $a1 - $a0 ), but in VML
736 # FIXME optimize for constants - compute directly
737 my $b1_1 = insert_formula_params
( "", "sum", "0", $a1, $a0 );
738 my $b1_2 = insert_formula_params
( "", "prod", "2", $b1_1, "3" );
739 my $b1 = insert_formula_params
( "", "sum", $a0, $b1_2, "0" );
741 # $b2 = $b1 + 1/3 * ( $a2 - $a0 );
742 # FIXME optimize for constants - compute directly
743 my $b2_1 = insert_formula_params
( "", "sum", "0", $a2, $a0 );
744 my $b2_2 = insert_formula_params
( "", "prod", "1", $b2_1, "3" );
745 my $b2 = insert_formula_params
( "", "sum", $b1, $b2_2, "0" );
749 return ( $b0, $b1, $b2, $b3 );
752 # Extend $path by one more point
753 sub add_point_to_path
( $$ )
757 if ( $path =~ /[0-9]$/ && $x =~ /^[0-9-]/ ) {
762 if ( $path =~ /[0-9]$/ && $y =~ /^[0-9-]/ ) {
768 # Start of an element
769 sub start_element
( $% )
771 my ( $element, %attr ) = @_;
773 push @levels, $element;
775 #print "element: $element\n";
777 if ( is_level
( -1, "presetShapeDefinitons" ) || is_level
( -1, "presetTextWarpDefinitions" ) ) {
778 $shape_name = $element;
781 $ignore_this_shape = 0;
792 @quadratic_bezier = ();
796 if ( $shape_name eq "sun" ) {
797 # hack for this shape
798 $variables{'100000'} = "21600";
799 $variables{'50000'} = "10800";
800 $variables{'25000'} = "5400";
801 $variables{'12500'} = "2700";
802 $variables{'3662'} = "791";
806 foreach my $name ( values( %shapes_ids ) ) {
807 if ( $name eq $shape_name ) {
813 error
( "Unknown shape '$shape_name'." );
816 elsif ( $element eq "pathLst" ) {
819 elsif ( $element eq "avLst" ) {
822 elsif ( $element eq "gdLst" ) {
825 elsif ( $element eq "ahLst" ) {
828 elsif ( $element eq "rect" ) {
829 $textboxrect = value
( $attr{'l'} ) . "," . value
( $attr{'t'} ) . "," .
830 value
( $attr{'r'} ) . "," . value
( $attr{'b'} );
832 elsif ( $state eq "path" ) {
833 if ( $element eq "path" ) {
834 $no_stroke = ( defined( $attr{'stroke'} ) && $attr{'stroke'} eq 'false' );
835 $no_fill = ( defined( $attr{'fill'} ) && $attr{'fill'} eq 'none' );
836 $path_w = $attr{'w'};
837 $path_h = $attr{'h'};
839 elsif ( $element eq "moveTo" ) {
842 elsif ( $element eq "lnTo" ) {
845 elsif ( $element eq "cubicBezTo" ) {
848 elsif ( $element eq "quadBezTo" ) {
849 my %points = ( 'x' => $last_pos_x, 'y' => $last_pos_y );
850 @quadratic_bezier = ( \
%points );
852 elsif ( $element eq "close" ) {
855 elsif ( $element eq "pt" ) {
856 # rememeber the last position for the arcTo
857 $last_pos_x = value
( $attr{'x'} );
858 $last_pos_y = value
( $attr{'y'} );
860 $last_pos_x *= ( value
( 'w' ) / $path_w ) if ( defined( $path_w ) );
861 $last_pos_y *= ( value
( 'h' ) / $path_h ) if ( defined( $path_h ) );
863 if ( $#quadratic_bezier >= 0 ) {
864 my %points = ( 'x' => $last_pos_x, 'y' => $last_pos_y );
865 push( @quadratic_bezier, \
%points );
868 add_point_to_path
( $last_pos_x, $last_pos_y );
871 elsif ( ( $element eq "arcTo" ) && ( $last_pos_x ne "" ) && ( $last_pos_y ne "" ) ) {
872 # there's no exact equivalent of arcTo in VML, so we have to
873 # compute here a bit...
874 my $stAng = value
( $attr{'stAng'} );
875 my $swAng = value
( $attr{'swAng'} );
876 my $wR = value
( $attr{'wR'} );
877 my $hR = value
( $attr{'hR'} );
879 $wR *= ( value
( 'w' ) / $path_w ) if ( defined( $path_w ) );
880 $hR *= ( value
( 'h' ) / $path_h ) if ( defined( $path_h ) );
882 if ( ( $stAng =~ /^[0-9-]+$/ ) && ( $swAng =~ /^[0-9-]+$/ ) ) {
883 if ( ( ( $stAng % 90 ) == 0 ) && ( ( $swAng % 90 ) == 0 ) && ( $swAng != 0 ) ) {
884 my $end = $stAng + $swAng;
885 my $step = ( $swAng > 0 )?
90: -90;
887 for ( my $cur = $stAng; $cur != $end; $cur += $step ) {
888 elliptic_quadrant
( $wR, $hR, ( $cur % 360 ), $step );
892 error
( "Unsupported numeric 'arcTo' ($attr{'wR'}, $attr{'hR'}, $stAng, $swAng)." );
896 error
( "Unsupported 'arcTo' conversion ($attr{'wR'}, $attr{'hR'}, $stAng, $swAng)." );
900 error
( "Unhandled path element '$element'." );
903 elsif ( $state eq "adjust" ) {
904 if ( $element eq "gd" ) {
905 my $adj_no = $attr{'name'};
909 if ( $adj_no eq "" ) {
912 elsif ( !( $adj_no =~ /^[0-9]*$/ ) ) {
916 elsif ( $adj_no != $max_adj_no + 1 ) {
917 error
( "Wrong order of adj values." );
921 $max_adj_no = $adj_no;
924 if ( $attr{'fmla'} =~ /^val ([0-9-]*)$/ ) {
925 my $val = sprintf( "%.0f", ( 21600 * $1 ) / 100000 );
927 $variables{$adj_no} = $val;
929 elsif ( $adjust eq "" ) {
933 $adjust = "$val,$adjust";
937 error
( "Wrong fmla '$attr{'fmla'}'." );
941 error
( "Unhandled adjust element '$element'." );
944 elsif ( $state eq "formulas" ) {
945 if ( $element eq "gd" ) {
946 if ( $attr{'fmla'} =~ /^\*\/ (h
|w
|ss
) adj
([0-9]+) 100000$/ ) {
947 insert_formula
( $attr{'name'}, "val #" . ( $max_adj_no - $2 ) );
949 elsif ( $attr{'fmla'} =~ /^pin [^ ]+ ([^ ]+) / ) {
950 print STDERR
"TODO Map 'pin' to VML as xrange for handles.\n";
952 if ( $pin_val eq "adj" ) {
953 insert_formula
( $attr{'name'}, "val #0" );
955 elsif ( $pin_val =~ /^adj([0-9]+)/ ) {
956 insert_formula
( $attr{'name'}, "val #" . ( $max_adj_no - $1 ) );
959 insert_formula
( $attr{'name'}, "val " . value
( $pin_val ) );
962 elsif ( $attr{'fmla'} =~ /adj/ ) {
963 error
( "Non-standard usage of adj in '$attr{'fmla'}'." );
966 convert_formula
( $attr{'name'}, $attr{'fmla'} );
970 elsif ( $state eq "handles" ) {
971 if ( $element eq "pos" ) {
972 $handles .= "<v:h position=\"" . value
( $attr{'x'} ) . "," . value
( $attr{'y'} ) . "\"/>\n";
980 my ( $element ) = @_;
984 if ( $element eq $shape_name ) {
985 if ( !$ignore_this_shape ) {
986 # we have all the info, generate the shape now
990 my $out = "<v:shapetype id=\"shapetype___ID__\" coordsize=\"21600,21600\" o:spt=\"__ID__\" ";
991 if ( $adjust ne "" ) {
992 $out .= "adj=\"$adjust\" ";
995 # optimize it [yes, we need this twice ;-)]
996 $path =~ s/([^0-9-@])0([^0-9-@])/$1$2/g;
997 $path =~ s/([^0-9-@])0([^0-9-@])/$1$2/g;
999 $out .= "path=\"$path\">\n";
1002 $out .= "<v:stroke joinstyle=\"miter\"/>\n";
1005 if ( $#formulas >= 0 )
1007 $out .= "<v:formulas>\n";
1008 foreach $fmla ( @formulas ) {
1009 $out .= "<v:f eqn=\"$fmla\"/>\n"
1011 $out .= "</v:formulas>\n";
1015 if ( $textboxrect ne "" ) { # TODO connectlocs, connectangles
1016 $out .= "<v:path gradientshapeok=\"t\" o:connecttype=\"rect\" textboxrect=\"$textboxrect\"/>\n";
1020 if ( $handles ne "" ) {
1021 $out .= "<v:handles>\n$handles</v:handles>\n";
1024 $out .="</v:shapetype>";
1027 $result_shapes{$shape_name} = $out;
1030 print STDERR
"Shape '$shape_name' ignored; see the above error(s) for the reason.\n";
1034 elsif ( $state eq "path" ) {
1035 if ( $element eq "path" ) {
1036 $path .= "ns" if ( $no_stroke );
1037 $path .= "nf" if ( $no_fill );
1040 elsif ( $element eq "quadBezTo" ) {
1041 # we have to convert the quadratic bezier to cubic
1042 if ( $#quadratic_bezier == 2 ) {
1043 my @points_x = quadratic_to_cubic_bezier
( 'x' );
1044 my @points_y = quadratic_to_cubic_bezier
( 'y' );
1047 # ignore the starting point
1048 for ( my $i = 1; $i < 4; ++$i ) {
1049 add_point_to_path
( $points_x[$i], $points_y[$i] );
1053 error
( "Wrong number of points of the quadratic bezier." );
1055 @quadratic_bezier = ();
1058 elsif ( $element eq "avLst" ) {
1061 elsif ( $element eq "gdLst" ) {
1064 elsif ( $element eq "ahLst" ) {
1069 # Text inside an element
1075 #################### A trivial XML parser ####################
1077 # Parse the attributes
1078 sub parse_start_element
( $ )
1080 # split the string containing both the elements and attributes
1081 my ( $element_tmp ) = @_;
1083 $element_tmp =~ s/\s*$//;
1084 $element_tmp =~ s/^\s*//;
1086 ( my $element = $element_tmp ) =~ s/\s.*$//;
1087 if ( $element_tmp =~ /\s/ ) {
1088 $element_tmp =~ s/^[^\s]*\s//;
1094 # we have the element, now the attributes
1098 foreach my $tmp ( split( /"/, $element_tmp ) ) {
1102 $key =~ s/\s*=\s*$//;
1110 if ( $element ne "" ) {
1111 start_element
( $element, %attr );
1130 elsif ( /-->/ && $in_comment ) {
1134 elsif ( $in_comment ) {
1137 # ignore empty lines
1141 next if ( $_ eq "" );
1143 # take care of lines where element continues
1144 if ( $line ne "" ) {
1152 # the actual parsing
1153 my @starts = split( /</, $line );
1155 foreach $start ( @starts ) {
1156 next if ( $start eq "" );
1158 @ends = split( />/, $start );
1159 my $element = $ends[0];
1160 my $data = $ends[1];
1162 # start or end element
1163 if ( $element =~ /^\/(.*)/ ) {
1166 elsif ( $element =~ /^(.*)\/$/ ) {
1167 parse_start_element
( $1 );
1168 ( my $end = $1 ) =~ s/\s.*$//;
1169 end_element
( $end );
1172 parse_start_element
( $element );
1176 characters
( $data ) if ( defined( $data ) && $data ne "" );
1182 open( IN
, "<$src_shapes" ) || die "Cannot open $src_shapes.";
1186 open( IN
, "<$src_text" ) || die "Cannot open $src_text.";
1190 if ( !defined( $result_shapes{'textBox'} ) ) {
1191 $result_shapes{'textBox'} =
1192 "<v:shapetype id=\"shapetype___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" .
1201 // Shape types generated from
1205 // which are part of the OOXML documentation
1207 #include <svx/escherex.hxx>
1209 const char* pShapeTypes[ ESCHER_ShpInst_COUNT ] =
1213 for ( $i = 0; $i < 203; ++$i ) {
1215 print " /* $i - $shapes_ids{$i} - handled separately */\n NULL,\n";
1218 print " /* $i - $shapes_ids{$i} */\n";
1219 my $out = $result_shapes{$shapes_ids{$i}};
1220 if ( defined( $out ) ) {
1222 $out =~ s/__ID__/$i/g;
1229 $out =~ s/\n/"\n "/g;