1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 // AccTextBase.cpp: implementation of the CAccTextBase class.
25 #include "AccTextBase.h"
27 #include <rtl/ustrbuf.hxx>
28 #include <sal/log.hxx>
29 #include <vcl/accessibility/AccessibleTextAttributeHelper.hxx>
30 #include <vcl/svapp.hxx>
31 #include <o3tl/char16_t2wchar_t.hxx>
33 #include <com/sun/star/accessibility/AccessibleScrollType.hpp>
34 #include <com/sun/star/accessibility/AccessibleTextType.hpp>
35 #include <com/sun/star/accessibility/XAccessible.hpp>
36 #include <com/sun/star/accessibility/XAccessibleContext.hpp>
37 #include <com/sun/star/accessibility/XAccessibleComponent.hpp>
38 #include <com/sun/star/accessibility/XAccessibleTextSelection.hpp>
39 #include "MAccessible.h"
41 using namespace css::accessibility
;
42 using namespace css::uno
;
46 sal_Int16
lcl_matchIA2TextBoundaryType(IA2TextBoundaryType boundaryType
)
50 case IA2_TEXT_BOUNDARY_CHAR
:
51 return com::sun::star::accessibility::AccessibleTextType::CHARACTER
;
52 case IA2_TEXT_BOUNDARY_WORD
:
53 return com::sun::star::accessibility::AccessibleTextType::WORD
;
54 case IA2_TEXT_BOUNDARY_SENTENCE
:
55 return com::sun::star::accessibility::AccessibleTextType::SENTENCE
;
56 case IA2_TEXT_BOUNDARY_PARAGRAPH
:
57 return com::sun::star::accessibility::AccessibleTextType::PARAGRAPH
;
58 case IA2_TEXT_BOUNDARY_LINE
:
59 return com::sun::star::accessibility::AccessibleTextType::LINE
;
60 case IA2_TEXT_BOUNDARY_ALL
:
61 // assert here, better handle it directly at call site
63 && "No match for IA2_TEXT_BOUNDARY_ALL, handle at call site.");
69 SAL_WARN("iacc2", "Unmatched text boundary type: " << boundaryType
);
75 // Construction/Destruction
78 CAccTextBase::CAccTextBase()
81 CAccTextBase::~CAccTextBase()
86 * Get special selection.
87 * @param startOffset Start selection offset.
88 * @param endOffset End selection offset.
89 * @param success Variant to accept the result of if the method call is successful.
92 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::get_addSelection(long startOffset
, long endOffset
)
98 if(pUNOInterface
== nullptr)
101 Reference
<XAccessibleContext
> pRContext
= pUNOInterface
->getAccessibleContext();
103 Reference
< XAccessibleTextSelection
> pRExtension(pRContext
,UNO_QUERY
);
105 if( pRExtension
.is() )
107 pRExtension
->addSelection(0, startOffset
, endOffset
);
112 pRXText
->setSelection(startOffset
, endOffset
);
116 } catch(...) { return E_FAIL
; }
120 * Get special attributes.
121 * @param offset Offset.
122 * @param startOffset Variant to accept start offset.
123 * @param endOffset Variant to accept end offset.
124 * @param textAttributes Variant to accept attributes.
127 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::get_attributes(long offset
, long * startOffset
, long * endOffset
, BSTR
* textAttributes
)
133 if (startOffset
== nullptr || endOffset
== nullptr || textAttributes
== nullptr)
141 if (offset
< 0 || offset
> pRXText
->getCharacterCount() )
145 const OUString sAttrs
= AccessibleTextAttributeHelper::GetIAccessible2TextAttributes(pRXText
,
146 IA2AttributeType::TextAttributes
,
147 offset
, *startOffset
, *endOffset
);
150 SysFreeString(*textAttributes
);
151 *textAttributes
= SysAllocString(o3tl::toW(sAttrs
.getStr()));
155 } catch(...) { return E_FAIL
; }
159 * Get caret position.
160 * @param offset Variant to accept caret offset.
163 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::get_caretOffset(long * offset
)
169 if (offset
== nullptr)
178 *offset
= pRXText
->getCaretPosition();
181 } catch(...) { return E_FAIL
; }
185 * Get character count.
186 * @param nCharacters Variant to accept character count.
189 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::get_characterCount(long * nCharacters
)
195 if (nCharacters
== nullptr)
204 *nCharacters
= pRXText
->getCharacterCount();
207 } catch(...) { return E_FAIL
; }
211 * Get character extents.
212 * @param offset Offset.
213 * @param x Variant to accept x position.
214 * @param y Variant to accept y position.
215 * @param width Variant to accept width.
216 * @param Height Variant to accept height.
219 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::get_characterExtents(long offset
, IA2CoordinateType coordType
, long * x
, long * y
, long * width
, long * height
)
225 if (x
== nullptr || height
== nullptr || y
== nullptr || width
== nullptr)
231 if (offset
< 0 || offset
> pRXText
->getCharacterCount())
234 css::awt::Rectangle rectangle
;
235 rectangle
= pRXText
->getCharacterBounds(offset
);
238 css::awt::Point aPoint
;
240 Reference
<XAccessibleContext
> pRContext
= pUNOInterface
->getAccessibleContext();
241 if( !pRContext
.is() )
245 Reference
<XAccessibleComponent
> pRComp(pRContext
,UNO_QUERY
);
248 if(coordType
== IA2_COORDTYPE_SCREEN_RELATIVE
)
250 css::awt::Point pt
= pRComp
->getLocationOnScreen();
254 else if(coordType
== IA2_COORDTYPE_PARENT_RELATIVE
)
256 css::awt::Point pt
= pRComp
->getLocation();
261 rectangle
.X
= rectangle
.X
+ aPoint
.X
;
262 rectangle
.Y
= rectangle
.Y
+ aPoint
.Y
;
267 // pRXText->getCharacterBounds() have different implement in different acc component
268 // But we need return the width/height == 1 for every component when offset == text length.
269 // So we ignore the return result of pRXText->getCharacterBounds() when offset == text length.
270 if (offset
== pRXText
->getCharacterCount())
277 *width
= rectangle
.Width
;
278 *height
= rectangle
.Height
;
283 } catch(...) { return E_FAIL
; }
287 * Get selections count.
288 * @param nSelections Variant to accept selections count.
291 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::get_nSelections(long * nSelections
)
297 if (nSelections
== nullptr)
300 if(pUNOInterface
== nullptr)
306 Reference
<XAccessibleContext
> pRContext
= pUNOInterface
->getAccessibleContext();
308 Reference
< XAccessibleTextSelection
> pRExtension(pRContext
,UNO_QUERY
);
310 if( pRExtension
.is() )
312 *nSelections
= pRExtension
->getSelectedPortionCount();
316 long iLength
= pRXText
->getSelectedText().getLength();
326 } catch(...) { return E_FAIL
; }
330 * Get offset of some special point.
331 * @param x X position of one point.
332 * @param x Y position of one point.
333 * @param coordType Type.
334 * @param offset Variant to accept offset.
337 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::get_offsetAtPoint(long x
, long y
, IA2CoordinateType coordType
, long * offset
)
343 if (offset
== nullptr)
349 css::awt::Point point
;
353 if (coordType
== IA2_COORDTYPE_SCREEN_RELATIVE
)
355 // convert from screen to local coordinates
356 Reference
<XAccessibleContext
> xContext
= pUNOInterface
->getAccessibleContext();
357 Reference
<XAccessibleComponent
> xComponent(xContext
, UNO_QUERY
);
358 if (!xComponent
.is())
361 css::awt::Point aObjectPos
= xComponent
->getLocationOnScreen();
362 point
.X
-= aObjectPos
.X
;
363 point
.Y
-= aObjectPos
.Y
;
366 *offset
= pRXText
->getIndexAtPoint(point
);
369 } catch(...) { return E_FAIL
; }
373 * Get selection range.
374 * @param selection selection count.
375 * @param startOffset Variant to accept the start offset of special selection.
376 * @param endOffset Variant to accept the end offset of special selection.
380 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::get_selection(long selectionIndex
, long * startOffset
, long * endOffset
)
386 if (startOffset
== nullptr || endOffset
== nullptr )
389 if(pUNOInterface
== nullptr )
393 get_nSelections(&nSelection
);
395 if(selectionIndex
>= nSelection
|| selectionIndex
< 0 )
398 Reference
<XAccessibleContext
> pRContext
= pUNOInterface
->getAccessibleContext();
400 Reference
< XAccessibleTextSelection
> pRExtension(pRContext
,UNO_QUERY
);
402 if( pRExtension
.is() )
404 *startOffset
= pRExtension
->getSeletedPositionStart(selectionIndex
);
405 *endOffset
= pRExtension
->getSeletedPositionEnd(selectionIndex
);
408 else if (pRXText
->getSelectionEnd() > -1)
410 *startOffset
= pRXText
->getSelectionStart();
411 *endOffset
= pRXText
->getSelectionEnd();
419 } catch(...) { return E_FAIL
; }
424 * @param startOffset Start position of special range.
425 * @param endOffset End position of special range.
426 * @param text Variant to accept the text of special range.
429 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::get_text(long startOffset
, long endOffset
, BSTR
* text
)
441 if (endOffset
< -1 || endOffset
< startOffset
)
447 if (endOffset
== -1 )
450 if(SUCCEEDED(get_characterCount(&nLen
)))
452 ouStr
= pRXText
->getTextRange(0, nLen
);
457 ouStr
= pRXText
->getTextRange(startOffset
, endOffset
);
460 SysFreeString(*text
);
461 *text
= SysAllocString(o3tl::toW(ouStr
.getStr()));
464 } catch(...) { return E_FAIL
; }
468 * Get special text before some position.
469 * @param offset Special position.
470 * @param boundaryType Boundary type.
471 * @param startOffset Variant to accept the start offset.
472 * @param endOffset Variant to accept the end offset.
473 * @param text Variant to accept the special text.
476 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::get_textBeforeOffset(long offset
, IA2TextBoundaryType boundaryType
, long * startOffset
, long * endOffset
, BSTR
* text
)
482 if (startOffset
== nullptr || endOffset
== nullptr || text
== nullptr)
488 if (boundaryType
== IA2_TEXT_BOUNDARY_ALL
)
491 get_nCharacters( &nChar
);
494 return get_text(0, nChar
, text
);
497 const sal_Int16 nUnoBoundaryType
= lcl_matchIA2TextBoundaryType(boundaryType
);
498 if (nUnoBoundaryType
< 0)
501 TextSegment segment
= pRXText
->getTextBeforeIndex(offset
, nUnoBoundaryType
);
502 OUString ouStr
= segment
.SegmentText
;
503 SysFreeString(*text
);
504 *text
= SysAllocString(o3tl::toW(ouStr
.getStr()));
505 *startOffset
= segment
.SegmentStart
;
506 *endOffset
= segment
.SegmentEnd
;
510 } catch(...) { return E_FAIL
; }
514 * Get special text after some position.
515 * @param offset Special position.
516 * @param boundaryType Boundary type.
517 * @param startOffset Variant to accept the start offset.
518 * @param endOffset Variant to accept the end offset.
519 * @param text Variant to accept the special text.
522 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::get_textAfterOffset(long offset
, IA2TextBoundaryType boundaryType
, long * startOffset
, long * endOffset
, BSTR
* text
)
528 if (startOffset
== nullptr || endOffset
== nullptr || text
== nullptr)
534 if (boundaryType
== IA2_TEXT_BOUNDARY_ALL
)
537 get_nCharacters( &nChar
);
540 return get_text(0, nChar
, text
);
543 const sal_Int16 nUnoBoundaryType
= lcl_matchIA2TextBoundaryType(boundaryType
);
544 if (nUnoBoundaryType
< 0)
547 TextSegment segment
= pRXText
->getTextBehindIndex(offset
, nUnoBoundaryType
);
548 OUString ouStr
= segment
.SegmentText
;
549 SysFreeString(*text
);
550 *text
= SysAllocString(o3tl::toW(ouStr
.getStr()));
551 *startOffset
= segment
.SegmentStart
;
552 *endOffset
= segment
.SegmentEnd
;
556 } catch(...) { return E_FAIL
; }
560 * Get special text at some position.
561 * @param offset Special position.
562 * @param boundaryType Boundary type.
563 * @param startOffset Variant to accept the start offset.
564 * @param endOffset Variant to accept the end offset.
565 * @param text Variant to accept the special text.
568 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::get_textAtOffset(long offset
, IA2TextBoundaryType boundaryType
, long * startOffset
, long * endOffset
, BSTR
* text
)
574 if (startOffset
== nullptr || text
== nullptr ||endOffset
== nullptr)
580 if (boundaryType
== IA2_TEXT_BOUNDARY_ALL
)
583 get_nCharacters( &nChar
);
586 return get_text(0, nChar
, text
);
589 const sal_Int16 nUnoBoundaryType
= lcl_matchIA2TextBoundaryType(boundaryType
);
590 if (nUnoBoundaryType
< 0)
593 TextSegment segment
= pRXText
->getTextAtIndex(offset
, nUnoBoundaryType
);
594 OUString ouStr
= segment
.SegmentText
;
595 SysFreeString(*text
);
596 *text
= SysAllocString(o3tl::toW(ouStr
.getStr()));
597 *startOffset
= segment
.SegmentStart
;
598 *endOffset
= segment
.SegmentEnd
;
602 } catch(...) { return E_FAIL
; }
607 * @param selectionIndex Special selection index
608 * @param success Variant to accept the method called result.
611 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::removeSelection(long selectionIndex
)
617 if(pUNOInterface
== nullptr)
622 Reference
<XAccessibleContext
> pRContext
= pUNOInterface
->getAccessibleContext();
624 Reference
< XAccessibleTextSelection
> pRExtension(pRContext
,UNO_QUERY
);
626 if( pRExtension
.is() )
628 pRExtension
->removeSelection(selectionIndex
);
633 pRXText
->setSelection(0, 0);
637 } catch(...) { return E_FAIL
; }
641 * Set caret position.
642 * @param offset Special position.
643 * @param success Variant to accept the method called result.
646 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::setCaretOffset(long offset
)
655 pRXText
->setCaretPosition(offset
);
659 } catch(...) { return E_FAIL
; }
663 * Set special selection.
664 * @param selectionIndex Special selection index.
665 * @param startOffset start position.
666 * @param endOffset end position.
667 * @param success Variant to accept the method called result.
670 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::setSelection(long, long startOffset
, long endOffset
)
681 pRXText
->setSelection(startOffset
, endOffset
);
685 } catch(...) { return E_FAIL
; }
689 * Get characters count.
690 * @param nCharacters Variant to accept the characters count.
693 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::get_nCharacters(long * nCharacters
)
699 if (nCharacters
== nullptr)
708 *nCharacters
= pRXText
->getCharacterCount();
712 } catch(...) { return E_FAIL
; }
715 // added by qiuhd, 2006/07/03, for direver 07/11
716 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::get_newText( IA2TextSegment
*)
721 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::get_oldText( IA2TextSegment
*)
727 * Scroll to special sub-string .
728 * @param startIndex Start index of sub string.
729 * @param endIndex End index of sub string.
732 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::scrollSubstringToPoint(long, long, IA2CoordinateType
, long, long )
737 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::scrollSubstringTo(long startIndex
, long endIndex
, IA2ScrollType type
)
746 AccessibleScrollType lUnoType
;
750 case IA2_SCROLL_TYPE_TOP_LEFT
:
751 lUnoType
= AccessibleScrollType_SCROLL_TOP_LEFT
;
753 case IA2_SCROLL_TYPE_BOTTOM_RIGHT
:
754 lUnoType
= AccessibleScrollType_SCROLL_BOTTOM_RIGHT
;
756 case IA2_SCROLL_TYPE_TOP_EDGE
:
757 lUnoType
= AccessibleScrollType_SCROLL_TOP_EDGE
;
759 case IA2_SCROLL_TYPE_BOTTOM_EDGE
:
760 lUnoType
= AccessibleScrollType_SCROLL_BOTTOM_EDGE
;
762 case IA2_SCROLL_TYPE_LEFT_EDGE
:
763 lUnoType
= AccessibleScrollType_SCROLL_LEFT_EDGE
;
765 case IA2_SCROLL_TYPE_RIGHT_EDGE
:
766 lUnoType
= AccessibleScrollType_SCROLL_RIGHT_EDGE
;
768 case IA2_SCROLL_TYPE_ANYWHERE
:
769 lUnoType
= AccessibleScrollType_SCROLL_ANYWHERE
;
775 if (pRXText
->scrollSubstringTo(startIndex
, endIndex
, lUnoType
))
780 } catch(...) { return E_FAIL
; }
785 * @param pXInterface UNO interface.
788 COM_DECLSPEC_NOTHROW STDMETHODIMP
CAccTextBase::put_XInterface(hyper pXInterface
)
790 // internal IUNOXWrapper - no mutex meeded
794 CUNOXWrapper::put_XInterface(pXInterface
);
796 if(pUNOInterface
== nullptr)
798 Reference
<XAccessibleContext
> pRContext
= pUNOInterface
->getAccessibleContext();
799 if( !pRContext
.is() )
803 Reference
<XAccessibleText
> pRXI(pRContext
,UNO_QUERY
);
807 } catch(...) { return E_FAIL
; }
810 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */