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