Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

soffice: Support text attrs according to IA2 spec #15649

Conversation

michaelweghorn
Copy link
Contributor

@michaelweghorn michaelweghorn commented Oct 18, 2023

Link to issue number:

Fixes #15648

Summary of the issue:

So far, LibreOffice was using custom attribute and value
names for reporting text attributes. Spelling errors were
not reported via any attribute. NVDA was using the presence
of a specific underline as heuristic to detect and report
spelling errors.
This works for some cases, but e.g. does not cause misspelled
words on a line being annonced as such when reading a
line in LibreOffice Writer (issue #15648).

Description of user facing changes

Announcement of text attributes also works with
LibreOffice version 24.2 and above.
When announcing a line in LibreOffice Writer, misspelled
words are announced as such with LibreOffice version 24.2
and above.

Description of development approach

Switch LibreOffice from using custom text attribute names
and values to using attributes according to the IAccessible2
text attributes specification
( https://wiki.linuxfoundation.org/accessibility/iaccessible2/textattributes )
instead and implement reporting of the "invalid:spelling;"
attribute for misspelled words:

https://gerrit.libreoffice.org/c/core/+/157804
https://gerrit.libreoffice.org/c/core/+/157845
https://gerrit.libreoffice.org/c/core/+/157867
https://gerrit.libreoffice.org/c/core/+/157939
https://gerrit.libreoffice.org/c/core/+/158088
https://gerrit.libreoffice.org/c/core/+/158089
https://gerrit.libreoffice.org/c/core/+/158090

These changes are contained in LibreOffice >= 24.2.

Adapt NVDA to evaluate those text attributes by
using the already existing implementation from
the IA2TextTextInfo base class in
SymphonyTextInfo._getFormatFieldAndOffsets.

For backwards-compatibility with LibreOffice
versions <= 7.6, keep support for the legacy
attributes and move the handling for that into
a new helper method
SymphonyTextInfo_getFormatFieldFromLegacyAttributesString.

For the case where the legacy attributes are used,
the text attribute string starts with "Version:1;"
(s. the LibreOffice code dropped in
https://gerrit.libreoffice.org/c/core/+/158090 ),
so use that as a criterion what code path to take.

Extract another helper method and address some of the
pre-existing lint issues, but silence
the C901 one for the method that was extracted to handle
the legacy attributes
("'SymphonyTextInfo._getFormatFieldFromLegacyAttributesString' is
too complex (27)").
It's at least already less complex than the single
one was before.

Testing strategy:

Test that incorrect spelling in the middle of a line in LibreOffice
Writer gets announced when testing the scenario described in
issue #15648 with both, the LibreOffice and the NVDA changes
in place.

Test that the character attributes from the sample document
attached to
https://bugs.documentfoundation.org/show_bug.cgi?id=157696
works with these changes in NVDA in place, and both,

  • a current LibreOffice development version containing
    the above-mentioned LibreOffice changes

  • LibreOffice 7.6.2 which does not contain the above-mentioned
    changes and therefore triggers the "legacy" code path.

    Known issues with pull request:

Requires the above-mentioned LibreOffice changes in addition
to actually make the scenario described in issue #15648
work.

Code Review Checklist:

  • Documentation:
    • Change log entry
    • User Documentation
    • Developer / Technical Documentation
    • Context sensitive help for GUI changes
  • Testing:
    • Unit tests
    • System (end to end) tests
    • Manual testing
  • UX of all users considered:
    • Speech
    • Braille
    • Low Vision
    • Different web browsers
    • Localization in other languages / culture than English
  • API is compatible with existing add-ons.
  • Security precautions taken.

@michaelweghorn michaelweghorn marked this pull request as ready for review October 18, 2023 12:33
@michaelweghorn michaelweghorn requested a review from a team as a code owner October 18, 2023 12:33
Copy link
Member

@seanbudd seanbudd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @michaelweghorn - just minor changes suggested

source/appModules/soffice.py Outdated Show resolved Hide resolved
source/appModules/soffice.py Outdated Show resolved Hide resolved
source/appModules/soffice.py Outdated Show resolved Hide resolved
source/appModules/soffice.py Outdated Show resolved Hide resolved
source/appModules/soffice.py Outdated Show resolved Hide resolved

return formatField

def _getFormatFieldAndOffsets(self, offset, formatConfig, calculateOffsets=True): # noqa: C901
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given C901 - could you ensure that we are reducing the function complexity in this change?
This could be done by factoring out the added code into a separate helper function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how to address this, can can you please be more specific what you want me to move?

The only thing added is this block:

		# LibreOffice >= 24.2 uses IAccessible2 text attributes, earlier versions use
		# custom attributes, with the attrtibutes string starting with "Version:1;"
		if attribsString and attribsString.startswith('Version:1;'):
			formatField = self._getFormatFieldFromLegacyAttributesString(
				attribsString,
				offset
			)
		else:
			formatField, (startOffset, endOffset) = super()._getFormatFieldAndOffsets(
				offset,
				formatConfig,
				calculateOffsets
			)

, for which I'm not sure whether it really makes things more readable to move that to a separate method.

In my eyes, the change already reduces complexity, since it already splits most of the existing method into a helper method (for the legacy handling). As mentioned in the description, for me, the easiest way to simplify that further would be by dropping the legacy handling once it's no more needed. Is there a guideline/policy on whether/how that's done, (e.g. can that be dropped half a year after an old version is end-of-life?), or does compatibility with other versions have to be maintained forever?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my eyes, the change already reduces complexity, since it already splits most of the existing method into a helper method (for the legacy handling). As mentioned in the description, for me, the easiest way to simplify that further would be by dropping the legacy handling once it's no more needed. Is there a guideline/policy on whether/how that's done, (e.g. can that be dropped half a year after an old version is end-of-life?), or does compatibility with other versions have to be maintained forever?

There is no clear policy - usually code is kept for as long as practical (i.e. it does not cause errors / require extensive maintenance). That is because there is no way to determine what versions of what applications are used by our users, and also because other screen readers on Windows are usually pretty good at keeping backward compatible with older versions. In this specific case however, we cannot really remove this code, as it is shared between LibreOffice, and Apache OpenOffice, I have no idea if these two product exchange the code, but if not removing the legacy handling would cause regressions for OpenOffice users.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation, @lukaszgo1 ! No, there's no systematic code exchange between LibreOffice and OpenOffice. My personal impression (also from a quick look at the git log) is that OpenOffice is currently mostly in some kind of maintenance mode, so I currently wouldn't expect any larger changes regarding accessibility there.

Copy link
Member

@seanbudd seanbudd Oct 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A C901 indicates that code is too complex - long functions are always a readability issue as well as a general complexity issue, as it leads to methods that perform multiple logical actions.
I would encourage moving that new block into a helper function.
With a large amount of inline code, i.e. a C901, removing groupable chunks into helper functions
The overall goal with a C901 is to reduce code complexity of the whole function.
This PR essentially introduces a new C901, while improving an existing one.

When adding noqa comments for C901, please see other examples, like below.
This indicates the procedure we follow to reduce C901 issues in the code base.

# C901 'setFocusObject' is too complex
# Note: when working on setFocusObject, look for opportunities to simplify
# and move logic out into smaller helper functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I've extracted another helper method now with the new block of code and everything that was above it and added another comment for the C901 for the method handling the legacy attributes.

@michaelweghorn michaelweghorn force-pushed the michaelweghorn/soffice_support_iaccessible2_text_attributes branch from 2da0505 to 29ca79b Compare October 19, 2023 07:48
tdf-gerrit pushed a commit to LibreOffice/core that referenced this pull request Oct 19, 2023
So far, reporting text attributes on the a11y layer on
Windows did not follow any standard/specification, but
LibreOffice's custom attribute values were mostly reported
as is (i.e. using the LibreOffice-internal attribute names
and values), and assistive tooling had to interpret those in order
to support reporting them to the user in a useful way.

For example, NVDA has custom code in the LibreOffice-specific
app module to do so. [1]

Stop using our custom attributes and switch to the
use of attributes according to the IAccessible2 text
attributes specification [2] instead, which is the applicable
specification for `IAccessibleText::get_attributes` that
is implemented here.

This implies that by reporting more IAccessible2 text attributes,
those should "automatically" work if assistive tooling handles
those, as is e.g. the case for NVDA and the the "invalid:spelling;"
attribute for spelling errors, for which bridging to IA2 has
been iplemented in

    Change-Id I54e5bcbb4bef4c73068243f91a3ee69c10326460
    tdf#157696 a11y: Report spelling error via IA2 "invalid:spelling" attr

(See also the other tdf#135922 commits preparing for this
change.)

A change in NVDA is still needed in addition to switch from only
handling the custom values for LO to use the existing code
path for handling IA2 text attrs instead.
Pending pull request that implents this: [3]

[1] https://github.com/nvaccess/nvda/blob/9878248c217156de4defe244d2df797d6b3bd0ca/source/appModules/soffice.py#L35-L137
[2] https://wiki.linuxfoundation.org/accessibility/iaccessible2/textattributes
[3] nvaccess/nvda#15649

Change-Id: I11492bb5d09d64fd153db1b73d97a331a98ee535
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158090
Tested-by: Jenkins
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
@AppVeyorBot
Copy link

See test results for failed build of commit 71980e49f7

@michaelweghorn michaelweghorn force-pushed the michaelweghorn/soffice_support_iaccessible2_text_attributes branch from 29ca79b to 0003245 Compare October 19, 2023 08:36
source/appModules/soffice.py Outdated Show resolved Hide resolved
source/appModules/soffice.py Outdated Show resolved Hide resolved
source/appModules/soffice.py Outdated Show resolved Hide resolved
@michaelweghorn michaelweghorn force-pushed the michaelweghorn/soffice_support_iaccessible2_text_attributes branch 2 times, most recently from 0492878 to beaa4eb Compare October 20, 2023 07:24
 ### Link to issue number:

Fixes nvaccess#15648

 ### Summary of the issue:

So far, LibreOffice was using custom attribute and value
names for reporting text attributes. Spelling errors were
not reported via any attribute. NVDA was using the presence
of a specific underline as heuristic to detect and report
spelling errors.
This works for some cases, but e.g. does not cause misspelled
words on a line being annonced as such when reading a
line in LibreOffice Writer (issue nvaccess#15648).

 ### Description of user facing changes

Announcement of text attributes also works with
LibreOffice version 24.2 and above.
When announcing a line in LibreOffice Writer, misspelled
words are announced as such with LibreOffice version 24.2
and above.

 ### Description of development approach

Switch LibreOffice from using custom text attribute names
and values to using attributes according to the IAccessible2
text attributes specification
( https://wiki.linuxfoundation.org/accessibility/iaccessible2/textattributes )
instead and implement reporting of the "invalid:spelling;"
attribute for misspelled words:

https://gerrit.libreoffice.org/c/core/+/157804
https://gerrit.libreoffice.org/c/core/+/157845
https://gerrit.libreoffice.org/c/core/+/157867
https://gerrit.libreoffice.org/c/core/+/157939
https://gerrit.libreoffice.org/c/core/+/158088
https://gerrit.libreoffice.org/c/core/+/158089
https://gerrit.libreoffice.org/c/core/+/158090

These changes are contained in LibreOffice >= 24.2.

Adapt NVDA to evaluate those text attributes by
using the already existing implementation from
the `IA2TextTextInfo` base class in
`SymphonyTextInfo._getFormatFieldAndOffsets`.

For backwards-compatibility with LibreOffice
versions <= 7.6, keep support for the legacy
attributes and move the handling for that into
a new helper method
`SymphonyTextInfo_getFormatFieldFromLegacyAttributesString`.

For the case where the legacy attributes are used,
the text attribute string starts with "Version:1;"
(s. the LibreOffice code dropped in
https://gerrit.libreoffice.org/c/core/+/158090 ),
so use that as a criterion what code path to take.

Extract another helper method and address some of the
pre-existing lint issues, but silence
the C901 one for the method that was extracted to handle
the legacy attributes
("'SymphonyTextInfo._getFormatFieldFromLegacyAttributesString' is
too complex (27)").
It's at least already less complex than the single
one was before.

 ### Testing strategy:

Test that incorrect spelling in the middle of a line in LibreOffice
Writer gets announced when testing the scenario described in
issue nvaccess#15648 with both, the LibreOffice and the NVDA changes
in place.

Test that the character attributes from the sample document
attached to
https://bugs.documentfoundation.org/show_bug.cgi?id=157696
works with these changes in NVDA in place, and *both*,

* a current LibreOffice development version containing
  the above-mentioned LibreOffice changes
* LibreOffice 7.6.2 which does not contain the above-mentioned
  changes and therefore triggers the "legacy" code path.

 ### Known issues with pull request:

Requires the above-mentioned LibreOffice changes in addition
to actually make the scenario described in issue nvaccess#15648
work.

 ### Code Review Checklist:

- [x] Documentation:
  - Change log entry
  - User Documentation
  - Developer / Technical Documentation
  - Context sensitive help for GUI changes
- [x] Testing:
  - Unit tests
  - System (end to end) tests
  - Manual testing
- [x] UX of all users considered:
  - Speech
  - Braille
  - Low Vision
  - Different web browsers
  - Localization in other languages / culture than English
- [x] API is compatible with existing add-ons.
- [x] Security precautions taken.
@michaelweghorn michaelweghorn force-pushed the michaelweghorn/soffice_support_iaccessible2_text_attributes branch from beaa4eb to a81ea50 Compare October 20, 2023 07:27
tdf-gerrit pushed a commit to LibreOffice/core that referenced this pull request Oct 21, 2023
Extend `CMAccessible::get_attributes` so that
it also reports the text-related IAccessible2
object attributes, since what is meant to be
reported as a text attribute and what is meant
to be reported as an object attribute differs
between the IAccessible2 specificiation and what
LibreOffice does on the UNO level, s. the commit message
in this previous change for more details:

    Change-Id Ief7c840d3c5274714a914ca0e56df0c5eaffb06d
    tdf#135922 a11y: Prepare reporting text attrs as IA2 obj attrs

Just use a character offset of 0 when querying via the
`XAccessibleText` interface here. The exct offset used
used shouldn't make any difference for paragraph-specific
attributes.

With this and the NVDA pull request [1] to evaluate attributes
according to the IAccessible2 text attributes and
IAccessible2 object attributes specifications, NVDA
now reports the alignment of paragraphs in Writer, e.g.
says "align center" since the corresponding attribute is
now reported for the paragraph object, as can also
be seen by querying the IAccessible2 interface manually
in NVDA's Python console:

    >>> focus.IAccessibleObject.attributes
    'heading-level:;level:;text-align:center;'

("text-align:center;" was not yet reported without
this change in place.)

[1] nvaccess/nvda#15649

Change-Id: I5723797232f89db6a2b74d4a601344f2078ee630
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158260
Tested-by: Jenkins
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
@seanbudd
Copy link
Member

Could you please avoid force pushing where possible? When reviewing, a reviewer can review changes since the last review. When a force push occurs, the previous review is lost. This means instead of checking that review comments have been actioned, the review must occur from scratch.

Copy link
Member

@seanbudd seanbudd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

source/appModules/soffice.py Outdated Show resolved Hide resolved
user_docs/en/changes.t2t Outdated Show resolved Hide resolved
@AppVeyorBot
Copy link

See test results for failed build of commit 3308a437a5

@seanbudd seanbudd merged commit de4e881 into nvaccess:master Oct 23, 2023
1 check failed
@nvaccessAuto nvaccessAuto added this to the 2024.1 milestone Oct 23, 2023
@michaelweghorn
Copy link
Contributor Author

Thanks for the review, @seanbudd !

Could you please avoid force pushing where possible? When reviewing, a reviewer can review changes since the last review. When a force push occurs, the previous review is lost. This means instead of checking that review comments have been actioned, the review must occur from scratch.

Sorry for that, I'll try to keep that in mind for any upcoming PRs. (The background for force-pushing is that for other projects I contribute to, the commits from the PR/MR/Gerrit changes are merged to the target branch as is and having a single "nice" commit is IMHO much more useful for reading and understanding the git history and using tools like git bisect or git blame. If I understand correctly, that's not a problem for NVDA, though, since the commits from the PR branch are not merged as is here anyway.)

@michaelweghorn michaelweghorn deleted the michaelweghorn/soffice_support_iaccessible2_text_attributes branch October 23, 2023 06:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

NVDA doesn't announce spelling error for words when reading line in LibreOffice Writer
5 participants