diff options
Diffstat (limited to 'Source/WebCore/platform/graphics/StringTruncator.cpp')
-rw-r--r-- | Source/WebCore/platform/graphics/StringTruncator.cpp | 113 |
1 files changed, 59 insertions, 54 deletions
diff --git a/Source/WebCore/platform/graphics/StringTruncator.cpp b/Source/WebCore/platform/graphics/StringTruncator.cpp index 72f80c03d..85a3ad29a 100644 --- a/Source/WebCore/platform/graphics/StringTruncator.cpp +++ b/Source/WebCore/platform/graphics/StringTruncator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2005, 2006, 2007, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -29,11 +29,13 @@ #include "config.h" #include "StringTruncator.h" -#include "Font.h" -#include "TextBreakIterator.h" +#include "FontCascade.h" +#include <wtf/text/TextBreakIterator.h> #include "TextRun.h" +#include <unicode/ubrk.h> #include <wtf/Assertions.h> #include <wtf/Vector.h> +#include <wtf/text/StringView.h> #include <wtf/unicode/CharacterNames.h> namespace WebCore { @@ -42,19 +44,19 @@ namespace WebCore { typedef unsigned TruncationFunction(const String&, unsigned length, unsigned keepCount, UChar* buffer, bool shouldInsertEllipsis); -static inline int textBreakAtOrPreceding(TextBreakIterator* it, int offset) +static inline int textBreakAtOrPreceding(UBreakIterator* it, int offset) { - if (isTextBreak(it, offset)) + if (ubrk_isBoundary(it, offset)) return offset; - int result = textBreakPreceding(it, offset); - return result == TextBreakDone ? 0 : result; + int result = ubrk_preceding(it, offset); + return result == UBRK_DONE ? 0 : result; } -static inline int boundedTextBreakFollowing(TextBreakIterator* it, int offset, int length) +static inline int boundedTextBreakFollowing(UBreakIterator* it, int offset, int length) { - int result = textBreakFollowing(it, offset); - return result == TextBreakDone ? length : result; + int result = ubrk_following(it, offset); + return result == UBRK_DONE ? length : result; } static unsigned centerTruncateToBuffer(const String& string, unsigned length, unsigned keepCount, UChar* buffer, bool shouldInsertEllipsis) @@ -69,6 +71,8 @@ static unsigned centerTruncateToBuffer(const String& string, unsigned length, un #if PLATFORM(IOS) // FIXME: We should guard this code behind an editing behavior. Then we can remove the PLATFORM(IOS)-guard. + // Or just turn it on for all platforms. It seems like good behavior everywhere. Might be better to generalize + // it to handle all whitespace, not just "space". // Strip single character before ellipsis character, when that character is preceded by a space if (omitStart > 1 && string[omitStart - 1] != space && omitStart > 2 && string[omitStart - 2] == space) @@ -86,15 +90,13 @@ static unsigned centerTruncateToBuffer(const String& string, unsigned length, un ++omitEnd; #endif - unsigned truncatedLength = shouldInsertEllipsis ? omitStart + 1 + (length - omitEnd) : length - (omitEnd - omitStart); + unsigned truncatedLength = omitStart + shouldInsertEllipsis + (length - omitEnd); ASSERT(truncatedLength <= length); - memcpy(buffer, string.deprecatedCharacters(), sizeof(UChar) * omitStart); - if (shouldInsertEllipsis) { - buffer[omitStart] = horizontalEllipsis; - memcpy(&buffer[omitStart + 1], &string.deprecatedCharacters()[omitEnd], sizeof(UChar) * (length - omitEnd)); - } else - memcpy(&buffer[omitStart], &string.deprecatedCharacters()[omitEnd], sizeof(UChar) * (length - omitEnd)); + StringView(string).substring(0, omitStart).getCharactersWithUpconvert(buffer); + if (shouldInsertEllipsis) + buffer[omitStart++] = horizontalEllipsis; + StringView(string).substring(omitEnd, length - omitEnd).getCharactersWithUpconvert(&buffer[omitStart]); return truncatedLength; } @@ -105,6 +107,8 @@ static unsigned rightTruncateToBuffer(const String& string, unsigned length, uns #if PLATFORM(IOS) // FIXME: We should guard this code behind an editing behavior. Then we can remove the PLATFORM(IOS)-guard. + // Or just turn it on for all platforms. It seems like good behavior everywhere. Might be better to generalize + // it to handle all whitespace, not just "space". // Strip single character before ellipsis character, when that character is preceded by a space if (keepCount > 1 && string[keepCount - 1] != space && keepCount > 2 && string[keepCount - 2] == space) @@ -119,7 +123,7 @@ static unsigned rightTruncateToBuffer(const String& string, unsigned length, uns unsigned keepLength = textBreakAtOrPreceding(it, keepCount); unsigned truncatedLength = shouldInsertEllipsis ? keepLength + 1 : keepLength; - memcpy(buffer, string.deprecatedCharacters(), sizeof(UChar) * keepLength); + StringView(string).substring(0, keepLength).getCharactersWithUpconvert(buffer); if (shouldInsertEllipsis) buffer[keepLength] = horizontalEllipsis; @@ -133,7 +137,7 @@ static unsigned rightClipToCharacterBuffer(const String& string, unsigned length NonSharedCharacterBreakIterator it(StringView(string).substring(0, length)); unsigned keepLength = textBreakAtOrPreceding(it, keepCount); - memcpy(buffer, string.deprecatedCharacters(), sizeof(UChar) * keepLength); + StringView(string).substring(0, keepLength).getCharactersWithUpconvert(buffer); return keepLength; } @@ -143,16 +147,20 @@ static unsigned rightClipToWordBuffer(const String& string, unsigned length, uns ASSERT(keepCount < length); ASSERT(keepCount < STRING_BUFFER_SIZE); - TextBreakIterator* it = wordBreakIterator(StringView(string).substring(0, length)); + UBreakIterator* it = wordBreakIterator(StringView(string).substring(0, length)); unsigned keepLength = textBreakAtOrPreceding(it, keepCount); - memcpy(buffer, string.deprecatedCharacters(), sizeof(UChar) * keepLength); + StringView(string).substring(0, keepLength).getCharactersWithUpconvert(buffer); #if PLATFORM(IOS) // FIXME: We should guard this code behind an editing behavior. Then we can remove the PLATFORM(IOS)-guard. + // Or just turn it on for all platforms. It seems like good behavior everywhere. Might be better to generalize + // it to handle all whitespace, not just "space". + // Motivated by <rdar://problem/7439327> truncation should not include a trailing space - while ((keepLength > 0) && (string[keepLength - 1] == space)) + while (keepLength && string[keepLength - 1] == space) --keepLength; #endif + return keepLength; } @@ -165,7 +173,7 @@ static unsigned leftTruncateToBuffer(const String& string, unsigned length, unsi NonSharedCharacterBreakIterator it(string); unsigned adjustedStartIndex = startIndex; - startIndex = boundedTextBreakFollowing(it, startIndex, length - startIndex); + boundedTextBreakFollowing(it, startIndex, length - startIndex); // Strip single character after ellipsis character, when that character is preceded by a space if (adjustedStartIndex < length && string[adjustedStartIndex] != space @@ -178,22 +186,20 @@ static unsigned leftTruncateToBuffer(const String& string, unsigned length, unsi if (shouldInsertEllipsis) { buffer[0] = horizontalEllipsis; - memcpy(&buffer[1], &string.deprecatedCharacters()[adjustedStartIndex], sizeof(UChar) * (length - adjustedStartIndex + 1)); + StringView(string).substring(adjustedStartIndex, length - adjustedStartIndex + 1).getCharactersWithUpconvert(&buffer[1]); return length - adjustedStartIndex + 1; } - memcpy(&buffer[0], &string.deprecatedCharacters()[adjustedStartIndex], sizeof(UChar) * (length - adjustedStartIndex + 1)); + StringView(string).substring(adjustedStartIndex, length - adjustedStartIndex + 1).getCharactersWithUpconvert(&buffer[0]); return length - adjustedStartIndex; } -static float stringWidth(const Font& renderer, const UChar* characters, unsigned length, bool disableRoundingHacks) +static float stringWidth(const FontCascade& renderer, const UChar* characters, unsigned length) { - TextRun run(characters, length); - if (disableRoundingHacks) - run.disableRoundingHacks(); + TextRun run(StringView(characters, length)); return renderer.width(run); } -static String truncateString(const String& string, float maxWidth, const Font& font, TruncationFunction truncateToBuffer, bool disableRoundingHacks, float* resultWidth = nullptr, bool shouldInsertEllipsis = true, float customTruncationElementWidth = 0, bool alwaysTruncate = false) +static String truncateString(const String& string, float maxWidth, const FontCascade& font, TruncationFunction truncateToBuffer, float* resultWidth = nullptr, bool shouldInsertEllipsis = true, float customTruncationElementWidth = 0, bool alwaysTruncate = false) { if (string.isEmpty()) return string; @@ -203,7 +209,7 @@ static String truncateString(const String& string, float maxWidth, const Font& f ASSERT(maxWidth >= 0); - float currentEllipsisWidth = shouldInsertEllipsis ? stringWidth(font, &horizontalEllipsis, 1, disableRoundingHacks) : customTruncationElementWidth; + float currentEllipsisWidth = shouldInsertEllipsis ? stringWidth(font, &horizontalEllipsis, 1) : customTruncationElementWidth; UChar stringBuffer[STRING_BUFFER_SIZE]; unsigned truncatedLength; @@ -218,11 +224,11 @@ static String truncateString(const String& string, float maxWidth, const Font& f truncatedLength = centerTruncateToBuffer(string, length, keepCount, stringBuffer, shouldInsertEllipsis); } else { keepCount = length; - memcpy(stringBuffer, string.deprecatedCharacters(), sizeof(UChar) * length); + StringView(string).getCharactersWithUpconvert(stringBuffer); truncatedLength = length; } - float width = stringWidth(font, stringBuffer, truncatedLength, disableRoundingHacks); + float width = stringWidth(font, stringBuffer, truncatedLength); if (!shouldInsertEllipsis && alwaysTruncate) width += customTruncationElementWidth; if ((width - maxWidth) < 0.0001) { // Ignore rounding errors. @@ -250,11 +256,10 @@ static String truncateString(const String& string, float maxWidth, const Font& f / (widthForSmallestKnownToNotFit - widthForLargestKnownToFit); keepCount = static_cast<unsigned>(maxWidth * ratio); - if (keepCount <= keepCountForLargestKnownToFit) { + if (keepCount <= keepCountForLargestKnownToFit) keepCount = keepCountForLargestKnownToFit + 1; - } else if (keepCount >= keepCountForSmallestKnownToNotFit) { + else if (keepCount >= keepCountForSmallestKnownToNotFit) keepCount = keepCountForSmallestKnownToNotFit - 1; - } ASSERT_WITH_SECURITY_IMPLICATION(keepCount < length); ASSERT(keepCount > 0); @@ -263,7 +268,7 @@ static String truncateString(const String& string, float maxWidth, const Font& f truncatedLength = truncateToBuffer(string, length, keepCount, stringBuffer, shouldInsertEllipsis); - width = stringWidth(font, stringBuffer, truncatedLength, disableRoundingHacks); + width = stringWidth(font, stringBuffer, truncatedLength); if (!shouldInsertEllipsis) width += customTruncationElementWidth; if (width <= maxWidth) { @@ -289,44 +294,44 @@ static String truncateString(const String& string, float maxWidth, const Font& f return String(stringBuffer, truncatedLength); } -String StringTruncator::centerTruncate(const String& string, float maxWidth, const Font& font, EnableRoundingHacksOrNot enableRoundingHacks) +String StringTruncator::centerTruncate(const String& string, float maxWidth, const FontCascade& font) { - return truncateString(string, maxWidth, font, centerTruncateToBuffer, !enableRoundingHacks); + return truncateString(string, maxWidth, font, centerTruncateToBuffer); } -String StringTruncator::rightTruncate(const String& string, float maxWidth, const Font& font, EnableRoundingHacksOrNot enableRoundingHacks) +String StringTruncator::rightTruncate(const String& string, float maxWidth, const FontCascade& font) { - return truncateString(string, maxWidth, font, rightTruncateToBuffer, !enableRoundingHacks); + return truncateString(string, maxWidth, font, rightTruncateToBuffer); } -float StringTruncator::width(const String& string, const Font& font, EnableRoundingHacksOrNot enableRoundingHacks) +float StringTruncator::width(const String& string, const FontCascade& font) { - return stringWidth(font, string.deprecatedCharacters(), string.length(), !enableRoundingHacks); + return stringWidth(font, StringView(string).upconvertedCharacters(), string.length()); } -String StringTruncator::centerTruncate(const String& string, float maxWidth, const Font& font, EnableRoundingHacksOrNot enableRoundingHacks, float& resultWidth, bool shouldInsertEllipsis, float customTruncationElementWidth) +String StringTruncator::centerTruncate(const String& string, float maxWidth, const FontCascade& font, float& resultWidth, bool shouldInsertEllipsis, float customTruncationElementWidth) { - return truncateString(string, maxWidth, font, centerTruncateToBuffer, !enableRoundingHacks, &resultWidth, shouldInsertEllipsis, customTruncationElementWidth); + return truncateString(string, maxWidth, font, centerTruncateToBuffer, &resultWidth, shouldInsertEllipsis, customTruncationElementWidth); } -String StringTruncator::rightTruncate(const String& string, float maxWidth, const Font& font, EnableRoundingHacksOrNot enableRoundingHacks, float& resultWidth, bool shouldInsertEllipsis, float customTruncationElementWidth) +String StringTruncator::rightTruncate(const String& string, float maxWidth, const FontCascade& font, float& resultWidth, bool shouldInsertEllipsis, float customTruncationElementWidth) { - return truncateString(string, maxWidth, font, rightTruncateToBuffer, !enableRoundingHacks, &resultWidth, shouldInsertEllipsis, customTruncationElementWidth); + return truncateString(string, maxWidth, font, rightTruncateToBuffer, &resultWidth, shouldInsertEllipsis, customTruncationElementWidth); } -String StringTruncator::leftTruncate(const String& string, float maxWidth, const Font& font, EnableRoundingHacksOrNot enableRoundingHacks, float& resultWidth, bool shouldInsertEllipsis, float customTruncationElementWidth) +String StringTruncator::leftTruncate(const String& string, float maxWidth, const FontCascade& font, float& resultWidth, bool shouldInsertEllipsis, float customTruncationElementWidth) { - return truncateString(string, maxWidth, font, leftTruncateToBuffer, !enableRoundingHacks, &resultWidth, shouldInsertEllipsis, customTruncationElementWidth); + return truncateString(string, maxWidth, font, leftTruncateToBuffer, &resultWidth, shouldInsertEllipsis, customTruncationElementWidth); } -String StringTruncator::rightClipToCharacter(const String& string, float maxWidth, const Font& font, EnableRoundingHacksOrNot enableRoundingHacks, float& resultWidth, bool shouldInsertEllipsis, float customTruncationElementWidth) +String StringTruncator::rightClipToCharacter(const String& string, float maxWidth, const FontCascade& font, float& resultWidth, bool shouldInsertEllipsis, float customTruncationElementWidth) { - return truncateString(string, maxWidth, font, rightClipToCharacterBuffer, !enableRoundingHacks, &resultWidth, shouldInsertEllipsis, customTruncationElementWidth); + return truncateString(string, maxWidth, font, rightClipToCharacterBuffer, &resultWidth, shouldInsertEllipsis, customTruncationElementWidth); } -String StringTruncator::rightClipToWord(const String& string, float maxWidth, const Font& font, EnableRoundingHacksOrNot enableRoundingHacks, float& resultWidth, bool shouldInsertEllipsis, float customTruncationElementWidth, bool alwaysTruncate) +String StringTruncator::rightClipToWord(const String& string, float maxWidth, const FontCascade& font, float& resultWidth, bool shouldInsertEllipsis, float customTruncationElementWidth, bool alwaysTruncate) { - return truncateString(string, maxWidth, font, rightClipToWordBuffer, !enableRoundingHacks, &resultWidth, shouldInsertEllipsis, customTruncationElementWidth, alwaysTruncate); + return truncateString(string, maxWidth, font, rightClipToWordBuffer, &resultWidth, shouldInsertEllipsis, customTruncationElementWidth, alwaysTruncate); } } // namespace WebCore |