summaryrefslogtreecommitdiff
path: root/Source/WebCore/platform/graphics/StringTruncator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/platform/graphics/StringTruncator.cpp')
-rw-r--r--Source/WebCore/platform/graphics/StringTruncator.cpp113
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