Re: AtkText attributes



Hi Brian,

> > > [...discussion about attributes and text ranges...]
> >
> > I think the basic tension here is between efficiency and complexity.  It's
> > inefficient to look at attributes a single character at a time, but simple.
> > It's more efficient to look at ranges of characters (or runs as they are 
> > often called), but then we run into interface complexity problems if we want 
> > to convey all of the attribute information.
> >
> > Perhaps there is a third way?  What about enumerating the unique attribute 
> > runs and then allowing the AT to get information about those runs, in 
> > addition to doing so a character at a time?  Thus, the text:
> >
> >  <font="times">This <bold>bold, <italic>itali</bold>ziced </italic> text</font>
> >
> > would contain 5 runs: [0-4], [5-10], [11-15], [16-21], and [22-26].
> 
> Yes, but many of the attributes overlap runs.  Therefore I'm not sure it is
> reasonable to refer to a run as a "unique attribute run".  Perhaps it is more
> accurate to say that each run is a "unique set of attributes run".  For 
> example run [5-10] has both a "font" setting and is "bolded".
> 
> As you point out below, it is necessary with this scheme for the user to loop
> over every single run before the desired one in order to get a complete list 
> of attributes that are set.

I'm afraid I may not have been clear.  I'm suggesting that *all* attribute
information be returned *every* time.  Then our "unique attribute run" for
[5-10] is "font times, bold, 12-point"; and [11-15] is "font times, bold,
italic, 12-point" (and of course [16-21] is "font times, italic, 12-point". 
Make more sense now?  (I'm presuming here that 12-point is the default size when
none is specified in HTML).

> Let's say I'm personally interested in the attributes on text [18-24]
> 
>    I would have to first call a function to find out that my section of 
>    interest falls between two runs [16-21] and [22-26].  Once this was 
>    established I would have to loop over all the runs before these to find
>    out what attributes are set.

No.  You would make the following 2 calls only:

  getAttributes(18, &attrStruct);  // what is it like at the start of my range?
  ... // calculation here
  getAttributes(22, &attrStruct);  // what is it like in the next run that's
                                   // within my range?

The first attrStruct returned would give you "font times, bold, italic,
12-point" for the range [16-21].  You would then notice that the end of this
run, 21, was less than 24, and so make the second call starting at index 22,
getting back the attrStruct "font times, italic, 12-point" for the range
[22-26].  Since 26 is greater than 24, you are now done.

> ...
> 
>    I call the function saying I am interested in the text from 18-21.  I am
>    returned perhaps an array of two structures which have the following info:
> 
>       struct[0]->attribute = font
>       struct[0]->value     = times
>       struct[0]->start     = 0
>       struct[0]->end       = 26
>       struct[1]->attribute = style
>       struct[1]->value     = italics
>       struct[1]->start     = 11
>       struct[1]->end       = 21
> 
>    Using this data it is very easy for me to see what attributes apply to the
>    text that I am interested in.  I can quickly see that the font attribute
>    applies to all of the text between 18-21 and that the italics style applies
>    to just 18-21.
> 
>    Does this seem like an overly burdened interface to you?

Your approach returns an array of unknown size that has to be allocated and then
de-allocated.  When if we've got a ransom letter, every character a different
font (or some other attribute).  I ask for a range [0-500].  I now get a huge
struct back.  Especially again in the Java case, where we don't support range
info, every situation will look like a ransom letter.

>...
>
> > If a screen reader were doing an attribute
> > search (a feature of outSPOKEN for Windows), they might start from the 
> > caret and go in run chunks.
> 
> The idea of searching is something I had not thought about.  My proposed 
> solution of returning the array of structures is a little ugly since it 
> requires the user to request the range from the caret to the end of the buffer 
> and then search on the results.  The idea of looping over each "unique set of 
> attributes run" resolves this issue but forces the calling function to keep
> track of everything.

But there is little to keep track of.  In outSPOKEN for Windows, the user
invokes the find command, and then types 'CTRL-B' for bold, followed by <CR>. 
outSPOKEN then starts from the mouse location and walks through all text records
in it's Off-Screen-Model 'till it finds text - any text - with the 'bold'
attribute.  It then starts accumulating that text 'till the next bit of text is
lacking the 'bold' attribute, and speaks/Brailles that string.

Similarly here in AtkText, we start at an index (let's say it's 0 in our
example).  So we have the following pseudo-code:

  typedef LOOKING 0
  typedef ACCUMULATING 1
  typedef DONE 2
  int i = 0;
  int maxIndex = atkTextObj.getSize();
  int state = LOOKING;
  int runStart, runEnd;
  while (i < maxIndex && state != DONE) {
    switch (state) {
    case LOOKING:
      atkTextObj.getAttributes(i, &attrStruct);
      i = attrStruct.runEnd;
      if (attrStruct.bold == 1) {
        runStart = i;
        state = ACCUMULATING;
      }
      break;
    case ACCUMULATING:
      atkTextObj.getAttributes(i, &attrStruct);
      i = attrStruct.runEnd;
      if (attrStruct.bold == 1) {
        runend = i;
        state = DONE;
      }
      break;
    }
  }
  printf("The next bold characters are at [%d, %d], and are %s", 
         runStart, runEnd, atkTextObj.getTextRange(runStart, runEnd));


> If we go with the idea of returning the array of structures, a way to provide
> this sort of funtionality would be to add another function that has a 
> "search_for" argument instead of an "end_range" argument.  This would give the 
> caller access to a speed efficient attribute search mechanism.

It seems to me we can keep the API smaller (and more maintainable and easier for
others to implement) by leaving the AT vendors some of the logic tasks (like the
code fragment above).

> > Another benefit of this approach is that it layers nicely on top of the Java
> > Accessibility API which doesn't provide range information: all ranges are 
> > simply the index in question (so if you ask about index 5, the range you get 
> > back is [5-5]).  So this approach would work well in the AT SPI.
> 
> But the current API lets you ask for the attributes over a range, not just at 
> a specific index (like 5 in your example above).

The Atk API works over a range.  Presumably the AT SPI will also work over a
range.  But there will be a bridge from the Java API to the AT SPI, and so we
will need to solve the attribute problem in that bridge.  And the Java API
doesn't work over a range.  Since we can always return a range of 1 in this
proposal, we have a very natural bridging.  And at such time as the Java API
supports ranges, we'll get improved performance.


Regards,

Peter Korn
Sun Accessibility team




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]