createFromAscii -> OUString literals in attribute_set_map_to_property_values
[LibreOffice.git] / vcl / unx / gtk3 / a11y / atktextattributes.cxx
blob7f3e5a23ce1eb7d782b5219fff6f6e53d0740c74
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "atktextattributes.hxx"
22 #include <com/sun/star/awt/FontSlant.hpp>
23 #include <com/sun/star/awt/FontStrikeout.hpp>
24 #include <com/sun/star/awt/FontUnderline.hpp>
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>
33 #include <com/sun/star/text/WritingMode2.hpp>
35 #include "atkwrapper.hxx"
37 #include <com/sun/star/accessibility/XAccessibleComponent.hpp>
39 #include <i18nlangtag/languagetag.hxx>
40 #include <tools/UnitConversion.hxx>
41 #include <o3tl/safeint.hxx>
42 #include <o3tl/string_view.hxx>
44 #include <stdio.h>
45 #include <string.h>
47 using namespace ::com::sun::star;
49 typedef gchar* (* AtkTextAttrFunc) ( const uno::Any& rAny );
50 typedef bool (* TextPropertyValueFunc) ( uno::Any& rAny, const gchar * value );
52 #define STRNCMP_PARAM( s ) s,sizeof( s )-1
54 /*****************************************************************************/
56 static AtkTextAttribute atk_text_attribute_paragraph_style = ATK_TEXT_ATTR_INVALID;
57 static AtkTextAttribute atk_text_attribute_font_effect = ATK_TEXT_ATTR_INVALID;
58 static AtkTextAttribute atk_text_attribute_decoration = ATK_TEXT_ATTR_INVALID;
59 static AtkTextAttribute atk_text_attribute_line_height = ATK_TEXT_ATTR_INVALID;
60 static AtkTextAttribute atk_text_attribute_rotation = ATK_TEXT_ATTR_INVALID;
61 static AtkTextAttribute atk_text_attribute_shadow = ATK_TEXT_ATTR_INVALID;
62 static AtkTextAttribute atk_text_attribute_tab_interval = ATK_TEXT_ATTR_INVALID;
63 static AtkTextAttribute atk_text_attribute_tab_stops = ATK_TEXT_ATTR_INVALID;
64 static AtkTextAttribute atk_text_attribute_writing_mode = ATK_TEXT_ATTR_INVALID;
65 static AtkTextAttribute atk_text_attribute_vertical_align = ATK_TEXT_ATTR_INVALID;
66 static AtkTextAttribute atk_text_attribute_misspelled = ATK_TEXT_ATTR_INVALID;
67 // #i92232#
68 static AtkTextAttribute atk_text_attribute_tracked_change = ATK_TEXT_ATTR_INVALID;
69 // #i92233#
70 static AtkTextAttribute atk_text_attribute_mm_to_pixel_ratio = ATK_TEXT_ATTR_INVALID;
72 /*****************************************************************************/
74 /**
75 * !! IMPORTANT NOTE !! : when adding items to this list, KEEP THE LIST SORTED
76 * and re-arrange the enum values accordingly.
79 namespace {
81 enum ExportedAttribute
83 TEXT_ATTRIBUTE_BACKGROUND_COLOR = 0,
84 TEXT_ATTRIBUTE_CASEMAP,
85 TEXT_ATTRIBUTE_FOREGROUND_COLOR,
86 TEXT_ATTRIBUTE_CONTOURED,
87 TEXT_ATTRIBUTE_CHAR_ESCAPEMENT,
88 TEXT_ATTRIBUTE_BLINKING,
89 TEXT_ATTRIBUTE_FONT_NAME,
90 TEXT_ATTRIBUTE_HEIGHT,
91 TEXT_ATTRIBUTE_HIDDEN,
92 TEXT_ATTRIBUTE_KERNING,
93 TEXT_ATTRIBUTE_LOCALE,
94 TEXT_ATTRIBUTE_POSTURE,
95 TEXT_ATTRIBUTE_RELIEF,
96 TEXT_ATTRIBUTE_ROTATION,
97 TEXT_ATTRIBUTE_SCALE,
98 TEXT_ATTRIBUTE_SHADOWED,
99 TEXT_ATTRIBUTE_STRIKETHROUGH,
100 TEXT_ATTRIBUTE_UNDERLINE,
101 TEXT_ATTRIBUTE_WEIGHT,
102 // #i92233#
103 TEXT_ATTRIBUTE_MM_TO_PIXEL_RATIO,
104 TEXT_ATTRIBUTE_JUSTIFICATION,
105 TEXT_ATTRIBUTE_BOTTOM_MARGIN,
106 TEXT_ATTRIBUTE_FIRST_LINE_INDENT,
107 TEXT_ATTRIBUTE_LEFT_MARGIN,
108 TEXT_ATTRIBUTE_LINE_SPACING,
109 TEXT_ATTRIBUTE_RIGHT_MARGIN,
110 TEXT_ATTRIBUTE_STYLE_NAME,
111 TEXT_ATTRIBUTE_TAB_STOPS,
112 TEXT_ATTRIBUTE_TOP_MARGIN,
113 TEXT_ATTRIBUTE_WRITING_MODE,
114 TEXT_ATTRIBUTE_LAST
119 static const char * ExportedTextAttributes[TEXT_ATTRIBUTE_LAST] =
121 "CharBackColor", // TEXT_ATTRIBUTE_BACKGROUND_COLOR
122 "CharCaseMap", // TEXT_ATTRIBUTE_CASEMAP
123 "CharColor", // TEXT_ATTRIBUTE_FOREGROUND_COLOR
124 "CharContoured", // TEXT_ATTRIBUTE_CONTOURED
125 "CharEscapement", // TEXT_ATTRIBUTE_CHAR_ESCAPEMENT
126 "CharFlash", // TEXT_ATTRIBUTE_BLINKING
127 "CharFontName", // TEXT_ATTRIBUTE_FONT_NAME
128 "CharHeight", // TEXT_ATTRIBUTE_HEIGHT
129 "CharHidden", // TEXT_ATTRIBUTE_HIDDEN
130 "CharKerning", // TEXT_ATTRIBUTE_KERNING
131 "CharLocale", // TEXT_ATTRIBUTE_LOCALE
132 "CharPosture", // TEXT_ATTRIBUTE_POSTURE
133 "CharRelief", // TEXT_ATTRIBUTE_RELIEF
134 "CharRotation", // TEXT_ATTRIBUTE_ROTATION
135 "CharScaleWidth", // TEXT_ATTRIBUTE_SCALE
136 "CharShadowed", // TEXT_ATTRIBUTE_SHADOWED
137 "CharStrikeout", // TEXT_ATTRIBUTE_STRIKETHROUGH
138 "CharUnderline", // TEXT_ATTRIBUTE_UNDERLINE
139 "CharWeight", // TEXT_ATTRIBUTE_WEIGHT
140 // #i92233#
141 "MMToPixelRatio", // TEXT_ATTRIBUTE_MM_TO_PIXEL_RATIO
142 "ParaAdjust", // TEXT_ATTRIBUTE_JUSTIFICATION
143 "ParaBottomMargin", // TEXT_ATTRIBUTE_BOTTOM_MARGIN
144 "ParaFirstLineIndent", // TEXT_ATTRIBUTE_FIRST_LINE_INDENT
145 "ParaLeftMargin", // TEXT_ATTRIBUTE_LEFT_MARGIN
146 "ParaLineSpacing", // TEXT_ATTRIBUTE_LINE_SPACING
147 "ParaRightMargin", // TEXT_ATTRIBUTE_RIGHT_MARGIN
148 "ParaStyleName", // TEXT_ATTRIBUTE_STYLE_NAME
149 "ParaTabStops", // TEXT_ATTRIBUTE_TAB_STOPS
150 "ParaTopMargin", // TEXT_ATTRIBUTE_TOP_MARGIN
151 "WritingMode" // TEXT_ATTRIBUTE_WRITING_MODE
154 /*****************************************************************************/
156 static gchar*
157 get_value( const uno::Sequence< beans::PropertyValue >& rAttributeList,
158 sal_Int32 nIndex, AtkTextAttrFunc func )
160 if( nIndex != -1 )
161 return func(rAttributeList[nIndex].Value);
163 return nullptr;
166 #define get_bool_value( list, index ) get_value( list, index, Bool2String )
167 #define get_height_value( list, index ) get_value( list, index, Float2String )
168 #define get_justification_value( list, index ) get_value( list, index, Adjust2Justification )
169 #define get_cmm_value( list, index ) get_value( list, index, CMM2UnitString )
170 #define get_scale_width( list, index ) get_value( list, index, Scale2String )
171 #define get_strikethrough_value( list, index ) get_value( list, index, Strikeout2String )
172 #define get_string_value( list, index ) get_value( list, index, GetString )
173 #define get_style_value( list, index ) get_value( list, index, FontSlant2Style )
174 #define get_underline_value( list, index ) get_value( list, index, Underline2String )
175 #define get_variant_value( list, index ) get_value( list, index, CaseMap2String )
176 #define get_weight_value( list, index ) get_value( list, index, Weight2String )
177 #define get_language_string( list, index ) get_value( list, index, Locale2String )
179 /*****************************************************************************/
181 static bool
182 InvalidValue( uno::Any&, const gchar * )
184 return false;
187 /*****************************************************************************/
189 static gchar*
190 Float2String(const uno::Any& rAny)
192 return g_strdup_printf( "%g", rAny.get<float>() );
195 static bool
196 String2Float( uno::Any& rAny, const gchar * value )
198 float fval;
200 if( 1 != sscanf( value, "%g", &fval ) )
201 return false;
203 rAny <<= fval;
204 return true;
207 /*****************************************************************************/
209 /// @throws uno::RuntimeException
210 static css::uno::Reference<css::accessibility::XAccessibleComponent>
211 getComponent( AtkText *pText )
213 AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
214 if( pWrap )
216 if( !pWrap->mpComponent.is() )
218 pWrap->mpComponent.set(pWrap->mpContext, css::uno::UNO_QUERY);
221 return pWrap->mpComponent;
224 return css::uno::Reference<css::accessibility::XAccessibleComponent>();
227 static gchar*
228 get_color_value(const uno::Sequence< beans::PropertyValue >& rAttributeList,
229 const sal_Int32 * pIndexArray,
230 ExportedAttribute attr,
231 AtkText * text)
233 sal_Int32 nColor = -1; // AUTOMATIC
234 sal_Int32 nIndex = pIndexArray[attr];
236 if( nIndex != -1 )
237 nColor = rAttributeList[nIndex].Value.get<sal_Int32>();
240 * Check for color value for 100% alpha white, which means
241 * "automatic". Grab the RGB value from XAccessibleComponent
242 * in this case.
245 if( (nColor == -1) && text )
249 css::uno::Reference<css::accessibility::XAccessibleComponent>
250 pComponent = getComponent( text );
251 if( pComponent.is() )
253 switch( attr )
255 case TEXT_ATTRIBUTE_BACKGROUND_COLOR:
256 nColor = pComponent->getBackground();
257 break;
258 case TEXT_ATTRIBUTE_FOREGROUND_COLOR:
259 nColor = pComponent->getForeground();
260 break;
261 default:
262 break;
267 catch(const uno::Exception&) {
268 g_warning( "Exception in get[Fore|Back]groundColor()" );
272 if( nColor != -1 )
274 sal_uInt8 blue = nColor & 0xFF;
275 sal_uInt8 green = (nColor >> 8) & 0xFF;
276 sal_uInt8 red = (nColor >> 16) & 0xFF;
278 return g_strdup_printf( "%u,%u,%u", red, green, blue );
281 return nullptr;
284 static bool
285 String2Color( uno::Any& rAny, const gchar * value )
287 int red, green, blue;
289 if( 3 != sscanf( value, "%d,%d,%d", &red, &green, &blue ) )
290 return false;
292 sal_Int32 nColor = static_cast<sal_Int32>(blue) | ( static_cast<sal_Int32>(green) << 8 ) | ( static_cast<sal_Int32>(red) << 16 );
293 rAny <<= nColor;
294 return true;
297 /*****************************************************************************/
299 static gchar*
300 FontSlant2Style(const uno::Any& rAny)
302 const gchar * value = nullptr;
304 awt::FontSlant aFontSlant;
305 if(!(rAny >>= aFontSlant))
306 return nullptr;
308 switch( aFontSlant )
310 case awt::FontSlant_NONE:
311 value = "normal";
312 break;
314 case awt::FontSlant_OBLIQUE:
315 value = "oblique";
316 break;
318 case awt::FontSlant_ITALIC:
319 value = "italic";
320 break;
322 case awt::FontSlant_REVERSE_OBLIQUE:
323 value = "reverse oblique";
324 break;
326 case awt::FontSlant_REVERSE_ITALIC:
327 value = "reverse italic";
328 break;
330 default:
331 break;
334 if( value )
335 return g_strdup( value );
337 return nullptr;
340 static bool
341 Style2FontSlant( uno::Any& rAny, const gchar * value )
343 awt::FontSlant aFontSlant;
345 if( strncmp( value, STRNCMP_PARAM( "normal" ) ) == 0 )
346 aFontSlant = awt::FontSlant_NONE;
347 else if( strncmp( value, STRNCMP_PARAM( "oblique" ) ) == 0 )
348 aFontSlant = awt::FontSlant_OBLIQUE;
349 else if( strncmp( value, STRNCMP_PARAM( "italic" ) ) == 0 )
350 aFontSlant = awt::FontSlant_ITALIC;
351 else if( strncmp( value, STRNCMP_PARAM( "reverse oblique" ) ) == 0 )
352 aFontSlant = awt::FontSlant_REVERSE_OBLIQUE;
353 else if( strncmp( value, STRNCMP_PARAM( "reverse italic" ) ) == 0 )
354 aFontSlant = awt::FontSlant_REVERSE_ITALIC;
355 else
356 return false;
358 rAny <<= aFontSlant;
359 return true;
362 /*****************************************************************************/
364 static gchar*
365 Weight2String(const uno::Any& rAny)
367 return g_strdup_printf( "%g", rAny.get<float>() * 4 );
370 static bool
371 String2Weight( uno::Any& rAny, const gchar * value )
373 float weight;
375 if( 1 != sscanf( value, "%g", &weight ) )
376 return false;
378 rAny <<= weight / 4;
379 return true;
382 /*****************************************************************************/
384 static gchar*
385 Adjust2Justification(const uno::Any& rAny)
387 const gchar * value = nullptr;
389 switch( static_cast<style::ParagraphAdjust>(rAny.get<short>()) )
391 case style::ParagraphAdjust_LEFT:
392 value = "left";
393 break;
395 case style::ParagraphAdjust_RIGHT:
396 value = "right";
397 break;
399 case style::ParagraphAdjust_BLOCK:
400 case style::ParagraphAdjust_STRETCH:
401 value = "fill";
402 break;
404 case style::ParagraphAdjust_CENTER:
405 value = "center";
406 break;
408 default:
409 break;
412 if( value )
413 return g_strdup( value );
415 return nullptr;
418 static bool
419 Justification2Adjust( uno::Any& rAny, const gchar * value )
421 style::ParagraphAdjust nParagraphAdjust;
423 if( strncmp( value, STRNCMP_PARAM( "left" ) ) == 0 )
424 nParagraphAdjust = style::ParagraphAdjust_LEFT;
425 else if( strncmp( value, STRNCMP_PARAM( "right" ) ) == 0 )
426 nParagraphAdjust = style::ParagraphAdjust_RIGHT;
427 else if( strncmp( value, STRNCMP_PARAM( "fill" ) ) == 0 )
428 nParagraphAdjust = style::ParagraphAdjust_BLOCK;
429 else if( strncmp( value, STRNCMP_PARAM( "center" ) ) == 0 )
430 nParagraphAdjust = style::ParagraphAdjust_CENTER;
431 else
432 return false;
434 rAny <<= static_cast<short>(nParagraphAdjust);
435 return true;
438 /*****************************************************************************/
440 const gchar * const font_strikethrough[] = {
441 "none", // FontStrikeout::NONE
442 "single", // FontStrikeout::SINGLE
443 "double", // FontStrikeout::DOUBLE
444 nullptr, // FontStrikeout::DONTKNOW
445 "bold", // FontStrikeout::BOLD
446 "with /", // FontStrikeout::SLASH
447 "with X" // FontStrikeout::X
450 static gchar*
451 Strikeout2String(const uno::Any& rAny)
453 sal_Int16 n = rAny.get<sal_Int16>();
455 if( n >= 0 && o3tl::make_unsigned(n) < SAL_N_ELEMENTS(font_strikethrough) )
456 return g_strdup( font_strikethrough[n] );
458 return nullptr;
461 static bool
462 String2Strikeout( uno::Any& rAny, const gchar * value )
464 for( sal_Int16 n=0; n < sal_Int16(SAL_N_ELEMENTS(font_strikethrough)); ++n )
466 if( ( nullptr != font_strikethrough[n] ) &&
467 0 == strncmp( value, font_strikethrough[n], strlen( font_strikethrough[n] ) ) )
469 rAny <<= n;
470 return true;
474 return false;
477 /*****************************************************************************/
479 static gchar*
480 Underline2String(const uno::Any& rAny)
482 const gchar * value = nullptr;
484 switch( rAny.get<sal_Int16>() )
486 case awt::FontUnderline::NONE:
487 value = "none";
488 break;
490 case awt::FontUnderline::SINGLE:
491 value = "single";
492 break;
494 case awt::FontUnderline::DOUBLE:
495 value = "double";
496 break;
498 default:
499 break;
502 if( value )
503 return g_strdup( value );
505 return nullptr;
508 static bool
509 String2Underline( uno::Any& rAny, const gchar * value )
511 short nUnderline;
513 if( strncmp( value, STRNCMP_PARAM( "none" ) ) == 0 )
514 nUnderline = awt::FontUnderline::NONE;
515 else if( strncmp( value, STRNCMP_PARAM( "single" ) ) == 0 )
516 nUnderline = awt::FontUnderline::SINGLE;
517 else if( strncmp( value, STRNCMP_PARAM( "double" ) ) == 0 )
518 nUnderline = awt::FontUnderline::DOUBLE;
519 else
520 return false;
522 rAny <<= nUnderline;
523 return true;
526 /*****************************************************************************/
528 static gchar*
529 GetString(const uno::Any& rAny)
531 OString aFontName = OUStringToOString( rAny.get< OUString > (), RTL_TEXTENCODING_UTF8 );
533 if( !aFontName.isEmpty() )
534 return g_strdup( aFontName.getStr() );
536 return nullptr;
539 static bool
540 SetString( uno::Any& rAny, const gchar * value )
542 OString aFontName( value );
544 if( !aFontName.isEmpty() )
546 rAny <<= OStringToOUString( aFontName, RTL_TEXTENCODING_UTF8 );
547 return true;
550 return false;
553 /*****************************************************************************/
555 // @see http://developer.gnome.org/doc/API/2.0/atk/AtkText.html#AtkTextAttribute
557 // CMM = 100th of mm
558 static gchar*
559 CMM2UnitString(const uno::Any& rAny)
561 double fValue = rAny.get<sal_Int32>();
562 fValue = fValue * 0.01;
564 return g_strdup_printf( "%gmm", fValue );
567 static bool
568 UnitString2CMM( uno::Any& rAny, const gchar * value )
570 float fValue = 0.0; // pb: don't use double here because of warning on linux
572 if( 1 != sscanf( value, "%gmm", &fValue ) )
573 return false;
575 fValue = fValue * 100;
577 rAny <<= static_cast<sal_Int32>(fValue);
578 return true;
581 /*****************************************************************************/
583 static const gchar * bool_values[] = { "true", "false" };
585 static gchar *
586 Bool2String( const uno::Any& rAny )
588 int n = 1;
590 if( rAny.get<bool>() )
591 n = 0;
593 return g_strdup( bool_values[n] );
596 static bool
597 String2Bool( uno::Any& rAny, const gchar * value )
599 bool bValue;
601 if( strncmp( value, STRNCMP_PARAM( "true" ) ) == 0 )
602 bValue = true;
603 else if( strncmp( value, STRNCMP_PARAM( "false" ) ) == 0 )
604 bValue = false;
605 else
606 return false;
608 rAny <<= bValue;
609 return true;
612 /*****************************************************************************/
614 static gchar*
615 Scale2String( const uno::Any& rAny )
617 return g_strdup_printf( "%g", static_cast<double>(rAny.get< sal_Int16 > ()) / 100 );
620 static bool
621 String2Scale( uno::Any& rAny, const gchar * value )
623 double dval;
625 if( 1 != sscanf( value, "%lg", &dval ) )
626 return false;
628 rAny <<= static_cast<sal_Int16>(dval * 100);
629 return true;
632 /*****************************************************************************/
634 static gchar *
635 CaseMap2String( const uno::Any& rAny )
637 const gchar * value;
639 switch( rAny.get<short>() )
641 case style::CaseMap::SMALLCAPS:
642 value = "small_caps";
643 break;
645 default:
646 value = "normal";
647 break;
650 return g_strdup(value);
653 static bool
654 String2CaseMap( uno::Any& rAny, const gchar * value )
656 short nCaseMap;
658 if( strncmp( value, STRNCMP_PARAM( "normal" ) ) == 0 )
659 nCaseMap = style::CaseMap::NONE;
660 else if( strncmp( value, STRNCMP_PARAM( "small_caps" ) ) == 0 )
661 nCaseMap = style::CaseMap::SMALLCAPS;
662 else
663 return false;
665 rAny <<= nCaseMap;
666 return true;
669 /*****************************************************************************/
671 const gchar * const font_stretch[] = {
672 "ultra_condensed",
673 "extra_condensed",
674 "condensed",
675 "semi_condensed",
676 "normal",
677 "semi_expanded",
678 "expanded",
679 "extra_expanded",
680 "ultra_expanded"
683 static gchar*
684 Kerning2Stretch(const uno::Any& rAny)
686 sal_Int16 n = rAny.get<sal_Int16>();
687 int i = 4;
689 // No good idea for a mapping - just return the basic info
690 if( n < 0 )
691 i=2;
692 else if( n > 0 )
693 i=6;
695 return g_strdup(font_stretch[i]);
698 /*****************************************************************************/
700 static gchar*
701 Locale2String(const uno::Any& rAny)
703 /* FIXME-BCP47: support language tags? And why is country lowercase? */
704 lang::Locale aLocale = rAny.get<lang::Locale> ();
705 LanguageTag aLanguageTag( aLocale);
706 return g_strdup_printf( "%s-%s",
707 OUStringToOString( aLanguageTag.getLanguage(), RTL_TEXTENCODING_ASCII_US).getStr(),
708 OUStringToOString( aLanguageTag.getCountry(), RTL_TEXTENCODING_ASCII_US).toAsciiLowerCase().getStr() );
711 static bool
712 String2Locale( uno::Any& rAny, const gchar * value )
714 /* FIXME-BCP47: support language tags? */
715 bool ret = false;
717 gchar ** str_array = g_strsplit_set( value, "-.@", -1 );
718 if( str_array[0] != nullptr )
720 ret = true;
722 lang::Locale aLocale;
724 aLocale.Language = OUString::createFromAscii(str_array[0]);
725 if( str_array[1] != nullptr )
727 gchar * country = g_ascii_strup(str_array[1], -1);
728 aLocale.Country = OUString::createFromAscii(country);
729 g_free(country);
732 rAny <<= aLocale;
735 g_strfreev(str_array);
736 return ret;
739 /*****************************************************************************/
741 // @see http://www.w3.org/TR/2002/WD-css3-fonts-20020802/#font-effect-prop
742 static const gchar * relief[] = { "none", "emboss", "engrave" };
743 const gchar * const outline = "outline";
745 static gchar *
746 get_font_effect(const uno::Sequence< beans::PropertyValue >& rAttributeList,
747 sal_Int32 nContourIndex, sal_Int32 nReliefIndex)
749 if( nContourIndex != -1 )
751 if( rAttributeList[nContourIndex].Value.get<bool>() )
752 return g_strdup(outline);
755 if( nReliefIndex != -1 )
757 sal_Int16 n = rAttributeList[nReliefIndex].Value.get<sal_Int16>();
758 if( n < 3)
759 return g_strdup(relief[n]);
762 return nullptr;
765 /*****************************************************************************/
767 // @see http://www.w3.org/TR/REC-CSS2/text.html#lining-striking-props
769 enum
771 DECORATION_NONE = 0,
772 DECORATION_BLINK,
773 DECORATION_UNDERLINE,
774 DECORATION_LINE_THROUGH
777 static const gchar * decorations[] = { "none", "blink", "underline", "line-through" };
779 static gchar *
780 get_text_decoration(const uno::Sequence< beans::PropertyValue >& rAttributeList,
781 sal_Int32 nBlinkIndex, sal_Int32 nUnderlineIndex,
782 sal_Int16 nStrikeoutIndex)
784 gchar * value_list[4] = { nullptr, nullptr, nullptr, nullptr };
785 gint count = 0;
787 // no property value found
788 if( ( nBlinkIndex == -1 ) && (nUnderlineIndex == -1 ) && (nStrikeoutIndex == -1))
789 return nullptr;
791 if( nBlinkIndex != -1 )
793 if( rAttributeList[nBlinkIndex].Value.get<bool>() )
794 value_list[count++] = const_cast <gchar *> (decorations[DECORATION_BLINK]);
796 if( nUnderlineIndex != -1 )
798 sal_Int16 n = rAttributeList[nUnderlineIndex].Value.get<sal_Int16> ();
799 if( n != awt::FontUnderline::NONE )
800 value_list[count++] = const_cast <gchar *> (decorations[DECORATION_UNDERLINE]);
802 if( nStrikeoutIndex != -1 )
804 sal_Int16 n = rAttributeList[nStrikeoutIndex].Value.get<sal_Int16> ();
805 if( n != awt::FontStrikeout::NONE && n != awt::FontStrikeout::DONTKNOW )
806 value_list[count++] = const_cast <gchar *> (decorations[DECORATION_LINE_THROUGH]);
809 if( count == 0 )
810 value_list[count++] = const_cast <gchar *> (decorations[DECORATION_NONE]);
812 return g_strjoinv(" ", value_list);
815 /*****************************************************************************/
817 // @see http://www.w3.org/TR/REC-CSS2/text.html#propdef-text-shadow
819 static const gchar * shadow_values[] = { "none", "black" };
821 static gchar *
822 Bool2Shadow( const uno::Any& rAny )
824 int n = 0;
826 if( rAny.get<bool>() )
827 n = 1;
829 return g_strdup( shadow_values[n] );
832 /*****************************************************************************/
834 static gchar *
835 Short2Degree( const uno::Any& rAny )
837 float f = rAny.get<sal_Int16>() / 10.0;
838 return g_strdup_printf( "%g", f );
841 /*****************************************************************************/
843 const gchar * const directions[] = { "ltr", "rtl", "rtl", "ltr", "none" };
845 static gchar *
846 WritingMode2Direction( const uno::Any& rAny )
848 sal_Int16 n = rAny.get<sal_Int16>();
850 if( 0 <= n && n <= text::WritingMode2::PAGE )
851 return g_strdup(directions[n]);
853 return nullptr;
856 // @see http://www.w3.org/TR/2001/WD-css3-text-20010517/#PrimaryTextAdvanceDirection
858 const gchar * const writing_modes[] = { "lr-tb", "rl-tb", "tb-rl", "tb-lr", "none" };
859 static gchar *
860 WritingMode2String( const uno::Any& rAny )
862 sal_Int16 n = rAny.get<sal_Int16>();
864 if( 0 <= n && n <= text::WritingMode2::PAGE )
865 return g_strdup(writing_modes[n]);
867 return nullptr;
870 /*****************************************************************************/
872 const char * const baseline_values[] = { "baseline", "sub", "super" };
874 // @see http://www.w3.org/TR/REC-CSS2/visudet.html#propdef-vertical-align
875 static gchar *
876 Escapement2VerticalAlign( const uno::Any& rAny )
878 sal_Int16 n = rAny.get<sal_Int16>();
879 gchar * ret = nullptr;
881 // Values are in %, 101% means "automatic"
882 if( n == 0 )
883 ret = g_strdup(baseline_values[0]);
884 else if( n == 101 )
885 ret = g_strdup(baseline_values[2]);
886 else if( n == -101 )
887 ret = g_strdup(baseline_values[1]);
888 else
889 ret = g_strdup_printf( "%d%%", n );
891 return ret;
894 /*****************************************************************************/
896 // @see http://www.w3.org/TR/REC-CSS2/visudet.html#propdef-line-height
897 static gchar *
898 LineSpacing2LineHeight( const uno::Any& rAny )
900 style::LineSpacing ls;
901 gchar * ret = nullptr;
903 if( rAny >>= ls )
905 if( ls.Mode == style::LineSpacingMode::PROP )
906 ret = g_strdup_printf( "%d%%", ls.Height );
907 else if( ls.Mode == style::LineSpacingMode::FIX )
908 ret = g_strdup_printf("%.3gpt", convertMm100ToPoint<double>(ls.Height));
911 return ret;
914 /*****************************************************************************/
916 // @see http://www.w3.org/People/howcome/t/970224HTMLERB-CSS/WD-tabs-970117.html
917 static gchar *
918 TabStopList2String( const uno::Any& rAny, bool default_tabs )
920 uno::Sequence< style::TabStop > theTabStops;
921 gchar * ret = nullptr;
923 if( rAny >>= theTabStops)
925 sal_Unicode lastFillChar = ' ';
927 for (const auto& rTabStop : theTabStops)
929 bool is_default_tab = (style::TabAlign_DEFAULT == rTabStop.Alignment);
931 if( is_default_tab != default_tabs )
932 continue;
934 double fValue = rTabStop.Position;
935 fValue = fValue * 0.01;
937 const gchar * tab_align = "";
938 switch( rTabStop.Alignment )
940 case style::TabAlign_LEFT :
941 tab_align = "left ";
942 break;
943 case style::TabAlign_CENTER :
944 tab_align = "center ";
945 break;
946 case style::TabAlign_RIGHT :
947 tab_align = "right ";
948 break;
949 case style::TabAlign_DECIMAL :
950 tab_align = "decimal ";
951 break;
952 default:
953 break;
956 const gchar * lead_char = "";
958 if( rTabStop.FillChar != lastFillChar )
960 lastFillChar = rTabStop.FillChar;
961 switch (lastFillChar)
963 case ' ':
964 lead_char = "blank ";
965 break;
967 case '.':
968 lead_char = "dotted ";
969 break;
971 case '-':
972 lead_char = "dashed ";
973 break;
975 case '_':
976 lead_char = "lined ";
977 break;
979 default:
980 lead_char = "custom ";
981 break;
985 gchar * tab_str = g_strdup_printf( "%s%s%gmm", lead_char, tab_align, fValue );
987 if( ret )
989 gchar * old_tab_str = ret;
990 ret = g_strconcat(old_tab_str, " ", tab_str, nullptr);
991 g_free( tab_str );
992 g_free( old_tab_str );
994 else
995 ret = tab_str;
999 return ret;
1002 static gchar *
1003 TabStops2String( const uno::Any& rAny )
1005 return TabStopList2String(rAny, false);
1008 static gchar *
1009 DefaultTabStops2String( const uno::Any& rAny )
1011 return TabStopList2String(rAny, true);
1014 /*****************************************************************************/
1016 extern "C" {
1018 static int
1019 attr_compare(const void *p1,const void *p2)
1021 const rtl_uString * pustr = static_cast<const rtl_uString *>(p1);
1022 const char * pc = *static_cast<const char * const *>(p2);
1024 return rtl_ustr_ascii_compare_WithLength(pustr->buffer, pustr->length, pc);
1029 static void
1030 find_exported_attributes( sal_Int32 *pArray,
1031 const css::uno::Sequence< css::beans::PropertyValue >& rAttributeList )
1033 for( sal_Int32 i = 0; i < rAttributeList.getLength(); i++ )
1035 const char ** pAttr = static_cast<const char **>(bsearch(rAttributeList[i].Name.pData,
1036 ExportedTextAttributes, TEXT_ATTRIBUTE_LAST, sizeof(const char *),
1037 attr_compare));
1039 if( pAttr )
1041 sal_Int32 nIndex = pAttr - ExportedTextAttributes;
1042 pArray[nIndex] = i;
1047 /*****************************************************************************/
1049 static AtkAttributeSet*
1050 attribute_set_prepend( AtkAttributeSet* attribute_set,
1051 AtkTextAttribute attribute,
1052 gchar * value )
1054 if( value )
1056 AtkAttribute *at = static_cast<AtkAttribute *>(g_malloc( sizeof (AtkAttribute) ));
1057 at->name = g_strdup( atk_text_attribute_get_name( attribute ) );
1058 at->value = value;
1060 return g_slist_prepend(attribute_set, at);
1063 return attribute_set;
1066 /*****************************************************************************/
1068 AtkAttributeSet*
1069 attribute_set_new_from_property_values(
1070 const uno::Sequence< beans::PropertyValue >& rAttributeList,
1071 bool run_attributes_only,
1072 AtkText *text)
1074 AtkAttributeSet* attribute_set = nullptr;
1076 sal_Int32 aIndexList[TEXT_ATTRIBUTE_LAST] = { -1 };
1078 // Initialize index array with -1
1079 for(sal_Int32 & rn : aIndexList)
1080 rn = -1;
1082 find_exported_attributes(aIndexList, rAttributeList);
1084 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_BG_COLOR,
1085 get_color_value(rAttributeList, aIndexList, TEXT_ATTRIBUTE_BACKGROUND_COLOR, run_attributes_only ? nullptr : text ) );
1087 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_FG_COLOR,
1088 get_color_value(rAttributeList, aIndexList, TEXT_ATTRIBUTE_FOREGROUND_COLOR, run_attributes_only ? nullptr : text) );
1090 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_INVISIBLE,
1091 get_bool_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_HIDDEN]));
1093 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_UNDERLINE,
1094 get_underline_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_UNDERLINE]));
1096 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_STRIKETHROUGH,
1097 get_strikethrough_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_STRIKETHROUGH]));
1099 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_SIZE,
1100 get_height_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_HEIGHT]));
1102 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_WEIGHT,
1103 get_weight_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_WEIGHT]));
1105 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_FAMILY_NAME,
1106 get_string_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_FONT_NAME]));
1108 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_VARIANT,
1109 get_variant_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_CASEMAP]));
1111 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_STYLE,
1112 get_style_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_POSTURE]));
1114 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_SCALE,
1115 get_scale_width(rAttributeList, aIndexList[TEXT_ATTRIBUTE_SCALE]));
1117 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_LANGUAGE,
1118 get_language_string(rAttributeList, aIndexList[TEXT_ATTRIBUTE_LOCALE]));
1120 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_DIRECTION,
1121 get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_WRITING_MODE], WritingMode2Direction));
1123 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_STRETCH,
1124 get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_KERNING], Kerning2Stretch));
1126 if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_font_effect )
1127 atk_text_attribute_font_effect = atk_text_attribute_register("font-effect");
1129 attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_font_effect,
1130 get_font_effect(rAttributeList, aIndexList[TEXT_ATTRIBUTE_CONTOURED], aIndexList[TEXT_ATTRIBUTE_RELIEF]));
1132 if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_decoration )
1133 atk_text_attribute_decoration = atk_text_attribute_register("text-decoration");
1135 attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_decoration,
1136 get_text_decoration(rAttributeList, aIndexList[TEXT_ATTRIBUTE_BLINKING],
1137 aIndexList[TEXT_ATTRIBUTE_UNDERLINE], aIndexList[TEXT_ATTRIBUTE_STRIKETHROUGH]));
1139 if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_rotation )
1140 atk_text_attribute_rotation = atk_text_attribute_register("text-rotation");
1142 attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_rotation,
1143 get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_ROTATION], Short2Degree));
1145 if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_shadow )
1146 atk_text_attribute_shadow = atk_text_attribute_register("text-shadow");
1148 attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_shadow,
1149 get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_SHADOWED], Bool2Shadow));
1151 if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_writing_mode )
1152 atk_text_attribute_writing_mode = atk_text_attribute_register("writing-mode");
1154 attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_writing_mode,
1155 get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_WRITING_MODE], WritingMode2String));
1157 if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_vertical_align )
1158 atk_text_attribute_vertical_align = atk_text_attribute_register("vertical-align");
1160 attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_vertical_align,
1161 get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_CHAR_ESCAPEMENT], Escapement2VerticalAlign));
1163 if( run_attributes_only )
1164 return attribute_set;
1166 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_LEFT_MARGIN,
1167 get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_LEFT_MARGIN]));
1169 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_RIGHT_MARGIN,
1170 get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_RIGHT_MARGIN]));
1172 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_INDENT,
1173 get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_FIRST_LINE_INDENT]));
1175 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_PIXELS_ABOVE_LINES,
1176 get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_TOP_MARGIN]));
1178 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_PIXELS_BELOW_LINES,
1179 get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_BOTTOM_MARGIN]));
1181 attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_JUSTIFICATION,
1182 get_justification_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_JUSTIFICATION]));
1184 if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_paragraph_style )
1185 atk_text_attribute_paragraph_style = atk_text_attribute_register("paragraph-style");
1187 attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_paragraph_style,
1188 get_string_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_STYLE_NAME]));
1190 if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_line_height )
1191 atk_text_attribute_line_height = atk_text_attribute_register("line-height");
1193 attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_line_height,
1194 get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_LINE_SPACING], LineSpacing2LineHeight));
1196 if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tab_interval )
1197 atk_text_attribute_tab_interval = atk_text_attribute_register("tab-interval");
1199 attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_tab_interval,
1200 get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_TAB_STOPS], DefaultTabStops2String));
1202 if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tab_stops )
1203 atk_text_attribute_tab_stops = atk_text_attribute_register("tab-stops");
1205 attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_tab_stops,
1206 get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_TAB_STOPS], TabStops2String));
1208 // #i92233#
1209 if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_mm_to_pixel_ratio )
1210 atk_text_attribute_mm_to_pixel_ratio = atk_text_attribute_register("mm-to-pixel-ratio");
1212 attribute_set = attribute_set_prepend( attribute_set, atk_text_attribute_mm_to_pixel_ratio,
1213 get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_MM_TO_PIXEL_RATIO], Float2String));
1215 return attribute_set;
1218 AtkAttributeSet*
1219 attribute_set_new_from_extended_attributes(
1220 const css::uno::Reference< css::accessibility::XAccessibleExtendedAttributes >& rExtendedAttributes )
1222 AtkAttributeSet *pSet = nullptr;
1224 // extended attributes is a string of colon-separated pairs of property and value,
1225 // with pairs separated by semicolons. Example: "heading-level:2;weight:bold;"
1226 uno::Any anyVal = rExtendedAttributes->getExtendedAttributes();
1227 OUString sExtendedAttrs;
1228 anyVal >>= sExtendedAttrs;
1229 sal_Int32 nIndex = 0;
1232 OUString sProperty = sExtendedAttrs.getToken( 0, ';', nIndex );
1234 sal_Int32 nColonPos = 0;
1235 OString sPropertyName = OUStringToOString( o3tl::getToken(sProperty, 0, ':', nColonPos ),
1236 RTL_TEXTENCODING_UTF8 );
1237 OString sPropertyValue = OUStringToOString( o3tl::getToken(sProperty, 0, ':', nColonPos ),
1238 RTL_TEXTENCODING_UTF8 );
1240 pSet = attribute_set_prepend( pSet,
1241 atk_text_attribute_register( sPropertyName.getStr() ),
1242 g_strdup_printf( "%s", sPropertyValue.getStr() ) );
1244 while ( nIndex >= 0 && nIndex < sExtendedAttrs.getLength() );
1246 return pSet;
1249 AtkAttributeSet* attribute_set_prepend_misspelled( AtkAttributeSet* attribute_set )
1251 if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_misspelled )
1252 atk_text_attribute_misspelled = atk_text_attribute_register( "text-spelling" );
1254 attribute_set = attribute_set_prepend( attribute_set, atk_text_attribute_misspelled,
1255 g_strdup_printf( "misspelled" ) );
1257 return attribute_set;
1260 // #i92232#
1261 AtkAttributeSet* attribute_set_prepend_tracked_change_insertion( AtkAttributeSet* attribute_set )
1263 if ( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tracked_change )
1265 atk_text_attribute_tracked_change = atk_text_attribute_register( "text-tracked-change" );
1268 attribute_set = attribute_set_prepend( attribute_set,
1269 atk_text_attribute_tracked_change,
1270 g_strdup_printf( "insertion" ) );
1272 return attribute_set;
1275 AtkAttributeSet* attribute_set_prepend_tracked_change_deletion( AtkAttributeSet* attribute_set )
1277 if ( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tracked_change )
1279 atk_text_attribute_tracked_change = atk_text_attribute_register( "text-tracked-change" );
1282 attribute_set = attribute_set_prepend( attribute_set,
1283 atk_text_attribute_tracked_change,
1284 g_strdup_printf( "deletion" ) );
1286 return attribute_set;
1289 AtkAttributeSet* attribute_set_prepend_tracked_change_formatchange( AtkAttributeSet* attribute_set )
1291 if ( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tracked_change )
1293 atk_text_attribute_tracked_change = atk_text_attribute_register( "text-tracked-change" );
1296 attribute_set = attribute_set_prepend( attribute_set,
1297 atk_text_attribute_tracked_change,
1298 g_strdup_printf( "attribute-change" ) );
1300 return attribute_set;
1303 /*****************************************************************************/
1305 namespace {
1307 struct AtkTextAttrMapping
1309 OUString name;
1310 TextPropertyValueFunc toPropertyValue;
1315 constexpr AtkTextAttrMapping g_TextAttrMap[]
1317 { u""_ustr, InvalidValue }, // ATK_TEXT_ATTR_INVALID = 0
1318 { u"ParaLeftMargin"_ustr, UnitString2CMM }, // ATK_TEXT_ATTR_LEFT_MARGIN
1319 { u"ParaRightMargin"_ustr, UnitString2CMM }, // ATK_TEXT_ATTR_RIGHT_MARGIN
1320 { u"ParaFirstLineIndent"_ustr, UnitString2CMM }, // ATK_TEXT_ATTR_INDENT
1321 { u"CharHidden"_ustr, String2Bool }, // ATK_TEXT_ATTR_INVISIBLE
1322 { u""_ustr, InvalidValue }, // ATK_TEXT_ATTR_EDITABLE
1323 { u"ParaTopMargin"_ustr, UnitString2CMM }, // ATK_TEXT_ATTR_PIXELS_ABOVE_LINES
1324 { u"ParaBottomMargin"_ustr, UnitString2CMM }, // ATK_TEXT_ATTR_PIXELS_BELOW_LINES
1325 { u""_ustr, InvalidValue }, // ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP
1326 { u""_ustr, InvalidValue }, // ATK_TEXT_ATTR_BG_FULL_HEIGHT
1327 { u""_ustr, InvalidValue }, // ATK_TEXT_ATTR_RISE
1328 { u"CharUnderline"_ustr, String2Underline }, // ATK_TEXT_ATTR_UNDERLINE
1329 { u"CharStrikeout"_ustr, String2Strikeout }, // ATK_TEXT_ATTR_STRIKETHROUGH
1330 { u"CharHeight"_ustr, String2Float }, // ATK_TEXT_ATTR_SIZE
1331 { u"CharScaleWidth"_ustr, String2Scale }, // ATK_TEXT_ATTR_SCALE
1332 { u"CharWeight"_ustr, String2Weight }, // ATK_TEXT_ATTR_WEIGHT
1333 { u"CharLocale"_ustr, String2Locale }, // ATK_TEXT_ATTR_LANGUAGE
1334 { u"CharFontName"_ustr, SetString }, // ATK_TEXT_ATTR_FAMILY_NAME
1335 { u"CharBackColor"_ustr, String2Color }, // ATK_TEXT_ATTR_BG_COLOR
1336 { u"CharColor"_ustr, String2Color }, // ATK_TEXT_ATTR_FG_COLOR
1337 { u""_ustr, InvalidValue }, // ATK_TEXT_ATTR_BG_STIPPLE
1338 { u""_ustr, InvalidValue }, // ATK_TEXT_ATTR_FG_STIPPLE
1339 { u""_ustr, InvalidValue }, // ATK_TEXT_ATTR_WRAP_MODE
1340 { u""_ustr, InvalidValue }, // ATK_TEXT_ATTR_DIRECTION
1341 { u"ParaAdjust"_ustr, Justification2Adjust }, // ATK_TEXT_ATTR_JUSTIFICATION
1342 { u""_ustr, InvalidValue }, // ATK_TEXT_ATTR_STRETCH
1343 { u"CharCaseMap"_ustr, String2CaseMap }, // ATK_TEXT_ATTR_VARIANT
1344 { u"CharPosture"_ustr, Style2FontSlant } // ATK_TEXT_ATTR_STYLE
1347 /*****************************************************************************/
1349 bool
1350 attribute_set_map_to_property_values(
1351 AtkAttributeSet* attribute_set,
1352 uno::Sequence< beans::PropertyValue >& rValueList )
1354 // Ensure enough space ..
1355 uno::Sequence< beans::PropertyValue > aAttributeList (SAL_N_ELEMENTS(g_TextAttrMap));
1356 auto pAttributeList = aAttributeList.getArray();
1358 sal_Int32 nIndex = 0;
1359 for( GSList * item = attribute_set; item != nullptr; item = g_slist_next( item ) )
1361 AtkAttribute* attribute = reinterpret_cast<AtkAttribute *>(item);
1363 AtkTextAttribute text_attr = atk_text_attribute_for_name( attribute->name );
1364 if( text_attr < SAL_N_ELEMENTS(g_TextAttrMap) )
1366 if( g_TextAttrMap[text_attr].name[0] != '\0' )
1368 if( ! g_TextAttrMap[text_attr].toPropertyValue( pAttributeList[nIndex].Value, attribute->value) )
1369 return false;
1371 pAttributeList[nIndex].Name = g_TextAttrMap[text_attr].name;
1372 pAttributeList[nIndex].State = beans::PropertyState_DIRECT_VALUE;
1373 ++nIndex;
1376 else
1378 // Unsupported text attribute
1379 return false;
1383 aAttributeList.realloc( nIndex );
1384 rValueList = aAttributeList;
1385 return true;
1388 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */