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

Furigana placed at the wrong locations #1

Closed
CoffeeMarker opened this issue Feb 22, 2016 · 7 comments
Closed

Furigana placed at the wrong locations #1

CoffeeMarker opened this issue Feb 22, 2016 · 7 comments

Comments

@CoffeeMarker
Copy link
Contributor

The furigana are placed at the wrong location in the following situations:

There are at least 3 furigana, while the length of the range is smaller than the amount of furigana, and the range starts on the first character of a sentence other than the first sentence.

So for example, 3 furigana on just the first character of the second sentence.
Furigana(text:"きつね", original: "狐", range NSMakeRange(14,1))
//assuming the second sentence starts at 14

There are at least 3 furigana, while the range starts at the last character of the sentence, the range is at least 2 and smaller than the amount of furigana.

So for example 3 furigana on the last character of the first sentence with a range that is 2 long.
Furigana(text:"さしみ", original: "刺身", range NSMakeRange(13,2))
//assuming the second sentence starts at 14

eyeplum added a commit that referenced this issue Feb 24, 2016
@eyeplum
Copy link
Collaborator

eyeplum commented Feb 24, 2016

Hi @CoffeeMarker ,

Thank you very much for your feedback.

I tried to add a new sentence and its furiganas according to your description:

// Furigana for New Sentence
Furigana(text: "さしみ", original: "刺身", range: NSMakeRange(46, 2)),
Furigana(text: "きつね", original: "", range: NSMakeRange(48, 1)),

// New Sentence
contents.appendAttributedString(NSAttributedString(string: "サーモン刺身狐、哺乳綱ネコ目(食肉目)イヌ科イヌ亜科の一部。", attributes: [NSFontAttributeName : exampleFont]))

Unfortunately, I can't find a way to reproduce this issue.

You can find the code above in the bug_reproduce branch.

If you can find a way to reproduce the issue, please let me know.

Thanks.

@eyeplum
Copy link
Collaborator

eyeplum commented Feb 24, 2016

@CoffeeMarker Also, I find that your example furiganas may have incorrect ranges:

Furigana(text:"さしみ", original: "刺身", range NSMakeRange(13,2)),
Furigana(text:"きつね", original: "", range NSMakeRange(14,1)),

You see, if 刺身 is at location 13, then any other words after 刺身 can't actually be at location 14, because the character at 14 is actually (where the character at 13 is ).

So, if I'm understanding the problem correctly, your example may need to be changed to this:

Furigana(text:"さしみ", original: "刺身", range NSMakeRange(13,2)),
Furigana(text:"きつね", original: "", range NSMakeRange(15,1)),  // the furigana for '狐' must be at location 15 because the character is actually at 15

You can change your code and see if the furiganas is displayed in the right location.

@eyeplum eyeplum closed this as completed Feb 24, 2016
@CoffeeMarker
Copy link
Contributor Author

@eyeplum
Thank you for looking into this bug.

Regarding you last comment, sorry for not clearly mentioning this in the first comment, but those Furigana ranges were tested separately, so overlap of the ranges is not the cause of the bug.

@eyeplum eyeplum reopened this Feb 24, 2016
@eyeplum
Copy link
Collaborator

eyeplum commented Feb 24, 2016

#2 Reproduced on iPhone 4S

eyeplum added a commit that referenced this issue Feb 24, 2016
We are using the method `attributesAtIndex(,atIndex,effectiveRange)`
to find out the effective range of the custom furigana text attribute
`kFuriganaAttributeName`. And then we use the range to decide whether we
should break the line in the current location.

As per Apple document:
> ...The range isn’t necessarily the maximum range covered by
> attributeName, and its extent is implementation-dependent. If you need
> the maximum range, use
> attribute:atIndex:longestEffectiveRange:inRange:.

Thus the attribute range may not be long enough to keep the furigana
text attribute as-whole, and as a result it may cause line break happen
in the middle of a furigana attributed text.

This commit fixes this issue by using the
`attribute:atIndex:longestEffectiveRange:inRange:` method to find out
the range instead.
@eyeplum
Copy link
Collaborator

eyeplum commented Feb 24, 2016

@CoffeeMarker I've just committed a quick fix on the bug_reproduce branch.

Please try it and see if the fix works.

Btw, as far as I've observed, the problem is caused by line breaking. When TextKit asks whether it should break a line at a certain position, we used this method to check if the position is in the middle of a kFuriganaAttributeName:

func attribute(_ attrName: String, atIndex location: Int, effectiveRange range: NSRangePointer) -> AnyObject?

But it turns out that this method sometimes may give us a range shorter than the maximum attribute range. Thus the check may fail to find out that the position is actually in the middle of a kFuriganaAttributeName.

The fix is quite easy, we just need to switch to a more accurate method:

func attribute(_ attrName: String, atIndex location: Int, longestEffectiveRange range: NSRangePointer, inRange rangeLimit: NSRange) -> AnyObject?

as Apple advised in the document:

The range isn’t necessarily the maximum range covered by attributeName, and its extent is implementation-dependent. If you need the maximum range, use attribute:atIndex:longestEffectiveRange:inRange:.

@CoffeeMarker
Copy link
Contributor Author

Ok, great, I tested it rigorously, and it does seem to be fixed now.

Thank you.

@eyeplum
Copy link
Collaborator

eyeplum commented Feb 24, 2016

No problem.

I've updated the master branch, or if you use Carthage, you can use the latest version 0.3.0.

Thank your so much for your feedback, it really helps!

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

No branches or pull requests

2 participants