xref: /trunk/main/xmloff/source/core/xmlehelp.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_xmloff.hxx"
30 #include <limits.h>
31 #include <tools/debug.hxx>
32 #include <tools/bigint.hxx>
33 #include <rtl/ustrbuf.hxx>
34 #include "xmlehelp.hxx"
35 
36 #ifndef _XMLOFF_XMTOKEN_HXX
37 #include <xmloff/xmltoken.hxx>
38 #endif
39 
40 using ::rtl::OUString;
41 using ::rtl::OUStringBuffer;
42 
43 using namespace ::xmloff::token;
44 
45 void SvXMLExportHelper::AddLength( sal_Int32 nValue, MapUnit eValueUnit,
46                                    OUStringBuffer& rOut,
47                                    MapUnit eOutUnit )
48 {
49     // the sign is processed seperatly
50     if( nValue < 0 )
51     {
52         nValue = -nValue;
53         rOut.append( sal_Unicode('-') );
54     }
55 
56     // The new length is (nVal * nMul)/(nDiv*nFac*10)
57     sal_Int32 nMul = 1000;
58     sal_Int32 nDiv = 1;
59     sal_Int32 nFac = 100;
60     enum XMLTokenEnum eUnit = XML_TOKEN_INVALID;
61     switch( eValueUnit )
62     {
63     case MAP_TWIP:
64         switch( eOutUnit )
65         {
66         case MAP_100TH_MM:
67         case MAP_10TH_MM:
68             DBG_ASSERT( MAP_INCH == eOutUnit,
69                         "output unit not supported for twip values" );
70         case MAP_MM:
71             // 0.01mm = 0.57twip (exactly)
72             nMul = 25400;   // 25.4 * 1000
73             nDiv = 1440;    // 72 * 20;
74             nFac = 100;
75             eUnit = XML_UNIT_MM;
76             break;
77 
78         case MAP_CM:
79             // 0.001cm = 0.57twip (exactly)
80             nMul = 25400;   // 2.54 * 10000
81             nDiv = 1440;    // 72 * 20;
82             nFac = 1000;
83             eUnit = XML_UNIT_CM;
84             break;
85 
86         case MAP_POINT:
87             // 0.01pt = 0.2twip (exactly)
88             nMul = 1000;
89             nDiv = 20;
90             nFac = 100;
91             eUnit = XML_UNIT_PT;
92             break;
93 
94         case MAP_INCH:
95         default:
96             DBG_ASSERT( MAP_INCH == eOutUnit,
97                         "output unit not supported for twip values" );
98             // 0.0001in = 0.144twip (exactly)
99             nMul = 100000;
100             nDiv = 1440;    // 72 * 20;
101             nFac = 10000;
102             eUnit = XML_UNIT_INCH;
103             break;
104         }
105         break;
106 
107     case MAP_POINT:
108         // 1pt = 1pt (exactly)
109         DBG_ASSERT( MAP_POINT == eOutUnit,
110                     "output unit not supported for pt values" );
111         nMul = 10;
112         nDiv = 1;
113         nFac = 1;
114         eUnit = XML_UNIT_PT;
115         break;
116     case MAP_10TH_MM:
117     case MAP_100TH_MM:
118         {
119             long nFac2 = (MAP_100TH_MM == eValueUnit) ? 100 : 10;
120             switch( eOutUnit )
121             {
122             case MAP_100TH_MM:
123             case MAP_10TH_MM:
124                 DBG_ASSERT( MAP_INCH == eOutUnit,
125                             "output unit not supported for 1/100mm values" );
126             case MAP_MM:
127                 // 0.01mm = 1 mm/100 (exactly)
128                 nMul = 10;
129                 nDiv = 1;
130                 nFac = nFac2;
131                 eUnit = XML_UNIT_MM;
132                 break;
133 
134             case MAP_CM:
135                 // 0.001mm = 1 mm/100 (exactly)
136                 nMul = 10;
137                 nDiv = 1;   // 72 * 20;
138                 nFac = 10*nFac2;
139                 eUnit = XML_UNIT_CM;
140                 break;
141 
142             case MAP_POINT:
143                 // 0.01pt = 0.35 mm/100 (exactly)
144                 nMul = 72000;
145                 nDiv = 2540;
146                 nFac = nFac2;
147                 eUnit = XML_UNIT_PT;
148                 break;
149 
150             case MAP_INCH:
151             default:
152                 DBG_ASSERT( MAP_INCH == eOutUnit,
153                             "output unit not supported for 1/100mm values" );
154                 // 0.0001in = 0.254 mm/100 (exactly)
155                 nMul = 100000;
156                 nDiv = 2540;
157                 nFac = 100*nFac2;
158                 eUnit = XML_UNIT_INCH;
159                 break;
160             }
161             break;
162         }
163         default:
164             DBG_ASSERT( 0, "input unit not handled" );
165             break;
166     }
167 
168 
169     sal_Int32 nLongVal = 0;
170     sal_Bool bOutLongVal = sal_True;
171     if( nValue > SAL_MAX_INT32 / nMul )
172     {
173         // A big int is required for calculation
174         BigInt nBigVal( nValue );
175         nBigVal *= nMul;
176         nBigVal /= nDiv;
177         nBigVal += 5;
178         nBigVal /= 10;
179 
180         if( nBigVal.IsLong() )
181         {
182             // To convert the value into a string a sal_Int32 is sufficient
183             nLongVal = sal_Int32( nBigVal );
184         }
185         else
186         {
187             BigInt nBigFac( nFac );
188             BigInt nBig10( 10 );
189             rOut.append( (sal_Int32)(nBigVal / nBigFac) );
190             if( !(nBigVal % nBigFac).IsZero() )
191             {
192                 rOut.append( sal_Unicode('.') );
193                 while( nFac > 1 && !(nBigVal % nBigFac).IsZero() )
194                 {
195                     nFac /= 10;
196                     nBigFac = nFac;
197                     rOut.append( (sal_Int32)((nBigVal / nBigFac) % nBig10 ) );
198                 }
199             }
200             bOutLongVal = sal_False;
201         }
202     }
203     else
204     {
205         nLongVal = nValue * nMul;
206         nLongVal /= nDiv;
207         nLongVal += 5;
208         nLongVal /= 10;
209     }
210 
211     if( bOutLongVal )
212     {
213         rOut.append( (sal_Int32)(nLongVal / nFac) );
214         if( nFac > 1 && (nLongVal % nFac) != 0 )
215         {
216             rOut.append( sal_Unicode('.') );
217             while( nFac > 1 && (nLongVal % nFac) != 0 )
218             {
219                 nFac /= 10;
220                 rOut.append( (sal_Int32)((nLongVal / nFac) % 10) );
221             }
222         }
223     }
224 
225     if( eUnit != XML_TOKEN_INVALID )
226         rOut.append( GetXMLToken(eUnit) );
227 }
228 
229 void SvXMLExportHelper::AddPercentage( sal_Int32 nValue, OUStringBuffer& rOut )
230 {
231     rOut.append( nValue );
232     rOut.append( sal_Unicode('%' ) );
233 }
234 
235 double SvXMLExportHelper::GetConversionFactor(::rtl::OUStringBuffer& rUnit,
236     const MapUnit eCoreUnit, const MapUnit eDestUnit)
237 {
238     double fRetval(1.0);
239     rUnit.setLength(0L);
240 
241     if(eCoreUnit != eDestUnit)
242     {
243         enum XMLTokenEnum eUnit = XML_TOKEN_INVALID;
244 
245         switch(eCoreUnit)
246         {
247             case MAP_TWIP:
248             {
249                 switch(eDestUnit)
250                 {
251                     case MAP_100TH_MM:
252                     case MAP_10TH_MM:
253                     {
254                         DBG_ASSERT(MAP_INCH == eDestUnit, "output unit not supported for twip values");
255                     }
256                     case MAP_MM:
257                     {
258                         // 0.01mm = 0.57twip (exactly)
259                         fRetval = ((25400.0 / 1440.0) / 1000.0);
260                         eUnit = XML_UNIT_MM;
261                         break;
262                     }
263                     case MAP_CM:
264                     {
265                         // 0.001cm = 0.57twip (exactly)
266                         fRetval = ((25400.0 / 1440.0) / 10000.0);
267                         eUnit = XML_UNIT_CM;
268                         break;
269                     }
270                     case MAP_POINT:
271                     {
272                         // 0.01pt = 0.2twip (exactly)
273                         fRetval = ((1000.0 / 20.0) / 1000.0);
274                         eUnit = XML_UNIT_PT;
275                         break;
276                     }
277                     case MAP_INCH:
278                     default:
279                     {
280                         DBG_ASSERT(MAP_INCH == eDestUnit, "output unit not supported for twip values");
281                         // 0.0001in = 0.144twip (exactly)
282                         fRetval = ((100000.0 / 1440.0) / 100000.0);
283                         eUnit = XML_UNIT_INCH;
284                         break;
285                     }
286                 }
287                 break;
288             }
289             case MAP_POINT:
290             {
291                 switch(eDestUnit)
292                 {
293                     case MAP_MM:
294                         // 1mm = 72 / 25.4 pt (exactly)
295                         fRetval = ( 25.4 / 72.0 );
296                         eUnit = XML_UNIT_MM;
297                         break;
298 
299                     case MAP_CM:
300                         // 1cm = 72 / 2.54 pt (exactly)
301                         fRetval = ( 2.54 / 72.0 );
302                         eUnit = XML_UNIT_CM;
303                         break;
304 
305                     case MAP_TWIP:
306                         // 1twip = 72 / 1440 pt (exactly)
307                         fRetval = 20.0;     // 1440.0 / 72.0
308                         eUnit = XML_UNIT_PC;
309                         break;
310 
311                     case MAP_INCH:
312                     default:
313                         DBG_ASSERT(MAP_INCH == eDestUnit, "output unit not supported for pt values");
314                         // 1in = 72 pt (exactly)
315                         fRetval = ( 1.0 / 72.0 );
316                         eUnit = XML_UNIT_INCH;
317                         break;
318                 }
319                 break;
320             }
321             case MAP_10TH_MM:
322             {
323                 switch(eDestUnit)
324                 {
325                     case MAP_100TH_MM:
326                     case MAP_10TH_MM:
327                     {
328                         DBG_ASSERT(MAP_INCH == eDestUnit, "output unit not supported for 1/100mm values");
329                     }
330                     case MAP_MM:
331                     {
332                         // 0.01mm = 1 mm/100 (exactly)
333                         fRetval = ((10.0 / 1.0) / 100.0);
334                         eUnit = XML_UNIT_MM;
335                         break;
336                     }
337                     case MAP_CM:
338                     {
339                         // 0.001mm = 1 mm/100 (exactly)
340                         fRetval = ((10.0 / 1.0) / 1000.0);
341                         eUnit = XML_UNIT_CM;
342                         break;
343                     }
344                     case MAP_POINT:
345                     {
346                         // 0.01pt = 0.35 mm/100 (exactly)
347                         fRetval = ((72000.0 / 2540.0) / 100.0);
348                         eUnit = XML_UNIT_PT;
349                         break;
350                     }
351                     case MAP_INCH:
352                     default:
353                     {
354                         DBG_ASSERT(MAP_INCH == eDestUnit, "output unit not supported for 1/100mm values");
355                         // 0.0001in = 0.254 mm/100 (exactly)
356                         fRetval = ((100000.0 / 2540.0) / 10000.0);
357                         eUnit = XML_UNIT_INCH;
358                         break;
359                     }
360                 }
361                 break;
362             }
363             case MAP_100TH_MM:
364             {
365                 switch(eDestUnit)
366                 {
367                     case MAP_100TH_MM:
368                     case MAP_10TH_MM:
369                     {
370                         DBG_ASSERT(MAP_INCH == eDestUnit, "output unit not supported for 1/100mm values");
371                     }
372                     case MAP_MM:
373                     {
374                         // 0.01mm = 1 mm/100 (exactly)
375                         fRetval = ((10.0 / 1.0) / 1000.0);
376                         eUnit = XML_UNIT_MM;
377                         break;
378                     }
379                     case MAP_CM:
380                     {
381                         // 0.001mm = 1 mm/100 (exactly)
382                         fRetval = ((10.0 / 1.0) / 10000.0);
383                         eUnit = XML_UNIT_CM;
384                         break;
385                     }
386                     case MAP_POINT:
387                     {
388                         // 0.01pt = 0.35 mm/100 (exactly)
389                         fRetval = ((72000.0 / 2540.0) / 1000.0);
390                         eUnit = XML_UNIT_PT;
391                         break;
392                     }
393                     case MAP_INCH:
394                     default:
395                     {
396                         DBG_ASSERT(MAP_INCH == eDestUnit, "output unit not supported for 1/100mm values");
397                         // 0.0001in = 0.254 mm/100 (exactly)
398                         fRetval = ((100000.0 / 2540.0) / 100000.0);
399                         eUnit = XML_UNIT_INCH;
400                         break;
401                     }
402                 }
403                 break;
404             }
405             default:
406                 DBG_ERROR("xmloff::SvXMLExportHelper::GetConversionFactor(), illegal eCoreUnit value!");
407                 break;
408         }
409 
410         if(eUnit != XML_TOKEN_INVALID)
411             rUnit.append(GetXMLToken(eUnit));
412     }
413 
414     return fRetval;
415 }
416 
417 MapUnit SvXMLExportHelper::GetUnitFromString(const ::rtl::OUString& rString, MapUnit eDefaultUnit)
418 {
419     sal_Int32 nPos = 0;
420     sal_Int32 nLen = rString.getLength();
421     MapUnit eRetUnit = eDefaultUnit;
422 
423     // skip white space
424     while( nPos < nLen && sal_Unicode(' ') == rString[nPos] )
425         nPos++;
426 
427     // skip negative
428     if( nPos < nLen && sal_Unicode('-') == rString[nPos] )
429         nPos++;
430 
431     // skip number
432     while( nPos < nLen && sal_Unicode('0') <= rString[nPos] && sal_Unicode('9') >= rString[nPos] )
433         nPos++;
434 
435     if( nPos < nLen && sal_Unicode('.') == rString[nPos] )
436     {
437         nPos++;
438         while( nPos < nLen && sal_Unicode('0') <= rString[nPos] && sal_Unicode('9') >= rString[nPos] )
439             nPos++;
440     }
441 
442     // skip white space
443     while( nPos < nLen && sal_Unicode(' ') == rString[nPos] )
444         nPos++;
445 
446     if( nPos < nLen )
447     {
448         switch(rString[nPos])
449         {
450             case sal_Unicode('%') :
451             {
452                 eRetUnit = MAP_RELATIVE;
453                 break;
454             }
455             case sal_Unicode('c'):
456             case sal_Unicode('C'):
457             {
458                 if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('m')
459                     || rString[nPos+1] == sal_Unicode('M')))
460                     eRetUnit = MAP_CM;
461                 break;
462             }
463             case sal_Unicode('e'):
464             case sal_Unicode('E'):
465             {
466                 // CSS1_EMS or CSS1_EMX later
467                 break;
468             }
469             case sal_Unicode('i'):
470             case sal_Unicode('I'):
471             {
472                 if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('n')
473                     || rString[nPos+1] == sal_Unicode('n')))
474                     eRetUnit = MAP_INCH;
475                 break;
476             }
477             case sal_Unicode('m'):
478             case sal_Unicode('M'):
479             {
480                 if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('m')
481                     || rString[nPos+1] == sal_Unicode('M')))
482                     eRetUnit = MAP_MM;
483                 break;
484             }
485             case sal_Unicode('p'):
486             case sal_Unicode('P'):
487             {
488                 if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('t')
489                     || rString[nPos+1] == sal_Unicode('T')))
490                     eRetUnit = MAP_POINT;
491                 if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('c')
492                     || rString[nPos+1] == sal_Unicode('C')))
493                     eRetUnit = MAP_TWIP;
494                 break;
495             }
496         }
497     }
498 
499     return eRetUnit;
500 }
501