Bump version to 4.1-6
[LibreOffice.git] / writerfilter / source / dmapper / ConversionHelper.cxx
blobbb1f204993eb34527449d2194329049322743333
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
19 #include <ConversionHelper.hxx>
20 #include <com/sun/star/table/BorderLine2.hpp>
21 #include <com/sun/star/table/BorderLineStyle.hpp>
22 #include <com/sun/star/lang/Locale.hpp>
23 #include <com/sun/star/text/HoriOrientation.hpp>
24 #include <com/sun/star/style/NumberingType.hpp>
25 #include <editeng/borderline.hxx>
26 #include <ooxml/resourceids.hxx>
27 #include <rtl/ustrbuf.hxx>
28 #include <tools/color.hxx>
29 #include <algorithm>
30 #include <functional>
32 using namespace com::sun::star;
33 using namespace com::sun::star::table::BorderLineStyle;
35 namespace writerfilter {
36 namespace dmapper{
37 namespace ConversionHelper{
39 const sal_Int16 API_LINE_SOLID = 0;
40 const sal_Int16 API_LINE_DOTTED = 1;
41 const sal_Int16 API_LINE_DASHED = 2;
43 #define TWIP_TO_MM100(TWIP) ((TWIP) >= 0 ? (((TWIP)*127L+36L)/72L) : (((TWIP)*127L-36L)/72L))
45 sal_Int32 MakeBorderLine( sal_Int32 nSprmValue, table::BorderLine2& rToFill )
47 //TODO: Lines are always solid
48 //Border
49 //borders are defined as:
50 // 0x XX XX XX XX
51 // || || || ||
52 // || || || ---- Line width in 1/8 pt
53 // || || ||
54 // || || ------- Line type: 0 - none 1 - single ... 25 - engrave 3D and 64 - 230 page borders
55 // || ||
56 // || ---------- Line color
57 // ||
58 // ------------- seven bits line space
59 // -------------- first bit: with shading
60 sal_Int16 nLineThicknessTwip = (sal_Int16)((nSprmValue & 0xff) * 20)/8L ;
61 sal_Int32 nLineType = ((nSprmValue & 0xff00) >> 8);
62 sal_Int32 nLineColor = (nSprmValue & 0xff0000)>>16;
63 sal_Int32 nLineDistance = (((nSprmValue & 0x3f000000)>>24) * 2540 + 36)/72L;
64 MakeBorderLine( nLineThicknessTwip, nLineType, nLineColor, rToFill, false);
65 return nLineDistance;
67 void MakeBorderLine( sal_Int32 nLineThickness, sal_Int32 nLineType,
68 sal_Int32 nLineColor,
69 table::BorderLine2& rToFill, bool bIsOOXML )
71 static const sal_Int32 aBorderDefColor[] =
73 // The first item means automatic color (COL_AUTO), but we
74 // do not use it anyway (see the next statement) .-)
75 0, COL_BLACK, COL_LIGHTBLUE, COL_LIGHTCYAN, COL_LIGHTGREEN,
76 COL_LIGHTMAGENTA, COL_LIGHTRED, COL_YELLOW, COL_WHITE, COL_BLUE,
77 COL_CYAN, COL_GREEN, COL_MAGENTA, COL_RED, COL_BROWN, COL_GRAY,
78 COL_LIGHTGRAY
80 //no auto color for borders
81 if(!nLineColor)
82 ++nLineColor;
83 if(!bIsOOXML && sal::static_int_cast<sal_uInt32>(nLineColor) < SAL_N_ELEMENTS(aBorderDefColor))
84 nLineColor = aBorderDefColor[nLineColor];
86 // Map to our border types, we should use of one equal line
87 // thickness, or one of smaller thickness. If too small we
88 // can make the defecit up in additional white space or
89 // object size
90 ::editeng::SvxBorderStyle const nLineStyle(
91 ::editeng::ConvertBorderStyleFromWord(nLineType));
92 rToFill.LineStyle = nLineStyle;
93 double const fConverted( (NONE == nLineStyle) ? 0.0 :
94 ::editeng::ConvertBorderWidthFromWord(nLineStyle, nLineThickness,
95 nLineType));
96 rToFill.LineWidth = convertTwipToMM100(fConverted);
97 rToFill.Color = nLineColor;
100 namespace {
101 void lcl_SwapQuotesInField(OUString &rFmt)
103 //Swap unescaped " and ' with ' and "
104 sal_Int32 nLen = rFmt.getLength();
105 OUStringBuffer aBuffer( rFmt.getStr() );
106 const sal_Unicode* pFmt = rFmt.getStr();
107 for (sal_Int32 nI = 0; nI < nLen; ++nI)
109 if ((pFmt[nI] == '\"') && (!nI || pFmt[nI-1] != '\\'))
110 aBuffer[nI] = '\'';
111 else if ((pFmt[nI] == '\'') && (!nI || pFmt[nI-1] != '\\'))
112 aBuffer[nI] = '\"';
114 rFmt = aBuffer.makeStringAndClear();
116 bool lcl_IsNotAM(OUString& rFmt, sal_Int32 nPos)
118 return (
119 (nPos == rFmt.getLength() - 1) ||
121 (rFmt[nPos+1] != 'M') &&
122 (rFmt[nPos+1] != 'm')
128 OUString ConvertMSFormatStringToSO(
129 const OUString& rFormat, lang::Locale& rLocale, bool bHijri)
131 OUString sFormat(rFormat);
132 lcl_SwapQuotesInField(sFormat);
134 //#102782#, #102815#, #108341# & #111944# have to work at the same time :-)
135 bool bForceJapanese(false);
136 bool bForceNatNum(false);
137 sal_Int32 nLen = sFormat.getLength();
138 sal_Int32 nI = 0;
139 // const sal_Unicode* pFormat = sFormat.getStr();
140 OUStringBuffer aNewFormat( sFormat );
141 while (nI < nLen)
143 if (aNewFormat[nI] == '\\')
144 nI++;
145 else if (aNewFormat[nI] == '\"')
147 ++nI;
148 //While not at the end and not at an unescaped end quote
149 while ((nI < nLen) && (!(aNewFormat[nI] == '\"') && (aNewFormat[nI-1] != '\\')))
150 ++nI;
152 else //normal unquoted section
154 sal_Unicode nChar = aNewFormat[nI];
155 if (nChar == 'O')
157 aNewFormat[nI] = 'M';
158 bForceNatNum = true;
160 else if (nChar == 'o')
162 aNewFormat[nI] = 'm';
163 bForceNatNum = true;
165 else if ((nChar == 'A') && lcl_IsNotAM(sFormat, nI))
167 aNewFormat[nI] = 'D';
168 bForceNatNum = true;
170 else if ((nChar == 'g') || (nChar == 'G'))
171 bForceJapanese = true;
172 else if ((nChar == 'a') && lcl_IsNotAM(sFormat, nI))
173 bForceJapanese = true;
174 else if (nChar == 'E')
176 if ((nI != nLen-1) && (aNewFormat[nI+1] == 'E'))
178 //todo: this cannot be the right way to replace a part of the string!
179 aNewFormat[nI] = 'Y';
180 aNewFormat[nI + 1] = 'Y';
181 aNewFormat.insert(nI + 2, "YY");
182 nLen+=2;
183 nI+=3;
185 bForceJapanese = true;
187 else if (nChar == 'e')
189 if ((nI != nLen-1) && (aNewFormat[nI+1] == 'e'))
191 //todo: this cannot be the right way to replace a part of the string!
192 aNewFormat[nI] = 'y';
193 aNewFormat[nI + 1] = 'y';
194 aNewFormat.insert(nI + 2, "yy");
195 nLen+=2;
196 nI+=3;
198 bForceJapanese = true;
200 else if (nChar == '/')
202 // MM We have to escape '/' in case it's used as a char
203 //todo: this cannot be the right way to replace a part of the string!
204 aNewFormat[nI] = '\\';
205 aNewFormat.insert(nI + 1, "/");
206 nI++;
207 nLen++;
210 ++nI;
213 if (bForceNatNum)
214 bForceJapanese = true;
216 if (bForceJapanese)
218 rLocale.Language = "ja";
219 rLocale.Country = "JP";
222 if (bForceNatNum)
224 aNewFormat.insert( 0, "[NatNum1][$-411]");
227 if (bHijri)
229 aNewFormat.insert( 0, "[~hijri]");
231 return aNewFormat.makeStringAndClear();
236 sal_Int32 convertTwipToMM100(sal_Int32 _t)
238 return TWIP_TO_MM100( _t );
242 sal_Int32 convertEMUToMM100(sal_Int32 _t)
244 return _t / 360;
247 /*-------------------------------------------------------------------------
248 contains a color from 0xTTRRGGBB to 0xTTRRGGBB
249 -----------------------------------------------------------------------*/
250 sal_Int32 ConvertColor(sal_Int32 nWordColor)
252 sal_uInt8
253 r(static_cast<sal_uInt8>(nWordColor&0xFF)),
254 g(static_cast<sal_uInt8>(((nWordColor)>>8)&0xFF)),
255 b(static_cast<sal_uInt8>((nWordColor>>16)&0xFF)),
256 t(static_cast<sal_uInt8>((nWordColor>>24)&0xFF));
257 sal_Int32 nRet = (t<<24) + (r<<16) + (g<<8) + b;
258 return nRet;
262 sal_Int16 convertTableJustification( sal_Int32 nIntValue )
264 sal_Int16 nOrient = text::HoriOrientation::LEFT_AND_WIDTH;
265 switch( nIntValue )
267 case 1 : nOrient = text::HoriOrientation::CENTER; break;
268 case 2 : nOrient = text::HoriOrientation::RIGHT; break;
269 case 0 :
270 //no break
271 default:;
274 return nOrient;
277 sal_Int16 ConvertNumberingType(sal_Int32 nNFC)
279 sal_Int16 nRet;
280 switch(nNFC)
282 case NS_ooxml::LN_Value_ST_NumberFormat_decimal:
283 case 0:
284 nRet = style::NumberingType::ARABIC;
285 break;
286 case NS_ooxml::LN_Value_ST_NumberFormat_upperRoman:
287 case 1:
288 nRet = style::NumberingType::ROMAN_UPPER;
289 break;
290 case NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman:
291 case 2:
292 nRet = style::NumberingType::ROMAN_LOWER;
293 break;
294 case 3:
295 nRet = style::NumberingType::CHARS_UPPER_LETTER_N;
296 break;
297 case 4:
298 nRet = style::NumberingType::CHARS_LOWER_LETTER_N;
299 break;
300 case 5:
301 nRet = style::NumberingType::ARABIC;
302 break;//ORDINAL
303 case NS_ooxml::LN_Value_ST_NumberFormat_bullet:
304 case 23:
305 case 25:
306 nRet = style::NumberingType::CHAR_SPECIAL;
307 break;
308 case NS_ooxml::LN_Value_ST_NumberFormat_none:
309 case 255:
310 nRet = style::NumberingType::NUMBER_NONE;
311 break;
312 case NS_ooxml::LN_Value_ST_NumberFormat_upperLetter:
313 nRet = style::NumberingType::CHARS_UPPER_LETTER;
314 break;
315 case NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter:
316 nRet = style::NumberingType::CHARS_LOWER_LETTER;
317 break;
318 case NS_ooxml::LN_Value_ST_NumberFormat_iroha:
319 nRet = style::NumberingType::IROHA_HALFWIDTH_JA;
320 break;
321 case NS_ooxml::LN_Value_ST_NumberFormat_irohaFullWidth:
322 nRet = style::NumberingType::IROHA_FULLWIDTH_JA;
323 break;
324 case NS_ooxml::LN_Value_ST_NumberFormat_aiueo:
325 nRet = style::NumberingType::AIU_HALFWIDTH_JA;
326 break;
327 case NS_ooxml::LN_Value_ST_NumberFormat_aiueoFullWidth:
328 nRet = style::NumberingType::AIU_FULLWIDTH_JA;
329 break;
330 case NS_ooxml::LN_Value_ST_NumberFormat_hebrew2:
331 nRet = style::NumberingType::CHARS_HEBREW;
332 break;
333 case NS_ooxml::LN_Value_ST_NumberFormat_thaiLetters:
334 nRet = style::NumberingType::CHARS_THAI;
335 break;
336 case NS_ooxml::LN_Value_ST_NumberFormat_russianLower:
337 nRet = style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_RU;
338 break;
339 case NS_ooxml::LN_Value_ST_NumberFormat_russianUpper:
340 nRet = style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_RU;
341 break;
342 case NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese:
343 case NS_ooxml::LN_Value_ST_NumberFormat_ideographEnclosedCircle:
344 nRet = style::NumberingType::CIRCLE_NUMBER;
345 break;
346 case NS_ooxml::LN_Value_ST_NumberFormat_ideographTraditional:
347 nRet = style::NumberingType::TIAN_GAN_ZH;
348 break;
349 case NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiac:
350 nRet = style::NumberingType::DI_ZI_ZH;
351 break;
352 case NS_ooxml::LN_Value_ST_NumberFormat_ganada:
353 nRet = style::NumberingType::HANGUL_SYLLABLE_KO;
354 break;
355 case NS_ooxml::LN_Value_ST_NumberFormat_chosung:
356 nRet = style::NumberingType::HANGUL_JAMO_KO;
357 break;
358 case NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital:
359 case NS_ooxml::LN_Value_ST_NumberFormat_koreanCounting:
360 case NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital2:
361 nRet = style::NumberingType::NUMBER_HANGUL_KO;
362 break;
363 case NS_ooxml::LN_Value_ST_NumberFormat_ideographLegalTraditional:
364 nRet = style::NumberingType::NUMBER_UPPER_ZH_TW;
365 break;
366 case NS_ooxml::LN_Value_ST_NumberFormat_arabicAlpha:
367 nRet = style::NumberingType::CHARS_ARABIC;
368 break;
369 case NS_ooxml::LN_Value_ST_NumberFormat_hindiVowels:
370 nRet = style::NumberingType::CHARS_NEPALI;
371 break;
372 case NS_ooxml::LN_Value_ST_NumberFormat_japaneseLegal:
373 nRet = style::NumberingType::NUMBER_TRADITIONAL_JA;
374 break;
375 case NS_ooxml::LN_Value_ST_NumberFormat_chineseCounting:
376 case NS_ooxml::LN_Value_ST_NumberFormat_japaneseCounting:
377 case NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCounting:
378 case NS_ooxml::LN_Value_ST_NumberFormat_ideographDigital:
379 case NS_ooxml::LN_Value_ST_NumberFormat_chineseCountingThousand:
380 nRet = style::NumberingType::NUMBER_LOWER_ZH;
381 break;
382 case NS_ooxml::LN_Value_ST_NumberFormat_chineseLegalSimplified:
383 nRet = style::NumberingType::NUMBER_UPPER_ZH;
384 break;
385 default: nRet = style::NumberingType::ARABIC;
387 /* TODO: Lots of additional values are available - some are supported in the I18 framework
388 NS_ooxml::LN_Value_ST_NumberFormat_ordinal = 91682;
389 NS_ooxml::LN_Value_ST_NumberFormat_cardinalText = 91683;
390 NS_ooxml::LN_Value_ST_NumberFormat_ordinalText = 91684;
391 NS_ooxml::LN_Value_ST_NumberFormat_hex = 91685;
392 NS_ooxml::LN_Value_ST_NumberFormat_chicago = 91686;
393 NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth = 91691;
394 NS_ooxml::LN_Value_ST_NumberFormat_decimalHalfWidth = 91692;
395 NS_ooxml::LN_Value_ST_NumberFormat_japaneseDigitalTenThousand = 91694;
396 NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircle = 91695;
397 NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth2 = 91696;
398 NS_ooxml::LN_Value_ST_NumberFormat_decimalZero = 91699;
399 NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedFullstop = 91703;
400 NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedParen = 91704;
401 NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiacTraditional = 91709;
402 NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCountingThousand = 91712;
403 NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseDigital = 91713;
404 NS_ooxml::LN_Value_ST_NumberFormat_chineseLegalSimplified = 91715;
405 NS_ooxml::LN_Value_ST_NumberFormat_chineseCountingThousand = 91716;
406 NS_ooxml::LN_Value_ST_NumberFormat_koreanLegal = 91719;
407 NS_ooxml::LN_Value_ST_NumberFormat_vietnameseCounting = 91721;
408 NS_ooxml::LN_Value_ST_NumberFormat_numberInDash = 91725;
409 NS_ooxml::LN_Value_ST_NumberFormat_arabicAbjad:
410 NS_ooxml::LN_Value_ST_NumberFormat_hebrew1 = 91726;
411 NS_ooxml::LN_Value_ST_NumberFormat_hindiConsonants = 91731;
412 NS_ooxml::LN_Value_ST_NumberFormat_hindiNumbers = 91732;
413 NS_ooxml::LN_Value_ST_NumberFormat_hindiCounting = 91733;
414 NS_ooxml::LN_Value_ST_NumberFormat_thaiNumbers = 91735;
415 NS_ooxml::LN_Value_ST_NumberFormat_thaiCounting = 91736;*/
416 return nRet;
420 } // namespace ConversionHelper
421 } //namespace dmapper
422 } //namespace writerfilter
424 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */