Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Fix issue #7253: port gl-js line breaking behavior #7446

Merged
merged 4 commits into from
Jan 5, 2017

Conversation

ChrisLoer
Copy link
Contributor

Porting newline-handling changes from gl-js -- biggest change is the "raggedness minimizing" line breaking algorithm from mapbox/mapbox-gl-js#3743.

@mention-bot
Copy link

@ChrisLoer, thanks for your PR! By analyzing this pull request, we identified @ansis, @1ec5 and @jfirebaugh to be potential reviewers.

@ChrisLoer ChrisLoer force-pushed the cloer_linebreak_port branch 2 times, most recently from f87626d to de0b349 Compare December 15, 2016 04:28
@ChrisLoer ChrisLoer self-assigned this Dec 15, 2016
// We're iterating from last potential break towards the first
for (const PotentialBreak& potentialBreak : potentialBreaks) {
const float lineWidth = breakX - potentialBreak.x;
edges.push_front(LineBreakEdge{ .priorBreak = &potentialBreak,
Copy link
Contributor

Choose a reason for hiding this comment

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

Huh. Is this using C99 designated initializers? I was under the impression that these don't work in C++.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Apparently not part of C++ but still supported with a warning by clang and gcc. I'll switch to C++-style struct initialization -- I only picked up this style from Xcode suggesting fixes to the gl-js code I had pasted into the editor.

@ChrisLoer ChrisLoer force-pushed the cloer_linebreak_port branch from de0b349 to cc49840 Compare December 15, 2016 19:12
@ChrisLoer
Copy link
Contributor Author

@brunoabinader this touches the Qt-specific bidi.cpp, although it shouldn't change behavior at all.

{
}

BiDi::~BiDi() {
Copy link
Contributor

Choose a reason for hiding this comment

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

BiDi::~BiDi() = default;

edges.push_front(LineBreakEdge{ &potentialBreak,
calculateBadness(lineWidth, targetWidth, penalty, isLastBreak) + potentialBreak.badness });
}
edges.push_front(LineBreakEdge{ .priorBreak = nullptr, .badness = calculateBadness(breakX, targetWidth, penalty, isLastBreak)});
Copy link
Contributor

Choose a reason for hiding this comment

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

Replace the designated initializers here.

// ...and when targetWidth and maxWidth are close, strictly enforcing maxWidth can give
// more lopsided results.

std::list<LineBreakEdge> edges;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this use std::vector instead, with pushes to the back and a reversed sort order?

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 switched to using a std::vector, which for better or worse required wrapping the PotentialBreak in a shared_ptr so that I could maintain the singly-linked priorBreak list.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah ok. I think it's better to avoid shared_ptr, either by using a container that doesn't invalidate references on insert or by precalculating the number of potential breakpoints and preallocating the vector.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

std::list is a container that doesn't invalidate references on insert, right?

}
potentialBreaks.push_front(evaluateBreak(static_cast<int32_t>(logicalInput.size()), currentX, targetWidth, potentialBreaks, 0, true));
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to reduce the number of static_casts in this code by using std::size_t in more places?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Pushed the static casts into bidi.cpp implementations.

@ChrisLoer ChrisLoer force-pushed the cloer_linebreak_port branch from cc49840 to 3cf7eaa Compare December 20, 2016 18:59
// more lopsided results.

std::vector<LineBreakEdge> edges;
// We're iterating from last potential break towards the first
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this iteration order necessary or could it use for (const auto& potentialBreak : potentialBreaks)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops, the iteration order was vestigial from when I originally implemented this with a sliding window... no need to maintain that now.

}
edges.push_back(LineBreakEdge(nullptr, calculateBadness(breakX, targetWidth, penalty, isLastBreak)));

std::sort(edges.begin(), edges.end(), [](const LineBreakEdge& a, const LineBreakEdge& b) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than keeping the entire edges vector, wouldn't it suffice to keep a running minimum badness and prior break?

return a.badness < b.badness;
});

return std::make_shared<PotentialBreak>(PotentialBreak(breakIndex, breakX, edges.front().priorBreak, edges.front().badness));
Copy link
Contributor

Choose a reason for hiding this comment

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

std::make_shared<PotentialBreak>(breakIndex, breakX, ...)

}
potentialBreaks.push_back(evaluateBreak(logicalInput.size(), currentX, targetWidth, potentialBreaks, 0, true));
Copy link
Contributor

Choose a reason for hiding this comment

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

Return the result directly rather than doing push_back + back: return leastBadBreaks(*evaluateBreak(...));

@ChrisLoer ChrisLoer force-pushed the cloer_linebreak_port branch 3 times, most recently from 6c5a0e4 to a88357d Compare December 21, 2016 21:56
@ChrisLoer ChrisLoer force-pushed the cloer_linebreak_port branch 2 times, most recently from e98a7a7 to be3d57f Compare January 4, 2017 21:26
@ChrisLoer
Copy link
Contributor Author

@jfirebaugh @nickidlugash @1ec5 I've updated this PR with a commit that addresses some of the small issues that came up testing with Chinese map data (although the issues weren't specific to China).

Copy link
Contributor

@jfirebaugh jfirebaugh left a comment

Choose a reason for hiding this comment

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

👍

Don't forget to rebase test-suite and update the package.json SHA before merging.

* Don't include trailing spacing (as opposed to whitespace) in lineLength
* Modify BiDi interface to require initial bidi layout and linebreaking to happen in one call.
* Code style changes suggested by @kkaefer
- Put "breakable" punctuation (such as a hyphen) on the line that starts the break, not the line after the break.
- Process all characters with the line breaking algorithm, even if we don't have glyphs for them. Some fonts have glyph-less breakable characters (we end up treating them similarly to a "zero-width space").
- Don't include trailing white space in raggedness calculations
- Make the "favor short final lines" rule more aggressive (unlike the other changes, this one is purely an aesthetic choice)
@ChrisLoer ChrisLoer force-pushed the cloer_linebreak_port branch from be3d57f to 1015209 Compare January 5, 2017 17:20
@ChrisLoer ChrisLoer merged commit d5b878a into master Jan 5, 2017
1ec5 added a commit that referenced this pull request Jan 16, 2017
1ec5 added a commit that referenced this pull request Jan 19, 2017
Updated changelogs to mention #7446, #7356, #7465, #7616, #7445, #7444, #7526, #7586, #7574, and #7770. Also corrected the blurb about #7711.
@jfirebaugh jfirebaugh deleted the cloer_linebreak_port branch May 11, 2017 19:50
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants