1/*************************************************************************
2 *
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
6 *
7 * OpenOffice.org - a multi-platform office productivity suite
8 *
9 * This file is part of OpenOffice.org.
10 *
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
14 *
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org.  If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
25 *
26 ************************************************************************/
27
28// MARKER(update_precomp.py): autogen include statement, do not remove
29#include "precompiled_vcl.hxx"
30
31#include "aqua/salinst.h"
32
33#include "aqua11ytextattributeswrapper.h"
34
35#include <com/sun/star/accessibility/AccessibleTextType.hpp>
36#include <com/sun/star/awt/FontUnderline.hpp>
37#include <com/sun/star/awt/FontWeight.hpp>
38#include <com/sun/star/awt/FontStrikeout.hpp>
39
40using namespace ::com::sun::star::accessibility;
41using namespace ::com::sun::star::awt;
42using namespace ::com::sun::star::beans;
43using namespace ::com::sun::star::lang;
44using namespace ::com::sun::star::uno;
45using namespace ::rtl;
46
47@implementation AquaA11yTextAttributesWrapper : NSObject
48
49+(int)convertUnderlineStyle:(PropertyValue)property {
50    int underlineStyle = NSNoUnderlineStyle;
51    sal_Int16 value = 0;
52    property.Value >>= value;
53    if ( value != FontUnderline::NONE
54      && value != FontUnderline::DONTKNOW) {
55        underlineStyle = NSSingleUnderlineStyle;
56    }
57    return underlineStyle;
58}
59
60+(int)convertBoldStyle:(PropertyValue)property {
61    int boldStyle = 0;
62    float value = 0;
63    property.Value >>= value;
64    if ( value == FontWeight::SEMIBOLD
65      || value == FontWeight::BOLD
66      || value == FontWeight::ULTRABOLD
67      || value == FontWeight::BLACK ) {
68        boldStyle = NSBoldFontMask;
69    }
70    return boldStyle;
71}
72
73+(int)convertItalicStyle:(PropertyValue)property {
74    int italicStyle = 0;
75    sal_Int16 value = property.Value.get<FontSlant>();
76    if ( value == FontSlant_ITALIC ) {
77        italicStyle = NSItalicFontMask;
78    }
79    return italicStyle;
80}
81
82+(BOOL)isStrikethrough:(PropertyValue)property {
83    BOOL strikethrough = NO;
84    sal_Int16 value = 0;
85    property.Value >>= value;
86    if ( value != FontStrikeout::NONE
87      && value != FontStrikeout::DONTKNOW ) {
88        strikethrough = YES;
89    }
90    return strikethrough;
91}
92
93+(BOOL)convertBoolean:(PropertyValue)property {
94    BOOL myBoolean = NO;
95    bool value = sal_False;
96    property.Value >>= value;
97    if ( value ) {
98        myBoolean = YES;
99    }
100    return myBoolean;
101}
102
103+(NSNumber *)convertShort:(PropertyValue)property {
104    sal_Int16 value = 0;
105    property.Value >>= value;
106    return [ NSNumber numberWithShort: value ];
107}
108
109+(void)addColor:(sal_Int32)salColor forAttribute:(NSString *)attribute andRange:(NSRange)range toString:(NSMutableAttributedString *)string {
110    if ( salColor != -1 ) {
111        float elements[] = { salColor & 0x00ff0000, salColor & 0x0000ff00, salColor & 0x000000ff };
112        CGColorRef color = CGColorCreate ( CGColorSpaceCreateWithName ( kCGColorSpaceGenericRGB ), elements );
113        [ string addAttribute: attribute value: (id) color range: range ];
114        CGColorRelease ( color );
115    }
116}
117
118+(void)addFont:(NSFont *)font toString:(NSMutableAttributedString *)string forRange:(NSRange)range {
119    if ( font != nil ) {
120        NSDictionary * fontDictionary = [ NSDictionary dictionaryWithObjectsAndKeys:
121            [ font fontName ], NSAccessibilityFontNameKey,
122            [ font familyName ], NSAccessibilityFontFamilyKey,
123            [ font displayName ], NSAccessibilityVisibleNameKey,
124            [ NSNumber numberWithFloat: [ font pointSize ] ], NSAccessibilityFontSizeKey,
125            nil
126        ];
127        [ string addAttribute: NSAccessibilityFontTextAttribute
128                value: fontDictionary
129                range: range
130        ];
131    }
132}
133
134+(void)applyAttributesFrom:(Sequence < PropertyValue >)attributes toString:(NSMutableAttributedString *)string forRange:(NSRange)range storeDefaultsTo:(AquaA11yWrapper *)wrapperStore getDefaultsFrom:(AquaA11yWrapper *)wrapper {
135    NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
136    // constants
137    static const OUString attrUnderline = OUString::createFromAscii("CharUnderline");
138    static const OUString attrBold = OUString::createFromAscii("CharWeight");
139    static const OUString attrFontname = OUString::createFromAscii("CharFontName");
140    static const OUString attrItalic = OUString::createFromAscii("CharPosture");
141    static const OUString attrHeight = OUString::createFromAscii("CharHeight");
142    static const OUString attrStrikethrough = OUString::createFromAscii("CharStrikeout");
143    static const OUString attrShadow = OUString::createFromAscii("CharShadowed");
144    static const OUString attrUnderlineColor = OUString::createFromAscii("CharUnderlineColor");
145    static const OUString attrUnderlineHasColor = OUString::createFromAscii("CharUnderlineHasColor");
146    static const OUString attrForegroundColor = OUString::createFromAscii("CharColor");
147    static const OUString attrBackgroundColor = OUString::createFromAscii("CharBackColor");
148    static const OUString attrSuperscript = OUString::createFromAscii("CharEscapement");
149    // vars
150    OUString fontname;
151    int fonttraits = 0;
152    float fontsize = 0.0;
153    sal_Int32 underlineColor = 0;
154    BOOL underlineHasColor = NO;
155    // add attributes to string
156    for ( int attrIndex = 0; attrIndex < attributes.getLength(); attrIndex++ ) {
157        PropertyValue property = attributes [ attrIndex ];
158        // TODO: NSAccessibilityMisspelledTextAttribute, NSAccessibilityAttachmentTextAttribute, NSAccessibilityLinkTextAttribute
159        // NSAccessibilityStrikethroughColorTextAttribute is unsupported by UNP-API
160        if ( property.Value.hasValue() ) {
161            if ( property.Name.equals ( attrUnderline ) ) {
162                int style = [ AquaA11yTextAttributesWrapper convertUnderlineStyle: property ];
163                if ( style != NSNoUnderlineStyle ) {
164                    [ string addAttribute: NSAccessibilityUnderlineTextAttribute value: [ NSNumber numberWithInt: style ] range: range ];
165                }
166            } else if ( property.Name.equals ( attrFontname ) ) {
167                property.Value >>= fontname;
168            } else if ( property.Name.equals ( attrBold ) ) {
169                fonttraits |= [ AquaA11yTextAttributesWrapper convertBoldStyle: property ];
170            } else if ( property.Name.equals ( attrItalic ) ) {
171                fonttraits |= [ AquaA11yTextAttributesWrapper convertItalicStyle: property ];
172            } else if ( property.Name.equals ( attrHeight ) ) {
173                property.Value >>= fontsize;
174            } else if ( property.Name.equals ( attrStrikethrough ) ) {
175                if ( [ AquaA11yTextAttributesWrapper isStrikethrough: property ] ) {
176                    [ string addAttribute: NSAccessibilityStrikethroughTextAttribute value: [ NSNumber numberWithBool: YES ] range: range ];
177                }
178            } else if ( property.Name.equals ( attrShadow ) ) {
179                if ( [ AquaA11yTextAttributesWrapper convertBoolean: property ] ) {
180                    [ string addAttribute: NSAccessibilityShadowTextAttribute value: [ NSNumber numberWithBool: YES ] range: range ];
181                }
182            } else if ( property.Name.equals ( attrUnderlineColor ) ) {
183                property.Value >>= underlineColor;
184            } else if ( property.Name.equals ( attrUnderlineHasColor ) ) {
185                underlineHasColor = [ AquaA11yTextAttributesWrapper convertBoolean: property ];
186            } else if ( property.Name.equals ( attrForegroundColor ) ) {
187                [ AquaA11yTextAttributesWrapper addColor: property.Value.get<sal_Int32>() forAttribute: NSAccessibilityForegroundColorTextAttribute andRange: range toString: string ];
188            } else if ( property.Name.equals ( attrBackgroundColor ) ) {
189                [ AquaA11yTextAttributesWrapper addColor: property.Value.get<sal_Int32>() forAttribute: NSAccessibilityBackgroundColorTextAttribute andRange: range toString: string ];
190            } else if ( property.Name.equals ( attrSuperscript ) ) {
191                // values < zero mean subscript
192                // values > zero mean superscript
193                // this is true for both NSAccessibility-API and UNO-API
194                NSNumber * number = [ AquaA11yTextAttributesWrapper convertShort: property ];
195                if ( [ number shortValue ] != 0 ) {
196                    [ string addAttribute: NSAccessibilitySuperscriptTextAttribute value: number range: range ];
197                }
198            }
199        }
200    }
201    // add underline information
202    if ( underlineHasColor ) {
203        [ AquaA11yTextAttributesWrapper addColor: underlineColor forAttribute: NSAccessibilityUnderlineColorTextAttribute andRange: range toString: string ];
204    }
205    // add font information
206    if ( wrapperStore != nil ) { // default
207        [ wrapperStore setDefaultFontname: CreateNSString ( fontname ) ];
208        [ wrapperStore setDefaultFontsize: fontsize ];
209        NSFont * font = [ [ NSFontManager sharedFontManager ] fontWithFamily: CreateNSString ( fontname ) traits: fonttraits weight: 0 size: fontsize ];
210        [ AquaA11yTextAttributesWrapper addFont: font toString: string forRange: range ];
211    } else if ( wrapper != nil && fonttraits != 0 ) { // attribute run and bold and/or italic was found
212        NSFont * font = [ [ NSFontManager sharedFontManager ] fontWithFamily: [ wrapper defaultFontname ] traits: fonttraits weight: 0 size: [ wrapper defaultFontsize ] ];
213        [ AquaA11yTextAttributesWrapper addFont: font toString: string forRange: range ];
214    }
215    [ pool release ];
216}
217
218+(NSMutableAttributedString *)createAttributedStringForElement:(AquaA11yWrapper *)wrapper inOrigRange:(id)origRange {
219    static const Sequence < OUString > emptySequence;
220    // vars
221    NSMutableAttributedString * string = nil;
222    int loc = [ origRange rangeValue ].location;
223    int len = [ origRange rangeValue ].length;
224    int endIndex = loc + len;
225    int currentIndex = loc;
226    try {
227        NSString * myString = CreateNSString ( [ wrapper accessibleText ] -> getText() ); // TODO: dirty fix for i87817
228        string = [ [ NSMutableAttributedString alloc ] initWithString: CreateNSString ( [ wrapper accessibleText ] -> getTextRange ( loc, loc + len ) ) ];
229        if ( [ wrapper accessibleTextAttributes ] != nil && [myString characterAtIndex:0] != 57361) { // TODO: dirty fix for i87817
230            [ string beginEditing ];
231            // add default attributes for whole string
232            Sequence < PropertyValue > defaultAttributes = [ wrapper accessibleTextAttributes ] -> getDefaultAttributes ( emptySequence );
233            [ AquaA11yTextAttributesWrapper applyAttributesFrom: defaultAttributes toString: string forRange: [ origRange rangeValue ] storeDefaultsTo: wrapper getDefaultsFrom: nil ];
234            // add attributes for attribute run(s)
235            while ( currentIndex < endIndex ) {
236                TextSegment textSegment = [ wrapper accessibleText ] -> getTextAtIndex ( currentIndex, AccessibleTextType::ATTRIBUTE_RUN );
237                int endOfRange = endIndex > textSegment.SegmentEnd ? textSegment.SegmentEnd : endIndex;
238                NSRange rangeForAttributeRun = NSMakeRange ( currentIndex, endOfRange - currentIndex );
239                // add run attributes
240                Sequence < PropertyValue > attributes = [ wrapper accessibleTextAttributes ] -> getRunAttributes ( currentIndex, emptySequence );
241                [ AquaA11yTextAttributesWrapper applyAttributesFrom: attributes toString: string forRange: rangeForAttributeRun storeDefaultsTo: nil getDefaultsFrom: wrapper ];
242                currentIndex = textSegment.SegmentEnd;
243            }
244            [ string endEditing ];
245        }
246    } catch ( IllegalArgumentException & e ) {
247        // empty
248    } catch ( IndexOutOfBoundsException & e ) {
249        // empty
250    } catch ( RuntimeException& ) {
251        // at least don't crash
252    }
253    return string;
254}
255
256@end
257