OLD | NEW |
1 /* | 1 /* |
2 * (C) 1999 Lars Knoll (knoll@kde.org) | 2 * (C) 1999 Lars Knoll (knoll@kde.org) |
3 * (C) 2000 Dirk Mueller (mueller@kde.org) | 3 * (C) 2000 Dirk Mueller (mueller@kde.org) |
4 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. | 4 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. |
5 * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) | 5 * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) |
6 * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) | 6 * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) |
7 * | 7 * |
8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
(...skipping 14 matching lines...) Expand all Loading... |
25 #include "config.h" | 25 #include "config.h" |
26 #include "core/rendering/RenderText.h" | 26 #include "core/rendering/RenderText.h" |
27 | 27 |
28 #include "core/accessibility/AXObjectCache.h" | 28 #include "core/accessibility/AXObjectCache.h" |
29 #include "core/dom/Text.h" | 29 #include "core/dom/Text.h" |
30 #include "core/editing/VisiblePosition.h" | 30 #include "core/editing/VisiblePosition.h" |
31 #include "core/loader/TextResourceDecoder.h" | 31 #include "core/loader/TextResourceDecoder.h" |
32 #include "core/page/FrameView.h" | 32 #include "core/page/FrameView.h" |
33 #include "core/page/Settings.h" | 33 #include "core/page/Settings.h" |
34 #include "core/platform/graphics/FloatQuad.h" | 34 #include "core/platform/graphics/FloatQuad.h" |
35 #include "core/platform/text/Hyphenation.h" | |
36 #include "core/platform/text/TextBreakIterator.h" | 35 #include "core/platform/text/TextBreakIterator.h" |
37 #include "core/platform/text/transcoder/FontTranscoder.h" | 36 #include "core/platform/text/transcoder/FontTranscoder.h" |
38 #include "core/rendering/EllipsisBox.h" | 37 #include "core/rendering/EllipsisBox.h" |
39 #include "core/rendering/InlineTextBox.h" | 38 #include "core/rendering/InlineTextBox.h" |
40 #include "core/rendering/RenderBlock.h" | 39 #include "core/rendering/RenderBlock.h" |
41 #include "core/rendering/RenderCombineText.h" | 40 #include "core/rendering/RenderCombineText.h" |
42 #include "core/rendering/RenderLayer.h" | 41 #include "core/rendering/RenderLayer.h" |
43 #include "core/rendering/RenderView.h" | 42 #include "core/rendering/RenderView.h" |
44 #include "core/rendering/break_lines.h" | 43 #include "core/rendering/break_lines.h" |
45 #include "wtf/text/StringBuffer.h" | 44 #include "wtf/text/StringBuffer.h" |
(...skipping 836 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
882 if (fallbackFonts.isEmpty() && !glyphOverflow.left && !glyphOverflow.right &
& !glyphOverflow.top && !glyphOverflow.bottom) | 881 if (fallbackFonts.isEmpty() && !glyphOverflow.left && !glyphOverflow.right &
& !glyphOverflow.top && !glyphOverflow.bottom) |
883 m_knownToHaveNoOverflowAndNoFallbackFonts = true; | 882 m_knownToHaveNoOverflowAndNoFallbackFonts = true; |
884 } | 883 } |
885 | 884 |
886 static inline float hyphenWidth(RenderText* renderer, const Font& font) | 885 static inline float hyphenWidth(RenderText* renderer, const Font& font) |
887 { | 886 { |
888 RenderStyle* style = renderer->style(); | 887 RenderStyle* style = renderer->style(); |
889 return font.width(RenderBlock::constructTextRun(renderer, font, style->hyphe
nString().string(), style)); | 888 return font.width(RenderBlock::constructTextRun(renderer, font, style->hyphe
nString().string(), style)); |
890 } | 889 } |
891 | 890 |
892 static float maxWordFragmentWidth(RenderText* renderer, RenderStyle* style, cons
t Font& font, int wordOffset, int wordLength, int minimumPrefixLength, int minim
umSuffixLength, int& suffixStart) | |
893 { | |
894 suffixStart = 0; | |
895 if (wordLength <= minimumSuffixLength) | |
896 return 0; | |
897 | |
898 Vector<int, 8> hyphenLocations; | |
899 int hyphenLocation = wordLength - minimumSuffixLength; | |
900 String word = renderer->substring(wordOffset, wordLength); | |
901 while ((hyphenLocation = lastHyphenLocation(word, hyphenLocation, style->loc
ale())) >= minimumPrefixLength) | |
902 hyphenLocations.append(hyphenLocation); | |
903 | |
904 if (hyphenLocations.isEmpty()) | |
905 return 0; | |
906 | |
907 hyphenLocations.reverse(); | |
908 | |
909 float minimumFragmentWidthToConsider = font.pixelSize() * 5 / 4 + hyphenWidt
h(renderer, font); | |
910 float maxFragmentWidth = 0; | |
911 for (size_t k = 0; k < hyphenLocations.size(); ++k) { | |
912 int fragmentLength = hyphenLocations[k] - suffixStart; | |
913 StringBuilder fragmentWithHyphen; | |
914 if (renderer->is8Bit()) | |
915 fragmentWithHyphen.append(renderer->characters8() + wordOffset + suf
fixStart, fragmentLength); | |
916 else | |
917 fragmentWithHyphen.append(renderer->characters16() + wordOffset + su
ffixStart, fragmentLength); | |
918 fragmentWithHyphen.append(style->hyphenString()); | |
919 | |
920 TextRun run = RenderBlock::constructTextRun(renderer, font, fragmentWith
Hyphen.toString(), style); | |
921 run.setCharactersLength(fragmentWithHyphen.length()); | |
922 run.setCharacterScanForCodePath(!renderer->canUseSimpleFontCodePath()); | |
923 float fragmentWidth = font.width(run); | |
924 | |
925 // Narrow prefixes are ignored. See tryHyphenating in RenderBlockLineLay
out.cpp. | |
926 if (fragmentWidth <= minimumFragmentWidthToConsider) | |
927 continue; | |
928 | |
929 suffixStart += fragmentLength; | |
930 maxFragmentWidth = max(maxFragmentWidth, fragmentWidth); | |
931 } | |
932 | |
933 return maxFragmentWidth; | |
934 } | |
935 | |
936 void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si
mpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow) | 891 void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Si
mpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow) |
937 { | 892 { |
938 ASSERT(m_hasTab || preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflow
AndNoFallbackFonts); | 893 ASSERT(m_hasTab || preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflow
AndNoFallbackFonts); |
939 | 894 |
940 m_minWidth = 0; | 895 m_minWidth = 0; |
941 m_maxWidth = 0; | 896 m_maxWidth = 0; |
942 m_firstLineMinWidth = 0; | 897 m_firstLineMinWidth = 0; |
943 m_lastLineLineMinWidth = 0; | 898 m_lastLineLineMinWidth = 0; |
944 | 899 |
945 if (isBR()) | 900 if (isBR()) |
(...skipping 23 matching lines...) Expand all Loading... |
969 | 924 |
970 // Non-zero only when kerning is enabled, in which case we measure words wit
h their trailing | 925 // Non-zero only when kerning is enabled, in which case we measure words wit
h their trailing |
971 // space, then subtract its width. | 926 // space, then subtract its width. |
972 float wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.width(R
enderBlock::constructTextRun(this, f, &space, 1, styleToUse)) + wordSpacing : 0; | 927 float wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.width(R
enderBlock::constructTextRun(this, f, &space, 1, styleToUse)) + wordSpacing : 0; |
973 | 928 |
974 // If automatic hyphenation is allowed, we keep track of the width of the wi
dest word (or word | 929 // If automatic hyphenation is allowed, we keep track of the width of the wi
dest word (or word |
975 // fragment) encountered so far, and only try hyphenating words that are wid
er. | 930 // fragment) encountered so far, and only try hyphenating words that are wid
er. |
976 float maxWordWidth = numeric_limits<float>::max(); | 931 float maxWordWidth = numeric_limits<float>::max(); |
977 int minimumPrefixLength = 0; | 932 int minimumPrefixLength = 0; |
978 int minimumSuffixLength = 0; | 933 int minimumSuffixLength = 0; |
979 if (styleToUse->hyphens() == HyphensAuto && canHyphenate(styleToUse->locale(
))) { | |
980 maxWordWidth = 0; | |
981 | |
982 // Map 'hyphenate-limit-{before,after}: auto;' to 2. | |
983 minimumPrefixLength = styleToUse->hyphenationLimitBefore(); | |
984 if (minimumPrefixLength < 0) | |
985 minimumPrefixLength = 2; | |
986 | |
987 minimumSuffixLength = styleToUse->hyphenationLimitAfter(); | |
988 if (minimumSuffixLength < 0) | |
989 minimumSuffixLength = 2; | |
990 } | |
991 | |
992 int firstGlyphLeftOverflow = -1; | 934 int firstGlyphLeftOverflow = -1; |
993 | 935 |
994 bool breakAll = (styleToUse->wordBreak() == BreakAllWordBreak || styleToUse-
>wordBreak() == BreakWordBreak) && styleToUse->autoWrap(); | 936 bool breakAll = (styleToUse->wordBreak() == BreakAllWordBreak || styleToUse-
>wordBreak() == BreakWordBreak) && styleToUse->autoWrap(); |
995 | 937 |
996 for (int i = 0; i < len; i++) { | 938 for (int i = 0; i < len; i++) { |
997 UChar c = uncheckedCharacterAt(i); | 939 UChar c = uncheckedCharacterAt(i); |
998 | 940 |
999 bool previousCharacterIsSpace = isSpace; | 941 bool previousCharacterIsSpace = isSpace; |
1000 | 942 |
1001 bool isNewline = false; | 943 bool isNewline = false; |
(...skipping 25 matching lines...) Expand all Loading... |
1027 ignoringSpaces = true; | 969 ignoringSpaces = true; |
1028 | 970 |
1029 if (ignoringSpaces && !isSpace) | 971 if (ignoringSpaces && !isSpace) |
1030 ignoringSpaces = false; | 972 ignoringSpaces = false; |
1031 | 973 |
1032 // Ignore spaces and soft hyphens | 974 // Ignore spaces and soft hyphens |
1033 if (ignoringSpaces) { | 975 if (ignoringSpaces) { |
1034 ASSERT(lastWordBoundary == i); | 976 ASSERT(lastWordBoundary == i); |
1035 lastWordBoundary++; | 977 lastWordBoundary++; |
1036 continue; | 978 continue; |
1037 } else if (c == softHyphen && styleToUse->hyphens() != HyphensNone) { | 979 } else if (c == softHyphen) { |
1038 currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoun
dary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow); | 980 currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoun
dary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow); |
1039 if (firstGlyphLeftOverflow < 0) | 981 if (firstGlyphLeftOverflow < 0) |
1040 firstGlyphLeftOverflow = glyphOverflow.left; | 982 firstGlyphLeftOverflow = glyphOverflow.left; |
1041 lastWordBoundary = i + 1; | 983 lastWordBoundary = i + 1; |
1042 continue; | 984 continue; |
1043 } | 985 } |
1044 | 986 |
1045 bool hasBreak = breakAll || isBreakable(breakIterator, i, nextBreakable)
; | 987 bool hasBreak = breakAll || isBreakable(breakIterator, i, nextBreakable)
; |
1046 bool betweenWords = true; | 988 bool betweenWords = true; |
1047 int j = i; | 989 int j = i; |
1048 while (c != '\n' && c != ' ' && c != '\t' && (c != softHyphen || styleTo
Use->hyphens() == HyphensNone)) { | 990 while (c != '\n' && c != ' ' && c != '\t' && (c != softHyphen)) { |
1049 j++; | 991 j++; |
1050 if (j == len) | 992 if (j == len) |
1051 break; | 993 break; |
1052 c = uncheckedCharacterAt(j); | 994 c = uncheckedCharacterAt(j); |
1053 if (isBreakable(breakIterator, j, nextBreakable) && characterAt(j -
1) != softHyphen) | 995 if (isBreakable(breakIterator, j, nextBreakable) && characterAt(j -
1) != softHyphen) |
1054 break; | 996 break; |
1055 if (breakAll) { | 997 if (breakAll) { |
1056 betweenWords = false; | 998 betweenWords = false; |
1057 break; | 999 break; |
1058 } | 1000 } |
1059 } | 1001 } |
1060 | 1002 |
1061 int wordLen = j - i; | 1003 int wordLen = j - i; |
1062 if (wordLen) { | 1004 if (wordLen) { |
1063 bool isSpace = (j < len) && c == ' '; | 1005 bool isSpace = (j < len) && c == ' '; |
1064 float w; | 1006 float w; |
1065 if (wordTrailingSpaceWidth && isSpace) | 1007 if (wordTrailingSpaceWidth && isSpace) |
1066 w = widthFromCache(f, i, wordLen + 1, leadWidth + currMaxWidth,
&fallbackFonts, &glyphOverflow) - wordTrailingSpaceWidth; | 1008 w = widthFromCache(f, i, wordLen + 1, leadWidth + currMaxWidth,
&fallbackFonts, &glyphOverflow) - wordTrailingSpaceWidth; |
1067 else { | 1009 else { |
1068 w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, &fal
lbackFonts, &glyphOverflow); | 1010 w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth, &fal
lbackFonts, &glyphOverflow); |
1069 if (c == softHyphen && styleToUse->hyphens() != HyphensNone) | 1011 if (c == softHyphen) |
1070 currMinWidth += hyphenWidth(this, f); | 1012 currMinWidth += hyphenWidth(this, f); |
1071 } | 1013 } |
1072 | 1014 |
1073 if (w > maxWordWidth) { | 1015 maxWordWidth = max(maxWordWidth, w); |
1074 int suffixStart; | |
1075 float maxFragmentWidth = maxWordFragmentWidth(this, styleToUse,
f, i, wordLen, minimumPrefixLength, minimumSuffixLength, suffixStart); | |
1076 | |
1077 if (suffixStart) { | |
1078 float suffixWidth; | |
1079 if (wordTrailingSpaceWidth && isSpace) | |
1080 suffixWidth = widthFromCache(f, i + suffixStart, wordLen
- suffixStart + 1, leadWidth + currMaxWidth, 0, 0) - wordTrailingSpaceWidth; | |
1081 else | |
1082 suffixWidth = widthFromCache(f, i + suffixStart, wordLen
- suffixStart, leadWidth + currMaxWidth, 0, 0); | |
1083 | |
1084 maxFragmentWidth = max(maxFragmentWidth, suffixWidth); | |
1085 | |
1086 currMinWidth += maxFragmentWidth - w; | |
1087 maxWordWidth = max(maxWordWidth, maxFragmentWidth); | |
1088 } else | |
1089 maxWordWidth = w; | |
1090 } | |
1091 | 1016 |
1092 if (firstGlyphLeftOverflow < 0) | 1017 if (firstGlyphLeftOverflow < 0) |
1093 firstGlyphLeftOverflow = glyphOverflow.left; | 1018 firstGlyphLeftOverflow = glyphOverflow.left; |
1094 currMinWidth += w; | 1019 currMinWidth += w; |
1095 if (betweenWords) { | 1020 if (betweenWords) { |
1096 if (lastWordBoundary == i) | 1021 if (lastWordBoundary == i) |
1097 currMaxWidth += w; | 1022 currMaxWidth += w; |
1098 else | 1023 else |
1099 currMaxWidth += widthFromCache(f, lastWordBoundary, j - last
WordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow); | 1024 currMaxWidth += widthFromCache(f, lastWordBoundary, j - last
WordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow); |
1100 lastWordBoundary = j; | 1025 lastWordBoundary = j; |
(...skipping 829 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1930 | 1855 |
1931 SecureTextTimer* secureTextTimer = gSecureTextTimers->get(this); | 1856 SecureTextTimer* secureTextTimer = gSecureTextTimers->get(this); |
1932 if (!secureTextTimer) { | 1857 if (!secureTextTimer) { |
1933 secureTextTimer = new SecureTextTimer(this); | 1858 secureTextTimer = new SecureTextTimer(this); |
1934 gSecureTextTimers->add(this, secureTextTimer); | 1859 gSecureTextTimers->add(this, secureTextTimer); |
1935 } | 1860 } |
1936 secureTextTimer->restartWithNewText(lastTypedCharacterOffset); | 1861 secureTextTimer->restartWithNewText(lastTypedCharacterOffset); |
1937 } | 1862 } |
1938 | 1863 |
1939 } // namespace WebCore | 1864 } // namespace WebCore |
OLD | NEW |