1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/accessible/src/atk/nsMaiInterfaceText.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,488 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "InterfaceInitFuncs.h" 1.11 + 1.12 +#include "Accessible-inl.h" 1.13 +#include "HyperTextAccessible-inl.h" 1.14 +#include "nsMai.h" 1.15 + 1.16 +#include "nsIAccessibleTypes.h" 1.17 +#include "nsIPersistentProperties2.h" 1.18 +#include "nsISimpleEnumerator.h" 1.19 + 1.20 +#include "mozilla/Likely.h" 1.21 + 1.22 +using namespace mozilla; 1.23 +using namespace mozilla::a11y; 1.24 + 1.25 +static const char* sAtkTextAttrNames[ATK_TEXT_ATTR_LAST_DEFINED]; 1.26 + 1.27 +static AtkAttributeSet* 1.28 +ConvertToAtkTextAttributeSet(nsIPersistentProperties* aAttributes) 1.29 +{ 1.30 + if (!aAttributes) 1.31 + return nullptr; 1.32 + 1.33 + AtkAttributeSet* objAttributeSet = nullptr; 1.34 + nsCOMPtr<nsISimpleEnumerator> propEnum; 1.35 + nsresult rv = aAttributes->Enumerate(getter_AddRefs(propEnum)); 1.36 + NS_ENSURE_SUCCESS(rv, nullptr); 1.37 + 1.38 + bool hasMore = false; 1.39 + while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) { 1.40 + nsCOMPtr<nsISupports> sup; 1.41 + rv = propEnum->GetNext(getter_AddRefs(sup)); 1.42 + NS_ENSURE_SUCCESS(rv, objAttributeSet); 1.43 + 1.44 + nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup)); 1.45 + NS_ENSURE_TRUE(propElem, objAttributeSet); 1.46 + 1.47 + nsAutoCString name; 1.48 + rv = propElem->GetKey(name); 1.49 + NS_ENSURE_SUCCESS(rv, objAttributeSet); 1.50 + 1.51 + nsAutoString value; 1.52 + rv = propElem->GetValue(value); 1.53 + NS_ENSURE_SUCCESS(rv, objAttributeSet); 1.54 + 1.55 + AtkAttribute* objAttr = (AtkAttribute*)g_malloc(sizeof(AtkAttribute)); 1.56 + objAttr->name = g_strdup(name.get()); 1.57 + objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(value).get()); 1.58 + objAttributeSet = g_slist_prepend(objAttributeSet, objAttr); 1.59 + 1.60 + // Handle attributes where atk has its own name. 1.61 + const char* atkName = nullptr; 1.62 + nsAutoString atkValue; 1.63 + if (name.EqualsLiteral("color")) { 1.64 + // The format of the atk attribute is r,g,b and the gecko one is 1.65 + // rgb(r,g,b). 1.66 + atkValue = Substring(value, 5, value.Length() - 1); 1.67 + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FG_COLOR]; 1.68 + } else if (name.EqualsLiteral("background-color")) { 1.69 + // The format of the atk attribute is r,g,b and the gecko one is 1.70 + // rgb(r,g,b). 1.71 + atkValue = Substring(value, 5, value.Length() - 1); 1.72 + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_BG_COLOR]; 1.73 + } else if (name.EqualsLiteral("font-family")) { 1.74 + atkValue = value; 1.75 + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FAMILY_NAME]; 1.76 + } else if (name.Equals("font-size")) { 1.77 + // ATK wants the number of pixels without px at the end. 1.78 + atkValue = StringHead(value, value.Length() - 2); 1.79 + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_SIZE]; 1.80 + } else if (name.EqualsLiteral("font-weight")) { 1.81 + atkValue = value; 1.82 + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_WEIGHT]; 1.83 + } else if (name.EqualsLiteral("invalid")) { 1.84 + atkValue = value; 1.85 + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_INVALID]; 1.86 + } 1.87 + 1.88 + if (atkName) { 1.89 + objAttr = static_cast<AtkAttribute*>(g_malloc(sizeof(AtkAttribute))); 1.90 + objAttr->name = g_strdup(atkName); 1.91 + objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(atkValue).get()); 1.92 + objAttributeSet = g_slist_prepend(objAttributeSet, objAttr); 1.93 + } 1.94 + } 1.95 + 1.96 + // libatk-adaptor will free it 1.97 + return objAttributeSet; 1.98 +} 1.99 + 1.100 +static void 1.101 +ConvertTexttoAsterisks(AccessibleWrap* accWrap, nsAString& aString) 1.102 +{ 1.103 + // convert each char to "*" when it's "password text" 1.104 + if (accWrap->NativeRole() == roles::PASSWORD_TEXT) { 1.105 + for (uint32_t i = 0; i < aString.Length(); i++) 1.106 + aString.Replace(i, 1, NS_LITERAL_STRING("*")); 1.107 + } 1.108 +} 1.109 + 1.110 +extern "C" { 1.111 + 1.112 +static gchar* 1.113 +getTextCB(AtkText *aText, gint aStartOffset, gint aEndOffset) 1.114 +{ 1.115 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.116 + if (!accWrap) 1.117 + return nullptr; 1.118 + 1.119 + HyperTextAccessible* text = accWrap->AsHyperText(); 1.120 + if (!text || !text->IsTextRole()) 1.121 + return nullptr; 1.122 + 1.123 + nsAutoString autoStr; 1.124 + text->TextSubstring(aStartOffset, aEndOffset, autoStr); 1.125 + 1.126 + ConvertTexttoAsterisks(accWrap, autoStr); 1.127 + NS_ConvertUTF16toUTF8 cautoStr(autoStr); 1.128 + 1.129 + //copy and return, libspi will free it. 1.130 + return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr; 1.131 +} 1.132 + 1.133 +static gchar* 1.134 +getTextAfterOffsetCB(AtkText *aText, gint aOffset, 1.135 + AtkTextBoundary aBoundaryType, 1.136 + gint *aStartOffset, gint *aEndOffset) 1.137 +{ 1.138 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.139 + if (!accWrap) 1.140 + return nullptr; 1.141 + 1.142 + HyperTextAccessible* text = accWrap->AsHyperText(); 1.143 + if (!text || !text->IsTextRole()) 1.144 + return nullptr; 1.145 + 1.146 + nsAutoString autoStr; 1.147 + int32_t startOffset = 0, endOffset = 0; 1.148 + text->TextAfterOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr); 1.149 + 1.150 + *aStartOffset = startOffset; 1.151 + *aEndOffset = endOffset; 1.152 + 1.153 + ConvertTexttoAsterisks(accWrap, autoStr); 1.154 + NS_ConvertUTF16toUTF8 cautoStr(autoStr); 1.155 + return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr; 1.156 +} 1.157 + 1.158 +static gchar* 1.159 +getTextAtOffsetCB(AtkText *aText, gint aOffset, 1.160 + AtkTextBoundary aBoundaryType, 1.161 + gint *aStartOffset, gint *aEndOffset) 1.162 +{ 1.163 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.164 + if (!accWrap) 1.165 + return nullptr; 1.166 + 1.167 + HyperTextAccessible* text = accWrap->AsHyperText(); 1.168 + if (!text || !text->IsTextRole()) 1.169 + return nullptr; 1.170 + 1.171 + nsAutoString autoStr; 1.172 + int32_t startOffset = 0, endOffset = 0; 1.173 + text->TextAtOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr); 1.174 + *aStartOffset = startOffset; 1.175 + *aEndOffset = endOffset; 1.176 + 1.177 + ConvertTexttoAsterisks(accWrap, autoStr); 1.178 + NS_ConvertUTF16toUTF8 cautoStr(autoStr); 1.179 + return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr; 1.180 +} 1.181 + 1.182 +static gunichar 1.183 +getCharacterAtOffsetCB(AtkText* aText, gint aOffset) 1.184 +{ 1.185 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.186 + if (!accWrap) 1.187 + return 0; 1.188 + 1.189 + HyperTextAccessible* text = accWrap->AsHyperText(); 1.190 + if (!text || !text->IsTextRole()) 1.191 + return 0; 1.192 + 1.193 + // char16_t is unsigned short in Mozilla, gnuichar is guint32 in glib. 1.194 + return static_cast<gunichar>(text->CharAt(aOffset)); 1.195 +} 1.196 + 1.197 +static gchar* 1.198 +getTextBeforeOffsetCB(AtkText *aText, gint aOffset, 1.199 + AtkTextBoundary aBoundaryType, 1.200 + gint *aStartOffset, gint *aEndOffset) 1.201 +{ 1.202 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.203 + if (!accWrap) 1.204 + return nullptr; 1.205 + 1.206 + HyperTextAccessible* text = accWrap->AsHyperText(); 1.207 + if (!text || !text->IsTextRole()) 1.208 + return nullptr; 1.209 + 1.210 + nsAutoString autoStr; 1.211 + int32_t startOffset = 0, endOffset = 0; 1.212 + text->TextBeforeOffset(aOffset, aBoundaryType, 1.213 + &startOffset, &endOffset, autoStr); 1.214 + *aStartOffset = startOffset; 1.215 + *aEndOffset = endOffset; 1.216 + 1.217 + ConvertTexttoAsterisks(accWrap, autoStr); 1.218 + NS_ConvertUTF16toUTF8 cautoStr(autoStr); 1.219 + return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr; 1.220 +} 1.221 + 1.222 +static gint 1.223 +getCaretOffsetCB(AtkText *aText) 1.224 +{ 1.225 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.226 + if (!accWrap) 1.227 + return 0; 1.228 + 1.229 + HyperTextAccessible* text = accWrap->AsHyperText(); 1.230 + if (!text || !text->IsTextRole()) 1.231 + return 0; 1.232 + 1.233 + return static_cast<gint>(text->CaretOffset()); 1.234 +} 1.235 + 1.236 +static AtkAttributeSet* 1.237 +getRunAttributesCB(AtkText *aText, gint aOffset, 1.238 + gint *aStartOffset, 1.239 + gint *aEndOffset) 1.240 +{ 1.241 + *aStartOffset = -1; 1.242 + *aEndOffset = -1; 1.243 + 1.244 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.245 + if (!accWrap) 1.246 + return nullptr; 1.247 + 1.248 + HyperTextAccessible* text = accWrap->AsHyperText(); 1.249 + if (!text || !text->IsTextRole()) 1.250 + return nullptr; 1.251 + 1.252 + int32_t startOffset = 0, endOffset = 0; 1.253 + nsCOMPtr<nsIPersistentProperties> attributes = 1.254 + text->TextAttributes(false, aOffset, &startOffset, &endOffset); 1.255 + 1.256 + *aStartOffset = startOffset; 1.257 + *aEndOffset = endOffset; 1.258 + 1.259 + return ConvertToAtkTextAttributeSet(attributes); 1.260 +} 1.261 + 1.262 +static AtkAttributeSet* 1.263 +getDefaultAttributesCB(AtkText *aText) 1.264 +{ 1.265 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.266 + if (!accWrap) 1.267 + return nullptr; 1.268 + 1.269 + HyperTextAccessible* text = accWrap->AsHyperText(); 1.270 + if (!text || !text->IsTextRole()) 1.271 + return nullptr; 1.272 + 1.273 + nsCOMPtr<nsIPersistentProperties> attributes = text->DefaultTextAttributes(); 1.274 + return ConvertToAtkTextAttributeSet(attributes); 1.275 +} 1.276 + 1.277 +static void 1.278 +getCharacterExtentsCB(AtkText *aText, gint aOffset, 1.279 + gint *aX, gint *aY, 1.280 + gint *aWidth, gint *aHeight, 1.281 + AtkCoordType aCoords) 1.282 +{ 1.283 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.284 + if(!accWrap || !aX || !aY || !aWidth || !aHeight) 1.285 + return; 1.286 + 1.287 + HyperTextAccessible* text = accWrap->AsHyperText(); 1.288 + if (!text || !text->IsTextRole()) 1.289 + return; 1.290 + 1.291 + uint32_t geckoCoordType; 1.292 + if (aCoords == ATK_XY_SCREEN) 1.293 + geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE; 1.294 + else 1.295 + geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE; 1.296 + 1.297 + nsIntRect rect = text->CharBounds(aOffset, geckoCoordType); 1.298 + *aX = rect.x; 1.299 + *aY = rect.y; 1.300 + *aWidth = rect.width; 1.301 + *aHeight = rect.height; 1.302 +} 1.303 + 1.304 +static void 1.305 +getRangeExtentsCB(AtkText *aText, gint aStartOffset, gint aEndOffset, 1.306 + AtkCoordType aCoords, AtkTextRectangle *aRect) 1.307 +{ 1.308 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.309 + if(!accWrap || !aRect) 1.310 + return; 1.311 + 1.312 + HyperTextAccessible* text = accWrap->AsHyperText(); 1.313 + if (!text || !text->IsTextRole()) 1.314 + return; 1.315 + 1.316 + uint32_t geckoCoordType; 1.317 + if (aCoords == ATK_XY_SCREEN) 1.318 + geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE; 1.319 + else 1.320 + geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE; 1.321 + 1.322 + nsIntRect rect = text->TextBounds(aStartOffset, aEndOffset, geckoCoordType); 1.323 + aRect->x = rect.x; 1.324 + aRect->y = rect.y; 1.325 + aRect->width = rect.width; 1.326 + aRect->height = rect.height; 1.327 +} 1.328 + 1.329 +static gint 1.330 +getCharacterCountCB(AtkText *aText) 1.331 +{ 1.332 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.333 + if (!accWrap) 1.334 + return 0; 1.335 + 1.336 + HyperTextAccessible* textAcc = accWrap->AsHyperText(); 1.337 + return textAcc->IsDefunct() ? 1.338 + 0 : static_cast<gint>(textAcc->CharacterCount()); 1.339 +} 1.340 + 1.341 +static gint 1.342 +getOffsetAtPointCB(AtkText *aText, 1.343 + gint aX, gint aY, 1.344 + AtkCoordType aCoords) 1.345 +{ 1.346 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.347 + if (!accWrap) 1.348 + return -1; 1.349 + 1.350 + HyperTextAccessible* text = accWrap->AsHyperText(); 1.351 + if (!text || !text->IsTextRole()) 1.352 + return -1; 1.353 + 1.354 + return static_cast<gint>( 1.355 + text->OffsetAtPoint(aX, aY, 1.356 + (aCoords == ATK_XY_SCREEN ? 1.357 + nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE : 1.358 + nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE))); 1.359 +} 1.360 + 1.361 +static gint 1.362 +getTextSelectionCountCB(AtkText *aText) 1.363 +{ 1.364 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.365 + if (!accWrap) 1.366 + return 0; 1.367 + 1.368 + HyperTextAccessible* text = accWrap->AsHyperText(); 1.369 + if (!text || !text->IsTextRole()) 1.370 + return 0; 1.371 + 1.372 + return text->SelectionCount(); 1.373 +} 1.374 + 1.375 +static gchar* 1.376 +getTextSelectionCB(AtkText *aText, gint aSelectionNum, 1.377 + gint *aStartOffset, gint *aEndOffset) 1.378 +{ 1.379 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.380 + if (!accWrap) 1.381 + return nullptr; 1.382 + 1.383 + HyperTextAccessible* text = accWrap->AsHyperText(); 1.384 + if (!text || !text->IsTextRole()) 1.385 + return nullptr; 1.386 + 1.387 + int32_t startOffset = 0, endOffset = 0; 1.388 + text->SelectionBoundsAt(aSelectionNum, &startOffset, &endOffset); 1.389 + 1.390 + *aStartOffset = startOffset; 1.391 + *aEndOffset = endOffset; 1.392 + 1.393 + return getTextCB(aText, *aStartOffset, *aEndOffset); 1.394 +} 1.395 + 1.396 +// set methods 1.397 +static gboolean 1.398 +addTextSelectionCB(AtkText *aText, 1.399 + gint aStartOffset, 1.400 + gint aEndOffset) 1.401 +{ 1.402 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.403 + if (!accWrap) 1.404 + return FALSE; 1.405 + 1.406 + HyperTextAccessible* text = accWrap->AsHyperText(); 1.407 + if (!text || !text->IsTextRole()) 1.408 + return FALSE; 1.409 + 1.410 + return text->AddToSelection(aStartOffset, aEndOffset); 1.411 +} 1.412 + 1.413 +static gboolean 1.414 +removeTextSelectionCB(AtkText *aText, 1.415 + gint aSelectionNum) 1.416 +{ 1.417 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.418 + if (!accWrap) 1.419 + return FALSE; 1.420 + 1.421 + HyperTextAccessible* text = accWrap->AsHyperText(); 1.422 + if (!text || !text->IsTextRole()) 1.423 + return FALSE; 1.424 + 1.425 + return text->RemoveFromSelection(aSelectionNum); 1.426 +} 1.427 + 1.428 +static gboolean 1.429 +setTextSelectionCB(AtkText *aText, gint aSelectionNum, 1.430 + gint aStartOffset, gint aEndOffset) 1.431 +{ 1.432 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.433 + if (!accWrap) 1.434 + return FALSE; 1.435 + 1.436 + HyperTextAccessible* text = accWrap->AsHyperText(); 1.437 + if (!text || !text->IsTextRole()) 1.438 + return FALSE; 1.439 + 1.440 + return text->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset); 1.441 +} 1.442 + 1.443 +static gboolean 1.444 +setCaretOffsetCB(AtkText *aText, gint aOffset) 1.445 +{ 1.446 + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); 1.447 + if (!accWrap) 1.448 + return FALSE; 1.449 + 1.450 + HyperTextAccessible* text = accWrap->AsHyperText(); 1.451 + if (!text || !text->IsTextRole() || !text->IsValidOffset(aOffset)) 1.452 + return FALSE; 1.453 + 1.454 + text->SetCaretOffset(aOffset); 1.455 + return TRUE; 1.456 +} 1.457 +} 1.458 + 1.459 +void 1.460 +textInterfaceInitCB(AtkTextIface* aIface) 1.461 +{ 1.462 + NS_ASSERTION(aIface, "Invalid aIface"); 1.463 + if (MOZ_UNLIKELY(!aIface)) 1.464 + return; 1.465 + 1.466 + aIface->get_text = getTextCB; 1.467 + aIface->get_text_after_offset = getTextAfterOffsetCB; 1.468 + aIface->get_text_at_offset = getTextAtOffsetCB; 1.469 + aIface->get_character_at_offset = getCharacterAtOffsetCB; 1.470 + aIface->get_text_before_offset = getTextBeforeOffsetCB; 1.471 + aIface->get_caret_offset = getCaretOffsetCB; 1.472 + aIface->get_run_attributes = getRunAttributesCB; 1.473 + aIface->get_default_attributes = getDefaultAttributesCB; 1.474 + aIface->get_character_extents = getCharacterExtentsCB; 1.475 + aIface->get_range_extents = getRangeExtentsCB; 1.476 + aIface->get_character_count = getCharacterCountCB; 1.477 + aIface->get_offset_at_point = getOffsetAtPointCB; 1.478 + aIface->get_n_selections = getTextSelectionCountCB; 1.479 + aIface->get_selection = getTextSelectionCB; 1.480 + 1.481 + // set methods 1.482 + aIface->add_selection = addTextSelectionCB; 1.483 + aIface->remove_selection = removeTextSelectionCB; 1.484 + aIface->set_selection = setTextSelectionCB; 1.485 + aIface->set_caret_offset = setCaretOffsetCB; 1.486 + 1.487 + // Cache the string values of the atk text attribute names. 1.488 + for (uint32_t i = 0; i < ArrayLength(sAtkTextAttrNames); i++) 1.489 + sAtkTextAttrNames[i] = 1.490 + atk_text_attribute_get_name(static_cast<AtkTextAttribute>(i)); 1.491 +}