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