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