ia2AccessibleText.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* vim:expandtab:shiftwidth=2:tabstop=2:
  3. */
  4. /* This Source Code Form is subject to the terms of the Mozilla Public
  5. * License, v. 2.0. If a copy of the MPL was not distributed with this
  6. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  7. #include "ia2AccessibleText.h"
  8. #include "Accessible2.h"
  9. #include "AccessibleText_i.c"
  10. #include "HyperTextAccessibleWrap.h"
  11. #include "HyperTextAccessible-inl.h"
  12. #include "ProxyWrappers.h"
  13. #include "mozilla/ClearOnShutdown.h"
  14. using namespace mozilla;
  15. using namespace mozilla::a11y;
  16. StaticRefPtr<HyperTextAccessibleWrap> ia2AccessibleText::sLastTextChangeAcc;
  17. StaticAutoPtr<nsString> ia2AccessibleText::sLastTextChangeString;
  18. uint32_t ia2AccessibleText::sLastTextChangeStart = 0;
  19. uint32_t ia2AccessibleText::sLastTextChangeEnd = 0;
  20. bool ia2AccessibleText::sLastTextChangeWasInsert = false;
  21. // IAccessibleText
  22. STDMETHODIMP
  23. ia2AccessibleText::addSelection(long aStartOffset, long aEndOffset)
  24. {
  25. MOZ_ASSERT(!HyperTextProxyFor(this));
  26. HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
  27. if (textAcc->IsDefunct())
  28. return CO_E_OBJNOTCONNECTED;
  29. return textAcc->AddToSelection(aStartOffset, aEndOffset) ?
  30. S_OK : E_INVALIDARG;
  31. }
  32. STDMETHODIMP
  33. ia2AccessibleText::get_attributes(long aOffset, long *aStartOffset,
  34. long *aEndOffset, BSTR *aTextAttributes)
  35. {
  36. if (!aStartOffset || !aEndOffset || !aTextAttributes)
  37. return E_INVALIDARG;
  38. *aStartOffset = 0;
  39. *aEndOffset = 0;
  40. *aTextAttributes = nullptr;
  41. int32_t startOffset = 0, endOffset = 0;
  42. HRESULT hr;
  43. MOZ_ASSERT(!HyperTextProxyFor(this));
  44. HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
  45. if (textAcc->IsDefunct()) {
  46. return CO_E_OBJNOTCONNECTED;
  47. }
  48. nsCOMPtr<nsIPersistentProperties> attributes =
  49. textAcc->TextAttributes(true, aOffset, &startOffset, &endOffset);
  50. hr = AccessibleWrap::ConvertToIA2Attributes(attributes, aTextAttributes);
  51. if (FAILED(hr))
  52. return hr;
  53. *aStartOffset = startOffset;
  54. *aEndOffset = endOffset;
  55. return S_OK;
  56. }
  57. STDMETHODIMP
  58. ia2AccessibleText::get_caretOffset(long *aOffset)
  59. {
  60. if (!aOffset)
  61. return E_INVALIDARG;
  62. *aOffset = -1;
  63. MOZ_ASSERT(!HyperTextProxyFor(this));
  64. HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
  65. if (textAcc->IsDefunct()) {
  66. return CO_E_OBJNOTCONNECTED;
  67. }
  68. *aOffset = textAcc->CaretOffset();
  69. return *aOffset != -1 ? S_OK : S_FALSE;
  70. }
  71. STDMETHODIMP
  72. ia2AccessibleText::get_characterExtents(long aOffset,
  73. enum IA2CoordinateType aCoordType,
  74. long* aX, long* aY,
  75. long* aWidth, long* aHeight)
  76. {
  77. if (!aX || !aY || !aWidth || !aHeight)
  78. return E_INVALIDARG;
  79. *aX = *aY = *aWidth = *aHeight = 0;
  80. uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ?
  81. nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
  82. nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
  83. nsIntRect rect;
  84. MOZ_ASSERT(!HyperTextProxyFor(this));
  85. HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
  86. if (textAcc->IsDefunct())
  87. return CO_E_OBJNOTCONNECTED;
  88. rect = textAcc->CharBounds(aOffset, geckoCoordType);
  89. *aX = rect.x;
  90. *aY = rect.y;
  91. *aWidth = rect.width;
  92. *aHeight = rect.height;
  93. return S_OK;
  94. }
  95. STDMETHODIMP
  96. ia2AccessibleText::get_nSelections(long* aNSelections)
  97. {
  98. if (!aNSelections)
  99. return E_INVALIDARG;
  100. *aNSelections = 0;
  101. MOZ_ASSERT(!HyperTextProxyFor(this));
  102. HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
  103. if (textAcc->IsDefunct()) {
  104. return CO_E_OBJNOTCONNECTED;
  105. }
  106. *aNSelections = textAcc->SelectionCount();
  107. return S_OK;
  108. }
  109. STDMETHODIMP
  110. ia2AccessibleText::get_offsetAtPoint(long aX, long aY,
  111. enum IA2CoordinateType aCoordType,
  112. long* aOffset)
  113. {
  114. if (!aOffset)
  115. return E_INVALIDARG;
  116. *aOffset = 0;
  117. uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ?
  118. nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
  119. nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
  120. MOZ_ASSERT(!HyperTextProxyFor(this));
  121. HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
  122. if (textAcc->IsDefunct()) {
  123. return CO_E_OBJNOTCONNECTED;
  124. }
  125. *aOffset = textAcc->OffsetAtPoint(aX, aY, geckoCoordType);
  126. return *aOffset == -1 ? S_FALSE : S_OK;
  127. }
  128. STDMETHODIMP
  129. ia2AccessibleText::get_selection(long aSelectionIndex, long* aStartOffset,
  130. long* aEndOffset)
  131. {
  132. if (!aStartOffset || !aEndOffset)
  133. return E_INVALIDARG;
  134. *aStartOffset = *aEndOffset = 0;
  135. int32_t startOffset = 0, endOffset = 0;
  136. MOZ_ASSERT(!HyperTextProxyFor(this));
  137. HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
  138. if (textAcc->IsDefunct()) {
  139. return CO_E_OBJNOTCONNECTED;
  140. }
  141. if (!textAcc->SelectionBoundsAt(aSelectionIndex, &startOffset, &endOffset)) {
  142. return E_INVALIDARG;
  143. }
  144. *aStartOffset = startOffset;
  145. *aEndOffset = endOffset;
  146. return S_OK;
  147. }
  148. STDMETHODIMP
  149. ia2AccessibleText::get_text(long aStartOffset, long aEndOffset, BSTR* aText)
  150. {
  151. if (!aText)
  152. return E_INVALIDARG;
  153. *aText = nullptr;
  154. nsAutoString text;
  155. MOZ_ASSERT(!HyperTextProxyFor(this));
  156. HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
  157. if (textAcc->IsDefunct()) {
  158. return CO_E_OBJNOTCONNECTED;
  159. }
  160. if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) {
  161. return E_INVALIDARG;
  162. }
  163. textAcc->TextSubstring(aStartOffset, aEndOffset, text);
  164. if (text.IsEmpty())
  165. return S_FALSE;
  166. *aText = ::SysAllocStringLen(text.get(), text.Length());
  167. return *aText ? S_OK : E_OUTOFMEMORY;
  168. }
  169. STDMETHODIMP
  170. ia2AccessibleText::get_textBeforeOffset(long aOffset,
  171. enum IA2TextBoundaryType aBoundaryType,
  172. long* aStartOffset, long* aEndOffset,
  173. BSTR* aText)
  174. {
  175. if (!aStartOffset || !aEndOffset || !aText)
  176. return E_INVALIDARG;
  177. *aStartOffset = *aEndOffset = 0;
  178. *aText = nullptr;
  179. HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
  180. if (textAcc->IsDefunct())
  181. return CO_E_OBJNOTCONNECTED;
  182. if (!textAcc->IsValidOffset(aOffset))
  183. return E_INVALIDARG;
  184. nsAutoString text;
  185. int32_t startOffset = 0, endOffset = 0;
  186. if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) {
  187. startOffset = 0;
  188. endOffset = textAcc->CharacterCount();
  189. textAcc->TextSubstring(startOffset, endOffset, text);
  190. } else {
  191. AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType);
  192. if (boundaryType == -1)
  193. return S_FALSE;
  194. textAcc->TextBeforeOffset(aOffset, boundaryType, &startOffset, &endOffset, text);
  195. }
  196. *aStartOffset = startOffset;
  197. *aEndOffset = endOffset;
  198. if (text.IsEmpty())
  199. return S_FALSE;
  200. *aText = ::SysAllocStringLen(text.get(), text.Length());
  201. return *aText ? S_OK : E_OUTOFMEMORY;
  202. }
  203. STDMETHODIMP
  204. ia2AccessibleText::get_textAfterOffset(long aOffset,
  205. enum IA2TextBoundaryType aBoundaryType,
  206. long* aStartOffset, long* aEndOffset,
  207. BSTR* aText)
  208. {
  209. if (!aStartOffset || !aEndOffset || !aText)
  210. return E_INVALIDARG;
  211. *aStartOffset = 0;
  212. *aEndOffset = 0;
  213. *aText = nullptr;
  214. HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
  215. if (textAcc->IsDefunct())
  216. return CO_E_OBJNOTCONNECTED;
  217. if (!textAcc->IsValidOffset(aOffset))
  218. return E_INVALIDARG;
  219. nsAutoString text;
  220. int32_t startOffset = 0, endOffset = 0;
  221. if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) {
  222. startOffset = 0;
  223. endOffset = textAcc->CharacterCount();
  224. textAcc->TextSubstring(startOffset, endOffset, text);
  225. } else {
  226. AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType);
  227. if (boundaryType == -1)
  228. return S_FALSE;
  229. textAcc->TextAfterOffset(aOffset, boundaryType, &startOffset, &endOffset, text);
  230. }
  231. *aStartOffset = startOffset;
  232. *aEndOffset = endOffset;
  233. if (text.IsEmpty())
  234. return S_FALSE;
  235. *aText = ::SysAllocStringLen(text.get(), text.Length());
  236. return *aText ? S_OK : E_OUTOFMEMORY;
  237. }
  238. STDMETHODIMP
  239. ia2AccessibleText::get_textAtOffset(long aOffset,
  240. enum IA2TextBoundaryType aBoundaryType,
  241. long* aStartOffset, long* aEndOffset,
  242. BSTR* aText)
  243. {
  244. if (!aStartOffset || !aEndOffset || !aText)
  245. return E_INVALIDARG;
  246. *aStartOffset = *aEndOffset = 0;
  247. *aText = nullptr;
  248. HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
  249. if (textAcc->IsDefunct())
  250. return CO_E_OBJNOTCONNECTED;
  251. if (!textAcc->IsValidOffset(aOffset))
  252. return E_INVALIDARG;
  253. nsAutoString text;
  254. int32_t startOffset = 0, endOffset = 0;
  255. if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) {
  256. startOffset = 0;
  257. endOffset = textAcc->CharacterCount();
  258. textAcc->TextSubstring(startOffset, endOffset, text);
  259. } else {
  260. AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType);
  261. if (boundaryType == -1)
  262. return S_FALSE;
  263. textAcc->TextAtOffset(aOffset, boundaryType, &startOffset, &endOffset, text);
  264. }
  265. *aStartOffset = startOffset;
  266. *aEndOffset = endOffset;
  267. if (text.IsEmpty())
  268. return S_FALSE;
  269. *aText = ::SysAllocStringLen(text.get(), text.Length());
  270. return *aText ? S_OK : E_OUTOFMEMORY;
  271. }
  272. STDMETHODIMP
  273. ia2AccessibleText::removeSelection(long aSelectionIndex)
  274. {
  275. MOZ_ASSERT(!HyperTextProxyFor(this));
  276. HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
  277. if (textAcc->IsDefunct())
  278. return CO_E_OBJNOTCONNECTED;
  279. return textAcc->RemoveFromSelection(aSelectionIndex) ?
  280. S_OK : E_INVALIDARG;
  281. }
  282. STDMETHODIMP
  283. ia2AccessibleText::setCaretOffset(long aOffset)
  284. {
  285. MOZ_ASSERT(!HyperTextProxyFor(this));
  286. HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
  287. if (textAcc->IsDefunct())
  288. return CO_E_OBJNOTCONNECTED;
  289. if (!textAcc->IsValidOffset(aOffset))
  290. return E_INVALIDARG;
  291. textAcc->SetCaretOffset(aOffset);
  292. return S_OK;
  293. }
  294. STDMETHODIMP
  295. ia2AccessibleText::setSelection(long aSelectionIndex, long aStartOffset,
  296. long aEndOffset)
  297. {
  298. MOZ_ASSERT(!HyperTextProxyFor(this));
  299. HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
  300. if (textAcc->IsDefunct())
  301. return CO_E_OBJNOTCONNECTED;
  302. return textAcc->SetSelectionBoundsAt(aSelectionIndex, aStartOffset, aEndOffset) ?
  303. S_OK : E_INVALIDARG;
  304. }
  305. STDMETHODIMP
  306. ia2AccessibleText::get_nCharacters(long* aNCharacters)
  307. {
  308. if (!aNCharacters)
  309. return E_INVALIDARG;
  310. *aNCharacters = 0;
  311. MOZ_ASSERT(!HyperTextProxyFor(this));
  312. HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
  313. if (textAcc->IsDefunct())
  314. return CO_E_OBJNOTCONNECTED;
  315. *aNCharacters = textAcc->CharacterCount();
  316. return S_OK;
  317. }
  318. STDMETHODIMP
  319. ia2AccessibleText::scrollSubstringTo(long aStartIndex, long aEndIndex,
  320. enum IA2ScrollType aScrollType)
  321. {
  322. MOZ_ASSERT(!HyperTextProxyFor(this));
  323. HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
  324. if (textAcc->IsDefunct())
  325. return CO_E_OBJNOTCONNECTED;
  326. if (!textAcc->IsValidRange(aStartIndex, aEndIndex))
  327. return E_INVALIDARG;
  328. textAcc->ScrollSubstringTo(aStartIndex, aEndIndex, aScrollType);
  329. return S_OK;
  330. }
  331. STDMETHODIMP
  332. ia2AccessibleText::scrollSubstringToPoint(long aStartIndex, long aEndIndex,
  333. enum IA2CoordinateType aCoordType,
  334. long aX, long aY)
  335. {
  336. uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ?
  337. nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
  338. nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE;
  339. MOZ_ASSERT(!HyperTextProxyFor(this));
  340. HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
  341. if (textAcc->IsDefunct())
  342. return CO_E_OBJNOTCONNECTED;
  343. if (!textAcc->IsValidRange(aStartIndex, aEndIndex))
  344. return E_INVALIDARG;
  345. textAcc->ScrollSubstringToPoint(aStartIndex, aEndIndex,
  346. geckoCoordType, aX, aY);
  347. return S_OK;
  348. }
  349. STDMETHODIMP
  350. ia2AccessibleText::get_newText(IA2TextSegment *aNewText)
  351. {
  352. return GetModifiedText(true, aNewText);
  353. }
  354. STDMETHODIMP
  355. ia2AccessibleText::get_oldText(IA2TextSegment *aOldText)
  356. {
  357. return GetModifiedText(false, aOldText);
  358. }
  359. // ia2AccessibleText
  360. HRESULT
  361. ia2AccessibleText::GetModifiedText(bool aGetInsertedText,
  362. IA2TextSegment *aText)
  363. {
  364. if (!aText)
  365. return E_INVALIDARG;
  366. if (!sLastTextChangeAcc)
  367. return S_OK;
  368. if (aGetInsertedText != sLastTextChangeWasInsert)
  369. return S_OK;
  370. if (sLastTextChangeAcc != this)
  371. return S_OK;
  372. aText->start = sLastTextChangeStart;
  373. aText->end = sLastTextChangeEnd;
  374. if (sLastTextChangeString->IsEmpty())
  375. return S_FALSE;
  376. aText->text = ::SysAllocStringLen(sLastTextChangeString->get(), sLastTextChangeString->Length());
  377. return aText->text ? S_OK : E_OUTOFMEMORY;
  378. }
  379. AccessibleTextBoundary
  380. ia2AccessibleText::GetGeckoTextBoundary(enum IA2TextBoundaryType aBoundaryType)
  381. {
  382. switch (aBoundaryType) {
  383. case IA2_TEXT_BOUNDARY_CHAR:
  384. return nsIAccessibleText::BOUNDARY_CHAR;
  385. case IA2_TEXT_BOUNDARY_WORD:
  386. return nsIAccessibleText::BOUNDARY_WORD_START;
  387. case IA2_TEXT_BOUNDARY_LINE:
  388. return nsIAccessibleText::BOUNDARY_LINE_START;
  389. //case IA2_TEXT_BOUNDARY_SENTENCE:
  390. //case IA2_TEXT_BOUNDARY_PARAGRAPH:
  391. // XXX: not implemented
  392. default:
  393. return -1;
  394. }
  395. }
  396. void
  397. ia2AccessibleText::InitTextChangeData()
  398. {
  399. ClearOnShutdown(&sLastTextChangeAcc);
  400. ClearOnShutdown(&sLastTextChangeString);
  401. }
  402. void
  403. ia2AccessibleText::UpdateTextChangeData(HyperTextAccessibleWrap* aAcc,
  404. bool aInsert, const nsString& aStr,
  405. int32_t aStart, uint32_t aLen)
  406. {
  407. if (!sLastTextChangeString)
  408. sLastTextChangeString = new nsString();
  409. sLastTextChangeAcc = aAcc;
  410. sLastTextChangeStart = aStart;
  411. sLastTextChangeEnd = aStart + aLen;
  412. sLastTextChangeWasInsert = aInsert;
  413. *sLastTextChangeString = aStr;
  414. }