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_vcl.hxx"
26 
27 #include "atktextattributes.hxx"
28 
29 #include <com/sun/star/awt/FontSlant.hpp>
30 #include <com/sun/star/awt/FontStrikeout.hpp>
31 #include <com/sun/star/awt/FontUnderline.hpp>
32 
33 #include <com/sun/star/style/CaseMap.hpp>
34 #include <com/sun/star/style/LineSpacing.hpp>
35 #include <com/sun/star/style/LineSpacingMode.hpp>
36 #include <com/sun/star/style/ParagraphAdjust.hpp>
37 #include <com/sun/star/style/TabAlign.hpp>
38 #include <com/sun/star/style/TabStop.hpp>
39 
40 #include <com/sun/star/text/WritingMode2.hpp>
41 
42 #include "atkwrapper.hxx"
43 
44 #include <com/sun/star/accessibility/XAccessibleComponent.hpp>
45 
46 #include <vcl/svapp.hxx>
47 #include <vcl/outdev.hxx>
48 
49 #include <stdio.h>
50 #include <string.h>
51 
52 using namespace ::com::sun::star;
53 
54 typedef gchar* (* AtkTextAttrFunc)       ( const uno::Any& rAny );
55 typedef bool   (* TextPropertyValueFunc) ( uno::Any& rAny, const gchar * value );
56 
57 #define STRNCMP_PARAM( s )  s,sizeof( s )-1
58 
59 
60 /*****************************************************************************/
61 
62 static AtkTextAttribute atk_text_attribute_paragraph_style = ATK_TEXT_ATTR_INVALID;
63 static AtkTextAttribute atk_text_attribute_font_effect = ATK_TEXT_ATTR_INVALID;
64 static AtkTextAttribute atk_text_attribute_decoration = ATK_TEXT_ATTR_INVALID;
65 static AtkTextAttribute atk_text_attribute_line_height = ATK_TEXT_ATTR_INVALID;
66 static AtkTextAttribute atk_text_attribute_rotation = ATK_TEXT_ATTR_INVALID;
67 static AtkTextAttribute atk_text_attribute_shadow = ATK_TEXT_ATTR_INVALID;
68 static AtkTextAttribute atk_text_attribute_tab_interval = ATK_TEXT_ATTR_INVALID;
69 static AtkTextAttribute atk_text_attribute_tab_stops = ATK_TEXT_ATTR_INVALID;
70 static AtkTextAttribute atk_text_attribute_writing_mode = ATK_TEXT_ATTR_INVALID;
71 static AtkTextAttribute atk_text_attribute_vertical_align = ATK_TEXT_ATTR_INVALID;
72 static AtkTextAttribute atk_text_attribute_misspelled = ATK_TEXT_ATTR_INVALID;
73 // --> OD 2010-03-01 #i92232#
74 static AtkTextAttribute atk_text_attribute_tracked_change = ATK_TEXT_ATTR_INVALID;
75 // <--
76 // --> OD 2010-03-05 #i92233#
77 static AtkTextAttribute atk_text_attribute_mm_to_pixel_ratio = ATK_TEXT_ATTR_INVALID;
78 // <--
79 
80 /*****************************************************************************/
81 
82 /**
83   * !! IMPORTANT NOTE !! : when adding items to this list, KEEP THE LIST SORTED
84   *                        and re-arrange the enum values accordingly.
85   */
86 
87 enum ExportedAttribute
88 {
89     TEXT_ATTRIBUTE_BACKGROUND_COLOR = 0,
90     TEXT_ATTRIBUTE_CASEMAP,
91     TEXT_ATTRIBUTE_FOREGROUND_COLOR,
92     TEXT_ATTRIBUTE_CONTOURED,
93     TEXT_ATTRIBUTE_CHAR_ESCAPEMENT,
94     TEXT_ATTRIBUTE_BLINKING,
95     TEXT_ATTRIBUTE_FONT_NAME,
96     TEXT_ATTRIBUTE_HEIGHT,
97     TEXT_ATTRIBUTE_HIDDEN,
98     TEXT_ATTRIBUTE_KERNING,
99     TEXT_ATTRIBUTE_LOCALE,
100     TEXT_ATTRIBUTE_POSTURE,
101     TEXT_ATTRIBUTE_RELIEF,
102     TEXT_ATTRIBUTE_ROTATION,
103     TEXT_ATTRIBUTE_SCALE,
104     TEXT_ATTRIBUTE_SHADOWED,
105     TEXT_ATTRIBUTE_STRIKETHROUGH,
106     TEXT_ATTRIBUTE_UNDERLINE,
107     TEXT_ATTRIBUTE_WEIGHT,
108     // --> OD 2010-03-05 #i92233#
109     TEXT_ATTRIBUTE_MM_TO_PIXEL_RATIO,
110     // <--
111     TEXT_ATTRIBUTE_JUSTIFICATION,
112     TEXT_ATTRIBUTE_BOTTOM_MARGIN,
113     TEXT_ATTRIBUTE_FIRST_LINE_INDENT,
114     TEXT_ATTRIBUTE_LEFT_MARGIN,
115     TEXT_ATTRIBUTE_LINE_SPACING,
116     TEXT_ATTRIBUTE_RIGHT_MARGIN,
117     TEXT_ATTRIBUTE_STYLE_NAME,
118     TEXT_ATTRIBUTE_TAB_STOPS,
119     TEXT_ATTRIBUTE_TOP_MARGIN,
120     TEXT_ATTRIBUTE_WRITING_MODE,
121     TEXT_ATTRIBUTE_LAST
122 };
123 
124 static const char * ExportedTextAttributes[TEXT_ATTRIBUTE_LAST] =
125 {
126     "CharBackColor",        // TEXT_ATTRIBUTE_BACKGROUND_COLOR
127     "CharCaseMap",          // TEXT_ATTRIBUTE_CASEMAP
128     "CharColor",            // TEXT_ATTRIBUTE_FOREGROUND_COLOR
129     "CharContoured",        // TEXT_ATTRIBUTE_CONTOURED
130     "CharEscapement",       // TEXT_ATTRIBUTE_CHAR_ESCAPEMENT
131     "CharFlash",            // TEXT_ATTRIBUTE_BLINKING
132     "CharFontName",         // TEXT_ATTRIBUTE_FONT_NAME
133     "CharHeight",           // TEXT_ATTRIBUTE_HEIGHT
134     "CharHidden",           // TEXT_ATTRIBUTE_HIDDEN
135     "CharKerning",          // TEXT_ATTRIBUTE_KERNING
136     "CharLocale",           // TEXT_ATTRIBUTE_LOCALE
137     "CharPosture",          // TEXT_ATTRIBUTE_POSTURE
138     "CharRelief",           // TEXT_ATTRIBUTE_RELIEF
139     "CharRotation",         // TEXT_ATTRIBUTE_ROTATION
140     "CharScaleWidth",       // TEXT_ATTRIBUTE_SCALE
141     "CharShadowed",         // TEXT_ATTRIBUTE_SHADOWED
142     "CharStrikeout",        // TEXT_ATTRIBUTE_STRIKETHROUGH
143     "CharUnderline",        // TEXT_ATTRIBUTE_UNDERLINE
144     "CharWeight",           // TEXT_ATTRIBUTE_WEIGHT
145     // --> OD 2010-03-05 #i92233#
146     "MMToPixelRatio",       // TEXT_ATTRIBUTE_MM_TO_PIXEL_RATIO
147     // <--
148     "ParaAdjust",           // TEXT_ATTRIBUTE_JUSTIFICATION
149     "ParaBottomMargin",     // TEXT_ATTRIBUTE_BOTTOM_MARGIN
150     "ParaFirstLineIndent",  // TEXT_ATTRIBUTE_FIRST_LINE_INDENT
151     "ParaLeftMargin",       // TEXT_ATTRIBUTE_LEFT_MARGIN
152     "ParaLineSpacing",      // TEXT_ATTRIBUTE_LINE_SPACING
153     "ParaRightMargin",      // TEXT_ATTRIBUTE_RIGHT_MARGIN
154     "ParaStyleName",        // TEXT_ATTRIBUTE_STYLE_NAME
155     "ParaTabStops",         // TEXT_ATTRIBUTE_TAB_STOPS
156     "ParaTopMargin",        // TEXT_ATTRIBUTE_TOP_MARGIN
157     "WritingMode"           // TEXT_ATTRIBUTE_WRITING_MODE
158 };
159 
160 
161 /*****************************************************************************/
162 
163 static gchar*
get_value(const uno::Sequence<beans::PropertyValue> & rAttributeList,sal_Int32 nIndex,AtkTextAttrFunc func)164 get_value( const uno::Sequence< beans::PropertyValue >& rAttributeList,
165            sal_Int32 nIndex, AtkTextAttrFunc func )
166 {
167     if( nIndex != -1 )
168         return func(rAttributeList[nIndex].Value);
169 
170     return NULL;
171 }
172 
173 #define get_bool_value( list, index ) get_value( list, index, Bool2String )
174 #define get_short_value( list, index ) get_value( list, index, Short2String )
175 //#define get_long_value( list, index ) get_value( list, index, Long2String ) pb: not used (warning on linux)
176 #define get_height_value( list, index ) get_value( list, index, Float2String )
177 #define get_justification_value( list, index ) get_value( list, index, Adjust2Justification )
178 #define get_cmm_value( list, index ) get_value( list, index, CMM2UnitString )
179 #define get_scale_width( list, index ) get_value( list, index, Scale2String )
180 #define get_strikethrough_value( list, index ) get_value( list, index, Strikeout2String )
181 #define get_string_value( list, index ) get_value( list, index, GetString )
182 #define get_style_value( list, index ) get_value( list, index, FontSlant2Style )
183 #define get_underline_value( list, index ) get_value( list, index, Underline2String )
184 #define get_variant_value( list, index ) get_value( list, index, CaseMap2String )
185 #define get_weight_value( list, index ) get_value( list, index, Weight2String )
186 #define get_language_string( list, index ) get_value( list, index, Locale2String )
187 
188 /*
189 static gchar*
190 dump_value( const uno::Sequence< beans::PropertyValue >& rAttributeList, sal_Int32 nIndex )
191 {
192     if( nIndex != -1 )
193     {
194         rtl::OString aName = rtl::OUStringToOString(rAttributeList[nIndex].Name, RTL_TEXTENCODING_UTF8);
195 
196         if( rAttributeList[nIndex].Value.has<sal_Int16> () )
197             OSL_TRACE( "%s = %d (short value)", aName.getStr(),
198                 rAttributeList[nIndex].Value.get<sal_Int16> () );
199 
200         else if( rAttributeList[nIndex].Value.has<sal_Int8> () )
201             OSL_TRACE( "%s = %d (byte value)", aName.getStr(),
202                 rAttributeList[nIndex].Value.get<sal_Int8> () );
203 
204         else if( rAttributeList[nIndex].Value.has<sal_Bool> () )
205             OSL_TRACE( "%s = %s (bool value)", aName.getStr(),
206                 rAttributeList[nIndex].Value.get<sal_Bool> () ? "true" : "false" );
207 
208         else if( rAttributeList[nIndex].Value.has<rtl::OUString> () )
209             OSL_TRACE( "%s = %s", aName.getStr(),
210                 rtl::OUStringToOString(rAttributeList[nIndex].Value.get<rtl::OUString> (),
211                     RTL_TEXTENCODING_UTF8).getStr() );
212     }
213 
214     return NULL;
215 }
216 */
217 
218 static inline
toPoint(sal_Int16 n)219 double toPoint(sal_Int16 n)
220 {
221     // 100th mm -> pt
222     return (double) (n * 72) / 2540;
223 }
224 
225 
226 /*****************************************************************************/
227 
228 /*
229 static gchar*
230 NullString(const uno::Any&)
231 {
232     return NULL;
233 }
234 */
235 
236 static bool
InvalidValue(uno::Any &,const gchar *)237 InvalidValue( uno::Any&, const gchar * )
238 {
239     return false;
240 }
241 
242 /*****************************************************************************/
243 
244 static gchar*
Float2String(const uno::Any & rAny)245 Float2String(const uno::Any& rAny)
246 {
247     return g_strdup_printf( "%g", rAny.get<float>() );
248 }
249 
250 static bool
String2Float(uno::Any & rAny,const gchar * value)251 String2Float( uno::Any& rAny, const gchar * value )
252 {
253     float fval;
254 
255     if( 1 != sscanf( value, "%g", &fval ) )
256         return false;
257 
258     rAny = uno::makeAny( fval );
259     return true;
260 }
261 
262 /*****************************************************************************/
263 
264 /*
265 static gchar*
266 Short2String(const uno::Any& rAny)
267 {
268     return g_strdup_printf( "%d", rAny.get<sal_Int16>() );
269 }
270 
271 static bool
272 String2Short( uno::Any& rAny, const gchar * value )
273 {
274     sal_Int32 lval;
275 
276     if( 1 != sscanf( value, "%d", &lval ) )
277         return false;
278 
279     rAny = uno::makeAny( (sal_Int16) lval );
280     return true;
281 }
282 */
283 
284 /*****************************************************************************/
285 /* pb: not used (warning on linux)
286 static gchar*
287 Long2String(const uno::Any& rAny)
288 {
289     return g_strdup_printf( "%ld", rAny.get<sal_Int32>() );
290 }
291 
292 static bool
293 String2Long( uno::Any& rAny, const gchar * value )
294 {
295     sal_Int32 lval;
296 
297     if( 1 != sscanf( value, "%ld", &lval ) )
298         return false;
299 
300     rAny = uno::makeAny( lval );
301     return true;
302 }
303 */
304 /*****************************************************************************/
305 
306 static accessibility::XAccessibleComponent*
getComponent(AtkText * pText)307     getComponent( AtkText *pText ) throw (uno::RuntimeException)
308 {
309     AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
310     if( pWrap )
311     {
312         if( !pWrap->mpComponent && pWrap->mpContext )
313         {
314             uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleComponent::static_type(NULL) );
315             pWrap->mpComponent = reinterpret_cast< accessibility::XAccessibleComponent * > (any.pReserved);
316             pWrap->mpComponent->acquire();
317         }
318 
319         return pWrap->mpComponent;
320     }
321 
322     return NULL;
323 }
324 
325 static gchar*
get_color_value(const uno::Sequence<beans::PropertyValue> & rAttributeList,const sal_Int32 * pIndexArray,ExportedAttribute attr,AtkText * text)326 get_color_value(const uno::Sequence< beans::PropertyValue >& rAttributeList,
327                 const sal_Int32 * pIndexArray,
328                 ExportedAttribute attr,
329                 AtkText * text)
330 {
331     sal_Int32 nColor = -1; // AUTOMATIC
332     sal_Int32 nIndex = pIndexArray[attr];
333 
334     if( nIndex != -1 )
335         nColor = rAttributeList[nIndex].Value.get<sal_Int32>();
336 
337     /*
338      * Check for color value for 100% alpha white, which means
339      * "automatic". Grab the RGB value from XAccessibleComponent
340      * in this case.
341      */
342 
343     if( (nColor == -1) && text )
344     {
345         try
346         {
347             accessibility::XAccessibleComponent *pComponent = getComponent( text );
348             if( pComponent )
349             {
350                 switch( attr )
351                 {
352                     case TEXT_ATTRIBUTE_BACKGROUND_COLOR:
353                         nColor = pComponent->getBackground();
354                         break;
355                     case TEXT_ATTRIBUTE_FOREGROUND_COLOR:
356                         nColor = pComponent->getForeground();
357                         break;
358                     default:
359                         break;
360                 }
361             }
362         }
363 
364         catch(const uno::Exception& e) {
365             g_warning( "Exception in get[Fore|Back]groundColor()" );
366         }
367     }
368 
369     if( nColor != -1 )
370     {
371         sal_uInt8 blue  = nColor & 0xFF;
372         sal_uInt8 green = (nColor >> 8) & 0xFF;
373         sal_uInt8 red   = (nColor >> 16) & 0xFF;
374 
375         return g_strdup_printf( "%u,%u,%u", red, green, blue );
376     }
377 
378     return NULL;
379 }
380 
381 static bool
String2Color(uno::Any & rAny,const gchar * value)382 String2Color( uno::Any& rAny, const gchar * value )
383 {
384     int red, green, blue;
385 
386     if( 3 != sscanf( value, "%d,%d,%d", &red, &green, &blue ) )
387         return false;
388 
389     sal_Int32 nColor = (sal_Int32) blue | ( (sal_Int32) green << 8 ) | ( ( sal_Int32 ) red << 16 );
390     rAny = uno::makeAny( nColor );
391     return true;
392 }
393 
394 /*****************************************************************************/
395 
396 static gchar*
FontSlant2Style(const uno::Any & rAny)397 FontSlant2Style(const uno::Any& rAny)
398 {
399     const gchar * value = NULL;
400 
401     switch( rAny.get<awt::FontSlant>() )
402     {
403         case awt::FontSlant_NONE:
404             value = "normal";
405             break;
406 
407         case awt::FontSlant_OBLIQUE:
408             value = "oblique";
409             break;
410 
411         case awt::FontSlant_ITALIC:
412             value = "italic";
413             break;
414 
415         case awt::FontSlant_REVERSE_OBLIQUE:
416             value = "reverse oblique";
417             break;
418 
419         case awt::FontSlant_REVERSE_ITALIC:
420             value = "reverse italic";
421             break;
422 
423         default:
424             break;
425     }
426 
427     if( value )
428          return g_strdup( value );
429 
430     return NULL;
431 }
432 
433 static bool
Style2FontSlant(uno::Any & rAny,const gchar * value)434 Style2FontSlant( uno::Any& rAny, const gchar * value )
435 {
436     awt::FontSlant aFontSlant;
437 
438     if( strncmp( value, STRNCMP_PARAM( "normal" ) ) )
439         aFontSlant = awt::FontSlant_NONE;
440     else if( strncmp( value, STRNCMP_PARAM( "oblique" ) ) )
441         aFontSlant = awt::FontSlant_OBLIQUE;
442     else if( strncmp( value, STRNCMP_PARAM( "italic" ) ) )
443         aFontSlant = awt::FontSlant_ITALIC;
444     else if( strncmp( value, STRNCMP_PARAM( "reverse oblique" ) ) )
445         aFontSlant = awt::FontSlant_REVERSE_OBLIQUE;
446     else if( strncmp( value, STRNCMP_PARAM( "reverse italic" ) ) )
447         aFontSlant = awt::FontSlant_REVERSE_ITALIC;
448     else
449         return false;
450 
451     rAny = uno::makeAny( aFontSlant );
452     return true;
453 }
454 
455 /*****************************************************************************/
456 
457 static gchar*
Weight2String(const uno::Any & rAny)458 Weight2String(const uno::Any& rAny)
459 {
460     return g_strdup_printf( "%g", rAny.get<float>() * 4 );
461 }
462 
463 static bool
String2Weight(uno::Any & rAny,const gchar * value)464 String2Weight( uno::Any& rAny, const gchar * value )
465 {
466     float weight;
467 
468     if( 1 != sscanf( value, "%g", &weight ) )
469         return false;
470 
471     rAny = uno::makeAny( weight / 4 );
472     return true;
473 }
474 
475 
476 /*****************************************************************************/
477 
478 static gchar*
Adjust2Justification(const uno::Any & rAny)479 Adjust2Justification(const uno::Any& rAny)
480 {
481     const gchar * value = NULL;
482 
483     switch( rAny.get<short>() )
484     {
485         case style::ParagraphAdjust_LEFT:
486             value = "left";
487             break;
488 
489         case style::ParagraphAdjust_RIGHT:
490             value = "right";
491             break;
492 
493         case style::ParagraphAdjust_BLOCK:
494         case style::ParagraphAdjust_STRETCH:
495             value = "fill";
496             break;
497 
498         case style::ParagraphAdjust_CENTER:
499             value = "center";
500             break;
501 
502         default:
503             break;
504     }
505 
506     if( value )
507         return g_strdup( value );
508 
509     return NULL;
510 }
511 
512 static bool
Justification2Adjust(uno::Any & rAny,const gchar * value)513 Justification2Adjust( uno::Any& rAny, const gchar * value )
514 {
515     short nParagraphAdjust;
516 
517     if( strncmp( value, STRNCMP_PARAM( "left" ) ) )
518         nParagraphAdjust = style::ParagraphAdjust_LEFT;
519     else if( strncmp( value, STRNCMP_PARAM( "right" ) ) )
520         nParagraphAdjust = style::ParagraphAdjust_RIGHT;
521     else if( strncmp( value, STRNCMP_PARAM( "fill" ) ) )
522         nParagraphAdjust = style::ParagraphAdjust_BLOCK;
523     else if( strncmp( value, STRNCMP_PARAM( "center" ) ) )
524         nParagraphAdjust = style::ParagraphAdjust_CENTER;
525     else
526         return false;
527 
528     rAny = uno::makeAny( nParagraphAdjust );
529     return true;
530 }
531 
532 /*****************************************************************************/
533 
534 const gchar * font_strikethrough[] = {
535     "none",   // FontStrikeout::NONE
536     "single", // FontStrikeout::SINGLE
537     "double", // FontStrikeout::DOUBLE
538     NULL,     // FontStrikeout::DONTKNOW
539     "bold",   // FontStrikeout::BOLD
540     "with /", // FontStrikeout::SLASH
541     "with X"  // FontStrikeout::X
542 };
543 
544 const sal_Int16 n_strikeout_constants = sizeof(font_strikethrough) / sizeof(gchar*);
545 
546 static gchar*
Strikeout2String(const uno::Any & rAny)547 Strikeout2String(const uno::Any& rAny)
548 {
549     sal_Int16 n = rAny.get<sal_Int16>();
550 
551     if( n >= 0 && n < n_strikeout_constants )
552         return g_strdup( font_strikethrough[n] );
553 
554     return NULL;
555 }
556 
557 static bool
String2Strikeout(uno::Any & rAny,const gchar * value)558 String2Strikeout( uno::Any& rAny, const gchar * value )
559 {
560     for( sal_Int16 n=0; n < n_strikeout_constants; ++n )
561     {
562         if( ( NULL != font_strikethrough[n] ) &&
563             0 == strncmp( value, font_strikethrough[n], strlen( font_strikethrough[n] ) ) )
564         {
565             rAny = uno::makeAny( n );
566             return true;
567         }
568     }
569 
570     return false;
571 }
572 
573 /*****************************************************************************/
574 
575 static gchar*
Underline2String(const uno::Any & rAny)576 Underline2String(const uno::Any& rAny)
577 {
578     const gchar * value = NULL;
579 
580     switch( rAny.get<sal_Int16>() )
581     {
582         case awt::FontUnderline::NONE:
583             value = "none";
584             break;
585 
586         case awt::FontUnderline::SINGLE:
587             value = "single";
588             break;
589 
590         case awt::FontUnderline::DOUBLE:
591             value = "double";
592             break;
593 
594         default:
595             break;
596     }
597 
598     if( value )
599         return g_strdup( value );
600 
601     return NULL;
602 }
603 
604 static bool
String2Underline(uno::Any & rAny,const gchar * value)605 String2Underline( uno::Any& rAny, const gchar * value )
606 {
607     short nUnderline;
608 
609     if( strncmp( value, STRNCMP_PARAM( "none" ) ) )
610         nUnderline = awt::FontUnderline::NONE;
611     else if( strncmp( value, STRNCMP_PARAM( "single" ) ) )
612         nUnderline = awt::FontUnderline::SINGLE;
613     else if( strncmp( value, STRNCMP_PARAM( "double" ) ) )
614         nUnderline = awt::FontUnderline::DOUBLE;
615     else
616         return false;
617 
618     rAny = uno::makeAny( nUnderline );
619     return true;
620 }
621 
622 /*****************************************************************************/
623 
624 static gchar*
GetString(const uno::Any & rAny)625 GetString(const uno::Any& rAny)
626 {
627     rtl::OString aFontName = rtl::OUStringToOString( rAny.get< rtl::OUString > (), RTL_TEXTENCODING_UTF8 );
628 
629     if( aFontName.getLength() )
630         return g_strdup( aFontName.getStr() );
631 
632     return NULL;
633 }
634 
635 static bool
SetString(uno::Any & rAny,const gchar * value)636 SetString( uno::Any& rAny, const gchar * value )
637 {
638     rtl::OString aFontName( value );
639 
640     if( aFontName.getLength() )
641     {
642         rAny = uno::makeAny( rtl::OStringToOUString( aFontName, RTL_TEXTENCODING_UTF8 ) );
643         return true;
644     }
645 
646     return false;
647 }
648 
649 /*****************************************************************************/
650 
651 // @see http://developer.gnome.org/doc/API/2.0/atk/AtkText.html#AtkTextAttribute
652 
653 // CMM = 100th of mm
654 static gchar*
CMM2UnitString(const uno::Any & rAny)655 CMM2UnitString(const uno::Any& rAny)
656 {
657     double fValue = rAny.get<sal_Int32>();
658     fValue = fValue * 0.01;
659 
660     return g_strdup_printf( "%gmm", fValue );
661 }
662 
663 static bool
UnitString2CMM(uno::Any & rAny,const gchar * value)664 UnitString2CMM( uno::Any& rAny, const gchar * value )
665 {
666     float fValue = 0.0; // pb: dont use double here because of warning on linux
667 
668     if( 1 != sscanf( value, "%gmm", &fValue ) )
669         return false;
670 
671     fValue = fValue * 100;
672 
673     rAny = uno::makeAny( (sal_Int32) fValue);
674     return true;
675 }
676 
677 /*****************************************************************************/
678 
679 static const gchar * bool_values[] = { "true", "false" };
680 
681 static gchar *
Bool2String(const uno::Any & rAny)682 Bool2String( const uno::Any& rAny )
683 {
684     int n = 1;
685 
686     if( rAny.get<sal_Bool>() )
687         n = 0;
688 
689     return g_strdup( bool_values[n] );
690 }
691 
692 static bool
String2Bool(uno::Any & rAny,const gchar * value)693 String2Bool( uno::Any& rAny, const gchar * value )
694 {
695     sal_Bool bValue;
696 
697     if( strncmp( value, STRNCMP_PARAM( "true" ) ) )
698         bValue = sal_True;
699     else if( strncmp( value, STRNCMP_PARAM( "false" ) ) )
700         bValue = sal_False;
701     else
702         return false;
703 
704     rAny = uno::makeAny(bValue);
705     return true;
706 }
707 
708 /*****************************************************************************/
709 
710 static gchar*
Scale2String(const uno::Any & rAny)711 Scale2String( const uno::Any& rAny )
712 {
713     return g_strdup_printf( "%g", (double) (rAny.get< sal_Int16 > ()) / 100 );
714 }
715 
716 static bool
String2Scale(uno::Any & rAny,const gchar * value)717 String2Scale( uno::Any& rAny, const gchar * value )
718 {
719     double dval;
720 
721     if( 1 != sscanf( value, "%lg", &dval ) )
722         return false;
723 
724     rAny = uno::makeAny((sal_Int16) (dval * 100));
725     return true;
726 }
727 
728 /*****************************************************************************/
729 
730 static gchar *
CaseMap2String(const uno::Any & rAny)731 CaseMap2String( const uno::Any& rAny )
732 {
733     const gchar * value = NULL;
734 
735     switch( rAny.get<short>() )
736     {
737         case style::CaseMap::SMALLCAPS:
738             value = "small_caps";
739             break;
740 
741         default:
742             value = "normal";
743             break;
744     }
745 
746     if( value )
747         return g_strdup( value );
748 
749     return NULL;
750 }
751 
752 static bool
String2CaseMap(uno::Any & rAny,const gchar * value)753 String2CaseMap( uno::Any& rAny, const gchar * value )
754 {
755     short nCaseMap;
756 
757     if( strncmp( value, STRNCMP_PARAM( "normal" ) ) )
758         nCaseMap = style::CaseMap::NONE;
759     else if( strncmp( value, STRNCMP_PARAM( "small_caps" ) ) )
760         nCaseMap = style::CaseMap::SMALLCAPS;
761     else
762         return false;
763 
764     rAny = uno::makeAny( nCaseMap );
765     return true;
766 }
767 
768 /*****************************************************************************/
769 
770 const gchar * font_stretch[] = {
771     "ultra_condensed",
772     "extra_condensed",
773     "condensed",
774     "semi_condensed",
775     "normal",
776     "semi_expanded",
777     "expanded",
778     "extra_expanded",
779     "ultra_expanded"
780 };
781 
782 static gchar*
Kerning2Stretch(const uno::Any & rAny)783 Kerning2Stretch(const uno::Any& rAny)
784 {
785     sal_Int16 n = rAny.get<sal_Int16>();
786     int i = 4;
787 
788     // No good idea for a mapping - just return the basic info
789     if( n < 0 )
790         i=2;
791     else if( n > 0 )
792         i=6;
793 
794     return g_strdup(font_stretch[i]);
795 }
796 
797 /*****************************************************************************/
798 
799 static gchar*
Locale2String(const uno::Any & rAny)800 Locale2String(const uno::Any& rAny)
801 {
802     lang::Locale aLocale = rAny.get<lang::Locale> ();
803     return g_strdup_printf( "%s-%s",
804         rtl::OUStringToOString( aLocale.Language, RTL_TEXTENCODING_ASCII_US).getStr(),
805         rtl::OUStringToOString( aLocale.Country, RTL_TEXTENCODING_ASCII_US).toAsciiLowerCase().getStr() );
806 }
807 
808 static bool
String2Locale(uno::Any & rAny,const gchar * value)809 String2Locale( uno::Any& rAny, const gchar * value )
810 {
811     bool ret = false;
812 
813     gchar ** str_array = g_strsplit_set( value, "-.@", -1 );
814     if( str_array[0] != NULL )
815     {
816         ret = true;
817 
818         lang::Locale aLocale;
819 
820         aLocale.Language = rtl::OUString::createFromAscii(str_array[0]);
821         if( str_array[1] != NULL )
822         {
823             gchar * country = g_ascii_strup(str_array[1], -1);
824             aLocale.Country = rtl::OUString::createFromAscii(country);
825             g_free(country);
826         }
827 
828         rAny = uno::makeAny(aLocale);
829     }
830 
831     g_strfreev(str_array);
832     return ret;
833 }
834 
835 /*****************************************************************************/
836 
837 // @see http://www.w3.org/TR/2002/WD-css3-fonts-20020802/#font-effect-prop
838 static const gchar * relief[] = { "none", "emboss", "engrave" };
839 static const gchar * outline  = "outline";
840 
841 static gchar *
get_font_effect(const uno::Sequence<beans::PropertyValue> & rAttributeList,sal_Int32 nContourIndex,sal_Int32 nReliefIndex)842 get_font_effect(const uno::Sequence< beans::PropertyValue >& rAttributeList,
843                 sal_Int32 nContourIndex, sal_Int32 nReliefIndex)
844 {
845     if( nContourIndex != -1 )
846     {
847         if( rAttributeList[nContourIndex].Value.get<sal_Bool>() )
848             return g_strdup(outline);
849     }
850 
851     if( nReliefIndex != -1 )
852     {
853         sal_Int16 n = rAttributeList[nReliefIndex].Value.get<sal_Int16>();
854         if( n <  3)
855             return g_strdup(relief[n]);
856     }
857 
858     return NULL;
859 }
860 
861 /*****************************************************************************/
862 
863 // @see http://www.w3.org/TR/REC-CSS2/text.html#lining-striking-props
864 
865 
866 enum
867 {
868     DECORATION_NONE = 0,
869     DECORATION_BLINK,
870     DECORATION_UNDERLINE,
871     DECORATION_LINE_THROUGH
872 };
873 
874 
875 static const gchar * decorations[] = { "none", "blink", "underline", "line-through" };
876 
877 static gchar *
get_text_decoration(const uno::Sequence<beans::PropertyValue> & rAttributeList,sal_Int32 nBlinkIndex,sal_Int32 nUnderlineIndex,sal_Int16 nStrikeoutIndex)878 get_text_decoration(const uno::Sequence< beans::PropertyValue >& rAttributeList,
879                     sal_Int32 nBlinkIndex, sal_Int32 nUnderlineIndex,
880                     sal_Int16 nStrikeoutIndex)
881 {
882     gchar * value_list[4] = { NULL, NULL, NULL, NULL };
883     gint count = 0;
884 
885     // no property value found
886     if( ( nBlinkIndex == -1 ) && (nUnderlineIndex == -1 ) && (nStrikeoutIndex == -1))
887         return NULL;
888 
889     if( nBlinkIndex != -1 )
890     {
891         if( rAttributeList[nBlinkIndex].Value.get<sal_Bool>() )
892             value_list[count++] = const_cast <gchar *> (decorations[DECORATION_BLINK]);
893     }
894     if( nUnderlineIndex != -1 )
895     {
896         sal_Int16 n = rAttributeList[nUnderlineIndex].Value.get<sal_Int16> ();
897         if( n != awt::FontUnderline::NONE )
898             value_list[count++] = const_cast <gchar *> (decorations[DECORATION_UNDERLINE]);
899     }
900     if( nStrikeoutIndex != -1 )
901     {
902         sal_Int16 n = rAttributeList[nStrikeoutIndex].Value.get<sal_Int16> ();
903         if( n != awt::FontStrikeout::NONE && n != awt::FontStrikeout::DONTKNOW )
904             value_list[count++] = const_cast <gchar *> (decorations[DECORATION_LINE_THROUGH]);
905     }
906 
907     if( count == 0 )
908         value_list[count++] = const_cast <gchar *> (decorations[DECORATION_NONE]);
909 
910     return g_strjoinv(" ", value_list);
911 }
912 
913 
914 /*****************************************************************************/
915 
916 // @see http://www.w3.org/TR/REC-CSS2/text.html#propdef-text-shadow
917 
918 static const gchar * shadow_values[] = { "none", "black" };
919 
920 static gchar *
Bool2Shadow(const uno::Any & rAny)921 Bool2Shadow( const uno::Any& rAny )
922 {
923     int n = 0;
924 
925     if( rAny.get<sal_Bool>() )
926         n = 1;
927 
928     return g_strdup( shadow_values[n] );
929 }
930 
931 /*****************************************************************************/
932 
933 static gchar *
Short2Degree(const uno::Any & rAny)934 Short2Degree( const uno::Any& rAny )
935 {
936     float f = rAny.get<sal_Int16>() / 10;
937     return g_strdup_printf( "%g", f );
938 }
939 
940 /*****************************************************************************/
941 
942 const gchar * directions[] = { "ltr", "rtl", "rtl", "ltr", "none" };
943 
944 static gchar *
WritingMode2Direction(const uno::Any & rAny)945 WritingMode2Direction( const uno::Any& rAny )
946 {
947     sal_Int16 n = rAny.get<sal_Int16>();
948 
949     if( 0 <= n && n <= text::WritingMode2::PAGE )
950         return g_strdup(directions[n]);
951 
952     return NULL;
953 }
954 
955 // @see http://www.w3.org/TR/2001/WD-css3-text-20010517/#PrimaryTextAdvanceDirection
956 
957 const gchar * writing_modes[] = { "lr-tb", "rl-tb", "tb-rl", "tb-lr", "none" };
958 static gchar *
WritingMode2String(const uno::Any & rAny)959 WritingMode2String( const uno::Any& rAny )
960 {
961     sal_Int16 n = rAny.get<sal_Int16>();
962 
963     if( 0 <= n && n <= text::WritingMode2::PAGE )
964         return g_strdup(writing_modes[n]);
965 
966     return NULL;
967 }
968 
969 /*****************************************************************************/
970 
971 const char * baseline_values[] = { "baseline", "sub", "super" };
972 
973 // @see http://www.w3.org/TR/REC-CSS2/visudet.html#propdef-vertical-align
974 static gchar *
Escapement2VerticalAlign(const uno::Any & rAny)975 Escapement2VerticalAlign( const uno::Any& rAny )
976 {
977     sal_Int16 n = rAny.get<sal_Int16>();
978     gchar * ret = NULL;
979 
980     // Values are in %, 101% means "automatic"
981     if( n == 0 )
982         ret = g_strdup(baseline_values[0]);
983     else if( n == 101 )
984         ret = g_strdup(baseline_values[2]);
985     else if( n == -101 )
986         ret = g_strdup(baseline_values[1]);
987     else
988         ret = g_strdup_printf( "%d%%", n );
989 
990     return ret;
991 }
992 
993 /*****************************************************************************/
994 
995 // @see http://www.w3.org/TR/REC-CSS2/visudet.html#propdef-line-height
996 static gchar *
LineSpacing2LineHeight(const uno::Any & rAny)997 LineSpacing2LineHeight( const uno::Any& rAny )
998 {
999     style::LineSpacing ls;
1000     gchar * ret = NULL;
1001 
1002     if( rAny >>= ls )
1003     {
1004         if( ls.Mode == style::LineSpacingMode::PROP )
1005             ret = g_strdup_printf( "%d%%", ls.Height );
1006         else if( ls.Mode == style::LineSpacingMode::FIX )
1007             ret = g_strdup_printf( "%.3gpt", toPoint(ls.Height) );
1008     }
1009 
1010     return ret;
1011 }
1012 
1013 /*****************************************************************************/
1014 
1015 // @see http://www.w3.org/People/howcome/t/970224HTMLERB-CSS/WD-tabs-970117.html
1016 static gchar *
TabStopList2String(const uno::Any & rAny,bool default_tabs)1017 TabStopList2String( const uno::Any& rAny, bool default_tabs )
1018 {
1019     uno::Sequence< style::TabStop > theTabStops;
1020     gchar * ret = NULL;
1021 
1022     if( rAny >>= theTabStops)
1023     {
1024         sal_Int32 indexOfTab = 0;
1025         sal_Int32 numberOfTabs = theTabStops.getLength();
1026         sal_Unicode lastFillChar = (sal_Unicode) ' ';
1027 
1028         for( ; indexOfTab < numberOfTabs; ++indexOfTab )
1029         {
1030             bool is_default_tab = (style::TabAlign_DEFAULT == theTabStops[indexOfTab].Alignment);
1031 
1032             if( is_default_tab != default_tabs )
1033                 continue;
1034 
1035             double fValue = theTabStops[indexOfTab].Position;
1036             fValue = fValue * 0.01;
1037 
1038             const gchar * tab_align = "";
1039             switch( theTabStops[indexOfTab].Alignment )
1040             {
1041                 case style::TabAlign_LEFT :
1042                     tab_align = "left ";
1043                     break;
1044                 case style::TabAlign_CENTER :
1045                     tab_align = "center ";
1046                     break;
1047                 case style::TabAlign_RIGHT :
1048                     tab_align = "right ";
1049                     break;
1050                 case style::TabAlign_DECIMAL :
1051                     tab_align = "decimal ";
1052                     break;
1053                 default:
1054                     break;
1055             }
1056 
1057             const gchar * lead_char = "";
1058 
1059             if( theTabStops[indexOfTab].FillChar != lastFillChar )
1060             {
1061                 lastFillChar = theTabStops[indexOfTab].FillChar;
1062                 switch (lastFillChar)
1063                 {
1064                     case (sal_Unicode) ' ':
1065                         lead_char = "blank ";
1066                         break;
1067 
1068                     case (sal_Unicode) '.':
1069                         lead_char = "dotted ";
1070                         break;
1071 
1072                     case (sal_Unicode) '-':
1073                         lead_char = "dashed ";
1074                         break;
1075 
1076                     case (sal_Unicode) '_':
1077                         lead_char = "lined ";
1078                         break;
1079 
1080                     default:
1081                         lead_char = "custom ";
1082                         break;
1083                 }
1084             }
1085 
1086             gchar * tab_str = g_strdup_printf( "%s%s%gmm", lead_char, tab_align, fValue );
1087 
1088             if( ret )
1089             {
1090                 gchar * old_tab_str = ret;
1091                 ret = g_strconcat(old_tab_str, " ", tab_str, NULL /* terminated */);
1092                 g_free( old_tab_str );
1093             }
1094             else
1095                 ret = tab_str;
1096         }
1097     }
1098 
1099     return ret;
1100 }
1101 
1102 static gchar *
TabStops2String(const uno::Any & rAny)1103 TabStops2String( const uno::Any& rAny )
1104 {
1105     return TabStopList2String(rAny, false);
1106 }
1107 
1108 static gchar *
DefaultTabStops2String(const uno::Any & rAny)1109 DefaultTabStops2String( const uno::Any& rAny )
1110 {
1111     return TabStopList2String(rAny, true);
1112 }
1113 
1114 /*****************************************************************************/
1115 
1116 extern "C" int
attr_compare(const void * p1,const void * p2)1117 attr_compare(const void *p1,const void *p2)
1118 {
1119     const rtl_uString * pustr = (const rtl_uString *) p1;
1120     const char * pc = *((const char **) p2);
1121 
1122     return rtl_ustr_ascii_compare_WithLength(pustr->buffer, pustr->length, pc);
1123 }
1124 
1125 static void
find_exported_attributes(sal_Int32 * pArray,const com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> & rAttributeList)1126 find_exported_attributes( sal_Int32 *pArray,
1127     const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& rAttributeList )
1128 {
1129     for( sal_Int32 i = 0; i < rAttributeList.getLength(); i++ )
1130     {
1131         const char ** pAttr = (const char **) bsearch(rAttributeList[i].Name.pData,
1132             ExportedTextAttributes, TEXT_ATTRIBUTE_LAST, sizeof(const char *),
1133             attr_compare);
1134 
1135         if( pAttr )
1136         {
1137             sal_Int32 nIndex = pAttr - ExportedTextAttributes;
1138             pArray[nIndex] = i;
1139         }
1140     }
1141 }
1142 
1143 /*****************************************************************************/
1144 
1145 static AtkAttributeSet*
attribute_set_prepend(AtkAttributeSet * attribute_set,AtkTextAttribute attribute,gchar * value)1146 attribute_set_prepend( AtkAttributeSet* attribute_set,
1147                        AtkTextAttribute attribute,
1148                        gchar * value )
1149 {
1150     if( value )
1151     {
1152         AtkAttribute *at = (AtkAttribute *) g_malloc( sizeof (AtkAttribute) );
1153         at->name  = g_strdup( atk_text_attribute_get_name( attribute ) );
1154         at->value = value;
1155 
1156         return g_slist_prepend(attribute_set, at);
1157     }
1158 
1159     return attribute_set;
1160 }
1161 
1162 /*****************************************************************************/
1163 
1164 AtkAttributeSet*
attribute_set_new_from_property_values(const uno::Sequence<beans::PropertyValue> & rAttributeList,bool run_attributes_only,AtkText * text)1165 attribute_set_new_from_property_values(
1166     const uno::Sequence< beans::PropertyValue >& rAttributeList,
1167     bool run_attributes_only,
1168     AtkText *text)
1169 {
1170     AtkAttributeSet* attribute_set = NULL;
1171 
1172     sal_Int32 aIndexList[TEXT_ATTRIBUTE_LAST] = { -1 };
1173 
1174     // Initialize index array with -1
1175     for( sal_Int32 attr = 0; attr < TEXT_ATTRIBUTE_LAST; ++attr )
1176         aIndexList[attr] = -1;
1177 
1178     find_exported_attributes(aIndexList, rAttributeList);
1179 
1180     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_BG_COLOR,
1181         get_color_value(rAttributeList, aIndexList, TEXT_ATTRIBUTE_BACKGROUND_COLOR, run_attributes_only ? NULL : text ) );
1182 
1183     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_FG_COLOR,
1184         get_color_value(rAttributeList, aIndexList, TEXT_ATTRIBUTE_FOREGROUND_COLOR, run_attributes_only ? NULL : text) );
1185 
1186     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_INVISIBLE,
1187         get_bool_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_HIDDEN]));
1188 
1189     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_UNDERLINE,
1190         get_underline_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_UNDERLINE]));
1191 
1192     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_STRIKETHROUGH,
1193         get_strikethrough_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_STRIKETHROUGH]));
1194 
1195     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_SIZE,
1196         get_height_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_HEIGHT]));
1197 
1198     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_WEIGHT,
1199         get_weight_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_WEIGHT]));
1200 
1201     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_FAMILY_NAME,
1202         get_string_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_FONT_NAME]));
1203 
1204     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_VARIANT,
1205         get_variant_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_CASEMAP]));
1206 
1207     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_STYLE,
1208         get_style_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_POSTURE]));
1209 
1210     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_SCALE,
1211         get_scale_width(rAttributeList, aIndexList[TEXT_ATTRIBUTE_SCALE]));
1212 
1213     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_LANGUAGE,
1214         get_language_string(rAttributeList, aIndexList[TEXT_ATTRIBUTE_LOCALE]));
1215 
1216     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_DIRECTION,
1217         get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_WRITING_MODE], WritingMode2Direction));
1218 
1219     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_STRETCH,
1220         get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_KERNING], Kerning2Stretch));
1221 
1222     if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_font_effect )
1223         atk_text_attribute_font_effect = atk_text_attribute_register("font-effect");
1224 
1225     attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_font_effect,
1226         get_font_effect(rAttributeList, aIndexList[TEXT_ATTRIBUTE_CONTOURED], aIndexList[TEXT_ATTRIBUTE_RELIEF]));
1227 
1228     if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_decoration )
1229         atk_text_attribute_decoration = atk_text_attribute_register("text-decoration");
1230 
1231     attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_decoration,
1232         get_text_decoration(rAttributeList, aIndexList[TEXT_ATTRIBUTE_BLINKING],
1233             aIndexList[TEXT_ATTRIBUTE_UNDERLINE], aIndexList[TEXT_ATTRIBUTE_STRIKETHROUGH]));
1234 
1235     if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_rotation )
1236         atk_text_attribute_rotation = atk_text_attribute_register("text-rotation");
1237 
1238     attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_rotation,
1239         get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_ROTATION], Short2Degree));
1240 
1241     if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_shadow )
1242         atk_text_attribute_shadow = atk_text_attribute_register("text-shadow");
1243 
1244     attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_shadow,
1245         get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_SHADOWED], Bool2Shadow));
1246 
1247     if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_writing_mode )
1248         atk_text_attribute_writing_mode = atk_text_attribute_register("writing-mode");
1249 
1250     attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_writing_mode,
1251         get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_WRITING_MODE], WritingMode2String));
1252 
1253     if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_vertical_align )
1254         atk_text_attribute_vertical_align = atk_text_attribute_register("vertical-align");
1255 
1256     attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_vertical_align,
1257         get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_CHAR_ESCAPEMENT], Escapement2VerticalAlign));
1258 
1259     if( run_attributes_only )
1260         return attribute_set;
1261 
1262     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_LEFT_MARGIN,
1263         get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_LEFT_MARGIN]));
1264 
1265     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_RIGHT_MARGIN,
1266         get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_RIGHT_MARGIN]));
1267 
1268     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_INDENT,
1269         get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_FIRST_LINE_INDENT]));
1270 
1271     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_PIXELS_ABOVE_LINES,
1272         get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_TOP_MARGIN]));
1273 
1274     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_PIXELS_BELOW_LINES,
1275         get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_BOTTOM_MARGIN]));
1276 
1277     attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_JUSTIFICATION,
1278         get_justification_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_JUSTIFICATION]));
1279 
1280     if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_paragraph_style )
1281         atk_text_attribute_paragraph_style = atk_text_attribute_register("paragraph-style");
1282 
1283     attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_paragraph_style,
1284         get_string_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_STYLE_NAME]));
1285 
1286     if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_line_height )
1287         atk_text_attribute_line_height = atk_text_attribute_register("line-height");
1288 
1289     attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_line_height,
1290         get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_LINE_SPACING], LineSpacing2LineHeight));
1291 
1292     if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tab_interval )
1293         atk_text_attribute_tab_interval = atk_text_attribute_register("tab-interval");
1294 
1295     attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_tab_interval,
1296         get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_TAB_STOPS], DefaultTabStops2String));
1297 
1298     if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tab_stops )
1299         atk_text_attribute_tab_stops = atk_text_attribute_register("tab-stops");
1300 
1301     attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_tab_stops,
1302         get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_TAB_STOPS], TabStops2String));
1303 
1304     // --> OD 2010-03-05 #i92233#
1305     if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_mm_to_pixel_ratio )
1306         atk_text_attribute_mm_to_pixel_ratio = atk_text_attribute_register("mm-to-pixel-ratio");
1307 
1308     attribute_set = attribute_set_prepend( attribute_set, atk_text_attribute_mm_to_pixel_ratio,
1309         get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_MM_TO_PIXEL_RATIO], Float2String));
1310     // <--
1311 
1312     return attribute_set;
1313 }
1314 
1315 
attribute_set_prepend_misspelled(AtkAttributeSet * attribute_set)1316 AtkAttributeSet* attribute_set_prepend_misspelled( AtkAttributeSet* attribute_set )
1317 {
1318 	if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_misspelled )
1319 		atk_text_attribute_misspelled = atk_text_attribute_register( "text-spelling" );
1320 
1321 	attribute_set = attribute_set_prepend( attribute_set, atk_text_attribute_misspelled,
1322 		g_strdup_printf( "misspelled" ) );
1323 
1324 	return attribute_set;
1325 }
1326 
1327 // --> OD 2010-03-01 #i92232#
attribute_set_prepend_tracked_change_insertion(AtkAttributeSet * attribute_set)1328 AtkAttributeSet* attribute_set_prepend_tracked_change_insertion( AtkAttributeSet* attribute_set )
1329 {
1330     if ( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tracked_change )
1331     {
1332         atk_text_attribute_tracked_change = atk_text_attribute_register( "text-tracked-change" );
1333     }
1334 
1335     attribute_set = attribute_set_prepend( attribute_set,
1336                                            atk_text_attribute_tracked_change,
1337                                            g_strdup_printf( "insertion" ) );
1338 
1339     return attribute_set;
1340 }
1341 
attribute_set_prepend_tracked_change_deletion(AtkAttributeSet * attribute_set)1342 AtkAttributeSet* attribute_set_prepend_tracked_change_deletion( AtkAttributeSet* attribute_set )
1343 {
1344     if ( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tracked_change )
1345     {
1346         atk_text_attribute_tracked_change = atk_text_attribute_register( "text-tracked-change" );
1347     }
1348 
1349     attribute_set = attribute_set_prepend( attribute_set,
1350                                            atk_text_attribute_tracked_change,
1351                                            g_strdup_printf( "deletion" ) );
1352 
1353     return attribute_set;
1354 }
1355 
attribute_set_prepend_tracked_change_formatchange(AtkAttributeSet * attribute_set)1356 AtkAttributeSet* attribute_set_prepend_tracked_change_formatchange( AtkAttributeSet* attribute_set )
1357 {
1358     if ( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tracked_change )
1359     {
1360         atk_text_attribute_tracked_change = atk_text_attribute_register( "text-tracked-change" );
1361     }
1362 
1363     attribute_set = attribute_set_prepend( attribute_set,
1364                                            atk_text_attribute_tracked_change,
1365                                            g_strdup_printf( "attribute-change" ) );
1366 
1367     return attribute_set;
1368 }
1369 // <--
1370 
1371 /*****************************************************************************/
1372 
1373 struct AtkTextAttrMapping
1374 {
1375     const char *          name;
1376     TextPropertyValueFunc toPropertyValue;
1377 };
1378 
1379 const AtkTextAttrMapping g_TextAttrMap[] =
1380 {
1381     { "", InvalidValue },                       // ATK_TEXT_ATTR_INVALID = 0
1382     { "ParaLeftMargin", UnitString2CMM },       // ATK_TEXT_ATTR_LEFT_MARGIN
1383     { "ParaRightMargin", UnitString2CMM },      // ATK_TEXT_ATTR_RIGHT_MARGIN
1384     { "ParaFirstLineIndent", UnitString2CMM },  // ATK_TEXT_ATTR_INDENT
1385     { "CharHidden", String2Bool },              // ATK_TEXT_ATTR_INVISIBLE
1386     { "", InvalidValue },                       // ATK_TEXT_ATTR_EDITABLE
1387     { "ParaTopMargin", UnitString2CMM },        // ATK_TEXT_ATTR_PIXELS_ABOVE_LINES
1388     { "ParaBottomMargin", UnitString2CMM },     // ATK_TEXT_ATTR_PIXELS_BELOW_LINES
1389     { "", InvalidValue },                       // ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP
1390     { "", InvalidValue },                       // ATK_TEXT_ATTR_BG_FULL_HEIGHT
1391     { "", InvalidValue },                       // ATK_TEXT_ATTR_RISE
1392     { "CharUnderline", String2Underline },      // ATK_TEXT_ATTR_UNDERLINE
1393     { "CharStrikeout", String2Strikeout },      // ATK_TEXT_ATTR_STRIKETHROUGH
1394     { "CharHeight", String2Float },             // ATK_TEXT_ATTR_SIZE
1395     { "CharScaleWidth", String2Scale },         // ATK_TEXT_ATTR_SCALE
1396     { "CharWeight", String2Weight },            // ATK_TEXT_ATTR_WEIGHT
1397     { "CharLocale", String2Locale },            // ATK_TEXT_ATTR_LANGUAGE
1398     { "CharFontName",  SetString },             // ATK_TEXT_ATTR_FAMILY_NAME
1399     { "CharBackColor", String2Color },          // ATK_TEXT_ATTR_BG_COLOR
1400     { "CharColor", String2Color },              // ATK_TEXT_ATTR_FG_COLOR
1401     { "", InvalidValue },                       // ATK_TEXT_ATTR_BG_STIPPLE
1402     { "", InvalidValue },                       // ATK_TEXT_ATTR_FG_STIPPLE
1403     { "", InvalidValue },                       // ATK_TEXT_ATTR_WRAP_MODE
1404     { "", InvalidValue },                       // ATK_TEXT_ATTR_DIRECTION
1405     { "ParaAdjust", Justification2Adjust },     // ATK_TEXT_ATTR_JUSTIFICATION
1406     { "", InvalidValue },                       // ATK_TEXT_ATTR_STRETCH
1407     { "CharCaseMap", String2CaseMap },          // ATK_TEXT_ATTR_VARIANT
1408     { "CharPosture", Style2FontSlant }          // ATK_TEXT_ATTR_STYLE
1409 };
1410 
1411 static const sal_Int32 g_TextAttrMapSize = sizeof( g_TextAttrMap ) / sizeof( AtkTextAttrMapping );
1412 
1413 /*****************************************************************************/
1414 
1415 bool
attribute_set_map_to_property_values(AtkAttributeSet * attribute_set,uno::Sequence<beans::PropertyValue> & rValueList)1416 attribute_set_map_to_property_values(
1417     AtkAttributeSet* attribute_set,
1418     uno::Sequence< beans::PropertyValue >& rValueList )
1419 {
1420     // Ensure enough space ..
1421     uno::Sequence< beans::PropertyValue > aAttributeList (g_TextAttrMapSize);
1422 
1423     sal_Int32 nIndex = 0;
1424     for( GSList * item = attribute_set; item != NULL; item = g_slist_next( item ) )
1425     {
1426         AtkAttribute* attribute = (AtkAttribute *) item;
1427 
1428         AtkTextAttribute text_attr = atk_text_attribute_for_name( attribute->name );
1429         if( text_attr < g_TextAttrMapSize )
1430         {
1431             if( g_TextAttrMap[text_attr].name[0] != '\0' )
1432             {
1433                 if( ! g_TextAttrMap[text_attr].toPropertyValue( aAttributeList[nIndex].Value, attribute->value) )
1434                     return false;
1435 
1436                 aAttributeList[nIndex].Name = rtl::OUString::createFromAscii( g_TextAttrMap[text_attr].name );
1437                 aAttributeList[nIndex].State = beans::PropertyState_DIRECT_VALUE;
1438                 ++nIndex;
1439             }
1440         }
1441         else
1442         {
1443             // Unsupported text attribute
1444             return false;
1445         }
1446     }
1447 
1448     aAttributeList.realloc( nIndex );
1449     rValueList = aAttributeList;
1450     return true;
1451 }
1452 
1453