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 "aqua/salinst.h"
28
29#include "aqua11ytextattributeswrapper.h"
30
31#include <com/sun/star/accessibility/AccessibleTextType.hpp>
32#include <com/sun/star/awt/FontUnderline.hpp>
33#include <com/sun/star/awt/FontWeight.hpp>
34#include <com/sun/star/awt/FontStrikeout.hpp>
35
36using namespace ::com::sun::star::accessibility;
37using namespace ::com::sun::star::awt;
38using namespace ::com::sun::star::beans;
39using namespace ::com::sun::star::lang;
40using namespace ::com::sun::star::uno;
41using namespace ::rtl;
42
43@implementation AquaA11yTextAttributesWrapper : NSObject
44
45+(int)convertUnderlineStyle:(PropertyValue)property {
46    int underlineStyle = NSNoUnderlineStyle;
47    sal_Int16 value = 0;
48    property.Value >>= value;
49    if ( value != FontUnderline::NONE
50      && value != FontUnderline::DONTKNOW) {
51        underlineStyle = NSSingleUnderlineStyle;
52    }
53    return underlineStyle;
54}
55
56+(int)convertBoldStyle:(PropertyValue)property {
57    int boldStyle = 0;
58    float value = 0;
59    property.Value >>= value;
60    if ( value == FontWeight::SEMIBOLD
61      || value == FontWeight::BOLD
62      || value == FontWeight::ULTRABOLD
63      || value == FontWeight::BLACK ) {
64        boldStyle = NSBoldFontMask;
65    }
66    return boldStyle;
67}
68
69+(int)convertItalicStyle:(PropertyValue)property {
70    int italicStyle = 0;
71    sal_Int16 value = property.Value.get<FontSlant>();
72    if ( value == FontSlant_ITALIC ) {
73        italicStyle = NSItalicFontMask;
74    }
75    return italicStyle;
76}
77
78+(BOOL)isStrikethrough:(PropertyValue)property {
79    BOOL strikethrough = NO;
80    sal_Int16 value = 0;
81    property.Value >>= value;
82    if ( value != FontStrikeout::NONE
83      && value != FontStrikeout::DONTKNOW ) {
84        strikethrough = YES;
85    }
86    return strikethrough;
87}
88
89+(BOOL)convertBoolean:(PropertyValue)property {
90    BOOL myBoolean = NO;
91    bool value = sal_False;
92    property.Value >>= value;
93    if ( value ) {
94        myBoolean = YES;
95    }
96    return myBoolean;
97}
98
99+(NSNumber *)convertShort:(PropertyValue)property {
100    sal_Int16 value = 0;
101    property.Value >>= value;
102    return [ NSNumber numberWithShort: value ];
103}
104
105+(void)addColor:(sal_Int32)salColor forAttribute:(NSString *)attribute andRange:(NSRange)range toString:(NSMutableAttributedString *)string {
106    if ( salColor != -1 ) {
107        float elements[] = { salColor & 0x00ff0000, salColor & 0x0000ff00, salColor & 0x000000ff };
108        CGColorRef color = CGColorCreate ( CGColorSpaceCreateWithName ( kCGColorSpaceGenericRGB ), elements );
109        [ string addAttribute: attribute value: (id) color range: range ];
110        CGColorRelease ( color );
111    }
112}
113
114+(void)addFont:(NSFont *)font toString:(NSMutableAttributedString *)string forRange:(NSRange)range {
115    if ( font != nil ) {
116        NSDictionary * fontDictionary = [ NSDictionary dictionaryWithObjectsAndKeys:
117            [ font fontName ], NSAccessibilityFontNameKey,
118            [ font familyName ], NSAccessibilityFontFamilyKey,
119            [ font displayName ], NSAccessibilityVisibleNameKey,
120            [ NSNumber numberWithFloat: [ font pointSize ] ], NSAccessibilityFontSizeKey,
121            nil
122        ];
123        [ string addAttribute: NSAccessibilityFontTextAttribute
124                value: fontDictionary
125                range: range
126        ];
127    }
128}
129
130+(void)applyAttributesFrom:(Sequence < PropertyValue >)attributes toString:(NSMutableAttributedString *)string forRange:(NSRange)range storeDefaultsTo:(AquaA11yWrapper *)wrapperStore getDefaultsFrom:(AquaA11yWrapper *)wrapper {
131    NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
132    // constants
133    static const OUString attrUnderline = OUString::createFromAscii("CharUnderline");
134    static const OUString attrBold = OUString::createFromAscii("CharWeight");
135    static const OUString attrFontname = OUString::createFromAscii("CharFontName");
136    static const OUString attrItalic = OUString::createFromAscii("CharPosture");
137    static const OUString attrHeight = OUString::createFromAscii("CharHeight");
138    static const OUString attrStrikethrough = OUString::createFromAscii("CharStrikeout");
139    static const OUString attrShadow = OUString::createFromAscii("CharShadowed");
140    static const OUString attrUnderlineColor = OUString::createFromAscii("CharUnderlineColor");
141    static const OUString attrUnderlineHasColor = OUString::createFromAscii("CharUnderlineHasColor");
142    static const OUString attrForegroundColor = OUString::createFromAscii("CharColor");
143    static const OUString attrBackgroundColor = OUString::createFromAscii("CharBackColor");
144    static const OUString attrSuperscript = OUString::createFromAscii("CharEscapement");
145    // vars
146    OUString fontname;
147    int fonttraits = 0;
148    float fontsize = 0.0;
149    sal_Int32 underlineColor = 0;
150    BOOL underlineHasColor = NO;
151    // add attributes to string
152    for ( int attrIndex = 0; attrIndex < attributes.getLength(); attrIndex++ ) {
153        PropertyValue property = attributes [ attrIndex ];
154        // TODO: NSAccessibilityMisspelledTextAttribute, NSAccessibilityAttachmentTextAttribute, NSAccessibilityLinkTextAttribute
155        // NSAccessibilityStrikethroughColorTextAttribute is unsupported by UNP-API
156        if ( property.Value.hasValue() ) {
157            if ( property.Name.equals ( attrUnderline ) ) {
158                int style = [ AquaA11yTextAttributesWrapper convertUnderlineStyle: property ];
159                if ( style != NSNoUnderlineStyle ) {
160                    [ string addAttribute: NSAccessibilityUnderlineTextAttribute value: [ NSNumber numberWithInt: style ] range: range ];
161                }
162            } else if ( property.Name.equals ( attrFontname ) ) {
163                property.Value >>= fontname;
164            } else if ( property.Name.equals ( attrBold ) ) {
165                fonttraits |= [ AquaA11yTextAttributesWrapper convertBoldStyle: property ];
166            } else if ( property.Name.equals ( attrItalic ) ) {
167                fonttraits |= [ AquaA11yTextAttributesWrapper convertItalicStyle: property ];
168            } else if ( property.Name.equals ( attrHeight ) ) {
169                property.Value >>= fontsize;
170            } else if ( property.Name.equals ( attrStrikethrough ) ) {
171                if ( [ AquaA11yTextAttributesWrapper isStrikethrough: property ] ) {
172                    [ string addAttribute: NSAccessibilityStrikethroughTextAttribute value: [ NSNumber numberWithBool: YES ] range: range ];
173                }
174            } else if ( property.Name.equals ( attrShadow ) ) {
175                if ( [ AquaA11yTextAttributesWrapper convertBoolean: property ] ) {
176                    [ string addAttribute: NSAccessibilityShadowTextAttribute value: [ NSNumber numberWithBool: YES ] range: range ];
177                }
178            } else if ( property.Name.equals ( attrUnderlineColor ) ) {
179                property.Value >>= underlineColor;
180            } else if ( property.Name.equals ( attrUnderlineHasColor ) ) {
181                underlineHasColor = [ AquaA11yTextAttributesWrapper convertBoolean: property ];
182            } else if ( property.Name.equals ( attrForegroundColor ) ) {
183                [ AquaA11yTextAttributesWrapper addColor: property.Value.get<sal_Int32>() forAttribute: NSAccessibilityForegroundColorTextAttribute andRange: range toString: string ];
184            } else if ( property.Name.equals ( attrBackgroundColor ) ) {
185                [ AquaA11yTextAttributesWrapper addColor: property.Value.get<sal_Int32>() forAttribute: NSAccessibilityBackgroundColorTextAttribute andRange: range toString: string ];
186            } else if ( property.Name.equals ( attrSuperscript ) ) {
187                // values < zero mean subscript
188                // values > zero mean superscript
189                // this is true for both NSAccessibility-API and UNO-API
190                NSNumber * number = [ AquaA11yTextAttributesWrapper convertShort: property ];
191                if ( [ number shortValue ] != 0 ) {
192                    [ string addAttribute: NSAccessibilitySuperscriptTextAttribute value: number range: range ];
193                }
194            }
195        }
196    }
197    // add underline information
198    if ( underlineHasColor ) {
199        [ AquaA11yTextAttributesWrapper addColor: underlineColor forAttribute: NSAccessibilityUnderlineColorTextAttribute andRange: range toString: string ];
200    }
201    // add font information
202    if ( wrapperStore != nil ) { // default
203        [ wrapperStore setDefaultFontname: CreateNSString ( fontname ) ];
204        [ wrapperStore setDefaultFontsize: fontsize ];
205        NSFont * font = [ [ NSFontManager sharedFontManager ] fontWithFamily: CreateNSString ( fontname ) traits: fonttraits weight: 0 size: fontsize ];
206        [ AquaA11yTextAttributesWrapper addFont: font toString: string forRange: range ];
207    } else if ( wrapper != nil && fonttraits != 0 ) { // attribute run and bold and/or italic was found
208        NSFont * font = [ [ NSFontManager sharedFontManager ] fontWithFamily: [ wrapper defaultFontname ] traits: fonttraits weight: 0 size: [ wrapper defaultFontsize ] ];
209        [ AquaA11yTextAttributesWrapper addFont: font toString: string forRange: range ];
210    }
211    [ pool release ];
212}
213
214+(NSMutableAttributedString *)createAttributedStringForElement:(AquaA11yWrapper *)wrapper inOrigRange:(id)origRange {
215    static const Sequence < OUString > emptySequence;
216    // vars
217    NSMutableAttributedString * string = nil;
218    int loc = [ origRange rangeValue ].location;
219    int len = [ origRange rangeValue ].length;
220    int endIndex = loc + len;
221    int currentIndex = loc;
222    try {
223        NSString * myString = CreateNSString ( [ wrapper accessibleText ] -> getText() ); // TODO: dirty fix for i87817
224        string = [ [ NSMutableAttributedString alloc ] initWithString: CreateNSString ( [ wrapper accessibleText ] -> getTextRange ( loc, loc + len ) ) ];
225        if ( [ wrapper accessibleTextAttributes ] != nil && [myString characterAtIndex:0] != 57361) { // TODO: dirty fix for i87817
226            [ string beginEditing ];
227            // add default attributes for whole string
228            Sequence < PropertyValue > defaultAttributes = [ wrapper accessibleTextAttributes ] -> getDefaultAttributes ( emptySequence );
229            [ AquaA11yTextAttributesWrapper applyAttributesFrom: defaultAttributes toString: string forRange: [ origRange rangeValue ] storeDefaultsTo: wrapper getDefaultsFrom: nil ];
230            // add attributes for attribute run(s)
231            while ( currentIndex < endIndex ) {
232                TextSegment textSegment = [ wrapper accessibleText ] -> getTextAtIndex ( currentIndex, AccessibleTextType::ATTRIBUTE_RUN );
233                int endOfRange = endIndex > textSegment.SegmentEnd ? textSegment.SegmentEnd : endIndex;
234                NSRange rangeForAttributeRun = NSMakeRange ( currentIndex, endOfRange - currentIndex );
235                // add run attributes
236                Sequence < PropertyValue > attributes = [ wrapper accessibleTextAttributes ] -> getRunAttributes ( currentIndex, emptySequence );
237                [ AquaA11yTextAttributesWrapper applyAttributesFrom: attributes toString: string forRange: rangeForAttributeRun storeDefaultsTo: nil getDefaultsFrom: wrapper ];
238                currentIndex = textSegment.SegmentEnd;
239            }
240            [ string endEditing ];
241        }
242    } catch ( IllegalArgumentException & e ) {
243        // empty
244    } catch ( IndexOutOfBoundsException & e ) {
245        // empty
246    } catch ( RuntimeException& ) {
247        // at least don't crash
248    }
249    return string;
250}
251
252@end
253