Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(146)

Side by Side Diff: third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp

Issue 2740083002: Add support for shaper-driven line breaking to HarfBuzzShaper (Closed)
Patch Set: [LayoutNG] Full on shaper-driven line breaking Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2012 Google Inc. All rights reserved. 2 * Copyright (c) 2012 Google Inc. All rights reserved.
3 * Copyright (C) 2013 BlackBerry Limited. All rights reserved. 3 * Copyright (C) 2013 BlackBerry Limited. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are 6 * modification, are permitted provided that the following conditions are
7 * met: 7 * met:
8 * 8 *
9 * * Redistributions of source code must retain the above copyright 9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 13 matching lines...) Expand all
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32 #include "platform/fonts/shaping/HarfBuzzShaper.h" 32 #include "platform/fonts/shaping/HarfBuzzShaper.h"
33 33
34 #include <hb.h>
35 #include <unicode/uchar.h>
36 #include <unicode/uscript.h>
37 #include <algorithm>
38 #include <memory>
39 #include "platform/LayoutUnit.h"
34 #include "platform/fonts/Font.h" 40 #include "platform/fonts/Font.h"
35 #include "platform/fonts/FontDescription.h" 41 #include "platform/fonts/FontDescription.h"
36 #include "platform/fonts/FontFallbackIterator.h" 42 #include "platform/fonts/FontFallbackIterator.h"
37 #include "platform/fonts/GlyphBuffer.h" 43 #include "platform/fonts/GlyphBuffer.h"
38 #include "platform/fonts/SmallCapsIterator.h" 44 #include "platform/fonts/SmallCapsIterator.h"
39 #include "platform/fonts/UTF16TextIterator.h" 45 #include "platform/fonts/UTF16TextIterator.h"
40 #include "platform/fonts/opentype/OpenTypeCapsSupport.h" 46 #include "platform/fonts/opentype/OpenTypeCapsSupport.h"
41 #include "platform/fonts/shaping/CaseMappingHarfBuzzBufferFiller.h" 47 #include "platform/fonts/shaping/CaseMappingHarfBuzzBufferFiller.h"
42 #include "platform/fonts/shaping/HarfBuzzFace.h" 48 #include "platform/fonts/shaping/HarfBuzzFace.h"
43 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h" 49 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h"
44 #include "platform/text/TextBreakIterator.h" 50 #include "platform/text/TextBreakIterator.h"
45 #include "wtf/Compiler.h" 51 #include "wtf/Compiler.h"
46 #include "wtf/MathExtras.h" 52 #include "wtf/MathExtras.h"
47 #include "wtf/PtrUtil.h" 53 #include "wtf/PtrUtil.h"
48 #include "wtf/text/Unicode.h" 54 #include "wtf/text/Unicode.h"
49 #include <algorithm>
50 #include <hb.h>
51 #include <memory>
52 #include <unicode/uchar.h>
53 #include <unicode/uscript.h>
54 55
55 namespace blink { 56 namespace blink {
56 enum HolesQueueItemAction { HolesQueueNextFont, HolesQueueRange }; 57 enum HolesQueueItemAction { HolesQueueNextFont, HolesQueueRange };
57 58
58 struct HolesQueueItem { 59 struct HolesQueueItem {
59 DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); 60 DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
60 HolesQueueItemAction m_action; 61 HolesQueueItemAction m_action;
61 unsigned m_startIndex; 62 unsigned m_startIndex;
62 unsigned m_numCharacters; 63 unsigned m_numCharacters;
63 HolesQueueItem(HolesQueueItemAction action, unsigned start, unsigned num) 64 HolesQueueItem(HolesQueueItemAction action, unsigned start, unsigned num)
(...skipping 637 matching lines...) Expand 10 before | Expand all | Expand 10 after
701 if (start < segmentRange.end && end > segmentRange.start) 702 if (start < segmentRange.end && end > segmentRange.start)
702 shapeSegment(&rangeData, segmentRange, result.get()); 703 shapeSegment(&rangeData, segmentRange, result.get());
703 } 704 }
704 return result.release(); 705 return result.release();
705 } 706 }
706 707
707 PassRefPtr<ShapeResult> HarfBuzzShaper::shape(const Font* font, 708 PassRefPtr<ShapeResult> HarfBuzzShaper::shape(const Font* font,
708 TextDirection direction) const { 709 TextDirection direction) const {
709 return shape(font, direction, 0, m_textLength); 710 return shape(font, direction, 0, m_textLength);
710 } 711 }
712
713 namespace {
714
715 unsigned previousBreakOpportunity(unsigned start,
716 unsigned offset,
717 unsigned textLength,
718 LazyLineBreakIterator& breakIterator,
719 LineBreakType breakType) {
720 unsigned pos = std::min(start + offset, textLength);
721 for (; pos > start; pos--) {
722 int nextBreak = 0;
723 if (breakIterator.isBreakable(pos, nextBreak, breakType))
724 return pos;
725 }
726 return start;
727 }
728
729 unsigned nextBreakOpportunity(unsigned offset,
730 LazyLineBreakIterator& breakIterator,
731 LineBreakType breakType) {
732 int nextBreak = 0;
733 breakIterator.isBreakable(offset, nextBreak, breakType);
734 return nextBreak;
735 }
736
737 unsigned previousSafeToBreakAfter(const UChar* text,
738 unsigned start,
739 unsigned offset) {
740 // TODO: This should use harf-buzz safe to break info when available. For now
drott 2017/03/22 21:01:11 s/harf-buzz/HarfBuzz/
741 // it'll scan back until the previous space character or something.
742 for (; offset > start; offset--) {
743 if (text[offset - 1] == spaceCharacter)
744 break;
745 }
746 return offset;
747 }
748
749 unsigned nextSafeToBreakBefore(const UChar* text,
750 unsigned end,
751 unsigned offset) {
752 for (; offset < end; offset++) {
753 if (text[offset] == spaceCharacter)
754 break;
755 }
756 return offset;
757 }
758
759 } // namespace
760
761 // Shapes a line of text by finding a valid and appropriate break opportunity
762 // based on the shaping results for the entire paragraph. Re-shapes the start
763 // and end of the line as needed.
764 //
765 // Definitions:
766 // Candidate break opportunity: Ideal point to break, disregarding line
767 // breaking rules. May be in the middle of a word
768 // or inside a ligature.
769 // Valid break opportunity: A point where a break is allowed according to
770 // the relevant breaking rules.
771 // Safe-to-break: A point where a break may occur without
772 // affecting the rendering or metrics of the
773 // text. Breaking at safe-to-break point does not
774 // require reshaping.
775 //
776 // For example:
777 // Given the string "Line breaking example", an available space of 100px and a
778 // mono-space font where each glyph is 10px wide.
779 //
780 // Line breaking example
781 // | |
782 // 0 100px
783 //
784 // The candidate (or ideal) break opportunity would be at an offset of 10 as
785 // the break would happen at exactly 100px in that case.
786 // The previous valid break opportunity though is at an offset of 5.
787 // If we further assume that the font kerns with space then even though it's a
788 // valid break opportunity reshaping is required as the combined width of the
789 // two segments "Line " and "breaking" may be different from "Line breaking".
790 PassRefPtr<ShapeResult> HarfBuzzShaper::shapeLine(const Font* font,
791 const ShapeResult* result,
792 unsigned startOffset,
793 const AtomicString locale,
794 LineBreakType breakType,
795 LayoutUnit availableSpace,
796 unsigned* breakOffset) const {
797 // The start position in the original shape results.
798 LayoutUnit startPosition = result->snappedStartPositionForOffset(startOffset);
drott 2017/03/22 21:01:11 IIUC, this one is pixel snapped, why is that the c
eae 2017/03/27 20:14:02 No, this snaps to the nearest 1/64th of a pixel, n
drott 2017/03/27 20:24:36 I see, that makes more sense, thank you for the ex
799
800 // If the start offset is not at a safe-to-break boundary content between
drott 2017/03/22 21:01:11 What do you mean by "content" here? Or probably th
eae 2017/03/27 20:14:02 Missing "the", thank you.
801 // the start and the next safe-to-break boundary needs to be reshaped and the
802 // available space adjusted to take the reshaping into account.
803 RefPtr<ShapeResult> lineStartResult;
804 unsigned firstSafe = nextSafeToBreakBefore(m_text, m_textLength, startOffset);
805 if (firstSafe != startOffset) {
806 LayoutUnit originalWidth =
807 result->snappedEndPositionForOffset(firstSafe) - startPosition;
808 lineStartResult = shape(font, result->direction(), startOffset, firstSafe);
809 availableSpace += lineStartResult->snappedWidth() - originalWidth;
810 }
811
812 // Find a candidate break opportunity by identifying the last offset before
813 // exceeding the available space and the determine the closest valid break
814 // preceding the candidate.
815 LazyLineBreakIterator breakIterator(String(m_text, m_textLength), locale);
816 LayoutUnit endPosition = startPosition + availableSpace;
817 unsigned candidateBreak = result->offsetForPosition(endPosition, false);
818 unsigned breakOpportunity = previousBreakOpportunity(
819 startOffset, candidateBreak, m_textLength, breakIterator, breakType);
820 if (breakOpportunity <= startOffset) {
821 breakOpportunity =
822 nextBreakOpportunity(candidateBreak, breakIterator, breakType);
823 }
824
825 RefPtr<ShapeResult> lineEndResult;
826 unsigned lastSafe = breakOpportunity;
827 while (breakOpportunity > startOffset) {
828 // If the previous valid break opportunity is not at a safe-to-break
829 // boundary reshape between the safe-to-break offset and the valid break
830 // offset. If the resulting width exceeds the available space the
831 // preceding boundary is tried until the available space is sufficient.
832 unsigned previousSafe = std::max(
drott 2017/03/22 21:01:11 Nice.
833 previousSafeToBreakAfter(m_text, startOffset, breakOpportunity),
834 startOffset);
835 if (previousSafe != breakOpportunity) {
836 LayoutUnit safePosition =
837 result->snappedStartPositionForOffset(previousSafe);
838 while (breakOpportunity > previousSafe && previousSafe > startOffset) {
839 lineEndResult =
840 shape(font, result->direction(), previousSafe, breakOpportunity);
841 if (safePosition + lineEndResult->snappedWidth() <= endPosition)
842 break;
843 lineEndResult = nullptr;
844 breakOpportunity =
845 previousBreakOpportunity(startOffset, breakOpportunity - 1,
846 m_textLength, breakIterator, breakType);
847 }
848 }
849
850 if (breakOpportunity > startOffset) {
851 lastSafe = previousSafe;
852 break;
853 }
854
855 // No suitable break opportunity, not exceeding the available space,
856 // found. Choose the next valid one even though it will overflow.
857 breakOpportunity =
858 nextBreakOpportunity(candidateBreak, breakIterator, breakType);
859 }
860
861 // Create shape results for the line by copying from the re-shaped result (if
862 // reshaping was needed) and the original shape results.
863 RefPtr<ShapeResult> lineResult =
864 ShapeResult::create(font, 0, result->direction());
865 unsigned maxLength = std::numeric_limits<unsigned>::max();
866 if (lineStartResult)
867 lineStartResult->copyRange(0, maxLength, lineResult.get());
868 if (lastSafe > firstSafe)
869 result->copyRange(firstSafe, lastSafe, lineResult.get());
870 if (lineEndResult)
871 lineEndResult->copyRange(lastSafe, maxLength, lineResult.get());
872
873 *breakOffset = breakOpportunity;
874 return lineResult.release();
875 }
876
711 } // namespace blink 877 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698