+2014-03-22 Darin Adler <darin@apple.com>
+
+ Remove String::deprecatedCharacters
+ https://bugs.webkit.org/show_bug.cgi?id=126854
+
+ Reviewed by Sam Weinig.
+
+ * wtf/text/StringBuilder.cpp:
+ (WTF::StringBuilder::reifyString): Removed code to update 16-bit shadow.
+
+ * wtf/text/StringBuilder.h: Removed deprecatedCharacters.
+ (WTF::StringBuilder::StringBuilder): Removed m_valid16BitShadowLength.
+ (WTF::StringBuilder::clear): Removed code to clear m_valid16BitShadowLength.
+ (WTF::StringBuilder::swap): Removed code to swap m_valid16BitShadowLength.
+
+ * wtf/text/StringImpl.cpp:
+ (WTF::StringImpl::~StringImpl): Removed code to free m_copyData16.
+ (WTF::StringImpl::upper): Use StringView::upconvertedCharacters for slow case.
+ (WTF::StringImpl::lower): Ditto.
+ (WTF::StringImpl::find): Use characters8/16 rather than deprecatedCharacters.
+ Added an 8-bit code path to one of the overloads. Might want to revisit later
+ to decide whether to use templates instead of copy/paste, or even use StringView
+ to cut down on duplicate code paths.
+ (WTF::StringImpl::findIgnoringCase): Ditto.
+ (WTF::StringImpl::sizeInBytes): Remove code to handle has16BitShadow case.
+ (WTF::equalIgnoringNullity): Added. To be called by the Vector template in the header.
+
+ * wtf/text/StringImpl.h: Removed deprecatedCharacters, has16BitShadow,
+ upconvertCharacters, getData16SlowCase, s_hashFlagHas16BitShadow, and m_copyData16.
+ (WTF::equalIgnoringNullity): Changed the template function into an inline that calls
+ a non-inline helper function. The non-inline function handles both 8-bit and 16-bit
+ strings.
+
+ * wtf/text/StringView.h:
+ (WTF::StringView::StringView): Added an overload so we can make one of these directly
+ from a StringImpl without first wrapping it in a string. Added an adapter so we can
+ use StringView as part of string concatenation. Added an append function so we can
+ append to a Vector<UChar>.
+
+ * wtf/text/WTFString.cpp:
+ (WTF::String::append): Use StringView::getCharactersWithUpconvert. Also changed
+ single-character append so it won't always turn an 8-bit string into a 16-bit one.
+ (WTF::String::insert): Removed one insert overload and changed the other to use
+ StringView::getCharactersWithUpconvert.
+ (WTF::String::truncate): Changed to use StringImpl::substring.
+ (WTF::String::percentage): Added characters8/16 paths instead of using
+ deprecatedCharacters.
+
+ * wtf/text/WTFString.h: Removed deprecatedCharacters, getCharactersWithUpconvert,
+ insert(UChar*, unsigned, unsigned), and the append overload for Vector<UChar>.
+
2014-03-20 Darin Adler <darin@apple.com>
Fix a header guard mistake (harmless but clearly wrong)
m_string = m_buffer.get();
else
m_string = StringImpl::createSubstringSharingImpl(m_buffer, 0, m_length);
-
- if (m_buffer->has16BitShadow() && m_valid16BitShadowLength < m_length)
- m_buffer->upconvertCharacters(m_valid16BitShadowLength, m_length);
-
- m_valid16BitShadowLength = m_length;
}
void StringBuilder::resize(unsigned newSize)
StringBuilder()
: m_length(0)
, m_is8Bit(true)
- , m_valid16BitShadowLength(0)
, m_bufferCharacters8(0)
{
}
return m_buffer->characters16();
}
- const UChar* deprecatedCharacters() const
- {
- if (!m_length)
- return 0;
- if (!m_string.isNull())
- return m_string.deprecatedCharacters();
- ASSERT(m_buffer);
- if (m_buffer->has16BitShadow() && m_valid16BitShadowLength < m_length)
- m_buffer->upconvertCharacters(m_valid16BitShadowLength, m_length);
-
- m_valid16BitShadowLength = m_length;
-
- return m_buffer->deprecatedCharacters();
- }
-
bool is8Bit() const { return m_is8Bit; }
void clear()
m_buffer = 0;
m_bufferCharacters8 = 0;
m_is8Bit = true;
- m_valid16BitShadowLength = 0;
}
void swap(StringBuilder& stringBuilder)
m_string.swap(stringBuilder.m_string);
m_buffer.swap(stringBuilder.m_buffer);
std::swap(m_is8Bit, stringBuilder.m_is8Bit);
- std::swap(m_valid16BitShadowLength, stringBuilder.m_valid16BitShadowLength);
std::swap(m_bufferCharacters8, stringBuilder.m_bufferCharacters8);
}
mutable String m_string;
RefPtr<StringImpl> m_buffer;
bool m_is8Bit;
- mutable unsigned m_valid16BitShadowLength;
union {
LChar* m_bufferCharacters8;
UChar* m_bufferCharacters16;
#include <wtf/StdLibExtras.h>
#include <wtf/WTFThreadData.h>
#include <wtf/text/CString.h>
+#include <wtf/text/StringView.h>
#include <wtf/unicode/CharacterNames.h>
#include <wtf/unicode/UTF8.h>
using namespace Unicode;
-COMPILE_ASSERT(sizeof(StringImpl) == 2 * sizeof(int) + 3 * sizeof(void*), StringImpl_should_stay_small);
+COMPILE_ASSERT(sizeof(StringImpl) == 2 * sizeof(int) + 2 * sizeof(void*), StringImpl_should_stay_small);
#ifdef STRING_STATS
StringStats StringImpl::m_stringStats;
BufferOwnership ownership = bufferOwnership();
- if (has16BitShadow()) {
- ASSERT(m_copyData16);
- fastFree(m_copyData16);
- }
-
if (ownership == BufferInternal)
return;
if (ownership == BufferOwned) {
return create(string, length);
}
-const UChar* StringImpl::getData16SlowCase() const
-{
- if (has16BitShadow())
- return m_copyData16;
-
- if (bufferOwnership() == BufferSubstring) {
- // If this is a substring, return a pointer into the parent string.
- // TODO: Consider severing this string from the parent string
- unsigned offset = m_data8 - substringBuffer()->characters8();
- return substringBuffer()->deprecatedCharacters() + offset;
- }
-
- STRING_STATS_ADD_UPCONVERTED_STRING(m_length);
-
- unsigned len = length();
-
- m_copyData16 = static_cast<UChar*>(fastMalloc(len * sizeof(UChar)));
-
- m_hashAndFlags |= s_hashFlagHas16BitShadow;
-
- upconvertCharacters(0, len);
-
- return m_copyData16;
-}
-
-void StringImpl::upconvertCharacters(unsigned start, unsigned end) const
-{
- ASSERT(is8Bit());
- ASSERT(has16BitShadow());
-
- for (size_t i = start; i < end; ++i)
- m_copyData16[i] = m_data8[i];
-}
-
-
bool StringImpl::containsOnlyWhitespace()
{
// FIXME: The definition of whitespace here includes a number of characters
}
upconvert:
- const UChar* source16 = deprecatedCharacters();
+ auto upconvertedCharacters = StringView(*this).upconvertedCharacters();
+ const UChar* source16 = upconvertedCharacters;
UChar* data16;
RefPtr<StringImpl> newImpl = createUninitialized(m_length, data16);
// Below, we pass in the hardcoded locale "tr". Passing that is more efficient than
// allocating memory just to turn localeIdentifier into a C string, and we assume
// there is no difference between the uppercasing for "tr" and "az" locales.
- const UChar* source16 = deprecatedCharacters();
+ auto upconvertedCharacters = StringView(*this).upconvertedCharacters();
+ const UChar* source16 = upconvertedCharacters;
UChar* data16;
RefPtr<StringImpl> newString = createUninitialized(length, data16);
UErrorCode status = U_ZERO_ERROR;
// Below, we pass in the hardcoded locale "tr". Passing that is more efficient than
// allocating memory just to turn localeIdentifier into a C string, and we assume
// there is no difference between the uppercasing for "tr" and "az" locales.
- const UChar* source16 = deprecatedCharacters();
+ auto upconvertedCharacters = StringView(*this).upconvertedCharacters();
+ const UChar* source16 = upconvertedCharacters;
UChar* data16;
RefPtr<StringImpl> newString = createUninitialized(length, data16);
UErrorCode status = U_ZERO_ERROR;
return std::min(index, length());
// Optimization 1: fast case for strings of length 1.
- if (matchLength == 1)
- return WTF::find(deprecatedCharacters(), length(), *matchString, index);
+ if (matchLength == 1) {
+ if (is8Bit())
+ return WTF::find(characters8(), length(), matchString[0], index);
+ return WTF::find(characters16(), length(), *matchString, index);
+ }
// Check index & matchLength are in range.
if (index > length())
// delta is the number of additional times to test; delta == 0 means test only once.
unsigned delta = searchLength - matchLength;
- const UChar* searchCharacters = deprecatedCharacters() + index;
-
// Optimization 2: keep a running hash of the strings,
// only call equal if the hashes match.
+
+ if (is8Bit()) {
+ const LChar* searchCharacters = characters8() + index;
+
+ unsigned searchHash = 0;
+ unsigned matchHash = 0;
+ for (unsigned i = 0; i < matchLength; ++i) {
+ searchHash += searchCharacters[i];
+ matchHash += matchString[i];
+ }
+
+ unsigned i = 0;
+ while (searchHash != matchHash || !equal(searchCharacters + i, matchString, matchLength)) {
+ if (i == delta)
+ return notFound;
+ searchHash += searchCharacters[i + matchLength];
+ searchHash -= searchCharacters[i];
+ ++i;
+ }
+ return index + i;
+ }
+
+ const UChar* searchCharacters = characters16() + index;
+
unsigned searchHash = 0;
unsigned matchHash = 0;
for (unsigned i = 0; i < matchLength; ++i) {
}
unsigned i = 0;
- // keep looping until we match
while (searchHash != matchHash || !equal(searchCharacters + i, matchString, matchLength)) {
if (i == delta)
return notFound;
// delta is the number of additional times to test; delta == 0 means test only once.
unsigned delta = searchLength - matchLength;
- const UChar* searchCharacters = deprecatedCharacters() + index;
+ if (is8Bit()) {
+ const LChar* searchCharacters = characters8() + index;
+
+ unsigned i = 0;
+ while (!equalIgnoringCase(searchCharacters + i, matchString, matchLength)) {
+ if (i == delta)
+ return notFound;
+ ++i;
+ }
+ return index + i;
+ }
+
+ const UChar* searchCharacters = characters16() + index;
unsigned i = 0;
- // keep looping until we match
while (!equalIgnoringCase(searchCharacters + i, matchString, matchLength)) {
if (i == delta)
return notFound;
{
// FIXME: support substrings
size_t size = length();
- if (is8Bit()) {
- if (has16BitShadow()) {
- size += 2 * size;
- }
- } else
+ if (!is8Bit())
size *= 2;
return size + sizeof(*this);
}
*buffer++ = static_cast<char>((ch & 0x3F) | 0x80);
}
-bool StringImpl::utf8Impl(
- const UChar* characters, unsigned length, char*& buffer, size_t bufferSize, ConversionMode mode)
+bool StringImpl::utf8Impl(const UChar* characters, unsigned length, char*& buffer, size_t bufferSize, ConversionMode mode)
{
if (mode == StrictConversionReplacingUnpairedSurrogatesWithFFFD) {
const UChar* charactersEnd = characters + length;
return true;
}
-CString StringImpl::utf8ForCharacters(
- const UChar* characters, unsigned length, ConversionMode mode)
+CString StringImpl::utf8ForCharacters(const UChar* characters, unsigned length, ConversionMode mode)
{
if (!length)
return CString("", 0);
0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff,
};
+bool equalIgnoringNullity(const UChar* a, size_t aLength, StringImpl* b)
+{
+ if (!b)
+ return !aLength;
+ if (aLength != b->length())
+ return false;
+ if (b->is8Bit()) {
+ const LChar* bCharacters = b->characters8();
+ for (unsigned i = 0; i < aLength; ++i) {
+ if (a[i] != bCharacters[i])
+ return false;
+ }
+ return true;
+ }
+ return !memcmp(a, b->characters16(), b->length() * sizeof(UChar));
+}
} // namespace WTF
ALWAYS_INLINE const LChar* characters8() const { ASSERT(is8Bit()); return m_data8; }
ALWAYS_INLINE const UChar* characters16() const { ASSERT(!is8Bit()); return m_data16; }
- ALWAYS_INLINE const UChar* deprecatedCharacters() const
- {
- if (!is8Bit())
- return m_data16;
-
- return getData16SlowCase();
- }
template <typename CharType>
ALWAYS_INLINE const CharType *characters() const;
WTF_EXPORT_STRING_API size_t sizeInBytes() const;
- bool has16BitShadow() const { return m_hashAndFlags & s_hashFlagHas16BitShadow; }
- WTF_EXPORT_STRING_API void upconvertCharacters(unsigned, unsigned) const;
bool isEmptyUnique() const
{
return !length() && !isStatic();
template <typename CharType> static PassRef<StringImpl> createUninitializedInternalNonEmpty(unsigned, CharType*&);
template <typename CharType> static PassRef<StringImpl> reallocateInternal(PassRefPtr<StringImpl>, unsigned, CharType*&);
template <typename CharType> static PassRef<StringImpl> createInternal(const CharType*, unsigned);
- WTF_EXPORT_STRING_API NEVER_INLINE const UChar* getData16SlowCase() const;
WTF_EXPORT_PRIVATE NEVER_INLINE unsigned hashSlowCase() const;
WTF_EXPORT_PRIVATE unsigned hashAndFlagsForEmptyUnique();
static const unsigned s_refCountFlagIsStaticString = 0x1;
static const unsigned s_refCountIncrement = 0x2; // This allows us to ref / deref without disturbing the static string flag.
- // The bottom 7 bits in the hash are flags.
- static const unsigned s_flagCount = 7;
+ // The bottom 6 bits in the hash are flags.
+ static const unsigned s_flagCount = 6;
static const unsigned s_flagMask = (1u << s_flagCount) - 1;
COMPILE_ASSERT(s_flagCount <= StringHasher::flagCount, StringHasher_reserves_enough_bits_for_StringImpl_flags);
- static const unsigned s_hashFlagHas16BitShadow = 1u << 6;
static const unsigned s_hashFlag8BitBuffer = 1u << 5;
static const unsigned s_hashFlagIsAtomic = 1u << 4;
static const unsigned s_hashFlagDidReportCost = 1u << 3;
unsigned m_refCount;
unsigned m_length;
const LChar* m_data8;
- mutable UChar* m_copyData16;
unsigned m_hashAndFlags;
// These values mimic ConstructFromLiteral.
const LChar* m_data8;
const UChar* m_data16;
};
- mutable UChar* m_copyData16;
mutable unsigned m_hashAndFlags;
};
WTF_EXPORT_STRING_API bool equalIgnoringCaseNonNull(const StringImpl*, const StringImpl*);
WTF_EXPORT_STRING_API bool equalIgnoringNullity(StringImpl*, StringImpl*);
+WTF_EXPORT_STRING_API bool equalIgnoringNullity(const UChar*, size_t length, StringImpl*);
template<typename CharacterType>
inline size_t find(const CharacterType* characters, unsigned length, CharacterType matchCharacter, unsigned index = 0)
return WTF::find(characters16(), m_length, character, start);
}
-template<size_t inlineCapacity>
-bool equalIgnoringNullity(const Vector<UChar, inlineCapacity>& a, StringImpl* b)
+template<size_t inlineCapacity> inline bool equalIgnoringNullity(const Vector<UChar, inlineCapacity>& a, StringImpl* b)
{
- if (!b)
- return !a.size();
- if (a.size() != b->length())
- return false;
- return !memcmp(a.data(), b->deprecatedCharacters(), b->length() * sizeof(UChar));
+ return equalIgnoringNullity(a.data(), a.size(), b);
}
template<typename CharacterType1, typename CharacterType2>
#ifndef StringView_h
#define StringView_h
-#include <wtf/text/WTFString.h>
+#include <wtf/text/StringConcatenate.h>
namespace WTF {
initialize(characters, length);
}
- StringView(const String& string)
- : m_characters(nullptr)
- , m_length(0)
+ StringView(const StringImpl& string)
{
- if (!string.impl())
- return;
-
if (string.is8Bit())
initialize(string.characters8(), string.length());
else
initialize(string.characters16(), string.length());
}
+ StringView(const String& string)
+ {
+ if (!string.impl()) {
+ m_characters = nullptr;
+ m_length = 0;
+ return;
+ }
+ if (string.is8Bit()) {
+ initialize(string.characters8(), string.length());
+ return;
+ }
+ initialize(string.characters16(), string.length());
+ }
+
static StringView empty()
{
return StringView(reinterpret_cast<const LChar*>(""), 0);
m_characters = m_upconvertedCharacters.data();
}
+template<> class StringTypeAdapter<StringView> {
+public:
+ StringTypeAdapter<StringView>(StringView string)
+ : m_string(string)
+ {
+ }
+
+ unsigned length() { return m_string.length(); }
+ bool is8Bit() { return m_string.is8Bit(); }
+ void writeTo(LChar* destination) { m_string.getCharactersWithUpconvert(destination); }
+ void writeTo(UChar* destination) { m_string.getCharactersWithUpconvert(destination); }
+
+private:
+ StringView m_string;
+};
+
+template<typename CharacterType, size_t inlineCapacity> void append(Vector<CharacterType, inlineCapacity>& buffer, StringView string)
+{
+ unsigned oldSize = buffer.size();
+ buffer.grow(oldSize + string.length());
+ string.getCharactersWithUpconvert(buffer.data() + oldSize);
+}
+
} // namespace WTF
+using WTF::append;
using WTF::StringView;
#endif // StringView_h
void String::append(const String& str)
{
+ // FIXME: This is extremely inefficient. So much so that we might want to take this out of String's API.
+
if (str.isEmpty())
return;
- // FIXME: This is extremely inefficient. So much so that we might want to take this
- // out of String's API. We can make it better by optimizing the case where exactly
- // one String is pointing at this StringImpl, but even then it's going to require a
- // call to fastMalloc every single time.
if (str.m_impl) {
if (m_impl) {
if (m_impl->is8Bit() && str.m_impl->is8Bit()) {
if (str.length() > std::numeric_limits<unsigned>::max() - m_impl->length())
CRASH();
RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(m_impl->length() + str.length(), data);
- memcpy(data, m_impl->deprecatedCharacters(), m_impl->length() * sizeof(UChar));
- memcpy(data + m_impl->length(), str.deprecatedCharacters(), str.length() * sizeof(UChar));
+ StringView(*m_impl).getCharactersWithUpconvert(data);
+ StringView(str).getCharactersWithUpconvert(data + m_impl->length());
m_impl = newImpl.release();
} else
m_impl = str.m_impl;
}
}
-template <typename CharacterType>
-inline void String::appendInternal(CharacterType c)
+void String::append(LChar character)
{
- // FIXME: This is extremely inefficient. So much so that we might want to take this
- // out of String's API. We can make it better by optimizing the case where exactly
- // one String is pointing at this StringImpl, but even then it's going to require a
- // call to fastMalloc every single time.
- if (m_impl) {
- UChar* data;
- if (m_impl->length() >= std::numeric_limits<unsigned>::max())
- CRASH();
- RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(m_impl->length() + 1, data);
- memcpy(data, m_impl->deprecatedCharacters(), m_impl->length() * sizeof(UChar));
- data[m_impl->length()] = c;
- m_impl = newImpl.release();
- } else
- m_impl = StringImpl::create(&c, 1);
-}
+ // FIXME: This is extremely inefficient. So much so that we might want to take this out of String's API.
-void String::append(LChar c)
-{
- appendInternal(c);
+ if (!m_impl) {
+ m_impl = StringImpl::create(&character, 1);
+ return;
+ }
+ if (!is8Bit()) {
+ append(static_cast<UChar>(character));
+ return;
+ }
+ if (m_impl->length() >= std::numeric_limits<unsigned>::max())
+ CRASH();
+ LChar* data;
+ RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(m_impl->length() + 1, data);
+ memcpy(data, m_impl->characters8(), m_impl->length());
+ data[m_impl->length()] = character;
+ m_impl = newImpl.release();
}
-void String::append(UChar c)
+void String::append(UChar character)
{
- appendInternal(c);
+ // FIXME: This is extremely inefficient. So much so that we might want to take this out of String's API.
+
+ if (character <= 0xFF && is8Bit()) {
+ append(static_cast<LChar>(character));
+ return;
+ }
+ if (!m_impl) {
+ m_impl = StringImpl::create(&character, 1);
+ return;
+ }
+ if (m_impl->length() >= std::numeric_limits<unsigned>::max())
+ CRASH();
+ UChar* data;
+ RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(m_impl->length() + 1, data);
+ StringView(*m_impl).getCharactersWithUpconvert(data);
+ data[m_impl->length()] = character;
+ m_impl = newImpl.release();
}
int codePointCompare(const String& a, const String& b)
return codePointCompare(a.impl(), b.impl());
}
-void String::insert(const String& str, unsigned pos)
+void String::insert(const String& string, unsigned position)
{
- if (str.isEmpty()) {
- if (str.isNull())
+ // FIXME: This is extremely inefficient. So much so that we might want to take this out of String's API.
+
+ unsigned lengthToInsert = string.length();
+
+ if (!lengthToInsert) {
+ if (string.isNull())
return;
if (isNull())
- m_impl = str.impl();
+ m_impl = string.impl();
+ return;
+ }
+
+ if (position >= length()) {
+ append(string);
return;
}
- insert(str.deprecatedCharacters(), str.length(), pos);
+
+ if (lengthToInsert > std::numeric_limits<unsigned>::max() - length())
+ CRASH();
+
+ RefPtr<StringImpl> newString;
+ if (is8Bit() && string.is8Bit()) {
+ LChar* data;
+ newString = StringImpl::createUninitialized(length() + lengthToInsert, data);
+ StringView(*m_impl).substring(0, position).getCharactersWithUpconvert(data);
+ StringView(string).getCharactersWithUpconvert(data + position);
+ StringView(*m_impl).substring(position).getCharactersWithUpconvert(data + position + lengthToInsert);
+ } else {
+ UChar* data;
+ newString = StringImpl::createUninitialized(length() + lengthToInsert, data);
+ StringView(*m_impl).substring(0, position).getCharactersWithUpconvert(data);
+ StringView(string).getCharactersWithUpconvert(data + position);
+ StringView(*m_impl).substring(position).getCharactersWithUpconvert(data + position + lengthToInsert);
+ }
+ m_impl = newString.release();
}
void String::append(const LChar* charactersToAppend, unsigned lengthToAppend)
{
+ // FIXME: This is extremely inefficient. So much so that we might want to take this out of String's API.
+
if (!m_impl) {
if (!charactersToAppend)
return;
void String::append(const UChar* charactersToAppend, unsigned lengthToAppend)
{
+ // FIXME: This is extremely inefficient. So much so that we might want to take this out of String's API.
+
if (!m_impl) {
if (!charactersToAppend)
return;
}
-void String::insert(const UChar* charactersToInsert, unsigned lengthToInsert, unsigned position)
-{
- if (position >= length()) {
- append(charactersToInsert, lengthToInsert);
- return;
- }
-
- ASSERT(m_impl);
-
- if (!lengthToInsert)
- return;
-
- ASSERT(charactersToInsert);
- UChar* data;
- if (lengthToInsert > std::numeric_limits<unsigned>::max() - length())
- CRASH();
- RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(length() + lengthToInsert, data);
- memcpy(data, deprecatedCharacters(), position * sizeof(UChar));
- memcpy(data + position, charactersToInsert, lengthToInsert * sizeof(UChar));
- memcpy(data + position + lengthToInsert, deprecatedCharacters() + position, (length() - position) * sizeof(UChar));
- m_impl = newImpl.release();
-}
-
UChar32 String::characterStartingAt(unsigned i) const
{
if (!m_impl || i >= m_impl->length())
void String::truncate(unsigned position)
{
- if (position >= length())
- return;
- UChar* data;
- RefPtr<StringImpl> newImpl = StringImpl::createUninitialized(position, data);
- memcpy(data, deprecatedCharacters(), position * sizeof(UChar));
- m_impl = newImpl.release();
+ if (m_impl)
+ m_impl = m_impl->substring(0, position);
}
template <typename CharacterType>
if ((*m_impl)[m_impl->length() - 1] != '%')
return false;
- result = charactersToIntStrict(m_impl->deprecatedCharacters(), m_impl->length() - 1);
+ if (m_impl->is8Bit())
+ result = charactersToIntStrict(m_impl->characters8(), m_impl->length() - 1);
+ else
+ result = charactersToIntStrict(m_impl->characters16(), m_impl->length() - 1);
return true;
}
return m_impl->length();
}
- const UChar* deprecatedCharacters() const
- {
- if (!m_impl)
- return 0;
- return m_impl->deprecatedCharacters();
- }
-
const LChar* characters8() const
{
if (!m_impl)
template <typename CharacterType>
inline const CharacterType* characters() const;
- // Like characters() and upconvert if CharacterType is UChar on a 8bit string.
- template <typename CharacterType>
- inline const CharacterType* getCharactersWithUpconvert() const;
-
bool is8Bit() const { return m_impl->is8Bit(); }
unsigned sizeInBytes() const
WTF_EXPORT_STRING_API void append(const LChar*, unsigned length);
WTF_EXPORT_STRING_API void append(const UChar*, unsigned length);
WTF_EXPORT_STRING_API void insert(const String&, unsigned pos);
- void insert(const UChar*, unsigned length, unsigned pos);
String& replace(UChar a, UChar b) { if (m_impl) m_impl = m_impl->replace(a, b); return *this; }
String& replace(UChar a, const String& b) { if (m_impl) m_impl = m_impl->replace(a, b.impl()); return *this; }
return characters16();
}
-template<>
-inline const LChar* String::getCharactersWithUpconvert<LChar>() const
-{
- ASSERT(is8Bit());
- return characters8();
-}
-
-template<>
-inline const UChar* String::getCharactersWithUpconvert<UChar>() const
-{
- return deprecatedCharacters();
-}
-
inline bool String::containsOnlyLatin1() const
{
if (isEmpty())
return codePointCompare(a.impl(), b.impl()) < 0;
}
-template<size_t inlineCapacity>
-inline void append(Vector<UChar, inlineCapacity>& vector, const String& string)
-{
- vector.append(string.deprecatedCharacters(), string.length());
-}
-
template<typename CharacterType>
inline void appendNumber(Vector<CharacterType>& vector, unsigned char number)
{
using WTF::KeepTrailingZeros;
using WTF::String;
using WTF::emptyString;
-using WTF::append;
using WTF::appendNumber;
using WTF::charactersAreAllASCII;
using WTF::charactersToIntStrict;
+2014-03-22 Darin Adler <darin@apple.com>
+
+ Remove String::deprecatedCharacters
+ https://bugs.webkit.org/show_bug.cgi?id=126854
+
+ Reviewed by Sam Weinig.
+
+ * bindings/scripts/StaticString.pm:
+ (GenerateStrings): Remove the code to generate the null m_copyData16 pointer.
+
+ * editing/TextIterator.cpp:
+ (WebCore::SearchBuffer::prependContext): Changed to use the new append function in
+ StringView.h and removed the one defined locally here.
+
+ * editing/VisibleUnits.cpp:
+ (WebCore::wordBreakIteratorForMinOffsetBoundary): Use the new append function
+ in StringView.h instead of using deprecatedCharacters.
+ (WebCore::wordBreakIteratorForMaxOffsetBoundary): Ditto.
+ Removed an append function defined locally here and use the one in StringView.h.
+
+ * editing/htmlediting.cpp:
+ (WebCore::stringWithRebalancedWhitespace): Use StringView::getCharactersWithUpconvert.
+
+ * html/parser/HTMLToken.h:
+ (WebCore::HTMLToken::appendToAttributeValue): Changed to take a StringView instead
+ of a const String&.
+
+ * loader/appcache/ManifestParser.cpp:
+ (WebCore::parseManifest): Use StringView and StringView::upconvertedCharacters.
+
+ * page/EventSource.cpp:
+ (WebCore::EventSource::didReceiveData): Use the new append overload from StringView.h.
+ Also added a comment about incorrect use of the decode function.
+
+ * page/ios/FrameIOS.mm:
+ (WebCore::Frame::interpretationsForCurrentRoot): Use the new StringView append function.
+ Also use simpler new-style for loops.
+
+ * platform/LinkHash.cpp:
+ (WebCore::visitedURLInline): Use the new append function and StringView::substring.
+ (WebCore::visitedLinkHash): Use upconvertedCharacters for the non-8-bit case.
+
+ * platform/URL.cpp:
+ (WebCore::findFirstOf): Chagned to take a StringView.
+ (WebCore::containsOnlyASCII): Added. Works on StringView. Could move to a WTF header in
+ the future if it's needed elsewhere.
+ (WebCore::protocolIs): Added. Works on StringView. Could put in URL.h if needed elsewhere,
+ or consider replacing the one that takes const String& with just this one.
+ (WebCore::appendEncodedHostname): Changed to take a StringView and use
+ StringView::upconvertedCharacters.
+ (WebCore::findHostnamesInMailToURL): Changed to take a StringView.
+ (WebCore::findHostnameInHierarchicalURL): Ditto.
+ (WebCore::encodeHostnames): Ditto.
+ (WebCore::encodeRelativeString): Ditto.
+
+ * platform/graphics/StringTruncator.cpp:
+ (WebCore::StringTruncator::width): Use StringView::upconvertedCharacters.
+
+ * platform/graphics/harfbuzz/HarfBuzzShaper.cpp:
+ (WebCore::HarfBuzzShaper::setFontFeatures): Use indexing directly on the string instead
+ of on a UChar*.
+ (WebCore::HarfBuzzShaper::shapeHarfBuzzRuns): Use StringView::upconvertedCharacters.
+
+ * platform/text/TextCodecICU.cpp:
+ (WebCore::TextCodecICU::encode): Use a Vector<UChar> rather than a String to copy and
+ replace the backslashes with yen signs. Also optimize case where there are no backslashes.
+
+ * rendering/RenderListMarker.cpp:
+ (WebCore::RenderListMarker::paint): Use TextRun::setText(StringView).
+
+ * rendering/RenderText.cpp:
+ (WebCore::maxWordFragmentWidth): Pass a String to RenderBlock::constructTextRun instead of
+ calling StringBuilder::deprecatedCharacters.
+
+ * rendering/RenderText.h: Removed deprecatedCharacters function.
+
+ * rendering/line/BreakingContextInlineHeaders.h: Added now-needed header include.
+
+ * rendering/svg/SVGInlineTextBox.cpp:
+ (WebCore::SVGInlineTextBox::constructTextRun): Use StringView version of TextRun constructor.
+
+ * rendering/svg/SVGTextMetrics.cpp:
+ (WebCore::SVGTextMetrics::SVGTextMetrics): Take references instead of pointers.
+ (WebCore::SVGTextMetrics::constructTextRun): Take references instead of pointers, and don't
+ take a character pointer any more. Instead, extract the text and use the StringView version of
+ the TextRun constructor.
+ (WebCore::SVGTextMetrics::measureCharacterRange): Take references instead of pointers and
+ update for above changes.
+ * rendering/svg/SVGTextMetrics.h: Updated for changes above. Also tweaked style a bit.
+
+ * rendering/svg/SVGTextMetricsBuilder.cpp:
+ (WebCore::SVGTextMetricsBuilder::advanceSimpleText): Updated for SVGTextMetrics changes.
+ (WebCore::SVGTextMetricsBuilder::advanceComplexText): Ditto.
+ (WebCore::SVGTextMetricsBuilder::initializeMeasurementWithTextRenderer): Ditto.
+ (WebCore::SVGTextMetricsBuilder::measureTextRenderer): Change code to store a character
+ for lastCharacter rather than storing a pointer to a character. Stop using TextRun::data16.
+
+ * rendering/svg/SVGTextQuery.cpp:
+ (WebCore::SVGTextQuery::subStringLengthCallback): Updated for SVGTextMetrics changes.
+ (WebCore::SVGTextQuery::startPositionOfCharacterCallback): Ditto.
+ (WebCore::SVGTextQuery::endPositionOfCharacterCallback): Ditto.
+ (WebCore::calculateGlyphBoundaries): Ditto.
+
+ * xml/XPathFunctions.cpp:
+ (WebCore::XPath::atomicSubstring): Added.
+ (WebCore::XPath::FunId::evaluate): Tweaked a bit to use a new style for loop.
+ Use the atomicSubstring function to avoid making a temporary String just to make an AtomicString.
+ That function also uses characters8/16 rather than depreccatedCharacters.
+
+ * xml/XPathNodeSet.h: Added begin and end so this collection can be iterated with new style for loop.
+
+ * xml/parser/XMLDocumentParserLibxml2.cpp:
+ (WebCore::XMLDocumentParser::doWrite): Use StringView::upconvertedCharacters.
+ (WebCore::parseAttributes): Ditto.
+
2014-03-22 Commit Queue <commit-queue@webkit.org>
Unreviewed, rolling out r166118.
StringImpl::StaticASCIILiteral::s_initialRefCount,
$length,
${name}String8,
- 0,
StringImpl::StaticASCIILiteral::s_initialFlags | (${hash} << StringImpl::StaticASCIILiteral::s_hashShift)
};
END
m_runOffset = 0;
}
-static void append(Vector<UChar>& buffer, StringView string)
-{
- unsigned oldSize = buffer.size();
- unsigned length = string.length();
- buffer.grow(oldSize + length);
- for (unsigned i = 0; i < length; ++i)
- buffer[oldSize + i] = string[i];
-}
-
static PassRefPtr<Range> characterSubrange(CharacterIterator& it, int offset, int length)
{
it.advance(offset);
}
size_t usableLength = std::min(m_buffer.capacity() - m_prefixLength, text.length() - wordBoundaryContextStart);
- WebCore::append(m_buffer, text.substring(text.length() - usableLength, usableLength));
+ WTF::append(m_buffer, text.substring(text.length() - usableLength, usableLength));
m_prefixLength += usableLength;
if (wordBoundaryContextStart || m_prefixLength == m_buffer.capacity())
// FIXME: Handle the case when we don't have an inline text box.
const InlineBox* previousBox = logicallyPreviousBox(visiblePosition, textBox, previousBoxInDifferentBlock, leafBoxes);
- int len = 0;
string.clear();
+
if (previousBox && previousBox->isInlineTextBox()) {
const InlineTextBox* previousTextBox = toInlineTextBox(previousBox);
previousBoxLength = previousTextBox->len();
- string.append(previousTextBox->renderer().text()->deprecatedCharacters() + previousTextBox->start(), previousBoxLength);
- len += previousBoxLength;
+ append(string, StringView(previousTextBox->renderer().text()).substring(previousTextBox->start(), previousBoxLength));
}
- string.append(textBox->renderer().text()->deprecatedCharacters() + textBox->start(), textBox->len());
- len += textBox->len();
+ append(string, StringView(textBox->renderer().text()).substring(textBox->start(), textBox->len()));
- return wordBreakIterator(StringView(string.data(), len));
+ return wordBreakIterator(StringView(string.data(), string.size()));
}
static TextBreakIterator* wordBreakIteratorForMaxOffsetBoundary(const VisiblePosition& visiblePosition, const InlineTextBox* textBox,
// FIXME: Handle the case when we don't have an inline text box.
const InlineBox* nextBox = logicallyNextBox(visiblePosition, textBox, nextBoxInDifferentBlock, leafBoxes);
- int len = 0;
string.clear();
- string.append(textBox->renderer().text()->deprecatedCharacters() + textBox->start(), textBox->len());
- len += textBox->len();
+ append(string, StringView(textBox->renderer().text()).substring(textBox->start(), textBox->len()));
if (nextBox && nextBox->isInlineTextBox()) {
const InlineTextBox* nextTextBox = toInlineTextBox(nextBox);
- string.append(nextTextBox->renderer().text()->deprecatedCharacters() + nextTextBox->start(), nextTextBox->len());
- len += nextTextBox->len();
+ append(string, StringView(nextTextBox->renderer().text()).substring(nextTextBox->start(), nextTextBox->len()));
}
- return wordBreakIterator(StringView(string.data(), len));
+ return wordBreakIterator(StringView(string.data(), string.size()));
}
static bool isLogicalStartOfWord(TextBreakIterator* iter, int position, bool hardLineBreak)
buffer[i] = character;
}
-static void append(Vector<UChar, 1024>& buffer, StringView string)
-{
- unsigned oldSize = buffer.size();
- unsigned length = string.length();
- buffer.grow(oldSize + length);
- for (unsigned i = 0; i < length; ++i)
- buffer[oldSize + i] = string[i];
-}
-
static void appendRepeatedCharacter(Vector<UChar, 1024>& buffer, UChar character, unsigned count)
{
unsigned oldSize = buffer.size();
String stringWithRebalancedWhitespace(const String& string, bool startIsStartOfParagraph, bool endIsEndOfParagraph)
{
- Vector<UChar> rebalancedString;
- append(rebalancedString, string);
+ Vector<UChar> rebalancedString(string.length());
+ StringView(string).getCharactersWithUpconvert(rebalancedString.data());
bool previousCharacterWasSpace = false;
for (size_t i = 0; i < rebalancedString.size(); i++) {
rebalancedString[i] = ' ';
previousCharacterWasSpace = true;
}
-
}
return String::adopt(rebalancedString);
#include "HTMLToken.h"
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
+#include <wtf/text/StringView.h>
namespace WebCore {
m_currentAttribute->value.append(character);
}
- void appendToAttributeValue(size_t i, const String& value)
+ void appendToAttributeValue(size_t i, StringView value)
{
ASSERT(!value.isEmpty());
ASSERT(m_type == StartTag || m_type == EndTag);
#include "TextResourceDecoder.h"
#include "URL.h"
+#include <wtf/text/StringView.h>
#include <wtf/unicode/CharacterNames.h>
namespace WebCore {
if (!s.startsWith("CACHE MANIFEST"))
return false;
- const UChar* end = s.deprecatedCharacters() + s.length();
- const UChar* p = s.deprecatedCharacters() + 14; // "CACHE MANIFEST" is 14 characters.
+ StringView manifestAfterSignature = StringView(s).substring(14); // "CACHE MANIFEST" is 14 characters.
+ auto upconvertedCharacters = manifestAfterSignature.upconvertedCharacters();
+ const UChar* p = upconvertedCharacters;
+ const UChar* end = p + manifestAfterSignature.length();
if (p < end && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r')
return false;
else if (mode == Unknown)
continue;
else if (mode == Explicit || mode == OnlineWhitelist) {
- const UChar* p = line.deprecatedCharacters();
+ auto upconvertedLineCharacters = StringView(line).upconvertedCharacters();
+ const UChar* p = upconvertedLineCharacters;
const UChar* lineEnd = p + line.length();
// Look for whitespace separating the URL from subsequent ignored tokens.
while (p < lineEnd && *p != '\t' && *p != ' ')
p++;
- if (mode == OnlineWhitelist && p - line.deprecatedCharacters() == 1 && *line.deprecatedCharacters() == '*') {
+ if (mode == OnlineWhitelist && p - upconvertedLineCharacters == 1 && line[0] == '*') {
// Wildcard was found.
manifest.allowAllNetworkRequests = true;
continue;
}
- URL url(manifestURL, String(line.deprecatedCharacters(), p - line.deprecatedCharacters()));
+ URL url(manifestURL, line.substring(0, p - upconvertedLineCharacters));
if (!url.isValid())
continue;
manifest.onlineWhitelistedURLs.append(url);
} else if (mode == Fallback) {
- const UChar* p = line.deprecatedCharacters();
+ auto upconvertedLineCharacters = StringView(line).upconvertedCharacters();
+ const UChar* p = upconvertedLineCharacters;
const UChar* lineEnd = p + line.length();
// Look for whitespace separating the two URLs
continue;
}
- URL namespaceURL(manifestURL, String(line.deprecatedCharacters(), p - line.deprecatedCharacters()));
+ URL namespaceURL(manifestURL, line.substring(0, p - upconvertedLineCharacters));
if (!namespaceURL.isValid())
continue;
if (namespaceURL.hasFragmentIdentifier())
ASSERT(m_state == OPEN);
ASSERT(m_requestInFlight);
- append(m_receiveBuf, m_decoder->decode(data, length));
+ // FIXME: Need to call flush at some point.
+ append(m_receiveBuf, StringView(m_decoder->decode(data, length)));
parseEventStream();
}
if (precedingTextStartPosition != createLegacyEditingPosition(node, marker->startOffset())) {
RefPtr<Range> precedingTextRange = Range::create(*document(), precedingTextStartPosition, createLegacyEditingPosition(node, marker->startOffset()));
String precedingText = plainText(precedingTextRange.get());
- if (unsigned length = precedingText.length()) {
- const UChar* characters = precedingText.deprecatedCharacters();
- for (size_t i = 0; i < interpretationsCount; ++i)
- interpretations.at(i).append(characters, length);
+ if (!precedingText.isEmpty()) {
+ for (auto& interpretation : interpretations)
+ append(interpretation, precedingText);
}
}
RefPtr<Range> rangeForMarker = Range::create(*document(), createLegacyEditingPosition(node, marker->startOffset()), createLegacyEditingPosition(node, marker->endOffset()));
String visibleTextForMarker = plainText(rangeForMarker.get());
size_t interpretationsCountForCurrentMarker = marker->alternatives().size() + 1;
- unsigned visibleTextForMarkerLength = visibleTextForMarker.length();
- const UChar* visibleTextForMarkerCharacters = visibleTextForMarker.deprecatedCharacters();
for (size_t i = 0; i < interpretationsCount; ++i) {
// Determine text for the ith interpretation. It will either be the visible text, or one of its
// alternatives stored in the marker.
size_t indexOfInterpretationForCurrentMarker = (i / combinationsSoFar) % interpretationsCountForCurrentMarker;
if (!indexOfInterpretationForCurrentMarker)
- interpretations.at(i).append(visibleTextForMarkerCharacters, visibleTextForMarkerLength);
- else {
- const String& alternative = marker->alternatives().at(i % marker->alternatives().size());
- interpretations.at(i).append(alternative.deprecatedCharacters(), alternative.length());
- }
+ append(interpretations[i], visibleTextForMarker);
+ else
+ append(interpretations[i], marker->alternatives().at(i % marker->alternatives().size()));
}
combinationsSoFar *= interpretationsCountForCurrentMarker;
// Finally, add any text after the last marker.
RefPtr<Range> afterLastMarkerRange = Range::create(*document(), precedingTextStartPosition, createLegacyEditingPosition(root, rootChildCount));
String textAfterLastMarker = plainText(afterLastMarkerRange.get());
- const UChar* textAfterLastMarkerCharacters = textAfterLastMarker.deprecatedCharacters();
- if (unsigned length = textAfterLastMarker.length()) {
- for (size_t i = 0; i < interpretationsCount; ++i)
- interpretations.at(i).append(textAfterLastMarkerCharacters, length);
+ if (!textAfterLastMarker.isEmpty()) {
+ for (auto& interpretation : interpretations)
+ append(interpretation, textAfterLastMarker);
}
NSMutableArray *result = [NSMutableArray array];
- for (size_t i = 0; i < interpretationsCount; ++i)
- [result addObject:static_cast<NSString *>(String(interpretations.at(i)))];
+ for (auto& interpretation : interpretations)
+ [result addObject:static_cast<NSString *>(interpretation)];
return result;
}
#include "LinkHash.h"
#include <wtf/text/AtomicString.h>
#include <wtf/text/StringHash.h>
-#include <wtf/text/WTFString.h>
+#include <wtf/text/StringView.h>
namespace WebCore {
}
if (!length)
- buffer.append(base.string().getCharactersWithUpconvert<CharacterType>(), base.string().length());
+ append(buffer, base.string());
else {
switch (characters[0]) {
case '/':
- buffer.append(base.string().getCharactersWithUpconvert<CharacterType>(), base.pathStart());
+ append(buffer, StringView(base.string()).substring(0, base.pathStart()));
break;
case '#':
- buffer.append(base.string().getCharactersWithUpconvert<CharacterType>(), base.pathEnd());
+ append(buffer, StringView(base.string()).substring(0, base.pathEnd()));
break;
default:
- buffer.append(base.string().getCharactersWithUpconvert<CharacterType>(), base.pathAfterLastSlash());
+ append(buffer, StringView(base.string()).substring(0, base.pathAfterLastSlash()));
break;
}
}
}
Vector<UChar, 512> url;
- visitedURLInline(base, attributeURL.string().deprecatedCharacters(), attributeURL.length(), url);
+ auto upconvertedCharacters = StringView(attributeURL.string()).upconvertedCharacters();
+ const UChar* characters = upconvertedCharacters;
+ visitedURLInline(base, characters, attributeURL.length(), url);
if (url.isEmpty())
return 0;
// Returns the index of the first index in string |s| of any of the characters
// in |toFind|. |toFind| should be a null-terminated string, all characters up
// to the null will be searched. Returns int if not found.
-static int findFirstOf(const UChar* s, int sLen, int startPos, const char* toFind)
+static int findFirstOf(StringView string, unsigned startPosition, const char* target)
{
- for (int i = startPos; i < sLen; i++) {
- const char* cur = toFind;
- while (*cur) {
- if (s[i] == *(cur++))
+ unsigned length = string.length();
+ for (unsigned i = startPosition; i < length; ++i) {
+ for (unsigned j = 0; target[j]; ++j) {
+ if (string[i] == target[j])
return i;
}
}
return String(buffer.data(), p - buffer.data());
}
+static bool containsOnlyASCII(StringView string)
+{
+ if (string.is8Bit())
+ return charactersAreAllASCII(string.characters8(), string.length());
+ return charactersAreAllASCII(string.characters16(), string.length());
+}
+
+static bool protocolIs(StringView stringURL, const char* protocol)
+{
+ assertProtocolIsGood(protocol);
+ unsigned length = stringURL.length();
+ for (unsigned i = 0; i < length; ++i) {
+ if (!protocol[i])
+ return stringURL[i] == ':';
+ if (!isLetterMatchIgnoringCase(stringURL[i], protocol[i]))
+ return false;
+ }
+ return false;
+}
+
// Appends the punycoded hostname identified by the given string and length to
// the output buffer. The result will not be null terminated.
-static void appendEncodedHostname(UCharBuffer& buffer, const UChar* str, unsigned strLen)
+static void appendEncodedHostname(UCharBuffer& buffer, StringView string)
{
// Needs to be big enough to hold an IDN-encoded name.
// For host names bigger than this, we won't do IDN encoding, which is almost certainly OK.
const unsigned hostnameBufferLength = 2048;
- if (strLen > hostnameBufferLength || charactersAreAllASCII(str, strLen)) {
- buffer.append(str, strLen);
+ if (string.length() > hostnameBufferLength || containsOnlyASCII(string)) {
+ append(buffer, string);
return;
}
UChar hostnameBuffer[hostnameBufferLength];
UErrorCode error = U_ZERO_ERROR;
- int32_t numCharactersConverted = uidna_IDNToASCII(str, strLen, hostnameBuffer,
+ int32_t numCharactersConverted = uidna_IDNToASCII(string.upconvertedCharacters(), string.length(), hostnameBuffer,
hostnameBufferLength, UIDNA_ALLOW_UNASSIGNED, 0, &error);
if (error == U_ZERO_ERROR)
buffer.append(hostnameBuffer, numCharactersConverted);
}
-static void findHostnamesInMailToURL(const UChar* str, int strLen, Vector<std::pair<int, int>>& nameRanges)
+static void findHostnamesInMailToURL(StringView string, Vector<std::pair<int, int>>& nameRanges)
{
// In a mailto: URL, host names come after a '@' character and end with a '>' or ',' or '?' or end of string character.
// Skip quoted strings so that characters in them don't confuse us.
int p = 0;
while (1) {
// Find start of host name or of quoted string.
- int hostnameOrStringStart = findFirstOf(str, strLen, p, "\"@?");
+ int hostnameOrStringStart = findFirstOf(string, p, "\"@?");
if (hostnameOrStringStart == -1)
return;
- UChar c = str[hostnameOrStringStart];
+ UChar c = string[hostnameOrStringStart];
p = hostnameOrStringStart + 1;
if (c == '?')
if (c == '@') {
// Find end of host name.
int hostnameStart = p;
- int hostnameEnd = findFirstOf(str, strLen, p, ">,?");
+ int hostnameEnd = findFirstOf(string, p, ">,?");
bool done;
if (hostnameEnd == -1) {
- hostnameEnd = strLen;
+ hostnameEnd = string.length();
done = true;
} else {
p = hostnameEnd;
// Skip quoted string.
ASSERT(c == '"');
while (1) {
- int escapedCharacterOrStringEnd = findFirstOf(str, strLen, p, "\"\\");
+ int escapedCharacterOrStringEnd = findFirstOf(string, p, "\"\\");
if (escapedCharacterOrStringEnd == -1)
return;
- c = str[escapedCharacterOrStringEnd];
+ c = string[escapedCharacterOrStringEnd];
p = escapedCharacterOrStringEnd + 1;
// If we are the end of the string, then break from the string loop back to the host name loop.
// Skip escaped character.
ASSERT(c == '\\');
- if (p == strLen)
+ if (p == static_cast<int>(string.length()))
return;
++p;
}
}
-static bool findHostnameInHierarchicalURL(const UChar* str, int strLen, int& startOffset, int& endOffset)
+static bool findHostnameInHierarchicalURL(StringView string, int& startOffset, int& endOffset)
{
// Find the host name in a hierarchical URL.
// It comes after a "://" sequence, with scheme characters preceding, and
// this should be the first colon in the string.
// It ends with the end of the string or a ":" or a path segment ending character.
// If there is a "@" character, the host part is just the part after the "@".
- int separator = findFirstOf(str, strLen, 0, ":");
- if (separator == -1 || separator + 2 >= strLen ||
- str[separator + 1] != '/' || str[separator + 2] != '/')
+ int separator = findFirstOf(string, 0, ":");
+ if (separator == -1 || separator + 2 >= static_cast<int>(string.length()) || string[separator + 1] != '/' || string[separator + 2] != '/')
return false;
// Check that all characters before the :// are valid scheme characters.
- if (!isSchemeFirstChar(str[0]))
+ if (!isSchemeFirstChar(string[0]))
return false;
for (int i = 1; i < separator; ++i) {
- if (!isSchemeChar(str[i]))
+ if (!isSchemeChar(string[i]))
return false;
}
int authorityStart = separator + 3;
// Find terminating character.
- int hostnameEnd = strLen;
- for (int i = authorityStart; i < strLen; ++i) {
- UChar c = str[i];
+ int hostnameEnd = string.length();
+ for (int i = authorityStart; i < hostnameEnd; ++i) {
+ UChar c = string[i];
if (c == ':' || (isPathSegmentEndChar(c) && c != 0)) {
hostnameEnd = i;
break;
}
// Find "@" for the start of the host name.
- int userInfoTerminator = findFirstOf(str, strLen, authorityStart, "@");
+ int userInfoTerminator = findFirstOf(string, authorityStart, "@");
int hostnameStart;
if (userInfoTerminator == -1 || userInfoTerminator > hostnameEnd)
hostnameStart = authorityStart;
// Converts all hostnames found in the given input to punycode, preserving the
// rest of the URL unchanged. The output will NOT be null-terminated.
-static void encodeHostnames(const String& str, UCharBuffer& output)
+static void encodeHostnames(StringView string, UCharBuffer& buffer)
{
- output.clear();
+ buffer.clear();
- if (protocolIs(str, "mailto")) {
+ if (protocolIs(string, "mailto")) {
Vector<std::pair<int, int>> hostnameRanges;
- findHostnamesInMailToURL(str.deprecatedCharacters(), str.length(), hostnameRanges);
+ findHostnamesInMailToURL(string, hostnameRanges);
int n = hostnameRanges.size();
int p = 0;
for (int i = 0; i < n; ++i) {
const std::pair<int, int>& r = hostnameRanges[i];
- output.append(&str.deprecatedCharacters()[p], r.first - p);
- appendEncodedHostname(output, &str.deprecatedCharacters()[r.first], r.second - r.first);
+ append(buffer, string.substring(p, r.first - p));
+ appendEncodedHostname(buffer, string.substring(r.first, r.second - r.first));
p = r.second;
}
// This will copy either everything after the last hostname, or the
// whole thing if there is no hostname.
- output.append(&str.deprecatedCharacters()[p], str.length() - p);
+ append(buffer, string.substring(p));
} else {
int hostStart, hostEnd;
- if (findHostnameInHierarchicalURL(str.deprecatedCharacters(), str.length(), hostStart, hostEnd)) {
- output.append(str.deprecatedCharacters(), hostStart); // Before hostname.
- appendEncodedHostname(output, &str.deprecatedCharacters()[hostStart], hostEnd - hostStart);
- output.append(&str.deprecatedCharacters()[hostEnd], str.length() - hostEnd); // After hostname.
+ if (findHostnameInHierarchicalURL(string, hostStart, hostEnd)) {
+ append(buffer, string.substring(0, hostStart)); // Before hostname.
+ appendEncodedHostname(buffer, string.substring(hostStart, hostEnd - hostStart));
+ append(buffer, string.substring(hostEnd)); // After hostname.
} else {
// No hostname to encode, return the input.
- output.append(str.deprecatedCharacters(), str.length());
+ append(buffer, string);
}
}
}
int pathEnd = -1;
if (encoding != pathEncoding && encoding.isValid() && !protocolIs(rel, "mailto") && !protocolIs(rel, "data") && !protocolIsJavaScript(rel)) {
// Find the first instance of either # or ?, keep pathEnd at -1 otherwise.
- pathEnd = findFirstOf(s.data(), s.size(), 0, "#?");
+ pathEnd = findFirstOf(StringView(s.data(), s.size()), 0, "#?");
}
if (pathEnd == -1) {
#include "TextRun.h"
#include <wtf/Assertions.h>
#include <wtf/Vector.h>
+#include <wtf/text/StringView.h>
#include <wtf/unicode/CharacterNames.h>
namespace WebCore {
float StringTruncator::width(const String& string, const Font& font, EnableRoundingHacksOrNot enableRoundingHacks)
{
- return stringWidth(font, string.deprecatedCharacters(), string.length(), !enableRoundingHacks);
+ return stringWidth(font, StringView(string).upconvertedCharacters(), string.length(), !enableRoundingHacks);
}
String StringTruncator::centerTruncate(const String& string, float maxWidth, const Font& font, EnableRoundingHacksOrNot enableRoundingHacks, float& resultWidth, bool shouldInsertEllipsis, float customTruncationElementWidth)
#include "Font.h"
#include "HarfBuzzFace.h"
#include "SurrogatePairAwareTextIterator.h"
-#include "TextRun.h"
#include "hb-icu.h"
#include <unicode/normlzr.h>
#include <unicode/uchar.h>
#include <wtf/MathExtras.h>
#include <wtf/StdLibExtras.h>
#include <wtf/Vector.h>
+#include <wtf/text/StringView.h>
namespace WebCore {
unsigned numFeatures = settings->size();
for (unsigned i = 0; i < numFeatures; ++i) {
hb_feature_t feature;
- const UChar* tag = settings->at(i).tag().string().deprecatedCharacters();
+ auto& tag = settings->at(i).tag();
feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]);
feature.value = settings->at(i).value();
feature.start = 0;
if (m_font->isSmallCaps() && u_islower(m_normalizedBuffer[currentRun->startIndex()])) {
String upperText = String(m_normalizedBuffer.get() + currentRun->startIndex(), currentRun->numCharacters()).upper();
currentFontData = m_font->glyphDataForCharacter(upperText[0], false, SmallCapsVariant).fontData;
- hb_buffer_add_utf16(harfBuzzBuffer.get(), reinterpret_cast<const uint16_t*>(upperText.deprecatedCharacters()), currentRun->numCharacters(), 0, currentRun->numCharacters());
+ const UChar* characters = StringView(upperText).upconvertedCharacters();
+ hb_buffer_add_utf16(harfBuzzBuffer.get(), reinterpret_cast<const uint16_t*>(characters), currentRun->numCharacters(), 0, currentRun->numCharacters());
} else
hb_buffer_add_utf16(harfBuzzBuffer.get(), reinterpret_cast<const uint16_t*>(m_normalizedBuffer.get() + currentRun->startIndex()), currentRun->numCharacters(), 0, currentRun->numCharacters());
// FIXME: We should see if there is "force ASCII range" mode in ICU;
// until then, we change the backslash into a yen sign.
// Encoding will change the yen sign back into a backslash.
- String copy;
- const UChar* source;
- const UChar* sourceLimit;
+ Vector<UChar> copy;
+ const UChar* source = characters;
if (shouldShowBackslashAsCurrencySymbolIn(m_encodingName)) {
- copy.append(characters, length);
- copy.replace('\\', 0xA5);
- source = copy.deprecatedCharacters();
- sourceLimit = source + copy.length();
- } else {
- source = characters;
- sourceLimit = source + length;
+ for (size_t i = 0; i < length; ++i) {
+ if (characters[i] == '\\') {
+ copy.reserveInitialCapacity(length);
+ for (size_t j = 0; j < i; ++j)
+ copy.uncheckedAppend(characters[i]);
+ for (size_t j = i; j < length; ++j) {
+ UChar character = characters[i];
+ if (character == '\\')
+ character = yenSign;
+ copy.uncheckedAppend(character);
+ }
+ source = copy.data();
+ break;
+ }
+ }
}
+ const UChar* sourceLimit = source + length;
UErrorCode err = U_ZERO_ERROR;
// Text is not arbitrary. We can judge whether it's RTL from the first character,
// and we only need to handle the direction U_RIGHT_TO_LEFT for now.
bool textNeedsReversing = u_charDirection(m_text[0]) == U_RIGHT_TO_LEFT;
- StringBuilder reversedText;
+ String reversedText;
if (textNeedsReversing) {
- int length = m_text.length();
- reversedText.reserveCapacity(length);
- for (int i = length - 1; i >= 0; --i)
- reversedText.append(m_text[i]);
- textRun.setText(reversedText.deprecatedCharacters(), length);
+ unsigned length = m_text.length();
+ StringBuilder buffer;
+ buffer.reserveCapacity(length);
+ for (unsigned i = 0; i < length; ++i)
+ buffer.append(m_text[length - i]);
+ reversedText = buffer.toString();
+ textRun.setText(StringView(reversedText));
}
const UChar suffix = listMarkerSuffix(type, m_listItem.value());
fragmentWithHyphen.append(word.substring(suffixStart, fragmentLength));
fragmentWithHyphen.append(style.hyphenString());
- TextRun run = RenderBlock::constructTextRun(renderer, font, fragmentWithHyphen.deprecatedCharacters(), fragmentWithHyphen.length(), style);
+ TextRun run = RenderBlock::constructTextRun(renderer, font, fragmentWithHyphen.toString(), style);
run.setCharactersLength(fragmentWithHyphen.length());
run.setCharacterScanForCodePath(!renderer->canUseSimpleFontCodePath());
float fragmentWidth = font.width(run, &fallbackFonts, &glyphOverflow);
bool is8Bit() const { return m_text.impl()->is8Bit(); }
const LChar* characters8() const { return m_text.impl()->characters8(); }
const UChar* characters16() const { return m_text.impl()->characters16(); }
- const UChar* deprecatedCharacters() const { return m_text.impl()->deprecatedCharacters(); }
UChar characterAt(unsigned) const;
UChar uncheckedCharacterAt(unsigned) const;
UChar operator[](unsigned i) const { return uncheckedCharacterAt(i); }
#include "RenderSVGInlineText.h"
#include "TrailingObjects.h"
#include "break_lines.h"
+#include <wtf/text/StringView.h>
#include <wtf/unicode/CharacterNames.h>
#if ENABLE(CSS_SHAPES) && ENABLE(CSS_SHAPE_INSIDE)
{
ASSERT(style);
- TextRun run(renderer().deprecatedCharacters() + fragment.characterOffset
- , fragment.length
+ TextRun run(StringView(renderer().text()).substring(fragment.characterOffset, fragment.length)
, 0 /* xPos, only relevant with allowTabs=true */
, 0 /* padding, only relevant for justified text, not relevant for SVG */
, TextRun::AllowTrailingExpansion
{
}
-SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText* textRenderer, const TextRun& run)
+SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText& textRenderer, const TextRun& run)
{
- ASSERT(textRenderer);
-
- float scalingFactor = textRenderer->scalingFactor();
+ float scalingFactor = textRenderer.scalingFactor();
ASSERT(scalingFactor);
- const Font& scaledFont = textRenderer->scaledFont();
+ const Font& scaledFont = textRenderer.scaledFont();
int length = 0;
// Calculate width/height using the scaled font, divide this result by the scalingFactor afterwards.
m_length = static_cast<unsigned>(length);
}
-TextRun SVGTextMetrics::constructTextRun(RenderSVGInlineText* text, const UChar* characters, unsigned position, unsigned length)
+TextRun SVGTextMetrics::constructTextRun(RenderSVGInlineText& text, unsigned position, unsigned length)
{
- const RenderStyle& style = text->style();
+ const RenderStyle& style = text.style();
- TextRun run(characters + position
- , length
+ TextRun run(StringView(text.text()).substring(position, length)
, 0 /* xPos, only relevant with allowTabs=true */
, 0 /* padding, only relevant for justified text, not relevant for SVG */
, TextRun::AllowTrailingExpansion
, isOverride(style.unicodeBidi()) /* directionalOverride */);
if (style.font().isSVGFont())
- run.setRenderingContext(SVGTextRunRenderingContext::create(*text));
+ run.setRenderingContext(SVGTextRunRenderingContext::create(text));
run.disableRoundingHacks();
run.disableSpacing();
// Propagate the maximum length of the characters buffer to the TextRun, even when we're only processing a substring.
- run.setCharactersLength(text->textLength() - position);
+ run.setCharactersLength(text.textLength() - position);
ASSERT(run.charactersLength() >= run.length());
return run;
}
-SVGTextMetrics SVGTextMetrics::measureCharacterRange(RenderSVGInlineText* text, unsigned position, unsigned length)
+SVGTextMetrics SVGTextMetrics::measureCharacterRange(RenderSVGInlineText& text, unsigned position, unsigned length)
{
- ASSERT(text);
- return SVGTextMetrics(text, constructTextRun(text, text->deprecatedCharacters(), position, length));
+ return SVGTextMetrics(text, constructTextRun(text, position, length));
}
-SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText* text, unsigned position, unsigned length, float width, const String& glyphName)
+SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText& text, unsigned position, unsigned length, float width, const String& glyphName)
{
- ASSERT(text);
-
- bool needsContext = text->style().font().isSVGFont();
- float scalingFactor = text->scalingFactor();
+ bool needsContext = text.style().font().isSVGFont();
+ float scalingFactor = text.scalingFactor();
ASSERT(scalingFactor);
m_width = width / scalingFactor;
- m_height = text->scaledFont().fontMetrics().floatHeight() / scalingFactor;
+ m_height = text.scaledFont().fontMetrics().floatHeight() / scalingFactor;
if (needsContext) {
m_glyph.isValid = true;
- m_glyph.unicodeString = text->text()->substring(position, length);
+ m_glyph.unicodeString = text.text()->substring(position, length);
m_glyph.name = glyphName;
}
class SVGTextMetrics {
public:
- enum MetricsType {
- SkippedSpaceMetrics
- };
+ enum MetricsType { SkippedSpaceMetrics };
SVGTextMetrics();
- SVGTextMetrics(MetricsType);
- SVGTextMetrics(RenderSVGInlineText*, unsigned position, unsigned length, float width, const String& glyphName);
+ explicit SVGTextMetrics(MetricsType);
+ SVGTextMetrics(RenderSVGInlineText&, unsigned position, unsigned length, float width, const String& glyphName);
- static SVGTextMetrics measureCharacterRange(RenderSVGInlineText*, unsigned position, unsigned length);
- static TextRun constructTextRun(RenderSVGInlineText*, const UChar* characters, unsigned position, unsigned length);
+ static SVGTextMetrics measureCharacterRange(RenderSVGInlineText&, unsigned position, unsigned length);
+ static TextRun constructTextRun(RenderSVGInlineText&, unsigned position = 0, unsigned length = std::numeric_limits<unsigned>::max());
bool isEmpty() const { return !m_width && !m_height && !m_glyph.isValid && m_length == 1; }
const Glyph& glyph() const { return m_glyph; }
private:
- SVGTextMetrics(RenderSVGInlineText*, const TextRun&);
+ SVGTextMetrics(RenderSVGInlineText&, const TextRun&);
float m_width;
float m_height;
m_totalWidth = m_simpleWidthIterator->runWidthSoFar();
#if ENABLE(SVG_FONTS)
- m_currentMetrics = SVGTextMetrics(m_text, m_textPosition, metricsLength, currentWidth, m_simpleWidthIterator->lastGlyphName());
+ m_currentMetrics = SVGTextMetrics(*m_text, m_textPosition, metricsLength, currentWidth, m_simpleWidthIterator->lastGlyphName());
#else
- m_currentMetrics = SVGTextMetrics(m_text, m_textPosition, metricsLength, currentWidth, emptyString());
+ m_currentMetrics = SVGTextMetrics(*m_text, m_textPosition, metricsLength, currentWidth, emptyString());
#endif
}
void SVGTextMetricsBuilder::advanceComplexText()
{
unsigned metricsLength = currentCharacterStartsSurrogatePair() ? 2 : 1;
- m_currentMetrics = SVGTextMetrics::measureCharacterRange(m_text, m_textPosition, metricsLength);
- m_complexStartToCurrentMetrics = SVGTextMetrics::measureCharacterRange(m_text, 0, m_textPosition + metricsLength);
+ m_currentMetrics = SVGTextMetrics::measureCharacterRange(*m_text, m_textPosition, metricsLength);
+ m_complexStartToCurrentMetrics = SVGTextMetrics::measureCharacterRange(*m_text, 0, m_textPosition + metricsLength);
ASSERT(m_currentMetrics.length() == metricsLength);
// Frequent case for Arabic text: when measuring a single character the arabic isolated form is taken
m_totalWidth = 0;
const Font& scaledFont = text->scaledFont();
- m_run = SVGTextMetrics::constructTextRun(text, text->deprecatedCharacters(), 0, text->textLength());
+ m_run = SVGTextMetrics::constructTextRun(*text);
m_isComplexText = scaledFont.codePath(m_run) == Font::Complex;
if (m_isComplexText)
}
SVGCharacterDataMap* allCharactersMap;
- const UChar* lastCharacter;
+ UChar lastCharacter;
bool processRenderer;
unsigned valueListPosition;
unsigned skippedCharacters;
int surrogatePairCharacters = 0;
while (advance()) {
- const UChar* currentCharacter = m_run.data16(m_textPosition);
- if (*currentCharacter == ' ' && !preserveWhiteSpace && (!data->lastCharacter || *data->lastCharacter == ' ')) {
+ UChar currentCharacter = m_run[m_textPosition];
+ if (currentCharacter == ' ' && !preserveWhiteSpace && (!data->lastCharacter || data->lastCharacter == ' ')) {
if (data->processRenderer)
textMetricsValues->append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics));
if (data->allCharactersMap)
if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition))
return false;
- SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset + startPosition, endPosition - startPosition);
+ SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(*queryData->textRenderer, fragment.characterOffset + startPosition, endPosition - startPosition);
data->subStringLength += queryData->isVerticalText ? metrics.height() : metrics.width();
return false;
}
data->startPosition = FloatPoint(fragment.x, fragment.y);
if (startPosition) {
- SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset, startPosition);
+ SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(*queryData->textRenderer, fragment.characterOffset, startPosition);
if (queryData->isVerticalText)
data->startPosition.move(0, metrics.height());
else
data->endPosition = FloatPoint(fragment.x, fragment.y);
- SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset, startPosition + 1);
+ SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(*queryData->textRenderer, fragment.characterOffset, startPosition + 1);
if (queryData->isVerticalText)
data->endPosition.move(0, metrics.height());
else
extent.setLocation(FloatPoint(fragment.x, fragment.y - queryData->textRenderer->scaledFont().fontMetrics().floatAscent() / scalingFactor));
if (startPosition) {
- SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset, startPosition);
+ SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(*queryData->textRenderer, fragment.characterOffset, startPosition);
if (queryData->isVerticalText)
extent.move(0, metrics.height());
else
extent.move(metrics.width(), 0);
}
- SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset + startPosition, 1);
+ SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(*queryData->textRenderer, fragment.characterOffset + startPosition, 1);
extent.setSize(FloatSize(metrics.width(), metrics.height()));
AffineTransform fragmentTransform;
return Expression::evaluationContext().position;
}
+static AtomicString atomicSubstring(StringBuilder& builder, unsigned start, unsigned length)
+{
+ ASSERT(start <= builder.length());
+ ASSERT(length <= builder.length() - start);
+ if (builder.is8Bit())
+ return AtomicString(builder.characters8() + start, length);
+ return AtomicString(builder.characters16() + start, length);
+}
+
Value FunId::evaluate() const
{
Value a = argument(0).evaluate();
StringBuilder idList; // A whitespace-separated list of IDs
- if (a.isNodeSet()) {
- const NodeSet& nodes = a.toNodeSet();
- for (size_t i = 0; i < nodes.size(); ++i) {
- String str = stringValue(nodes[i]);
- idList.append(str);
+ if (!a.isNodeSet())
+ idList.append(a.toString());
+ else {
+ for (auto& node : a.toNodeSet()) {
+ idList.append(stringValue(node.get()));
idList.append(' ');
}
- } else {
- String str = a.toString();
- idList.append(str);
}
TreeScope& contextScope = evaluationContext().node->treeScope();
// If there are several nodes with the same id, id() should return the first one.
// In WebKit, getElementById behaves so, too, although its behavior in this case is formally undefined.
- Node* node = contextScope.getElementById(String(idList.deprecatedCharacters() + startPos, endPos - startPos));
+ Node* node = contextScope.getElementById(atomicSubstring(idList, startPos, endPos - startPos));
if (node && resultSet.add(node).isNewEntry)
result.append(node);
void markSubtreesDisjoint(bool disjoint) { m_subtreesAreDisjoint = disjoint; }
bool subtreesAreDisjoint() const { return m_subtreesAreDisjoint || m_nodes.size() < 2; }
+ const RefPtr<Node>* begin() const { return m_nodes.begin(); }
+ const RefPtr<Node>* end() const { return m_nodes.end(); }
+
private:
void traversalSort() const;
// keep this alive until this function is done.
Ref<XMLDocumentParser> protect(*this);
- switchToUTF16(context->context());
XMLDocumentParserScope scope(document()->cachedResourceLoader());
- xmlParseChunk(context->context(), reinterpret_cast<const char*>(parseString.deprecatedCharacters()), sizeof(UChar) * parseString.length(), 0);
+
+ // FIXME: Can we parse 8-bit strings directly as Latin-1 instead of upconverting to UTF-16?
+ switchToUTF16(context->context());
+ xmlParseChunk(context->context(), reinterpret_cast<const char*>(StringView(parseString).upconvertedCharacters().get()), sizeof(UChar) * parseString.length(), 0);
// JavaScript (which may be run under the xmlParseChunk callstack) may
// cause the parser to be stopped or detached.
HashMap<String, String> parseAttributes(const String& string, bool& attrsOK)
{
+ String parseString = "<?xml version=\"1.0\"?><attrs " + string + " />";
+
AttributeParseState state;
state.gotAttributes = false;
memset(&sax, 0, sizeof(sax));
sax.startElementNs = attributesStartElementNsHandler;
sax.initialized = XML_SAX2_MAGIC;
+
RefPtr<XMLParserContext> parser = XMLParserContext::createStringParser(&sax, &state);
- String parseString = "<?xml version=\"1.0\"?><attrs " + string + " />";
- xmlParseChunk(parser->context(), reinterpret_cast<const char*>(parseString.deprecatedCharacters()), parseString.length() * sizeof(UChar), 1);
+
+ // FIXME: Can we parse 8-bit strings directly as Latin-1 instead of upconverting to UTF-16?
+ xmlParseChunk(parser->context(), reinterpret_cast<const char*>(StringView(parseString).upconvertedCharacters().get()), parseString.length() * sizeof(UChar), 1);
+
attrsOK = state.gotAttributes;
return state.attributes;
}
+2014-03-22 Darin Adler <darin@apple.com>
+
+ Remove String::deprecatedCharacters
+ https://bugs.webkit.org/show_bug.cgi?id=126854
+
+ Reviewed by Sam Weinig.
+
+ * WebKit.vcxproj/WebKitExportGenerator/WebKitExports.def.in:
+ Removed getData16SlowCase.
+
2014-03-21 Alex Christensen <achristensen@webkit.org>
[Win] Compile fixes with video not enabled.
symbolWithPointer(?fromUTF8WithLatin1Fallback@String@WTF@@SA?AV12@PBEI@Z, ?fromUTF8WithLatin1Fallback@String@WTF@@SA?AV12@PEBE_K@Z)
symbolWithPointer(?garbageCollectDocumentResources@CachedResourceLoader@WebCore@@QAEXXZ, ?garbageCollectDocumentResources@CachedResourceLoader@WebCore@@QEAAXXZ)
symbolWithPointer(?getCachedDOMStructure@WebCore@@YAPAVStructure@JSC@@PAVJSDOMGlobalObject@1@PBUClassInfo@3@@Z, ?getCachedDOMStructure@WebCore@@YAPEAVStructure@JSC@@PEAVJSDOMGlobalObject@1@PEBUClassInfo@3@@Z)
- symbolWithPointer(?getData16SlowCase@StringImpl@WTF@@ABEPB_WXZ, ?getData16SlowCase@StringImpl@WTF@@AEBAPEB_WXZ)
symbolWithPointer(?getElementById@TreeScope@WebCore@@QBEPAVElement@2@ABVString@WTF@@@Z, ?getElementById@TreeScope@WebCore@@QEBAPEAVElement@2@AEBVString@WTF@@@Z)
symbolWithPointer(?getLocationAndLengthFromRange@TextIterator@WebCore@@SA_NPAVNode@2@PBVRange@2@AAI2@Z, ?getLocationAndLengthFromRange@TextIterator@WebCore@@SA_NPEAVNode@2@PEBVRange@2@AEA_K2@Z)
symbolWithPointer(?hitTest@RenderView@WebCore@@QAE_NABVHitTestRequest@2@AAVHitTestResult@2@@Z, ?hitTest@RenderView@WebCore@@QEAA_NAEBVHitTestRequest@2@AEAVHitTestResult@2@@Z)
+2014-03-22 Darin Adler <darin@apple.com>
+
+ Remove String::deprecatedCharacters
+ https://bugs.webkit.org/show_bug.cgi?id=126854
+
+ Reviewed by Sam Weinig.
+
+ * Misc/WebNSStringDrawing.h: Added a FIXME about deleting this file; we can probably do it soon.
+ * Misc/WebNSStringDrawing.mm:
+ (+[NSString _web_setWordRoundingEnabled:]):
+ (+[NSString _web_wordRoundingEnabled]):
+ (+[NSString _web_setWordRoundingAllowed:]):
+ (+[NSString _web_wordRoundingAllowed]):
+ (+[NSString _web_setAscentRoundingEnabled:]):
+ (+[NSString _web_ascentRoundingEnabled]):
+ (-[NSString _web_drawAtPoint:withFont:]):
+ (-[NSString _web_sizeWithFont:]):
+ (-[NSString _web_sizeWithFont:forWidth:ellipsis:]):
+ (-[NSString _web_sizeWithFont:forWidth:ellipsis:letterSpacing:]):
+ (-[NSString _web_sizeWithFont:forWidth:ellipsis:letterSpacing:resultRange:]):
+ (-[NSString _web_drawAtPoint:forWidth:withFont:ellipsis:]):
+ (-[NSString _web_drawAtPoint:forWidth:withFont:ellipsis:letterSpacing:]):
+ (-[NSString _web_drawAtPoint:forWidth:withFont:ellipsis:letterSpacing:includeEmoji:]):
+ (-[NSString _web_drawInRect:withFont:ellipsis:alignment:lineSpacing:includeEmoji:truncationRect:measureOnly:]):
+ (-[NSString _web_drawInRect:withFont:ellipsis:alignment:lineSpacing:includeEmoji:truncationRect:]):
+ (-[NSString _web_drawInRect:withFont:ellipsis:alignment:lineSpacing:]):
+ (-[NSString _web_drawInRect:withFont:ellipsis:alignment:]):
+ (-[NSString _web_sizeInRect:withFont:ellipsis:lineSpacing:]):
+ (-[NSString _web_sizeInRect:withFont:ellipsis:]):
+ (-[NSString _web_stringForWidth:withFont:ellipsis:letterSpacing:includeEmoji:]):
+ (-[NSString _web_sizeForWidth:withAttributes:]):
+ (-[NSString _web_drawAtPoint:forWidth:withAttributes:]):
+ (-[NSString _web_sizeInRect:withAttributes:]):
+ (-[NSString _web_drawInRect:withAttributes:]):
+ Emptied out all these functions since callers aren't really using them any more.
+
2014-03-21 Tim Horton <timothy_horton@apple.com>
Always retrieve the screen scale factor from WKSI
#ifndef WebNSStringDrawing_h
#define WebNSStringDrawing_h
+// FIXME: Delete this header after testing to be sure it doesn't break any apps or frameworks.
+
#if TARGET_OS_IPHONE
#import <CoreGraphics/CoreGraphics.h>
#import "WebNSStringDrawing.h"
-#if PLATFORM(IOS)
-
-#import "EmojiFallbackFontSelector.h"
-#import <CoreFoundation/CFPriv.h>
-#import <CoreGraphics/CGColor.h>
-#import <float.h>
-#import <sys/types.h>
-#import <unicode/ubrk.h>
-#import <unicode/uchar.h>
-#import <unicode/utf.h>
-#import <WebCore/BidiResolver.h>
-#import <WebCore/break_lines.h>
-#import <WebCore/Font.h>
-#import <WebCore/FontCache.h>
-#import <WebCore/GraphicsContext.h>
-#import <WebCore/StringTruncator.h>
-#import <WebCore/TextBreakIterator.h>
-#import <WebCore/TextRun.h>
-#import <WebCore/WKGraphics.h>
-#import <WebCore/WebCoreSystemInterface.h>
-#import <wtf/text/WTFString.h>
-#import <wtf/unicode/CharacterNames.h>
-
-using namespace WebCore;
-using namespace std;
-
-static BOOL ascentRoundingEnabled = NO;
-
-static BOOL wordRoundingEnabled;
-
-static BOOL wordRoundingAllowed = YES;
-
-static inline bool linkedOnOrAfterIPhoneOS3()
-{
- static bool s_linkedOnOrAfterIOS3 = iosExecutableWasLinkedOnOrAfterVersion(wkIOSSystemVersion_3_0);
- return s_linkedOnOrAfterIOS3;
-}
-
-static inline bool shouldDisableWordRounding()
-{
- // Note that even when rounding hacks are not disabled at this level, they will only be applied
- // if +[WebView _setAllowsRoundingHacks:YES] is called. Thus, in iOS 5 and later, rounding hacks are never
- // applied (see WebKitInitialize() in WebUIKitSupport.mm).
+// FIXME: Delete this file after testing to be sure it doesn't break any apps or frameworks.
- if (!wordRoundingAllowed)
- return true;
-
- if (linkedOnOrAfterIPhoneOS3())
- return false;
-
- return !wordRoundingEnabled;
-}
-
-static inline int boundedTextBreakFollowing(TextBreakIterator* it, int offset, int length)
-{
- int result = textBreakFollowing(it, offset);
- return result == TextBreakDone ? length : result;
-}
-
-static inline Font rendererForFont( GSFontRef font )
-{
- GSFontTraitMask traits = GSFontGetSynthesizedTraits(font);
- float size = GSFontGetSize(font);
-
- static EmojiFallbackFontSelector* fontSelector = EmojiFallbackFontSelector::create().leakRef();
-
- FontPlatformData platformData(font, size, true, traits & GSBoldFontMask, traits & GSItalicFontMask);
- Font renderer(platformData, PassRefPtr<FontSelector>(fontSelector));
-
- return renderer;
-}
-
-static String applyEllipsisStyle(const String& srcString, WebEllipsisStyle style, float width, const Font& font, StringTruncator::EnableRoundingHacksOrNot enableRoundingHacks, float* resultWidth, bool insertEllipsis = true, float customTruncationElementWidth = 0, bool alwaysTruncate = false)
-{
- // If it is WebEllipsisStyleClip, WebEllipsisStyleWordWrap, or WebEllipsisStyleCharacterWrap,
- // and we don't have any confine on the width, then it is the same as WebEllipsisStyleNone.
- if (style >= WebEllipsisStyleClip && width >= FLT_MAX)
- style = WebEllipsisStyleNone;
-
- float truncatedWidth = width;
- String truncatedString(srcString);
-
- switch (style) {
- case WebEllipsisStyleNone:
- truncatedWidth = StringTruncator::width(srcString, font, enableRoundingHacks);
- break;
- case WebEllipsisStyleHead:
- truncatedString = StringTruncator::leftTruncate(srcString, width, font, enableRoundingHacks, truncatedWidth, insertEllipsis, customTruncationElementWidth);
- break;
- case WebEllipsisStyleTail:
- truncatedString = StringTruncator::rightTruncate(srcString, width, font, enableRoundingHacks, truncatedWidth, insertEllipsis, customTruncationElementWidth);
- break;
- case WebEllipsisStyleCenter:
- truncatedString = StringTruncator::centerTruncate(srcString, width, font, enableRoundingHacks, truncatedWidth, insertEllipsis, customTruncationElementWidth);
- break;
-
- // Character wrap is the same as clipping for a single line, since we can't clip mid-character.
- case WebEllipsisStyleCharacterWrap:
- case WebEllipsisStyleClip:
- // If we were given a specific width to draw in, we shouldn't draw larger than that.
- truncatedString = StringTruncator::rightClipToCharacter(srcString, width, font, enableRoundingHacks, truncatedWidth, insertEllipsis, customTruncationElementWidth);
- break;
- case WebEllipsisStyleWordWrap:
- // If we were given a specific width to draw in, we shouldn't draw larger than that.
- truncatedString = StringTruncator::rightClipToWord(srcString, width, font, enableRoundingHacks, truncatedWidth, insertEllipsis, customTruncationElementWidth, alwaysTruncate);
- break;
- }
-
- if (resultWidth)
- *resultWidth = truncatedWidth;
-
- return truncatedString;
-}
-
-static float drawAtPoint(const UChar* str, const int runLength, const FloatPoint& point, const Font& renderer, GraphicsContext* context, bool drawUnderLine = false, BidiStatus* status = 0, int length = -1)
-{
- TextRun textRun(str, runLength);
- if (shouldDisableWordRounding())
- textRun.disableRoundingHacks();
-
- float width = 0;
- if (!status)
- width = renderer.drawText(context, textRun, point);
- else
- width = context->drawBidiText(renderer, textRun, point, WebCore::Font::DoNotPaintIfFontNotReady, status, length);
-
- if (drawUnderLine)
- context->drawLineForText(point, width, false);
- return width;
-}
-
-static bool needsBidiLayout(const UChar *characters, unsigned length, UCharDirection& baseDirection, bool oneParagraph = false)
-{
- bool foundFirstStrong = false;
- bool result = false;
- baseDirection = U_LEFT_TO_RIGHT;
- for (unsigned i = 0; i < length;) {
- UChar32 c;
- U16_NEXT(characters, i, length, c);
- switch (UCharDirection(c)) {
- case U_RIGHT_TO_LEFT:
- case U_RIGHT_TO_LEFT_ARABIC:
- if (!foundFirstStrong) {
- foundFirstStrong = true;
- baseDirection = U_RIGHT_TO_LEFT;
- }
- FALLTHROUGH; // To the rest of strongly directional cases.
- case U_LEFT_TO_RIGHT_EMBEDDING:
- case U_LEFT_TO_RIGHT_OVERRIDE:
- case U_RIGHT_TO_LEFT_EMBEDDING:
- case U_RIGHT_TO_LEFT_OVERRIDE:
- case U_POP_DIRECTIONAL_FORMAT:
- result = true;
- if (foundFirstStrong)
- return result;
- break;
- case U_LEFT_TO_RIGHT:
- foundFirstStrong = true;
- if (result)
- return result;
- break;
- case U_BLOCK_SEPARATOR:
- if (oneParagraph)
- return result;
- break;
- default:
- break;
- }
- }
- return result;
-}
+#if PLATFORM(IOS)
@implementation NSString (WebStringDrawing)
+ (void)_web_setWordRoundingEnabled:(BOOL)flag
{
- if (!linkedOnOrAfterIPhoneOS3())
- wordRoundingEnabled = flag;
}
+ (BOOL)_web_wordRoundingEnabled
{
- return wordRoundingEnabled;
+ return NO;
}
+ (void)_web_setWordRoundingAllowed:(BOOL)flag
{
- wordRoundingAllowed = flag;
}
+ (BOOL)_web_wordRoundingAllowed
{
- return wordRoundingAllowed;
+ return YES;
}
+ (void)_web_setAscentRoundingEnabled:(BOOL)flag
{
- ascentRoundingEnabled = flag;
}
+ (BOOL)_web_ascentRoundingEnabled
{
- return ascentRoundingEnabled;
-}
-
-#pragma mark Internal primitives used for string drawing/sizing
-
-// These methods should not be called from outside of this file
-
-- (CGSize)__web_drawAtPoint:(CGPoint)point
- forWidth:(CGFloat)width
- withFont:(GSFontRef)font
- ellipsis:(WebEllipsisStyle)ellipsisStyle
- letterSpacing:(float)letterSpacing
- includeEmoji:(BOOL)includeEmoji
- measureOnly:(BOOL)measureOnly
- renderedStringOut:(NSString **)renderedStringOut
- drawUnderline:(BOOL)drawUnderline
-{
- if (width < 0) {
-#ifndef NDEBUG
- fprintf(stderr, "%s: width must be greater than zero.\n", __FUNCTION__);
-#endif
- return CGSizeZero;
- }
-
- if (font == NULL) {
-#ifndef NDEBUG
- fprintf(stderr, "%s: font must be non-null.\n", __FUNCTION__);
-#endif
- return CGSizeZero;
- }
-
- if ([self isEqualToString:@""]) {
- return CGSizeZero;
- }
-
- FontCachePurgePreventer fontCachePurgePreventer;
-
- Font renderer = rendererForFont(font);
- if (letterSpacing != 0.0)
- renderer.setLetterSpacing(letterSpacing);
-
- String fullString(self);
- UCharDirection base = U_LEFT_TO_RIGHT;
- bool stringNeedsBidi = needsBidiLayout(fullString.deprecatedCharacters(), fullString.length(), base);
- float stringWidth;
- String s = (width >= FLT_MAX && !measureOnly) ? fullString : applyEllipsisStyle(fullString, ellipsisStyle, width, renderer, shouldDisableWordRounding() ? StringTruncator::DisableRoundingHacks : StringTruncator::EnableRoundingHacks, &stringWidth);
-
- if (!measureOnly) {
- CGContextRef cgContext= WKGetCurrentGraphicsContext();
- GraphicsContext context(static_cast<PlatformGraphicsContext*>(cgContext), false);
- context.setEmojiDrawingEnabled(includeEmoji);
-
- if (stringNeedsBidi) {
- BidiStatus status(base, base, base, BidiContext::create((base == U_LEFT_TO_RIGHT) ? 0 : 1, base, false));
- // FIXME: For proper bidi rendering, we need to pass the whole string, rather than the truncated string.
- // Otherwise, weak/neutral characters on either side of the ellipsis may pick up the wrong direction
- // if there are strong characters ellided.
- stringWidth = drawAtPoint(s.deprecatedCharacters(), s.length(), point, renderer, &context, drawUnderline, &status);
- } else {
- stringWidth = drawAtPoint(s.deprecatedCharacters(), s.length(), point, renderer, &context, drawUnderline);
- }
- }
-
- if (renderedStringOut)
- *renderedStringOut = (NSString *)s;
-
- return CGSizeMake(stringWidth, GSFontGetLineSpacing(font));
-}
-
-- (CGSize)__web_drawAtPoint:(CGPoint)point
- forWidth:(CGFloat)width
- withFont:(GSFontRef)font
- ellipsis:(WebEllipsisStyle)ellipsisStyle
- letterSpacing:(float)letterSpacing
- includeEmoji:(BOOL)includeEmoji
- measureOnly:(BOOL)measureOnly
- renderedStringOut:(NSString **)renderedStringOut
-{
- return [self __web_drawAtPoint:point
- forWidth:width
- withFont:font
- ellipsis:ellipsisStyle
- letterSpacing:letterSpacing
- includeEmoji:includeEmoji
- measureOnly:measureOnly
- renderedStringOut:renderedStringOut
- drawUnderline:NO];
-}
-
-- (CGSize)__web_drawAtPoint:(CGPoint)point
- forWidth:(CGFloat)width
- withFont:(GSFontRef)font
- ellipsis:(WebEllipsisStyle)ellipsisStyle
- letterSpacing:(float)letterSpacing
- includeEmoji:(BOOL)includeEmoji
- measureOnly:(BOOL)measureOnly
-{
- return [self __web_drawAtPoint:point
- forWidth:width
- withFont:font
- ellipsis:ellipsisStyle
- letterSpacing:letterSpacing
- includeEmoji:includeEmoji
- measureOnly:measureOnly
- renderedStringOut:nil];
+ return NO;
}
-- (CGSize)__web_drawInRect:(CGRect)rect
- withFont:(GSFontRef)font
- ellipsis:(WebEllipsisStyle)ellipsisStyle
- alignment:(WebTextAlignment)alignment
- letterSpacing:(CGFloat)letterSpacing
- lineSpacing:(CGFloat)lineSpacing
- includeEmoji:(BOOL)includeEmoji
- truncationRect:(CGRect *)truncationRect
- measureOnly:(BOOL)measureOnly
- renderedStringOut:(NSString **)renderedStringOut
- drawUnderline:(BOOL)drawUnderline
-{
- if (rect.size.width < 0) {
-#ifndef NDEBUG
- fprintf(stderr, "%s: width must be greater than zero.\n", __FUNCTION__);
-#endif
- return CGSizeZero;
- }
-
- if (font == NULL) {
-#ifndef NDEBUG
- fprintf(stderr, "%s: font must be non-null.\n", __FUNCTION__);
-#endif
- return CGSizeZero;
- }
-
- String renderedString = (renderedStringOut ? String("") : String());
-
- FontCachePurgePreventer fontCachePurgePreventer;
-
- Font renderer = rendererForFont(font);
- renderer.setLetterSpacing(letterSpacing);
- String drawString = String(self);
- if (drawString.contains('\r')) {
- drawString.replace("\r\n", "\n");
- drawString.replace('\r', '\n');
- }
- int length = drawString.length();
-
- CGPoint textPoint;
- CGPoint cursor = rect.origin;
- BOOL hasCustomLinespacing = YES;
- if (lineSpacing == 0.0) {
- lineSpacing = GSFontGetLineSpacing(font);
- hasCustomLinespacing = NO;
- }
- float ascent = GSFontGetAscent(font);
- if (ascentRoundingEnabled) {
- // This opt-in ascent rounding mode matches standard WebKit text rendering and is used by clients that want
- // to match, like a placeholder label inside a textfield that needs to line up exactly with text in the
- // WebView that will eventually replace it.
- ascent = ceilf(ascent);
- } else {
- // For all other drawing, we round to the nearest 1/128 to avoid inaccurate results in the computations below,
- // due to limited floating-point precision. We round to the nearest 1/128 because a) it is a power of two,
- // and you can exactly multiply integers by a power of 2, and b) it is small enough to not effect rendering
- // at any resolution that we will conceivably use. See <rdar://problem/8102100>.
- ascent = ceilf(ascent * 128) / 128.0f;
- }
- float maxLineWidth = 0;
- cursor.y += ascent;
-
- const UniChar *buffer = drawString.deprecatedCharacters();
- const UniChar *startOfLine = buffer;
-
- BOOL lastLine = NO;
- BOOL finishedLastLine = NO;
- UCharDirection base;
- BOOL paragraphNeedsBidi = needsBidiLayout(buffer, length, base, true);
- BidiStatus status;
- if (paragraphNeedsBidi)
- status = BidiStatus(base, base, base, BidiContext::create((base == U_LEFT_TO_RIGHT) ? 0 : 1, base, false));
-
- int lengthRemaining = length;
-
- while (lengthRemaining > 0 && !finishedLastLine) {
- if ((cursor.y - rect.origin.y) + lineSpacing > rect.size.height)
- lastLine = YES;
-
- BOOL reachedEndOfLine = NO;
- BOOL foundNewline = NO;
-
- UniChar *pos = const_cast<UniChar*>(startOfLine);
- float lineWidth = 0.0f;
- float trailingSpaceWidth = 0.0f; // Width of trailing space(s) on line, if any
- int trailingSpaceCount = 0; // Count of trailing space(s) on line, if any
-
- BOOL lastLineEllipsed = lastLine && (ellipsisStyle >= WebEllipsisStyleHead && ellipsisStyle <= WebEllipsisStyleCenter);
- BOOL lastLineClipped = lastLine && (ellipsisStyle >= WebEllipsisStyleClip);
- int skippedWhitespace = 0;
-
- while (!(lastLineEllipsed || lastLineClipped) && lengthRemaining > 0 && !reachedEndOfLine) {
- int breakPos = 0;
-
- if (ellipsisStyle != WebEllipsisStyleCharacterWrap) {
- //FIXME: <rdar://problem/12457790> investigate perf impact after merging TOT r129662.
- LazyLineBreakIterator breakIterator(String(pos, lengthRemaining));
- breakPos = nextBreakablePosition(breakIterator, 0);
- }
-
- // FIXME: This code currently works because there are no characters with these break or whitespace
- // properties outside plane 0. If that ever changes, surrogate pair handling will be needed everywhere
- // below where the width or a break or space is assumed to be 1.
- BOOL foundSpace = NO;
-
- if (breakPos < lengthRemaining) {
- ULineBreak breakProperty = (ULineBreak) u_getIntPropertyValue(pos[breakPos], UCHAR_LINE_BREAK);
- switch (breakProperty) {
- case U_LB_SPACE:
- case U_LB_ZWSPACE:
- foundSpace = YES;
- break;
- case U_LB_LINE_FEED:
- case U_LB_NEXT_LINE:
- case U_LB_MANDATORY_BREAK:
- case U_LB_CARRIAGE_RETURN:
- foundNewline = YES;
- break;
- default:
- if (ellipsisStyle == WebEllipsisStyleCharacterWrap) {
- // We can break on characters. We should do something smarter, like split the length of the entire line
- // Don't, however, break in the middle of a character.
- NonSharedCharacterBreakIterator it(StringView(pos, lengthRemaining));
- breakPos = boundedTextBreakFollowing(it, 0, lengthRemaining);
- }
- break;
- }
- }
-
- // NSLog(@"apparently the break is %x", pos[breakPos]);
-
- // ICU reports the break to us as the position just before the character it gives us (between two characters).
- // measure everything up to the break
- TextRun textRun(pos, breakPos);
- if (shouldDisableWordRounding())
- textRun.disableRoundingHacks();
- float wordWidth = renderer.width(textRun);
-
- // NSLog(@"measuring at pos = %d len = %d, size = %f", pos - startOfLine, breakPos, wordWidth);
- if (lineWidth + wordWidth <= rect.size.width) {
- // advance to the break character.
- pos += breakPos;
- lengthRemaining = length - (pos - buffer);
- lineWidth += wordWidth;
-
- // Reset trailing spaces if there was a real word.
- if (breakPos > 0) {
- trailingSpaceWidth = 0.0f;
- trailingSpaceCount = 0;
- }
-
- reachedEndOfLine = foundNewline;
- // don't ask the renderer to draw the line break character itself - skip ahead.
- if (foundNewline) {
- pos++;
- lengthRemaining--;
- skippedWhitespace++;
- } else if (foundSpace) {
- if (lengthRemaining > 0) {
- // measure space break width
- TextRun textRun(pos, 1);
- if (shouldDisableWordRounding())
- textRun.disableRoundingHacks();
-
- float spaceWidth = renderer.width(textRun);
-
- if (lineWidth + spaceWidth < rect.size.width) {
- // Space fits on line, add it...
- lineWidth += spaceWidth;
- trailingSpaceWidth += spaceWidth;
- trailingSpaceCount++;
- pos++;
- lengthRemaining--;
- } else {
- // Space does not fit on this line - it is legal then to skip through all consecutive spaces
- reachedEndOfLine = YES;
- do { // Line breaking code reported we found a space, so always skip at least one.
- lengthRemaining--;
- pos++;
- skippedWhitespace++;
- if (pos[-1] == '\n') { // Stop the loop just after a newline character, as spaces after that should render
- foundNewline = YES; // Record the fact that we found a new line
- break;
- }
- } while (lengthRemaining > 0 && u_isWhitespace(pos[0])); // continue to skip end-of-line whitespace
- }
- }
- } else if (wordWidth == 0 && breakPos == 0 && lengthRemaining > 0) {
- // Should not happen, but be safe and make sure we always either add width to the line or advance by a character.
- // If not, skip ahead.
- // FIXME: Should advance using character iterator and look for paragraph separator, but don't bother for now
- // since this is a "can't happen" path.
- pos++;
- lengthRemaining--;
- }
- } else {
- reachedEndOfLine = YES;
- foundNewline = NO; // We are not consuming any paragraph break, so don't react to it yet.
- if (lineWidth == 0 && lengthRemaining > 0) {
- // We have nothing on the line so far but reached the end of the line?
- // This must be a long word that doesn't fit inside the entire width
- // Fit it on a line one character at a time and break when no more characters fit
- // Force at least one character to avoid the edge case where a single glyph doesn't fit within width
- NonSharedCharacterBreakIterator it(StringView(pos, lengthRemaining));
- int offset = 0;
- int nextCharBreak = boundedTextBreakFollowing(it, offset, lengthRemaining);
- TextRun textRun(pos, nextCharBreak);
- if (shouldDisableWordRounding())
- textRun.disableRoundingHacks();
- lineWidth += renderer.width(textRun);
- float newLineWidth = lineWidth;
- do {
- lineWidth = newLineWidth;
- offset = nextCharBreak;
- if (lengthRemaining > offset) {
- nextCharBreak = boundedTextBreakFollowing(it, offset, lengthRemaining);
- TextRun textRun(pos + offset, nextCharBreak - offset);
- if (shouldDisableWordRounding())
- textRun.disableRoundingHacks();
- newLineWidth += renderer.width(textRun);
- }
- } while (newLineWidth <= rect.size.width && lengthRemaining > offset);
- // Update pos and lengthRemaining. Due to the semantics of boundedTextBreakFollowing, this will
- // never exceed the bounds.
- ASSERT(lengthRemaining >= offset);
- pos += offset;
- lengthRemaining -= offset;
- }
- }
- }
-
- if (lastLineEllipsed || lastLineClipped) {
- int i;
- for (i = 0; i < lengthRemaining && pos[i] != '\n'; i++) {
- /* Empty body - we just want to know if there's a newline between here and the end of the string */
- }
-
- bool droppingLines = (i != lengthRemaining);
-
- String lastLine = String(pos, i);
- if (lastLineEllipsed && i < lengthRemaining && !(pos[i] == '\n' && i == lengthRemaining - 1)) {
- // linebreak on last line with extra content that won't be rendered - insert an ellipse (5133005);
- // the exception is if we're at the last character and its a newline - next line won't render/size so don't ellipsise
- // This is OK for bidi since characters after a newline will not influence direction preceding it.
- const UChar ellipsisCharacter = 0x2026;
- lastLine.append(ellipsisCharacter);
- }
- // The last line is either everything that's left or everything until the next newline character
- if (!measureOnly) {
- bool insertEllipsis = (truncationRect == NULL);
- bool forceTruncation = (droppingLines && truncationRect);
- float customTruncationElementWidth = truncationRect ? truncationRect->size.width : 0;
-
- textPoint = cursor;
- String ellipsisResult;
- float lastLineWidth;
- if (alignment == WebTextAlignmentCenter) {
- ellipsisResult = applyEllipsisStyle(lastLine, ellipsisStyle, rect.size.width, renderer, shouldDisableWordRounding() ? StringTruncator::DisableRoundingHacks : StringTruncator::EnableRoundingHacks, &lastLineWidth, insertEllipsis, customTruncationElementWidth);
- if (lastLineWidth != 0) // special case for single glyphs wider than the rect to which we are rendering... applyEllipsisStyle can return 0 in this case.
- textPoint.x += (rect.size.width - lastLineWidth) / 2.0f;
- } else if (alignment == WebTextAlignmentRight) {
- ellipsisResult = applyEllipsisStyle(lastLine, ellipsisStyle, rect.size.width, renderer, shouldDisableWordRounding() ? StringTruncator::DisableRoundingHacks : StringTruncator::EnableRoundingHacks, &lastLineWidth, insertEllipsis, customTruncationElementWidth);
- if (lastLineWidth != 0)
- textPoint.x += rect.size.width - lastLineWidth;
- } else {
- ellipsisResult = applyEllipsisStyle(lastLine, ellipsisStyle, rect.size.width, renderer, shouldDisableWordRounding() ? StringTruncator::DisableRoundingHacks : StringTruncator::EnableRoundingHacks, &lastLineWidth, insertEllipsis, customTruncationElementWidth, forceTruncation);
- if (truncationRect && (ellipsisResult != lastLine || droppingLines)
- && lastLineWidth && base == U_RIGHT_TO_LEFT)
- textPoint.x += truncationRect->size.width;
- }
- CGContextRef cgContext = WKGetCurrentGraphicsContext();
- GraphicsContext context(static_cast<PlatformGraphicsContext*>(cgContext), false);
- context.setEmojiDrawingEnabled(includeEmoji);
- // FIXME: For proper bidi rendering, we need to pass the whole string, rather than the truncated string.
- // Otherwise, weak/neutral characters on either side of the ellipsis may pick up the wrong direction
- // if there are strong characters ellided.
- lineWidth = drawAtPoint(ellipsisResult.deprecatedCharacters(), ellipsisResult.length(), textPoint, renderer, &context, drawUnderline, paragraphNeedsBidi ? &status : 0);
- if (!renderedString.isNull())
- renderedString.append(ellipsisResult.deprecatedCharacters(), ellipsisResult.length());
-
- if (truncationRect) {
- if (ellipsisResult == lastLine && !droppingLines) {
- *truncationRect = CGRectNull;
- } else {
- truncationRect->origin = textPoint;
- truncationRect->origin.x += (base == U_RIGHT_TO_LEFT) ? (-truncationRect->size.width) : lineWidth;
- truncationRect->origin.y -= ascent;
- truncationRect->size.height = ascent - GSFontGetDescent(font);
- }
- }
- } else {
- applyEllipsisStyle(lastLine, ellipsisStyle, rect.size.width, renderer, shouldDisableWordRounding() ? StringTruncator::DisableRoundingHacks : StringTruncator::EnableRoundingHacks, &lineWidth);
- }
- } else {
- if (!measureOnly) {
- textPoint = cursor;
- if (alignment == WebTextAlignmentCenter && lineWidth <= rect.size.width) {
- textPoint.x += (rect.size.width - (lineWidth - trailingSpaceWidth)) / 2.0f;
- } else if (alignment == WebTextAlignmentRight && lineWidth <= rect.size.width) {
- textPoint.x += rect.size.width - (lineWidth - trailingSpaceWidth);
- }
- CGContextRef cgContext = WKGetCurrentGraphicsContext();
- GraphicsContext context(static_cast<PlatformGraphicsContext*>(cgContext), false);
- context.setEmojiDrawingEnabled(includeEmoji);
- if (paragraphNeedsBidi) {
- drawAtPoint(startOfLine, pos - startOfLine + lengthRemaining, textPoint, renderer, &context, drawUnderline, &status, pos - startOfLine - trailingSpaceCount - skippedWhitespace);
- if (!renderedString.isNull())
- renderedString.append(startOfLine, pos - startOfLine + lengthRemaining);
- } else {
- drawAtPoint(startOfLine, pos - startOfLine - trailingSpaceCount - skippedWhitespace, textPoint, renderer, &context, drawUnderline);
- if (!renderedString.isNull())
- renderedString.append(startOfLine, pos - startOfLine);
- }
- }
- startOfLine = pos;
- }
- if (lastLine)
- finishedLastLine = YES;
- else if (foundNewline) {
- // Redetermine whether the succeeding paragraph needs bidi layout, and if so, determine the base direction
- paragraphNeedsBidi = needsBidiLayout(startOfLine, lengthRemaining, base, true);
- if (paragraphNeedsBidi)
- status = BidiStatus(base, base, base, BidiContext::create((base == U_LEFT_TO_RIGHT) ? 0 : 1, base, false));
- }
- maxLineWidth = max(maxLineWidth, lineWidth);
- cursor.y += lineSpacing;
- }
-
- CGSize drawnSize;
- drawnSize.width = ceilf(maxLineWidth);
- if (!hasCustomLinespacing) {
- if (measureOnly)
- drawnSize.height = ceilf(cursor.y - rect.origin.y - ascent);
- else
- drawnSize.height = min<CGFloat>(ceilf(cursor.y - rect.origin.y - ascent), rect.size.height);
- } else {
- // for custom linespacing, the formula above does not hold true.
- float descent = GSFontGetDescent(font);
- if (measureOnly)
- drawnSize.height = ceilf(cursor.y - rect.origin.y - lineSpacing - descent);
- else
- drawnSize.height = min<CGFloat>(ceilf(cursor.y - rect.origin.y - lineSpacing - descent), rect.size.height);
- }
-
- if (renderedStringOut)
- *renderedStringOut = (NSString *)renderedString;
-
- return drawnSize;
-}
-
-- (CGSize)__web_drawInRect:(CGRect)rect
- withFont:(GSFontRef)font
- ellipsis:(WebEllipsisStyle)ellipsisStyle
- alignment:(WebTextAlignment)alignment
- letterSpacing:(CGFloat)letterSpacing
- lineSpacing:(CGFloat)lineSpacing
- includeEmoji:(BOOL)includeEmoji
- truncationRect:(CGRect *)truncationRect
- measureOnly:(BOOL)measureOnly
- renderedStringOut:(NSString **)renderedStringOut
-{
- return [self __web_drawInRect:rect
- withFont:font
- ellipsis:ellipsisStyle
- alignment:alignment
- letterSpacing:letterSpacing
- lineSpacing:lineSpacing includeEmoji:includeEmoji
- truncationRect:truncationRect
- measureOnly:measureOnly
- renderedStringOut:renderedStringOut
- drawUnderline:NO];
-}
-
-- (CGSize)__web_drawInRect:(CGRect)rect
- withFont:(GSFontRef)font
- ellipsis:(WebEllipsisStyle)ellipsisStyle
- alignment:(WebTextAlignment)alignment
- letterSpacing:(CGFloat)letterSpacing
- lineSpacing:(CGFloat)lineSpacing
- includeEmoji:(BOOL)includeEmoji
- truncationRect:(CGRect *)truncationRect
- measureOnly:(BOOL)measureOnly
-{
- return [self __web_drawInRect:rect
- withFont:font
- ellipsis:ellipsisStyle
- alignment:alignment
- letterSpacing:letterSpacing
- lineSpacing:lineSpacing includeEmoji:includeEmoji
- truncationRect:truncationRect
- measureOnly:measureOnly
- renderedStringOut:nil];
-}
-
-
-#pragma mark Public methods
-
- (CGSize)_web_drawAtPoint:(CGPoint)point withFont:(GSFontRef)font
{
- return [self _web_drawAtPoint:point forWidth:FLT_MAX withFont:font ellipsis:WebEllipsisStyleNone letterSpacing:0.0f includeEmoji:YES];
+ return CGSizeZero;
}
- (CGSize)_web_sizeWithFont:(GSFontRef)font
{
- return [self _web_sizeWithFont:font forWidth:FLT_MAX ellipsis:WebEllipsisStyleNone letterSpacing:0.0f];
+ return CGSizeZero;
}
- (CGSize)_web_sizeWithFont:(GSFontRef)font forWidth:(float)width ellipsis:(WebEllipsisStyle)ellipsisStyle
{
- return [self _web_sizeWithFont:font forWidth:width ellipsis:ellipsisStyle letterSpacing:0.0f];
+ return CGSizeZero;
}
- (CGSize)_web_sizeWithFont:(GSFontRef)font forWidth:(float)width ellipsis:(WebEllipsisStyle)ellipsisStyle letterSpacing:(float)letterSpacing
{
- return [self _web_sizeWithFont:font forWidth:width ellipsis:ellipsisStyle letterSpacing:letterSpacing resultRange:NULL];
+ return CGSizeZero;
}
- (CGSize)_web_sizeWithFont:(GSFontRef)font forWidth:(float)width ellipsis:(WebEllipsisStyle)ellipsisStyle letterSpacing:(float)letterSpacing resultRange:(NSRange *)resultRangeOut
{
- if (width < 0) {
-#ifndef NDEBUG
- fprintf(stderr, "%s: width must be greater than zero.\n", __FUNCTION__);
-#endif
- return CGSizeZero;
- }
-
- if (font == NULL) {
-#ifndef NDEBUG
- fprintf(stderr, "%s: font must be non-null.\n", __FUNCTION__);
-#endif
- return CGSizeZero;
- }
-
- if ([self isEqualToString:@""]) {
- return CGSizeZero;
- }
-
- float stringWidth;
- String s = String(self);
-
- FontCachePurgePreventer fontCachePurgePreventer;
-
- Font renderer = rendererForFont(font);
- if (letterSpacing != 0.0)
- renderer.setLetterSpacing(letterSpacing);
-
- if (resultRangeOut) {
- // Don't insert the ellipsis.
- String truncated = applyEllipsisStyle(s, ellipsisStyle, width, renderer, shouldDisableWordRounding() ? StringTruncator::DisableRoundingHacks : StringTruncator::EnableRoundingHacks, &stringWidth, false);
- NSRange resultRange = NSMakeRange(0, truncated.length());
- *resultRangeOut = resultRange;
- } else {
- applyEllipsisStyle(s, ellipsisStyle, width, renderer, shouldDisableWordRounding() ? StringTruncator::DisableRoundingHacks : StringTruncator::EnableRoundingHacks, &stringWidth);
- }
-
- // Ensure integral sizes. Ceil to avoid possible clipping.
- CGSize size = CGSizeMake (stringWidth, GSFontGetLineSpacing(font));
- size.width = ceilf(size.width);
- size.height = ceilf(size.height);
- return size;
+ return CGSizeZero;
}
- (CGSize)_web_drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(GSFontRef)font ellipsis:(WebEllipsisStyle)ellipsisStyle
{
- return [self _web_drawAtPoint:point forWidth:width withFont:font ellipsis:ellipsisStyle letterSpacing:0.0f includeEmoji:YES];
+ return CGSizeZero;
}
- (CGSize)_web_drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(GSFontRef)font ellipsis:(WebEllipsisStyle)ellipsisStyle letterSpacing:(float)letterSpacing
{
- return [self _web_drawAtPoint:(CGPoint)point forWidth:width withFont:font ellipsis:ellipsisStyle letterSpacing:letterSpacing includeEmoji:YES];
+ return CGSizeZero;
}
- (CGSize)_web_drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(GSFontRef)font ellipsis:(WebEllipsisStyle)ellipsisStyle letterSpacing:(float)letterSpacing includeEmoji:(BOOL)includeEmoji
{
- return [self __web_drawAtPoint:point forWidth:width withFont:font ellipsis:ellipsisStyle letterSpacing:letterSpacing includeEmoji:includeEmoji measureOnly:NO];
+ return CGSizeZero;
}
- (CGSize)_web_drawInRect:(CGRect)rect withFont:(GSFontRef)font ellipsis:(WebEllipsisStyle)ellipsisStyle alignment:(WebTextAlignment)alignment lineSpacing:(int)lineSpacing includeEmoji:(BOOL)includeEmoji truncationRect:(CGRect *)truncationRect measureOnly:(BOOL)measureOnly
{
- return [self __web_drawInRect:rect withFont:font ellipsis:ellipsisStyle alignment:alignment letterSpacing:(CGFloat)0.0 lineSpacing:(CGFloat)lineSpacing includeEmoji:includeEmoji truncationRect:truncationRect measureOnly:measureOnly];
+ if (truncationRect)
+ *truncationRect = CGRectZero;
+ return CGSizeZero;
}
- (CGSize)_web_drawInRect:(CGRect)rect withFont:(GSFontRef)font ellipsis:(WebEllipsisStyle)ellipsisStyle alignment:(WebTextAlignment)alignment lineSpacing:(int)lineSpacing includeEmoji:(BOOL)includeEmoji truncationRect:(CGRect *)truncationRect
{
- return [self _web_drawInRect:rect withFont:font ellipsis:ellipsisStyle alignment:alignment lineSpacing:lineSpacing includeEmoji:includeEmoji truncationRect:truncationRect measureOnly:NO];
+ if (truncationRect)
+ *truncationRect = CGRectZero;
+ return CGSizeZero;
}
- (CGSize)_web_drawInRect:(CGRect)rect withFont:(GSFontRef)font ellipsis:(WebEllipsisStyle)ellipsisStyle alignment:(WebTextAlignment)alignment lineSpacing:(int)lineSpacing
{
- return [self _web_drawInRect:rect withFont:font ellipsis:ellipsisStyle alignment:alignment lineSpacing:lineSpacing includeEmoji:YES truncationRect:nil measureOnly:NO];
+ return CGSizeZero;
}
- (CGSize)_web_drawInRect:(CGRect)rect withFont:(GSFontRef)font ellipsis:(WebEllipsisStyle)ellipsisStyle alignment:(WebTextAlignment)alignment
{
- return [self _web_drawInRect:rect withFont:font ellipsis:ellipsisStyle alignment:alignment lineSpacing:0 includeEmoji:YES truncationRect:nil measureOnly:NO];
+ return CGSizeZero;
}
- (CGSize)_web_sizeInRect:(CGRect)rect withFont:(GSFontRef)font ellipsis:(WebEllipsisStyle)ellipsisStyle lineSpacing:(int)lineSpacing
{
- return [self _web_drawInRect:rect withFont:font ellipsis:ellipsisStyle alignment:WebTextAlignmentLeft lineSpacing:lineSpacing includeEmoji:YES truncationRect:nil measureOnly:YES];
+ return CGSizeZero;
}
- (CGSize)_web_sizeInRect:(CGRect)rect withFont:(GSFontRef)font ellipsis:(WebEllipsisStyle)ellipsisStyle
{
- return [self _web_drawInRect:rect withFont:font ellipsis:ellipsisStyle alignment:WebTextAlignmentLeft lineSpacing:0 includeEmoji:YES truncationRect:nil measureOnly:YES];
+ return CGSizeZero;
}
- (NSString *)_web_stringForWidth:(float)width withFont:(GSFontRef)font ellipsis:(WebEllipsisStyle)ellipsisStyle letterSpacing:(float)letterSpacing includeEmoji:(BOOL)includeEmoji
{
- UNUSED_PARAM(includeEmoji);
-
- if (width <= 0) {
-#ifndef NDEBUG
- fprintf(stderr, "%s: width must be greater than zero.\n", __FUNCTION__);
-#endif
- return @"";
- }
-
- if (font == NULL) {
-#ifndef NDEBUG
- fprintf(stderr, "%s: font must be non-null.\n", __FUNCTION__);
-#endif
- return self;
- }
-
- FontCachePurgePreventer fontCachePurgePreventer;
-
- Font renderer = rendererForFont(font);
- if (letterSpacing != 0.0)
- renderer.setLetterSpacing(letterSpacing);
-
- return applyEllipsisStyle(self, ellipsisStyle, width, renderer, shouldDisableWordRounding() ? StringTruncator::DisableRoundingHacks : StringTruncator::EnableRoundingHacks, 0);
+ return @"";
}
- (CGSize)_web_sizeForWidth:(CGFloat)width withAttributes:(id <WebTextRenderingAttributes>)attributes
{
- // FIXME: We're not computing the correct truncation rect here
- attributes.truncationRect = CGRectZero;
- return [self __web_drawAtPoint:CGPointZero
- forWidth:width
- withFont:attributes.font
- ellipsis:attributes.ellipsisStyle
- letterSpacing:attributes.letterSpacing
- includeEmoji:attributes.includeEmoji
- measureOnly:YES
- renderedStringOut:attributes.renderString];
+ return CGSizeZero;
}
- (CGSize)_web_drawAtPoint:(CGPoint)point forWidth:(CGFloat)width withAttributes:(id <WebTextRenderingAttributes>)attributes
{
- // FIXME: We're not computing the correct truncation rect here
- attributes.truncationRect = CGRectZero;
- return [self __web_drawAtPoint:point
- forWidth:width
- withFont:attributes.font
- ellipsis:attributes.ellipsisStyle
- letterSpacing:attributes.letterSpacing
- includeEmoji:attributes.includeEmoji
- measureOnly:NO
- renderedStringOut:attributes.renderString
- drawUnderline:attributes.drawUnderline];
+ return CGSizeZero;
}
- (CGSize)_web_sizeInRect:(CGRect)rect withAttributes:(id <WebTextRenderingAttributes>)attributes
{
- // FIXME: We're not computing the correct truncation rect here
- CGSize size = [self __web_drawInRect:rect
- withFont:attributes.font
- ellipsis:attributes.ellipsisStyle
- alignment:attributes.alignment
- letterSpacing:attributes.letterSpacing
- lineSpacing:attributes.lineSpacing
- includeEmoji:attributes.includeEmoji
- truncationRect:NULL
- measureOnly:YES
- renderedStringOut:attributes.renderString];
- return size;
+ return CGSizeZero;
}
- (CGSize)_web_drawInRect:(CGRect)rect withAttributes:(id <WebTextRenderingAttributes>)attributes
{
- // FIXME: We're not computing the correct truncation rect here
- CGSize size = [self __web_drawInRect:rect
- withFont:attributes.font
- ellipsis:attributes.ellipsisStyle
- alignment:attributes.alignment
- letterSpacing:attributes.letterSpacing
- lineSpacing:attributes.lineSpacing
- includeEmoji:attributes.includeEmoji
- truncationRect:NULL
- measureOnly:NO
- renderedStringOut:attributes.renderString
- drawUnderline:attributes.drawUnderline];
- return size;
+ return CGSizeZero;
}
@end
+2014-03-22 Darin Adler <darin@apple.com>
+
+ Remove String::deprecatedCharacters
+ https://bugs.webkit.org/show_bug.cgi?id=126854
+
+ Reviewed by Sam Weinig.
+
+ * WebKitStatistics.cpp:
+ (WebKitStatistics::comClassNameCounts): Update to not use Vector::append(String).
+
2014-03-17 Brent Fulgham <bfulgham@apple.com>
Provide preference to enable additional AVFoundation options
#include "WebKitStatisticsPrivate.h"
#include <WebCore/BString.h>
+#include <wtf/text/StringBuilder.h>
using namespace WebCore;
HRESULT STDMETHODCALLTYPE WebKitStatistics::comClassNameCounts(
/* [retval][out] */ BSTR *output)
{
- typedef HashCountedSet<String>::const_iterator Iterator;
- Iterator end = gClassNameCount.end();
- Vector<UChar> vector;
- for (Iterator current = gClassNameCount.begin(); current != end; ++current) {
- append(vector, String::format("%4u", current->value));
- vector.append('\t');
- append(vector, static_cast<String>(current->key));
- vector.append('\n');
+ StringBuilder builder;
+ for (auto& slot : gClassNameCount) {
+ builder.appendNumber(slot.value);
+ builder.append('\t');
+ builder.append(slot.key);
+ builder.append('\n');
}
- *output = BString(String::adopt(vector)).release();
+ *output = BString(builder.toString()).release();
return S_OK;
}