Reduce WTF::String operations that do unnecessary Unicode operations instead of ASCII
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Nov 2017 17:32:42 +0000 (17:32 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Nov 2017 17:32:42 +0000 (17:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=179907

Reviewed by Sam Weinig.

Source/JavaScriptCore:

* inspector/agents/InspectorDebuggerAgent.cpp:
(Inspector::matches): Removed explicit TextCaseSensitive because RegularExpression now
defaults to that.

* runtime/StringPrototype.cpp:
(JSC::stringIncludesImpl): Use String::find since there is no overload of
String::contains that takes a start offset now that we removed the one that took a
caseSensitive boolean. We can add one later if we like, but this should do for now.

* yarr/RegularExpression.h: Moved the TextCaseSensitivity enumeration here from
the StringImpl.h header because it is only used here.

Source/WebCore:

* Modules/plugins/YouTubePluginReplacement.cpp:
(WebCore::hasCaseInsensitivePrefix): Deleted.
(WebCore::processAndCreateYouTubeURL): Use startsWithLettersIgnoringASCIICase.

* Modules/websockets/WebSocketHandshake.cpp:
(WebCore::WebSocketHandshake::readHTTPHeaders): Use isAllASCII.

* accessibility/atk/AccessibilityObjectAtk.cpp:
(WebCore::AccessibilityObject::getLengthForTextRange const): Use text().length().

* accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::traverseToOffsetInRange): Use isHTMLSpace instead of
isSpaceOrNewline since the code is trying to skip collapsible HTML spaces, not
arbitrary Unicode whitespace.
* accessibility/AccessibilityList.cpp:
(WebCore::AccessibilityList::childHasPseudoVisibleListItemMarkers): Use
isAllSpecialCharacters<isHTMLSpace> for the same reason as above.

* accessibility/AccessibilityNodeObject.cpp:
(WebCore::AccessibilityNodeObject::isSearchField const): Use containsIgnoringASCIICase.

* accessibility/AccessibilityObject.cpp:
(WebCore::AccessibilityObject::accessibilityObjectContainsText const): Use
new findPlainText function exported from TextIterator so this can share the
same search matching logic used to find text in webpages.
(WebCore::AccessibilityObject::selectText): Use capitalize and its return value
rather than makeCapitalize modifying a string in place.

* accessibility/AccessibilityRenderObject.cpp:
(WebCore::objectInclusionFromAltText): Use isAllSpecialCharacters<isHTMLSpace>
for the same reason as above.
(WebCore::AccessibilityRenderObject::computeAccessibilityIsIgnored const): Ditto.

* bindings/js/JSDOMConvertStrings.cpp:
(WebCore::stringToByteString): Use isAllLatin1.

* contentextensions/ContentExtensionParser.cpp:
(WebCore::ContentExtensions::containsOnlyASCIIWithNoUppercase): Use
StringView::codeUnits instead of String::at.

* contentextensions/ContentExtensionsBackend.cpp:
(WebCore::ContentExtensions::ContentExtensionsBackend::actionsForResourceLoad const):
Use isAllASCII.
* contentextensions/URLFilterParser.cpp:
(WebCore::ContentExtensions::URLFilterParser::addPattern): Ditto.

* css/CSSFontFaceSrcValue.cpp:
(WebCore::CSSFontFaceSrcValue::isSupportedFormat const): Use protocolIs and
endsWithIgnoringASCIICase.

* css/DOMCSSNamespace.cpp:
(WebCore::valueWithoutImportant): Use endsWithIgnoringASCIICase.

* css/parser/CSSPropertyParser.cpp:
(WebCore::parseGridTemplateAreasRow): Use isAllSpecialCharacters<isCSSSpace>,
for the preflight, which matches what the actual parsing code uses.

* dom/CharacterData.cpp:
(WebCore::CharacterData::containsOnlyWhitespace const): Deleted. Callers can
efficiently get at the data and do this kind of check on the data directly.
* dom/CharacterData.h: Updated for the above.

* dom/DataTransfer.cpp:
(WebCore::normalizeType): Use startsWith since the string is already converted
to ASCII lowercase.

* dom/Position.cpp:
(WebCore::Position::leadingWhitespacePosition const): Use isHTMLSpace since
since the code is trying to check for collapsible HTML spaces, not general
Unicode spaces. Other call sites of isSpaceOrNewline need to be checked for
this, but I did not fix them all at this time.
(WebCore::Position::trailingWhitespacePosition const): Ditto.

* editing/Editor.cpp:
(WebCore::Editor::editorUIUpdateTimerFired): Use noBreakSpace.

* editing/FrameSelection.cpp:
(WebCore::FrameSelection::debugRenderer const): Use text().length() instead
of textLength.
(WebCore::FrameSelection::selectionAtWordStart const): Use noBreakSpace.
(WebCore::FrameSelection::wordSelectionContainingCaretSelection): Ditto.
(WebCore::FrameSelection::actualSelectionAtSentenceStart const): Ditto.

* editing/TextIterator.cpp:
(WebCore::textNodeOffsetInFlow): Use text().length().
(WebCore::TextIterator::handleTextNode): Ditto.
(WebCore::collapsedSpaceLength): Updated since RenderText::text now returns
a reference rather than a pointer.
(WebCore::findPlainText): Added. Uses SearchBuffer to search for one string
within another. Exported so accessibility code can do this operation.
* editing/TextIterator.h: Updated for the above.

* editing/TypingCommand.cpp:
(WebCore::TypingCommand::markMisspellingsAfterTyping): Use noBreakSpace.

* editing/VisibleUnits.cpp:
(WebCore::findStartOfParagraph): Updated since RenderText::text now returns
a reference.
(WebCore::findEndOfParagraph): Ditto.

* editing/cocoa/HTMLConverter.mm:
(HTMLConverter::_processText): Use String::characterAt instead of String::at.
Use capitalize instead of makeCapitalized.

* editing/cocoa/WebContentReaderCocoa.mm:
(WebCore::stripMicrosoftPrefix): Use findIgnoringASCIICase.

* html/Autofill.cpp:
(WebCore::AutofillData::createFromHTMLFormControlElement): Use
startsWithLettersIgnoringASCIICase.

* html/BaseTextInputType.cpp:
(WebCore::BaseTextInputType::patternMismatch const): Removed explicit
TextCaseSensitive since it now is the default, and needed to touch this anyway
because the enumeration is now in a different namespace.

* html/EmailInputType.cpp:
(WebCore::isValidEmailAddress): Updated to use JSC::Yarr::TextCaseInsensitive.

* html/HTMLObjectElement.cpp:
(WebCore::HTMLObjectElement::hasFallbackContent const): Use
isAllSpecialCharacters<isHTMLSpace>.
(WebCore::HTMLObjectElement::shouldAllowQuickTimeClassIdQuirk): Use
startsWithLettersIgnoringASCIICase.
(WebCore::HTMLObjectElement::hasValidClassId): Use protocolIs.
(WebCore::preventsParentObjectFromExposure): Use isAllSpecialCharacters<isHTMLSpace>.

* html/parser/HTMLConstructionSite.cpp:
(WebCore::HTMLConstructionSite::setCompatibilityModeFromDoctype):
Use startsWithLettersIgnoringASCIICase.

* html/parser/HTMLMetaCharsetParser.cpp:
(WebCore::extractCharset): Use findIgnoringASCIICase.

* html/parser/XSSAuditor.cpp:
(WebCore::XSSAuditor::isContainedInRequest): Use containsIgnoringASCIICase.

* html/track/WebVTTParser.cpp:
(WebCore::WebVTTParser::hasRequiredFileIdentifier): Don't pass the length to
the String::startsWith function. There has never been a version of that function
that takes the length, there is no need to pass the length since the function
handles null-terminated strings like the one here, and in the past the length
has been getting converted to a boolean making the comparison be case sensitive.
Removing the argument entirely leaves it case sensitive.

* inspector/InspectorNodeFinder.cpp:
(WebCore::InspectorNodeFinder::matchesElement): Use startsWithIgnoringASCIICase
and endsWithIgnoringASCIICase.

* inspector/InspectorStyleSheet.cpp:
(WebCore::selectorsFromSource): Use JSC::Yarr::TextCaseSensitive.

* inspector/agents/InspectorDOMAgent.cpp:
(WebCore::containsOnlyHTMLWhitespace): Made this a non-member function
and reimplemented using isAllSpecialCharacters<isHTMLSpace>().
(WebCore::InspectorDOMAgent::innerFirstChild): Use containsOnlyHTMLWhitespace.
(WebCore::InspectorDOMAgent::innerNextSibling): Ditto.
(WebCore::InspectorDOMAgent::innerPreviousSibling): Ditto.
(WebCore::InspectorDOMAgent::innerChildNodeCount): Ditto.
(WebCore::InspectorDOMAgent::didInsertDOMNode): Ditto.
(WebCore::InspectorDOMAgent::didRemoveDOMNode): Ditto.
* inspector/agents/InspectorDOMAgent.h: Updated for above change.

* loader/appcache/ApplicationCacheStorage.cpp:
(WebCore::ApplicationCacheStorage::shouldStoreResourceAsFlatFile):
Use startsWithLettersIgnoringASCIICase.

* page/Base64Utilities.cpp:
(WebCore::Base64Utilities::btoa): Use isAllLatin1.

* page/Frame.cpp:
(WebCore::createRegExpForLabels): Removed TextCaseSensitive argument since
that is now the default and also used JSC::Yarr::TextCaseInsensitive.
(WebCore::matchLabelsAgainstString): More of the same.

* page/FrameView.cpp:
(WebCore::countRenderedCharactersInRenderObjectWithThreshold): Use
text().length().

* page/SecurityOrigin.cpp:
(WebCore::isFeedWithNestedProtocolInHTTPFamily): Use
startsWithLettersIgnoringASCIICase.

* page/UserContentURLPattern.cpp:
(WebCore::UserContentURLPattern::matchesHost const):
Use endsWithIgnoringASCIICase.
* page/csp/ContentSecurityPolicySource.cpp:
(WebCore::ContentSecurityPolicySource::hostMatches const): Ditto.

* page/csp/ContentSecurityPolicySourceList.cpp:
(WebCore::ContentSecurityPolicySourceList::parseNonceSource):
Use startsWithIgnoringASCIICase.

* page/ios/FrameIOS.mm:
(WebCore::Frame::wordsInCurrentParagraph const): Use noBreakSpace.

* platform/ContentType.cpp:
(WebCore::ContentType::parameter const): Use findIgnoringASCIICase.

* platform/MIMETypeRegistry.cpp:
(WebCore::MIMETypeRegistry::isSupportedFontMIMEType): Use
startsWithLettersIgnoringASCIICase.
(WebCore::MIMETypeRegistry::isSupportedJSONMIMEType): Use
mimeType.endsWithIgnoringASCIICase.
(WebCore::MIMETypeRegistry::isTextMIMEType): Use
startsWithLettersIgnoringASCIICase.
(WebCore::MIMETypeRegistry::isXMLMIMEType): Use endsWithIgnoringASCIICase.
(WebCore::MIMETypeRegistry::isJavaAppletMIMEType): Use
startsWithLettersIgnoringASCIICase.
(WebCore::MIMETypeRegistry::canShowMIMEType): Ditto.

* platform/URL.cpp:
(WebCore::isAllASCII): Renamed from containsOnlyASCII.
(WebCore::appendEncodedHostname): Use isAllASCII.

* platform/URLParser.cpp:
(WebCore::containsOnlyASCII): Deleted.
(WebCore::URLParser::domainToASCII): Use StringImpl::isAllASCII. Changed
to take StringImpl& to guarantee we won't keep doing null checks since
the caller already checks for null.
(WebCore::URLParser::parseHostAndPort): Pass StringImpl&.
* platform/URLParser.h: Updated for above.

* platform/graphics/MediaPlayer.cpp:
(WebCore::MediaPlayer::supportsType): Use endsWithIgnoringASCIICase
and startsWithLettersIgnoringASCIICase.

* platform/graphics/avfoundation/CDMPrivateMediaSourceAVFObjC.mm:
(WebCore::validKeySystemRE): Use JSC::Yarr::TextCaseInsensitive.

* platform/graphics/cocoa/FontCacheCoreText.cpp:
(WebCore::FontCache::similarFont): Use containsIgnoringASCIICase for
the Geeza font special cases.

* platform/graphics/mac/MediaPlayerPrivateQTKit.mm:
(WebCore::shouldRejectMIMEType): Use startsWithLettersIgnoringASCIICase.

* platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp:
(WebCore::GraphicsContext3D::getUnmangledInfoLog): Removed
TextCaseSensitive since it now is the default.

* platform/mac/PublicSuffixMac.mm:
(WebCore::topPrivatelyControlledDomain): Use isAllASCII.

* platform/mac/SSLKeyGeneratorMac.mm:
(WebCore::signedPublicKeyAndChallengeString): Use isAllASCII.

* platform/mac/StringUtilities.mm:
(WebCore::stringMatchesWildcardString): Use JSC::Yarr::TextCaseInsensitive.

* platform/mediastream/RealtimeMediaSourceCenter.cpp:
(WebCore::addStringToSHA1): Use isAllASCII.

* platform/network/CacheValidation.cpp:
(WebCore::parseCacheControlDirectives): Use containsIgnoringASCIICase.

* platform/network/HTTPParsers.cpp:
(WebCore::parseHTTPRefresh): Use findIgnoringASCIICase.
(WebCore::findCharsetInMediaType): Ditto.
(WebCore::parseRange): Use startsWithLettersIgnoringASCIICase.

* platform/network/curl/AuthenticationChallengeCurl.cpp:
(WebCore::AuthenticationChallenge::protectionSpaceFromHandle):
Use findIgnoringASCIICase.
* platform/network/curl/MultipartHandle.cpp:
(WebCore::MultipartHandle::extractBoundary): Ditto.
* platform/network/curl/ResourceHandleCurlDelegate.cpp:
(WebCore::ResourceHandleCurlDelegate::handleDataURL): Use
endsWithIgnoringASCIICase.
* platform/network/curl/ResourceResponseCurl.cpp:
(WebCore::ResourceResponse::isAppendableHeader): Use
startsWithLettersIgnoringASCIICase.
(WebCore::ResourceResponse::appendHTTPHeaderField): Ditto.

* platform/win/ClipboardUtilitiesWin.cpp:
(WebCore::extractMarkupFromCFHTML): Use findIgnoringASCIICase.
(WebCore::fragmentFromCFHTML): Ditto.

* rendering/BidiRun.cpp:
(WebCore::BidiRun::BidiRun): Use text().length().
* rendering/HitTestResult.cpp:
(WebCore::HitTestResult::absolutePDFURL const): Use
endsWithIgnoringASCIICase.
* rendering/InlineFlowBox.cpp:
(WebCore::InlineFlowBox::placeBoxRangeInInlineDirection): Use text().length().
* rendering/InlineIterator.h:
(WebCore::InlineIterator::fastIncrementInTextNode): Ditto.
(WebCore::InlineIterator::increment): Dtto.
* rendering/InlineTextBox.cpp:
(WebCore::InlineTextBox::isLineBreak const): Updated since RenderText::text
now returns a StringImpl&.
(WebCore::InlineTextBox::selectionStartEnd const): Use text().length().
(WebCore::InlineTextBox::text const): Updated since RenderText::text
now returns a StringImpl&.
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::constructTextRun): Use text().length().
* rendering/RenderBlockFlow.cpp:
(WebCore::isVisibleRenderText): Use isAllSpecialCharacters<isHTMLSpace>().
(WebCore::RenderBlockFlow::computeInlinePreferredLogicalWidths const):
Use the new trimmedPreferredWidths that returns a structure instead of the
old one with lots of arguments. Also use text().length().
* rendering/RenderBlockLineLayout.cpp:
(WebCore::endsWithHTMLSpaces): Renamed and changed to use isHTMLSpace
instead of isASCIISpace.
(WebCore::reachedEndOfTextRenderer): Use endsWithHTMLSpaces.
(WebCore::RenderBlockFlow::computeInlineDirectionPositionsForSegment):
Updated for hcanges to RenderText.
(WebCore::RenderBlockFlow::handleTrailingSpaces): Ditto.
(WebCore::RenderBlockFlow::determineStartPosition): Ditto.

* rendering/RenderCombineText.cpp:
(WebCore::RenderCombineText::combineTextIfNeeded): Use
isAllSpecialCharacters<isHTMLSpace>.
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::calculateClipRects const): Ditto.

* rendering/RenderListBox.cpp:
(WebCore::bolder): Added. Helper function.
(WebCore::RenderListBox::updateFromElement): Rewrote to
only compute the bolder font once rather than for every item.
(WebCore::RenderListBox::paintItemForeground): Updated for
change to applyTextTransform.

* rendering/RenderMenuList.cpp:
(WebCore::RenderMenuList::adjustInnerStyle): Updated for change
to RenderText::text.
(RenderMenuList::updateOptionsWidth): Updated for change to
applyTextTransform.
(RenderMenuList::itemText const): Ditto.

* rendering/RenderText.cpp:
(WebCore::capitalize): Renamed from makeCapitalized. Changed to
take and return a String instead of taking a String*.
(WebCore::RenderText::RenderText): Use isAllASCII. Also moved
initialization of most non-bitfield members to the class definition.
(WebCore::RenderText::positionForPoint): Use text().
(WebCore::RenderText::widthFromCache const): Ditto.
(WebCore::RenderText::hangablePunctuationStartWidth const): Ditto.
(WebCore::RenderText::hangablePunctuationEndWidth const): Ditto.
(WebCore::RenderText::isHangableStopOrComma): Ditto.
(WebCore::RenderText::firstCharacterIndexStrippingSpaces const): Ditto.
(WebCore::RenderText::lastCharacterIndexStrippingSpaces const): Ditto.
(WebCore::RenderText::trimmedPreferredWidths): Changed to return values
in a structure instead of taking lots of arguments.
(WebCore::RenderText::computePreferredLogicalWidths): Updated to use
the text() function.
(WebCore::isAllCollapsibleWhitespace): Added.
(WebCore::RenderText::isAllCollapsibleWhitespace const): Updated to
use a tighter loop.
(WebCore::isAllPossiblyCollapsibleWhitespace): Added.
(WebCore::RenderText::containsOnlyHTMLWhitespace const): Updated to
use a tighter loop. Renamed from containsOnlyWhitespace.
(WebCore::RenderText::setTextWithOffset): Updated to  use text().
(WebCore::isInlineFlowOrEmptyText): Rewrote to be easier to read.
(WebCore::RenderText::previousCharacter const): Got rid of unneeded
null check and simplified.
(WebCore::applyTextTransform): Changed to return a String rather
than modifying one that is passed in.
(WebCore::RenderText::setRenderedText): Updated use of applyTextTransform.
(WebCore::RenderText::secureText): More of the same.
(WebCore::RenderText::computeCanUseSimplifiedTextMeasuring const): Ditto.
(WebCore::RenderText::textWithoutConvertingBackslashToYenSymbol const): Ditto.
(WebCore::RenderText::width const): Ditto.
(WebCore::RenderText::collectSelectionRectsForLineBoxes): Ditto.
(WebCore::RenderText::previousOffset const): Ditto.
(WebCore::RenderText::previousOffsetForBackwardDeletion const): Ditto.
(WebCore::RenderText::nextOffset const): Ditto.
(WebCore::RenderText::computeCanUseSimpleFontCodePath const): Ditto.
(WebCore::RenderText::stringView const): Ditto.

* rendering/RenderText.h: Made some more members private and final.
Updated for above, including adding the Widths structure. Got rid of the
textLength function, which existed as a workaround before we could mark
a function like length final. Made the text function return a StringImpl&,
which is good since the m_text string is never null, and so callers end
up using StringImpl directly and saving null checks. Removed functions
that are not needed, including is8Bit, characters8, characters16,
uncheckedCharacterAt, operator[], and isAllASCII.

* rendering/RenderTextFragment.cpp:
(WebCore::RenderTextFragment::setText): Use text().length().
* rendering/RenderTextLineBoxes.cpp:
(WebCore::RenderTextLineBoxes::caretMaxOffset const): Ditto.
(WebCore::RenderTextLineBoxes::positionForPoint const): Ditto.
(WebCore::RenderTextLineBoxes::setSelectionState): Ditto.
(WebCore::RenderTextLineBoxes::absoluteQuads const): Ditto.
* rendering/SimpleLineLayout.cpp:
(WebCore::SimpleLineLayout::canUseForFontAndText): Ditto.
* rendering/SimpleLineLayoutCoverage.cpp:
(WebCore::SimpleLineLayout::textLengthForSubtree): Ditto.
(WebCore::SimpleLineLayout::collectNonEmptyLeafRenderBlockFlows): Ditto.
* rendering/SimpleLineLayoutFlowContents.cpp:
(WebCore::SimpleLineLayout::initializeSegments): Ditto.
* rendering/SimpleLineLayoutFunctions.cpp:
(WebCore::SimpleLineLayout::textOffsetForPoint): Ditto.
* rendering/SimpleLineLayoutFunctions.h:
(WebCore::SimpleLineLayout::findCaretMaximumOffset): Ditto.
* rendering/line/BreakingContext.h:
(WebCore::shouldAddBorderPaddingMargin): Ditto.
(WebCore::shouldSkipWhitespaceAfterStartObject): Ditto.
(WebCore::iteratorIsBeyondEndOfRenderCombineText): Ditto.
(WebCore::textWidth): Ditto.
(WebCore::BreakingContext::handleText): Ditto.
(WebCore::BreakingContext::optimalLineBreakLocationForTrailingWord): Ditto.
* rendering/line/TrailingObjects.cpp:
(WebCore::TrailingObjects::updateWhitespaceCollapsingTransitionsForTrailingBoxes): Ditto.

* rendering/mathml/RenderMathMLFenced.cpp:
(WebCore::RenderMathMLFenced::updateFromElement): Removed stray use of "unsigned int".

* rendering/svg/RenderSVGInlineText.cpp:
(WebCore::RenderSVGInlineText::characterStartsNewTextChunk const): Use text().length().
(WebCore::RenderSVGInlineText::positionForPoint): Ditto.
* rendering/svg/SVGTextLayoutAttributesBuilder.cpp:
(WebCore::processRenderSVGInlineText): Ditto.
* rendering/svg/SVGTextLayoutEngine.cpp:
(WebCore::SVGTextLayoutEngine::currentLogicalCharacterAttributes): Ditto.
* rendering/svg/SVGTextQuery.cpp:
(WebCore::SVGTextQuery::modifyStartEndPositionsRespectingLigatures const): Ditto.

* style/RenderTreeUpdater.cpp:
(WebCore::RenderTreeUpdater::updateRenderTree): Use isAllSpecialCharacters<isHTMLSpace>.
(WebCore::RenderTreeUpdater::textRendererIsNeeded): Ditto.

* svg/SVGTests.cpp:
(WebCore::SVGTests::hasFeatureForLegacyBindings): Use startsWithLettersIgnoringASCIICase.
* xml/parser/XMLDocumentParserLibxml2.cpp:
(WebCore::shouldAllowExternalLoad): Ditto.

Source/WebKit:

* NetworkProcess/cache/NetworkCache.cpp:
(WebKit::NetworkCache::isMediaMIMEType): Use startsWithLettersIgnoringASCIICase.
* NetworkProcess/cache/NetworkCacheKey.cpp:
(WebKit::NetworkCache::hashString): Use isAllASCII..
* UIProcess/API/C/WKWebsitePolicies.cpp:
(WKWebsitePoliciesSetCustomHeaderFields): Use startsWithLettersIgnoringASCIICase..
* UIProcess/API/Cocoa/_WKWebsitePolicies.mm:
(-[_WKWebsitePolicies setCustomHeaderFields:]): Ditto.
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::savePDFToFileInDownloadsFolder): Use endsWithIgnoringASCIICase.
* UIProcess/WebPreferences.cpp:
(WebKit::WebPreferences::WebPreferences): Initialize m_identifier explicitly. Somehow
changing the String default constructor to be "= default" led to a warning that we
otherwise did not get about not initializing m_identifier. Arguably a compiler bug,
but legitimately strange that the copy constructor does not copy m_identifier and so
nice to be explicit about it, I guess.
* UIProcess/mac/WebPageProxyMac.mm:
(WebKit::WebPageProxy::savePDFToTemporaryFolderAndOpenWithNativeApplicationRaw): Use
endsWithIgnoringASCIICase.
(WebKit::WebPageProxy::openPDFFromTemporaryFolderWithNativeApplication): Ditto.
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::createPlugin): Ditto.
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::platformEditorState const): Use isAllSpecialCharacters<isHTMLSpace>.

Source/WebKitLegacy/mac:

* History/BinaryPropertyList.cpp:
(BinaryPropertyListPlan::writeStringObject): Use isAllASCII.
(BinaryPropertyListSerializer::appendStringObject): Ditto.
* WebView/WebHTMLRepresentation.mm:
(regExpForLabels): Removed TextCaseSensitive since it is now the default.
(matchLabelsAgainstString): Use JSC::Yarr::TextCaseInsensitive.

Source/WebKitLegacy/win:

* Plugins/PluginDatabaseWin.cpp:
(WebCore::PluginDatabase::getPluginPathsInDirectories const): Use
startsWithLettersIgnoringASCIICase and endsWithIgnoringASCIICase.
* WebDownloadCFNet.cpp:
(WebDownload::initToResumeWithBundle): Use endsWithIgnoringASCIICase.

* WebView.cpp:
(WebView::markAllMatchesForText): Fix old code that was passing TextCaseSensitivity
to a function that actually takes FindOptions. By luck, TextCaseSensitive happens to
be 0, which is correct FindOptions for case sensitive matching, and TextCaseInsensitive
happens to be 1, which is correct FindOptions for case insensitive matching, so fixing
the code does not cause any change in behavior.

Source/WTF:

* wtf/text/ASCIIFastPath.h: Moved the using for charactersAreAllASCII here since
the function is defined here.

* wtf/text/AtomicString.h: Removed overloads of contains, find, startsWith, and
endsWith that take a boolean indicating whether they should be "case sensitive".
When false, this was doing Unicode case folding, and no callers needed that.
Also tweaked formatting and argument names.

* wtf/text/IntegerToStringConversion.h: Added an include of LChar.h since this file
uses that. Also tweaked formatting a bit.

* wtf/text/StringImpl.cpp:
(WTF::StringImpl::containsOnlyWhitespace): Deleted. Despite its name sounding like
it used the full Unicode whitespace definition, this actually checked isASCIISpace.
Callers now all use isAllSpecialCharacters instead with the whitespace definition
that is appropriate to each call site.
(WTF::latin1CaseFoldTable): Deleted.
(WTF::equalCompatibilityCaseless): Deleted.
(WTF::StringImpl::findIgnoringCase): Deleted.
(WTF::findIgnoringCaseInner): Deleted.
(WTF::reverseFindIgnoringCaseInner): Deleted.
(WTF::StringImpl::reverseFindIgnoringCase): Deleted.
(WTF::equalInner): Removed boolean caseSensitive argument.
(WTF::StringImpl::startsWith): Ditto.
(WTF::StringImpl::endsWith): Ditto.

* wtf/text/StringImpl.h: Moved TextCaseSensitivity out into a different header.
Moved ASCIIFastPath.h include here from WTFString.h. Moved isAllSpecialCharacters
free function here from WTFString.h. Moved lots of function bodies out of class
definitions to make the class definitions easier to read. Sorted things a bit.
Tweaked formatting. Marked constructor that takes one argument explicit. Added
an isEmpty function like the one in String. Renamed copyChars to copyCharacters.
Added isAllASCII, isAllLatin1 and isAllSpecialCharacters functions. Removed
boolean caseSensitive arguments from various functions. Removed findIgnoringCase
and reverseFindIgnoringCase. Added a FIXME to codePointCompare about the way it
treats null and empty strings as equal. Changed length argument in remove to
unsigned to match other lengths.

* wtf/text/WTFString.cpp:
(WTF::String::removeInternal): Changed length argument to be unsigned.
(WTF::createWithFormatAndArguments): Use emptyString.
(WTF::String::isSafeToSendToAnotherThread const): Rewrote to be easier to read.

* wtf/text/WTFString.h: Moved ASCIIFastPath.h to StringImpl.h. Moved lots of
function bodies out of class definitions to make the class definitions easier
to read, made others one-liners. Removed the String::at function but kept the
String::characterAt function; the two were identical. Removed boolean
caseSensitive arguments from various functions. Removed findIgnoringCase and
reverseFindIgnoringCase. Renamed containsOnlyASCII to isAllASCII and
containsOnlyLatin1 to isAllLatin1 to match the naming of isAllSpecialCharacters.
Moved the inline implementations of functions that are defined above further
down, after things like the ASCIILiteral class and various functions.

* wtf/text/icu/UTextProviderLatin1.cpp: Updated name of copyChars.

Tools:

* DumpRenderTree/mac/DumpRenderTree.mm:
(changeWindowScaleIfNeeded): Use containsIgnoringASCIICase.
* WebKitTestRunner/TestInvocation.cpp:
(WTR::TestInvocation::urlContains const): Ditto.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225117 268f45cc-cd09-0410-ab3c-d52691b4dbfc

137 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp
Source/JavaScriptCore/runtime/JSString.cpp
Source/JavaScriptCore/runtime/StringPrototype.cpp
Source/JavaScriptCore/yarr/RegularExpression.h
Source/WTF/ChangeLog
Source/WTF/wtf/text/ASCIIFastPath.h
Source/WTF/wtf/text/AtomicString.h
Source/WTF/wtf/text/IntegerToStringConversion.h
Source/WTF/wtf/text/StringImpl.cpp
Source/WTF/wtf/text/StringImpl.h
Source/WTF/wtf/text/StringView.h
Source/WTF/wtf/text/WTFString.cpp
Source/WTF/wtf/text/WTFString.h
Source/WTF/wtf/text/icu/UTextProviderLatin1.cpp
Source/WebCore/ChangeLog
Source/WebCore/Modules/plugins/YouTubePluginReplacement.cpp
Source/WebCore/Modules/websockets/WebSocketHandshake.cpp
Source/WebCore/accessibility/AXObjectCache.cpp
Source/WebCore/accessibility/AccessibilityList.cpp
Source/WebCore/accessibility/AccessibilityNodeObject.cpp
Source/WebCore/accessibility/AccessibilityObject.cpp
Source/WebCore/accessibility/AccessibilityRenderObject.cpp
Source/WebCore/accessibility/atk/AccessibilityObjectAtk.cpp
Source/WebCore/bindings/js/JSDOMConvertStrings.cpp
Source/WebCore/contentextensions/ContentExtensionParser.cpp
Source/WebCore/contentextensions/ContentExtensionsBackend.cpp
Source/WebCore/contentextensions/URLFilterParser.cpp
Source/WebCore/css/CSSFontFaceSrcValue.cpp
Source/WebCore/css/DOMCSSNamespace.cpp
Source/WebCore/css/parser/CSSPropertyParser.cpp
Source/WebCore/dom/CharacterData.cpp
Source/WebCore/dom/CharacterData.h
Source/WebCore/dom/DataTransfer.cpp
Source/WebCore/dom/Position.cpp
Source/WebCore/editing/Editor.cpp
Source/WebCore/editing/FrameSelection.cpp
Source/WebCore/editing/TextIterator.cpp
Source/WebCore/editing/TextIterator.h
Source/WebCore/editing/TypingCommand.cpp
Source/WebCore/editing/VisibleUnits.cpp
Source/WebCore/editing/cocoa/HTMLConverter.mm
Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm
Source/WebCore/html/Autofill.cpp
Source/WebCore/html/BaseTextInputType.cpp
Source/WebCore/html/EmailInputType.cpp
Source/WebCore/html/HTMLObjectElement.cpp
Source/WebCore/html/TypeAhead.cpp
Source/WebCore/html/parser/HTMLConstructionSite.cpp
Source/WebCore/html/parser/HTMLMetaCharsetParser.cpp
Source/WebCore/html/parser/XSSAuditor.cpp
Source/WebCore/html/track/WebVTTParser.cpp
Source/WebCore/inspector/InspectorNodeFinder.cpp
Source/WebCore/inspector/InspectorStyleSheet.cpp
Source/WebCore/inspector/agents/InspectorDOMAgent.cpp
Source/WebCore/inspector/agents/InspectorDOMAgent.h
Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp
Source/WebCore/page/Base64Utilities.cpp
Source/WebCore/page/Frame.cpp
Source/WebCore/page/FrameView.cpp
Source/WebCore/page/SecurityOrigin.cpp
Source/WebCore/page/UserContentURLPattern.cpp
Source/WebCore/page/csp/ContentSecurityPolicySource.cpp
Source/WebCore/page/csp/ContentSecurityPolicySourceList.cpp
Source/WebCore/page/ios/FrameIOS.mm
Source/WebCore/platform/ContentType.cpp
Source/WebCore/platform/MIMETypeRegistry.cpp
Source/WebCore/platform/URL.cpp
Source/WebCore/platform/URLParser.cpp
Source/WebCore/platform/URLParser.h
Source/WebCore/platform/graphics/MediaPlayer.cpp
Source/WebCore/platform/graphics/avfoundation/CDMPrivateMediaSourceAVFObjC.mm
Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp
Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp
Source/WebCore/platform/mac/PublicSuffixMac.mm
Source/WebCore/platform/mac/SSLKeyGeneratorMac.mm
Source/WebCore/platform/mac/StringUtilities.mm
Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp
Source/WebCore/platform/network/CacheValidation.cpp
Source/WebCore/platform/network/HTTPParsers.cpp
Source/WebCore/platform/network/curl/AuthenticationChallengeCurl.cpp
Source/WebCore/platform/network/curl/MultipartHandle.cpp
Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.cpp
Source/WebCore/platform/network/curl/ResourceResponseCurl.cpp
Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp
Source/WebCore/rendering/BidiRun.cpp
Source/WebCore/rendering/HitTestResult.cpp
Source/WebCore/rendering/InlineFlowBox.cpp
Source/WebCore/rendering/InlineIterator.h
Source/WebCore/rendering/InlineTextBox.cpp
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderBlockFlow.cpp
Source/WebCore/rendering/RenderBlockLineLayout.cpp
Source/WebCore/rendering/RenderCombineText.cpp
Source/WebCore/rendering/RenderLayer.cpp
Source/WebCore/rendering/RenderListBox.cpp
Source/WebCore/rendering/RenderMenuList.cpp
Source/WebCore/rendering/RenderText.cpp
Source/WebCore/rendering/RenderText.h
Source/WebCore/rendering/RenderTextFragment.cpp
Source/WebCore/rendering/RenderTextLineBoxes.cpp
Source/WebCore/rendering/SimpleLineLayout.cpp
Source/WebCore/rendering/SimpleLineLayoutCoverage.cpp
Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp
Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp
Source/WebCore/rendering/SimpleLineLayoutFunctions.h
Source/WebCore/rendering/line/BreakingContext.h
Source/WebCore/rendering/line/TrailingObjects.cpp
Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp
Source/WebCore/rendering/svg/RenderSVGInlineText.cpp
Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp
Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp
Source/WebCore/rendering/svg/SVGTextQuery.cpp
Source/WebCore/style/RenderTreeUpdater.cpp
Source/WebCore/svg/SVGTests.cpp
Source/WebCore/xml/parser/XMLDocumentParserLibxml2.cpp
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/cache/NetworkCache.cpp
Source/WebKit/NetworkProcess/cache/NetworkCacheKey.cpp
Source/WebKit/UIProcess/API/C/WKWebsitePolicies.cpp
Source/WebKit/UIProcess/API/Cocoa/_WKWebsitePolicies.mm
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPreferences.cpp
Source/WebKit/UIProcess/mac/WebPageProxyMac.mm
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm
Source/WebKitLegacy/mac/ChangeLog
Source/WebKitLegacy/mac/History/BinaryPropertyList.cpp
Source/WebKitLegacy/mac/WebView/WebHTMLRepresentation.mm
Source/WebKitLegacy/win/ChangeLog
Source/WebKitLegacy/win/Plugins/PluginDatabaseWin.cpp
Source/WebKitLegacy/win/WebDownloadCFNet.cpp
Source/WebKitLegacy/win/WebView.cpp
Tools/ChangeLog
Tools/DumpRenderTree/mac/DumpRenderTree.mm
Tools/WebKitTestRunner/TestInvocation.cpp

index 2f2f1ac..ceeb7f8 100644 (file)
@@ -1,3 +1,22 @@
+2017-11-23  Darin Adler  <darin@apple.com>
+
+        Reduce WTF::String operations that do unnecessary Unicode operations instead of ASCII
+        https://bugs.webkit.org/show_bug.cgi?id=179907
+
+        Reviewed by Sam Weinig.
+
+        * inspector/agents/InspectorDebuggerAgent.cpp:
+        (Inspector::matches): Removed explicit TextCaseSensitive because RegularExpression now
+        defaults to that.
+
+        * runtime/StringPrototype.cpp:
+        (JSC::stringIncludesImpl): Use String::find since there is no overload of
+        String::contains that takes a start offset now that we removed the one that took a
+        caseSensitive boolean. We can add one later if we like, but this should do for now.
+
+        * yarr/RegularExpression.h: Moved the TextCaseSensitivity enumeration here from
+        the StringImpl.h header because it is only used here.
+
 2017-11-22  Simon Fraser  <simon.fraser@apple.com>
 
         Followup after r225084: if anyone called GenericTypedArrayView() it didn't compile,
index 84370b1..3b367ff 100644 (file)
@@ -335,7 +335,7 @@ static Ref<InspectorObject> buildObjectForBreakpointCookie(const String& url, in
 static bool matches(const String& url, const String& pattern, bool isRegex)
 {
     if (isRegex) {
-        JSC::Yarr::RegularExpression regex(pattern, TextCaseSensitive);
+        JSC::Yarr::RegularExpression regex(pattern);
         return regex.match(url) != -1;
     }
     return url == pattern;
index fdeda1d..2065275 100644 (file)
@@ -117,8 +117,7 @@ static const unsigned maxLengthForOnStackResolve = 2048;
 void JSRopeString::resolveRopeInternal8(LChar* buffer) const
 {
     if (isSubstring()) {
-        StringImpl::copyChars(
-            buffer, substringBase()->m_value.characters8() + substringOffset(), length());
+        StringImpl::copyCharacters(buffer, substringBase()->m_value.characters8() + substringOffset(), length());
         return;
     }
     
@@ -138,7 +137,7 @@ void JSRopeString::resolveRopeInternal8NoSubstring(LChar* buffer) const
     for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) {
         const StringImpl& fiberString = *fiber(i)->m_value.impl();
         unsigned length = fiberString.length();
-        StringImpl::copyChars(position, fiberString.characters8(), length);
+        StringImpl::copyCharacters(position, fiberString.characters8(), length);
         position += length;
     }
     ASSERT((buffer + length()) == position);
@@ -147,7 +146,7 @@ void JSRopeString::resolveRopeInternal8NoSubstring(LChar* buffer) const
 void JSRopeString::resolveRopeInternal16(UChar* buffer) const
 {
     if (isSubstring()) {
-        StringImpl::copyChars(
+        StringImpl::copyCharacters(
             buffer, substringBase()->m_value.characters16() + substringOffset(), length());
         return;
     }
@@ -169,9 +168,9 @@ void JSRopeString::resolveRopeInternal16NoSubstring(UChar* buffer) const
         const StringImpl& fiberString = *fiber(i)->m_value.impl();
         unsigned length = fiberString.length();
         if (fiberString.is8Bit())
-            StringImpl::copyChars(position, fiberString.characters8(), length);
+            StringImpl::copyCharacters(position, fiberString.characters8(), length);
         else
-            StringImpl::copyChars(position, fiberString.characters16(), length);
+            StringImpl::copyCharacters(position, fiberString.characters16(), length);
         position += length;
     }
     ASSERT((buffer + length()) == position);
@@ -335,7 +334,7 @@ void JSRopeString::resolveRopeSlowCase8(LChar* buffer) const
         
         unsigned length = currentFiber->length();
         position -= length;
-        StringImpl::copyChars(position, characters, length);
+        StringImpl::copyCharacters(position, characters, length);
     }
 
     ASSERT(buffer == position);
@@ -363,9 +362,9 @@ void JSRopeString::resolveRopeSlowCase(UChar* buffer) const
                 unsigned length = currentFiberAsRope->length();
                 position -= length;
                 if (string->is8Bit())
-                    StringImpl::copyChars(position, string->characters8() + offset, length);
+                    StringImpl::copyCharacters(position, string->characters8() + offset, length);
                 else
-                    StringImpl::copyChars(position, string->characters16() + offset, length);
+                    StringImpl::copyCharacters(position, string->characters16() + offset, length);
                 continue;
             }
             for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->fiber(i); ++i)
@@ -377,9 +376,9 @@ void JSRopeString::resolveRopeSlowCase(UChar* buffer) const
         unsigned length = string->length();
         position -= length;
         if (string->is8Bit())
-            StringImpl::copyChars(position, string->characters8(), length);
+            StringImpl::copyCharacters(position, string->characters8(), length);
         else
-            StringImpl::copyChars(position, string->characters16(), length);
+            StringImpl::copyCharacters(position, string->characters16(), length);
     }
 
     ASSERT(buffer == position);
index adbfad2..051e905 100644 (file)
@@ -341,7 +341,7 @@ static ALWAYS_INLINE JSValue jsSpliceSubstrings(ExecState* exec, JSString* sourc
         int bufferPos = 0;
         for (int i = 0; i < rangeCount; i++) {
             if (int srcLen = substringRanges[i].length) {
-                StringImpl::copyChars(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
+                StringImpl::copyCharacters(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
                 bufferPos += srcLen;
             }
         }
@@ -360,7 +360,7 @@ static ALWAYS_INLINE JSValue jsSpliceSubstrings(ExecState* exec, JSString* sourc
     int bufferPos = 0;
     for (int i = 0; i < rangeCount; i++) {
         if (int srcLen = substringRanges[i].length) {
-            StringImpl::copyChars(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
+            StringImpl::copyCharacters(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
             bufferPos += srcLen;
         }
     }
@@ -413,13 +413,13 @@ static ALWAYS_INLINE JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, J
         for (int i = 0; i < maxCount; i++) {
             if (i < rangeCount) {
                 if (int srcLen = substringRanges[i].length) {
-                    StringImpl::copyChars(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
+                    StringImpl::copyCharacters(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
                     bufferPos += srcLen;
                 }
             }
             if (i < separatorCount) {
                 if (int sepLen = separators[i].length()) {
-                    StringImpl::copyChars(buffer + bufferPos, separators[i].characters8(), sepLen);
+                    StringImpl::copyCharacters(buffer + bufferPos, separators[i].characters8(), sepLen);
                     bufferPos += sepLen;
                 }
             }
@@ -440,18 +440,18 @@ static ALWAYS_INLINE JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, J
         if (i < rangeCount) {
             if (int srcLen = substringRanges[i].length) {
                 if (source.is8Bit())
-                    StringImpl::copyChars(buffer + bufferPos, source.characters8() + substringRanges[i].position, srcLen);
+                    StringImpl::copyCharacters(buffer + bufferPos, source.characters8() + substringRanges[i].position, srcLen);
                 else
-                    StringImpl::copyChars(buffer + bufferPos, source.characters16() + substringRanges[i].position, srcLen);
+                    StringImpl::copyCharacters(buffer + bufferPos, source.characters16() + substringRanges[i].position, srcLen);
                 bufferPos += srcLen;
             }
         }
         if (i < separatorCount) {
             if (int sepLen = separators[i].length()) {
                 if (separators[i].is8Bit())
-                    StringImpl::copyChars(buffer + bufferPos, separators[i].characters8(), sepLen);
+                    StringImpl::copyCharacters(buffer + bufferPos, separators[i].characters8(), sepLen);
                 else
-                    StringImpl::copyChars(buffer + bufferPos, separators[i].characters16(), sepLen);
+                    StringImpl::copyCharacters(buffer + bufferPos, separators[i].characters16(), sepLen);
                 bufferPos += sepLen;
             }
         }
@@ -1799,7 +1799,7 @@ static EncodedJSValue JSC_HOST_CALL stringIncludesImpl(VM& vm, ExecState* exec,
         RETURN_IF_EXCEPTION(scope, encodedJSValue());
     }
 
-    return JSValue::encode(jsBoolean(stringToSearchIn.contains(searchString, true, start)));
+    return JSValue::encode(jsBoolean(stringToSearchIn.find(searchString, start) != notFound));
 }
 
 EncodedJSValue JSC_HOST_CALL stringProtoFuncIncludes(ExecState* exec)
@@ -1900,7 +1900,7 @@ static JSValue normalize(ExecState* exec, const UChar* source, size_t sourceLeng
 
     if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) {
         // The behavior is not specified when normalize fails.
-        // Now we throw a type erorr since it seems that the contents of the string are invalid.
+        // Now we throw a type error since it seems that the contents of the string are invalid.
         return throwTypeError(exec, scope);
     }
 
index 2842774..207390b 100644 (file)
 
 namespace JSC { namespace Yarr {
 
-enum MultilineMode {
-    MultilineDisabled,
-    MultilineEnabled
-};
+enum MultilineMode { MultilineDisabled, MultilineEnabled };
+enum TextCaseSensitivity { TextCaseSensitive, TextCaseInsensitive };
 
 class JS_EXPORT_PRIVATE RegularExpression {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    RegularExpression(const String&, TextCaseSensitivity, MultilineMode = MultilineDisabled);
+    explicit RegularExpression(const String&, TextCaseSensitivity = TextCaseSensitive, MultilineMode = MultilineDisabled);
     ~RegularExpression();
 
     RegularExpression(const RegularExpression&);
index ef246cf..c13ecb4 100644 (file)
@@ -1,3 +1,65 @@
+2017-11-23  Darin Adler  <darin@apple.com>
+
+        Reduce WTF::String operations that do unnecessary Unicode operations instead of ASCII
+        https://bugs.webkit.org/show_bug.cgi?id=179907
+
+        Reviewed by Sam Weinig.
+
+        * wtf/text/ASCIIFastPath.h: Moved the using for charactersAreAllASCII here since
+        the function is defined here.
+
+        * wtf/text/AtomicString.h: Removed overloads of contains, find, startsWith, and
+        endsWith that take a boolean indicating whether they should be "case sensitive".
+        When false, this was doing Unicode case folding, and no callers needed that.
+        Also tweaked formatting and argument names.
+
+        * wtf/text/IntegerToStringConversion.h: Added an include of LChar.h since this file
+        uses that. Also tweaked formatting a bit.
+
+        * wtf/text/StringImpl.cpp:
+        (WTF::StringImpl::containsOnlyWhitespace): Deleted. Despite its name sounding like
+        it used the full Unicode whitespace definition, this actually checked isASCIISpace.
+        Callers now all use isAllSpecialCharacters instead with the whitespace definition
+        that is appropriate to each call site.
+        (WTF::latin1CaseFoldTable): Deleted.
+        (WTF::equalCompatibilityCaseless): Deleted.
+        (WTF::StringImpl::findIgnoringCase): Deleted.
+        (WTF::findIgnoringCaseInner): Deleted.
+        (WTF::reverseFindIgnoringCaseInner): Deleted.
+        (WTF::StringImpl::reverseFindIgnoringCase): Deleted.
+        (WTF::equalInner): Removed boolean caseSensitive argument.
+        (WTF::StringImpl::startsWith): Ditto.
+        (WTF::StringImpl::endsWith): Ditto.
+
+        * wtf/text/StringImpl.h: Moved TextCaseSensitivity out into a different header.
+        Moved ASCIIFastPath.h include here from WTFString.h. Moved isAllSpecialCharacters
+        free function here from WTFString.h. Moved lots of function bodies out of class
+        definitions to make the class definitions easier to read. Sorted things a bit.
+        Tweaked formatting. Marked constructor that takes one argument explicit. Added
+        an isEmpty function like the one in String. Renamed copyChars to copyCharacters.
+        Added isAllASCII, isAllLatin1 and isAllSpecialCharacters functions. Removed
+        boolean caseSensitive arguments from various functions. Removed findIgnoringCase
+        and reverseFindIgnoringCase. Added a FIXME to codePointCompare about the way it
+        treats null and empty strings as equal. Changed length argument in remove to
+        unsigned to match other lengths.
+
+        * wtf/text/WTFString.cpp:
+        (WTF::String::removeInternal): Changed length argument to be unsigned.
+        (WTF::createWithFormatAndArguments): Use emptyString.
+        (WTF::String::isSafeToSendToAnotherThread const): Rewrote to be easier to read.
+
+        * wtf/text/WTFString.h: Moved ASCIIFastPath.h to StringImpl.h. Moved lots of
+        function bodies out of class definitions to make the class definitions easier
+        to read, made others one-liners. Removed the String::at function but kept the
+        String::characterAt function; the two were identical. Removed boolean
+        caseSensitive arguments from various functions. Removed findIgnoringCase and
+        reverseFindIgnoringCase. Renamed containsOnlyASCII to isAllASCII and
+        containsOnlyLatin1 to isAllLatin1 to match the naming of isAllSpecialCharacters.
+        Moved the inline implementations of functions that are defined above further
+        down, after things like the ASCIILiteral class and various functions.
+
+        * wtf/text/icu/UTextProviderLatin1.cpp: Updated name of copyChars.
+
 2017-11-22  Stephan Szabo  <stephan.szabo@sony.com>
 
         tuple related items are used in WTF without including tuple
index eb54828..2642a5b 100644 (file)
@@ -194,4 +194,6 @@ inline void copyLCharsFromUCharSource(LChar* destination, const UChar* source, s
 
 } // namespace WTF
 
+using WTF::charactersAreAllASCII;
+
 #endif // ASCIIFastPath_h
index 7658e05..b863ab0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004-2006, 2008, 2014-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -72,8 +72,7 @@ public:
     {
     }
 
-    template<unsigned characterCount>
-    ALWAYS_INLINE AtomicString(const char (&characters)[characterCount], ConstructFromLiteralTag)
+    template<unsigned characterCount> ALWAYS_INLINE AtomicString(const char (&characters)[characterCount], ConstructFromLiteralTag)
         : m_string(AtomicStringImpl::addLiteral(characters, characterCount - 1))
     {
         COMPILE_ASSERT(characterCount > 1, AtomicStringFromLiteralNotEmpty);
@@ -112,51 +111,27 @@ public:
     WTF_EXPORT_STRING_API static AtomicString number(double);
     // If we need more overloads of the number function, we can add all the others that String has, but these seem to do for now.
 
-    bool contains(UChar c) const { return m_string.contains(c); }
-    bool contains(const LChar* s, bool caseSensitive = true) const
-        { return m_string.contains(s, caseSensitive); }
-    bool contains(const String& s) const
-        { return m_string.contains(s); }
-    bool contains(const String& s, bool caseSensitive) const
-        { return m_string.contains(s, caseSensitive); }
-    bool containsIgnoringASCIICase(const String& s) const
-        { return m_string.containsIgnoringASCIICase(s); }
-
-    size_t find(UChar c, unsigned start = 0) const { return m_string.find(c, start); }
-    size_t find(const LChar* s, unsigned start = 0, bool caseSentitive = true) const
-        { return m_string.find(s, start, caseSentitive); }
-    size_t find(const String& s, unsigned start = 0, bool caseSentitive = true) const
-        { return m_string.find(s, start, caseSentitive); }
-    size_t findIgnoringASCIICase(const String& s) const
-        { return m_string.findIgnoringASCIICase(s); }
-    size_t findIgnoringASCIICase(const String& s, unsigned startOffset) const
-        { return m_string.findIgnoringASCIICase(s, startOffset); }
-    size_t find(CharacterMatchFunctionPtr matchFunction, unsigned start = 0) const
-        { return m_string.find(matchFunction, start); }
-
-    bool startsWith(const String& s) const
-        { return m_string.startsWith(s); }
-    bool startsWithIgnoringASCIICase(const String& s) const
-        { return m_string.startsWithIgnoringASCIICase(s); }
-    bool startsWith(const String& s, bool caseSensitive) const
-        { return m_string.startsWith(s, caseSensitive); }
-    bool startsWith(UChar character) const
-        { return m_string.startsWith(character); }
-    template<unsigned matchLength>
-    bool startsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const
-        { return m_string.startsWith<matchLength>(prefix, caseSensitive); }
-
-    bool endsWith(const String& s) const
-        { return m_string.endsWith(s); }
-    bool endsWithIgnoringASCIICase(const String& s) const
-        { return m_string.endsWithIgnoringASCIICase(s); }
-    bool endsWith(const String& s, bool caseSensitive) const
-        { return m_string.endsWith(s, caseSensitive); }
-    bool endsWith(UChar character) const
-        { return m_string.endsWith(character); }
-    template<unsigned matchLength>
-    bool endsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const
-        { return m_string.endsWith<matchLength>(prefix, caseSensitive); }
+    bool contains(UChar character) const { return m_string.contains(character); }
+    bool contains(const LChar* string) const { return m_string.contains(string); }
+    bool contains(const String& string) const { return m_string.contains(string); }
+    bool containsIgnoringASCIICase(const String& string) const { return m_string.containsIgnoringASCIICase(string); }
+
+    size_t find(UChar character, unsigned start = 0) const { return m_string.find(character, start); }
+    size_t find(const LChar* string, unsigned start = 0) const { return m_string.find(string, start); }
+    size_t find(const String& string, unsigned start = 0) const { return m_string.find(string, start); }
+    size_t findIgnoringASCIICase(const String& string) const { return m_string.findIgnoringASCIICase(string); }
+    size_t findIgnoringASCIICase(const String& string, unsigned startOffset) const { return m_string.findIgnoringASCIICase(string, startOffset); }
+    size_t find(CharacterMatchFunctionPtr matchFunction, unsigned start = 0) const { return m_string.find(matchFunction, start); }
+
+    bool startsWith(const String& string) const { return m_string.startsWith(string); }
+    bool startsWithIgnoringASCIICase(const String& string) const { return m_string.startsWithIgnoringASCIICase(string); }
+    bool startsWith(UChar character) const { return m_string.startsWith(character); }
+    template<unsigned matchLength> bool startsWith(const char (&prefix)[matchLength]) const { return m_string.startsWith<matchLength>(prefix); }
+
+    bool endsWith(const String& string) const { return m_string.endsWith(string); }
+    bool endsWithIgnoringASCIICase(const String& string) const { return m_string.endsWithIgnoringASCIICase(string); }
+    bool endsWith(UChar character) const { return m_string.endsWith(character); }
+    template<unsigned matchLength> bool endsWith(const char (&prefix)[matchLength]) const { return m_string.endsWith<matchLength>(prefix); }
 
     WTF_EXPORT_STRING_API AtomicString convertToASCIILowercase() const;
     WTF_EXPORT_STRING_API AtomicString convertToASCIIUppercase() const;
@@ -172,13 +147,13 @@ public:
 #if USE(CF)
     AtomicString(CFStringRef);
 #endif
+
 #ifdef __OBJC__
     AtomicString(NSString*);
     operator NSString*() const { return m_string; }
 #endif
 
-    // AtomicString::fromUTF8 will return a null string if
-    // the input data contains invalid UTF-8 sequences.
+    // AtomicString::fromUTF8 will return a null string if the input data contains invalid UTF-8 sequences.
     static AtomicString fromUTF8(const char*, size_t);
     static AtomicString fromUTF8(const char*);
 
@@ -229,53 +204,53 @@ inline AtomicString::AtomicString()
 {
 }
 
-inline AtomicString::AtomicString(const LChar* s)
-    : m_string(AtomicStringImpl::add(s))
+inline AtomicString::AtomicString(const LChar* string)
+    : m_string(AtomicStringImpl::add(string))
 {
 }
 
-inline AtomicString::AtomicString(const char* s)
-    : m_string(AtomicStringImpl::add(s))
+inline AtomicString::AtomicString(const char* string)
+    : m_string(AtomicStringImpl::add(string))
 {
 }
 
-inline AtomicString::AtomicString(const LChar* s, unsigned length)
-    : m_string(AtomicStringImpl::add(s, length))
+inline AtomicString::AtomicString(const LChar* string, unsigned length)
+    : m_string(AtomicStringImpl::add(string, length))
 {
 }
 
-inline AtomicString::AtomicString(const UChar* s, unsigned length)
-    : m_string(AtomicStringImpl::add(s, length))
+inline AtomicString::AtomicString(const UChar* string, unsigned length)
+    : m_string(AtomicStringImpl::add(string, length))
 {
 }
 
-inline AtomicString::AtomicString(const UChar* s)
-    : m_string(AtomicStringImpl::add(s))
+inline AtomicString::AtomicString(const UChar* string)
+    : m_string(AtomicStringImpl::add(string))
 {
 }
 
-inline AtomicString::AtomicString(AtomicStringImpl* imp)
-    : m_string(imp)
+inline AtomicString::AtomicString(AtomicStringImpl* string)
+    : m_string(string)
 {
 }
 
-inline AtomicString::AtomicString(RefPtr<AtomicStringImpl>&& imp)
-    : m_string(WTFMove(imp))
+inline AtomicString::AtomicString(RefPtr<AtomicStringImpl>&& string)
+    : m_string(WTFMove(string))
 {
 }
 
-inline AtomicString::AtomicString(StringImpl* imp)
-    : m_string(AtomicStringImpl::add(imp))
+inline AtomicString::AtomicString(StringImpl* string)
+    : m_string(AtomicStringImpl::add(string))
 {
 }
 
-inline AtomicString::AtomicString(const StaticStringImpl* imp)
-    : m_string(AtomicStringImpl::add(imp))
+inline AtomicString::AtomicString(const StaticStringImpl* string)
+    : m_string(AtomicStringImpl::add(string))
 {
 }
 
-inline AtomicString::AtomicString(const String& s)
-    : m_string(AtomicStringImpl::add(s.impl()))
+inline AtomicString::AtomicString(const String& string)
+    : m_string(AtomicStringImpl::add(string.impl()))
 {
 }
 
@@ -290,17 +265,21 @@ inline AtomicString::AtomicString(UniquedStringImpl* uid)
 }
 
 #if USE(CF)
-inline AtomicString::AtomicString(CFStringRef s)
-    :  m_string(AtomicStringImpl::add(s))
+
+inline AtomicString::AtomicString(CFStringRef string)
+    :  m_string(AtomicStringImpl::add(string))
 {
 }
+
 #endif
 
 #ifdef __OBJC__
-inline AtomicString::AtomicString(NSString* s)
-    : m_string(AtomicStringImpl::add((__bridge CFStringRef)s))
+
+inline AtomicString::AtomicString(NSString* string)
+    : m_string(AtomicStringImpl::add((__bridge CFStringRef)string))
 {
 }
+
 #endif
 
 // Define external global variables for the commonly used atomic strings.
index 61942e7..9db8303 100644 (file)
 #ifndef IntegerToStringConversion_h
 #define IntegerToStringConversion_h
 
+#include <wtf/text/LChar.h>
+
 namespace WTF {
 
-enum PositiveOrNegativeNumber {
-    PositiveNumber,
-    NegativeNumber
-};
+enum PositiveOrNegativeNumber { PositiveNumber, NegativeNumber };
 
-template<typename T> struct IntegerToStringConversionTrait;
+template<typename> struct IntegerToStringConversionTrait;
 
 template<typename T, typename UnsignedIntegerType, PositiveOrNegativeNumber NumberType, typename AdditionalArgumentType>
 static typename IntegerToStringConversionTrait<T>::ReturnType numberToStringImpl(UnsignedIntegerType number, AdditionalArgumentType additionalArgument)
@@ -63,7 +62,6 @@ inline typename IntegerToStringConversionTrait<T>::ReturnType numberToStringUnsi
     return numberToStringImpl<T, UnsignedIntegerType, PositiveNumber>(number, additionalArgument);
 }
 
-
 template<typename CharacterType, typename UnsignedIntegerType, PositiveOrNegativeNumber NumberType>
 static void writeNumberToBufferImpl(UnsignedIntegerType number, CharacterType* destination)
 {
@@ -97,7 +95,6 @@ inline void writeNumberToBufferUnsigned(UnsignedIntegerType number, CharacterTyp
     return writeNumberToBufferImpl<CharacterType, UnsignedIntegerType, PositiveNumber>(number, destination);
 }
 
-
 template<typename UnsignedIntegerType, PositiveOrNegativeNumber NumberType>
 static unsigned lengthOfNumberAsStringImpl(UnsignedIntegerType number)
 {
@@ -128,7 +125,6 @@ inline unsigned lengthOfNumberAsStringUnsigned(UnsignedIntegerType number)
     return lengthOfNumberAsStringImpl<UnsignedIntegerType, PositiveNumber>(number);
 }
 
-
 } // namespace WTF
 
 #endif // IntegerToStringConversion_h
index d17f39b..99eae09 100644 (file)
@@ -162,7 +162,6 @@ Ref<StringImpl> StringImpl::createWithoutCopying(const UChar* characters, unsign
 {
     if (!length)
         return *empty();
-
     return adoptRef(*new StringImpl(characters, length, ConstructWithoutCopying));
 }
 
@@ -170,12 +169,10 @@ Ref<StringImpl> StringImpl::createWithoutCopying(const LChar* characters, unsign
 {
     if (!length)
         return *empty();
-
     return adoptRef(*new StringImpl(characters, length, ConstructWithoutCopying));
 }
 
-template <typename CharType>
-inline Ref<StringImpl> StringImpl::createUninitializedInternal(unsigned length, CharType*& data)
+template<typename CharacterType> inline Ref<StringImpl> StringImpl::createUninitializedInternal(unsigned length, CharacterType*& data)
 {
     if (!length) {
         data = 0;
@@ -184,20 +181,19 @@ inline Ref<StringImpl> StringImpl::createUninitializedInternal(unsigned length,
     return createUninitializedInternalNonEmpty(length, data);
 }
 
-template <typename CharType>
-inline Ref<StringImpl> StringImpl::createUninitializedInternalNonEmpty(unsigned length, CharType*& data)
+template<typename CharacterType> inline Ref<StringImpl> StringImpl::createUninitializedInternalNonEmpty(unsigned length, CharacterType*& data)
 {
     ASSERT(length);
 
     // Allocate a single buffer large enough to contain the StringImpl
     // struct as well as the data which it contains. This removes one
     // heap allocation from this call.
-    if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(CharType)))
+    if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(CharacterType)))
         CRASH();
-    StringImpl* string = static_cast<StringImpl*>(stringMalloc(allocationSize<CharType>(length)));
+    StringImpl* string = static_cast<StringImpl*>(stringMalloc(allocationSize<CharacterType>(length)));
 
-    data = string->tailPointer<CharType>();
-    return constructInternal<CharType>(string, length);
+    data = string->tailPointer<CharacterType>();
+    return constructInternal<CharacterType>(*string, length);
 }
 
 Ref<StringImpl> StringImpl::createUninitialized(unsigned length, LChar*& data)
@@ -210,8 +206,7 @@ Ref<StringImpl> StringImpl::createUninitialized(unsigned length, UChar*& data)
     return createUninitializedInternal(length, data);
 }
 
-template <typename CharType>
-inline Ref<StringImpl> StringImpl::reallocateInternal(Ref<StringImpl>&& originalString, unsigned length, CharType*& data)
+template<typename CharacterType> inline Ref<StringImpl> StringImpl::reallocateInternal(Ref<StringImpl>&& originalString, unsigned length, CharacterType*& data)
 {
     ASSERT(originalString->hasOneRef());
     ASSERT(originalString->bufferOwnership() == BufferInternal);
@@ -222,14 +217,14 @@ inline Ref<StringImpl> StringImpl::reallocateInternal(Ref<StringImpl>&& original
     }
 
     // Same as createUninitialized() except here we use stringRealloc.
-    if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(CharType)))
+    if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(CharacterType)))
         CRASH();
 
     originalString->~StringImpl();
-    auto* string = static_cast<StringImpl*>(stringRealloc(&originalString.leakRef(), allocationSize<CharType>(length)));
+    auto* string = static_cast<StringImpl*>(stringRealloc(&originalString.leakRef(), allocationSize<CharacterType>(length)));
 
-    data = string->tailPointer<CharType>();
-    return constructInternal<CharType>(string, length);
+    data = string->tailPointer<CharacterType>();
+    return constructInternal<CharacterType>(*string, length);
 }
 
 Ref<StringImpl> StringImpl::reallocate(Ref<StringImpl>&& originalString, unsigned length, LChar*& data)
@@ -244,15 +239,13 @@ Ref<StringImpl> StringImpl::reallocate(Ref<StringImpl>&& originalString, unsigne
     return reallocateInternal(WTFMove(originalString), length, data);
 }
 
-template <typename CharType>
-inline Ref<StringImpl> StringImpl::createInternal(const CharType* characters, unsigned length)
+template<typename CharacterType> inline Ref<StringImpl> StringImpl::createInternal(const CharacterType* characters, unsigned length)
 {
     if (!characters || !length)
         return *empty();
-
-    CharType* data;
+    CharacterType* data;
     auto string = createUninitializedInternalNonEmpty(length, data);
-    memcpy(data, characters, length * sizeof(CharType));
+    copyCharacters(data, characters, length);
     return string;
 }
 
@@ -275,7 +268,7 @@ Ref<StringImpl> StringImpl::create8BitIfPossible(const UChar* characters, unsign
     auto string = createUninitializedInternalNonEmpty(length, data);
 
     for (size_t i = 0; i < length; ++i) {
-        if (characters[i] & 0xff00)
+        if (characters[i] & 0xFF00)
             return create(characters, length);
         data[i] = static_cast<LChar>(characters[i]);
     }
@@ -298,29 +291,6 @@ Ref<StringImpl> StringImpl::create(const LChar* string)
     return create(string, length);
 }
 
-bool StringImpl::containsOnlyWhitespace()
-{
-    // FIXME: Should rename this to containsOnlyASCIIWhitespace.
-    // Most WebKit callers instead want containsOnlyHTMLWhitespace which, unlike this,
-    // would *not* treat U+000B LINE TABULATION as a space.
-
-    if (is8Bit()) {
-        for (unsigned i = 0; i < m_length; ++i) {
-            UChar c = m_data8[i];
-            if (!isASCIISpace(c))
-                return false;
-        }
-        return true;
-    }
-
-    for (unsigned i = 0; i < m_length; ++i) {
-        UChar c = m_data16[i];
-        if (!isASCIISpace(c))
-            return false;
-    }
-    return true;
-}
-
 Ref<StringImpl> StringImpl::substring(unsigned start, unsigned length)
 {
     if (start >= m_length)
@@ -381,11 +351,8 @@ Ref<StringImpl> StringImpl::convertToLowercaseWithoutLocale()
     if (!(ored & ~0x7F)) {
         UChar* data16;
         auto newImpl = createUninitializedInternalNonEmpty(m_length, data16);
-        
-        for (unsigned i = 0; i < m_length; ++i) {
-            UChar c = m_data16[i];
-            data16[i] = toASCIILower(c);
-        }
+        for (unsigned i = 0; i < m_length; ++i)
+            data16[i] = toASCIILower(m_data16[i]);
         return newImpl;
     }
 
@@ -452,9 +419,9 @@ Ref<StringImpl> StringImpl::convertToUppercaseWithoutLocale()
         // Do a faster loop for the case where all the characters are ASCII.
         unsigned ored = 0;
         for (int i = 0; i < length; ++i) {
-            LChar c = m_data8[i];
-            ored |= c;
-            data8[i] = toASCIIUpper(c);
+            LChar character = m_data8[i];
+            ored |= character;
+            data8[i] = toASCIIUpper(character);
         }
         if (!(ored & ~0x7F))
             return newImpl;
@@ -466,11 +433,11 @@ Ref<StringImpl> StringImpl::convertToUppercaseWithoutLocale()
         //  1. Some Latin-1 characters when converted to upper case are 16 bit characters.
         //  2. Lower case sharp-S converts to "SS" (two characters)
         for (int32_t i = 0; i < length; ++i) {
-            LChar c = m_data8[i];
-            if (UNLIKELY(c == smallLetterSharpS))
+            LChar character = m_data8[i];
+            if (UNLIKELY(character == smallLetterSharpS))
                 ++numberSharpSCharacters;
-            ASSERT(u_toupper(c) <= 0xFFFF);
-            UChar upper = u_toupper(c);
+            ASSERT(u_toupper(character) <= 0xFFFF);
+            UChar upper = u_toupper(character);
             if (UNLIKELY(upper > 0xFF)) {
                 // Since this upper-cased character does not fit in an 8-bit string, we need to take the 16-bit path.
                 goto upconvert;
@@ -487,13 +454,13 @@ Ref<StringImpl> StringImpl::convertToUppercaseWithoutLocale()
         LChar* dest = data8;
 
         for (int32_t i = 0; i < length; ++i) {
-            LChar c = m_data8[i];
-            if (c == smallLetterSharpS) {
+            LChar character = m_data8[i];
+            if (character == smallLetterSharpS) {
                 *dest++ = 'S';
                 *dest++ = 'S';
             } else {
-                ASSERT(u_toupper(c) <= 0xFF);
-                *dest++ = static_cast<LChar>(u_toupper(c));
+                ASSERT(u_toupper(character) <= 0xFF);
+                *dest++ = static_cast<LChar>(u_toupper(character));
             }
         }
 
@@ -510,9 +477,9 @@ upconvert:
     // Do a faster loop for the case where all the characters are ASCII.
     unsigned ored = 0;
     for (int i = 0; i < length; ++i) {
-        UChar c = source16[i];
-        ored |= c;
-        data16[i] = toASCIIUpper(c);
+        UChar character = source16[i];
+        ored |= character;
+        data16[i] = toASCIIUpper(character);
     }
     if (!(ored & ~0x7F))
         return newImpl;
@@ -634,8 +601,7 @@ SlowPath:
         if (!need16BitCharacters) {
             LChar* data8;
             auto folded = createUninitializedInternalNonEmpty(m_length, data8);
-            for (unsigned i = 0; i < failingIndex; ++i)
-                data8[i] = m_data8[i];
+            copyCharacters(data8, m_data8, failingIndex);
             for (unsigned i = failingIndex; i < m_length; ++i) {
                 auto character = m_data8[i];
                 if (isASCII(character))
@@ -707,8 +673,7 @@ ALWAYS_INLINE Ref<StringImpl> StringImpl::convertASCIICase(StringImpl& impl, con
 SlowPath:
     CharacterType* newData;
     auto newImpl = createUninitializedInternalNonEmpty(length, newData);
-    for (unsigned i = 0; i < failingIndex; ++i)
-        newData[i] = data[i];
+    copyCharacters(newData, data, failingIndex);
     for (unsigned i = failingIndex; i < length; ++i)
         newData[i] = type == CaseConvertType::Lower ? toASCIILower(data[i]) : toASCIIUpper(data[i]);
     return newImpl;
@@ -760,9 +725,9 @@ class UCharPredicate {
 public:
     inline UCharPredicate(CharacterMatchFunctionPtr function): m_function(function) { }
 
-    inline bool operator()(UChar ch) const
+    inline bool operator()(UChar character) const
     {
-        return m_function(ch);
+        return m_function(character);
     }
 
 private:
@@ -771,9 +736,9 @@ private:
 
 class SpaceOrNewlinePredicate {
 public:
-    inline bool operator()(UChar ch) const
+    inline bool operator()(UChar character) const
     {
-        return isSpaceOrNewline(ch);
+        return isSpaceOrNewline(character);
     }
 };
 
@@ -787,11 +752,10 @@ Ref<StringImpl> StringImpl::stripWhiteSpace(IsWhiteSpaceFunctionPtr isWhiteSpace
     return stripMatchedCharacters(UCharPredicate(isWhiteSpace));
 }
 
-template <typename CharType>
-ALWAYS_INLINE Ref<StringImpl> StringImpl::removeCharacters(const CharType* characters, CharacterMatchFunctionPtr findMatch)
+template<typename CharacterType> ALWAYS_INLINE Ref<StringImpl> StringImpl::removeCharacters(const CharacterType* characters, CharacterMatchFunctionPtr findMatch)
 {
-    const CharType* from = characters;
-    const CharType* fromend = from + m_length;
+    auto* from = characters;
+    auto* fromend = from + m_length;
     
     // Assume the common case will not remove any characters
     while (from != fromend && !findMatch(*from))
@@ -799,12 +763,12 @@ ALWAYS_INLINE Ref<StringImpl> StringImpl::removeCharacters(const CharType* chara
     if (from == fromend)
         return *this;
     
-    StringBuffer<CharType> data(m_length);
-    CharType* to = data.characters();
+    StringBuffer<CharacterType> data(m_length);
+    auto* to = data.characters();
     unsigned outc = from - characters;
     
     if (outc)
-        memcpy(to, characters, outc * sizeof(CharType));
+        copyCharacters(to, characters, outc);
 
     while (true) {
         while (from != fromend && findMatch(*from))
@@ -827,17 +791,16 @@ Ref<StringImpl> StringImpl::removeCharacters(CharacterMatchFunctionPtr findMatch
     return removeCharacters(characters16(), findMatch);
 }
 
-template <typename CharType, class UCharPredicate>
-inline Ref<StringImpl> StringImpl::simplifyMatchedCharactersToSpace(UCharPredicate predicate)
+template<typename CharacterType, class UCharPredicate> inline Ref<StringImpl> StringImpl::simplifyMatchedCharactersToSpace(UCharPredicate predicate)
 {
-    StringBuffer<CharType> data(m_length);
+    StringBuffer<CharacterType> data(m_length);
 
-    const CharType* from = characters<CharType>();
-    const CharType* fromend = from + m_length;
+    auto* from = characters<CharacterType>();
+    auto* fromend = from + m_length;
     int outc = 0;
     bool changedToSpace = false;
     
-    CharType* to = data.characters();
+    auto* to = data.characters();
     
     while (true) {
         while (from != fromend && predicate(*from)) {
@@ -962,54 +925,6 @@ float StringImpl::toFloat(bool* ok)
     return charactersToFloat(characters16(), m_length, ok);
 }
 
-// Table is based on ftp://ftp.unicode.org/Public/UNIDATA/CaseFolding.txt
-static const UChar latin1CaseFoldTable[256] = {
-    0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
-    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
-    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
-    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
-    0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
-    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
-    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
-    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
-    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
-    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
-    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
-    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x03bc, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
-    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
-    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00d7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00df,
-    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
-    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff,
-};
-
-static inline bool equalCompatibilityCaseless(const LChar* a, const LChar* b, unsigned length)
-{
-    while (length--) {
-        if (latin1CaseFoldTable[*a++] != latin1CaseFoldTable[*b++])
-            return false;
-    }
-    return true;
-}
-
-static inline bool equalCompatibilityCaseless(const UChar* a, const LChar* b, unsigned length)
-{
-    while (length--) {
-        if (u_foldCase(*a++, U_FOLD_CASE_DEFAULT) != latin1CaseFoldTable[*b++])
-            return false;
-    }
-    return true;
-}
-
-static inline bool equalCompatibilityCaseless(const LChar* a, const UChar* b, unsigned length)
-{
-    return equalCompatibilityCaseless(b, a, length);
-}
-
-static inline bool equalCompatibilityCaseless(const UChar* a, const UChar* b, unsigned length)
-{
-    return !u_memcasecmp(a, b, length, U_FOLD_CASE_DEFAULT);
-}
-
 size_t StringImpl::find(CharacterMatchFunctionPtr matchFunction, unsigned start)
 {
     if (is8Bit())
@@ -1089,50 +1004,6 @@ size_t StringImpl::find(const LChar* matchString, unsigned index)
     return index + i;
 }
 
-size_t StringImpl::findIgnoringCase(const LChar* matchString, unsigned index)
-{
-    // Check for null or empty string to match against
-    if (!matchString)
-        return notFound;
-    size_t matchStringLength = strlen(reinterpret_cast<const char*>(matchString));
-    if (matchStringLength > std::numeric_limits<unsigned>::max())
-        CRASH();
-    unsigned matchLength = matchStringLength;
-    if (!matchLength)
-        return std::min(index, length());
-
-    // Check index & matchLength are in range.
-    if (index > length())
-        return notFound;
-    unsigned searchLength = length() - index;
-    if (matchLength > searchLength)
-        return notFound;
-    // delta is the number of additional times to test; delta == 0 means test only once.
-    unsigned delta = searchLength - matchLength;
-
-    if (is8Bit()) {
-        const LChar* searchCharacters = characters8() + index;
-
-        unsigned i = 0;
-        while (!equalCompatibilityCaseless(searchCharacters + i, matchString, matchLength)) {
-            if (i == delta)
-                return notFound;
-            ++i;
-        }
-        return index + i;
-    }
-
-    const UChar* searchCharacters = characters16() + index;
-
-    unsigned i = 0;
-    while (!equalCompatibilityCaseless(searchCharacters + i, matchString, matchLength)) {
-        if (i == delta)
-            return notFound;
-        ++i;
-    }
-    return index + i;
-}
-
 size_t StringImpl::find(StringImpl* matchString)
 {
     // Check for null string to match against
@@ -1181,50 +1052,6 @@ size_t StringImpl::find(StringImpl* matchString, unsigned index)
     return findCommon(*this, *matchString, index);
 }
 
-template <typename SearchCharacterType, typename MatchCharacterType>
-ALWAYS_INLINE static size_t findIgnoringCaseInner(const SearchCharacterType* searchCharacters, const MatchCharacterType* matchCharacters, unsigned index, unsigned searchLength, unsigned matchLength)
-{
-    // delta is the number of additional times to test; delta == 0 means test only once.
-    unsigned delta = searchLength - matchLength;
-
-    unsigned i = 0;
-    // keep looping until we match
-    while (!equalCompatibilityCaseless(searchCharacters + i, matchCharacters, matchLength)) {
-        if (i == delta)
-            return notFound;
-        ++i;
-    }
-    return index + i;
-}
-
-size_t StringImpl::findIgnoringCase(StringImpl* matchString, unsigned index)
-{
-    // Check for null or empty string to match against
-    if (!matchString)
-        return notFound;
-    unsigned matchLength = matchString->length();
-    if (!matchLength)
-        return std::min(index, length());
-
-    // Check index & matchLength are in range.
-    if (index > length())
-        return notFound;
-    unsigned searchLength = length() - index;
-    if (matchLength > searchLength)
-        return notFound;
-
-    if (is8Bit()) {
-        if (matchString->is8Bit())
-            return findIgnoringCaseInner(characters8() + index, matchString->characters8(), index, searchLength, matchLength);
-        return findIgnoringCaseInner(characters8() + index, matchString->characters16(), index, searchLength, matchLength);
-    }
-
-    if (matchString->is8Bit())
-        return findIgnoringCaseInner(characters16() + index, matchString->characters8(), index, searchLength, matchLength);
-
-    return findIgnoringCaseInner(characters16() + index, matchString->characters16(), index, searchLength, matchLength);
-}
-
 size_t StringImpl::findIgnoringASCIICase(const StringImpl& matchString) const
 {
     return ::WTF::findIgnoringASCIICase(*this, matchString, 0);
@@ -1249,11 +1076,11 @@ size_t StringImpl::findIgnoringASCIICase(const StringImpl* matchString, unsigned
     return ::WTF::findIgnoringASCIICase(*this, *matchString, startOffset);
 }
 
-size_t StringImpl::reverseFind(UChar c, unsigned index)
+size_t StringImpl::reverseFind(UChar character, unsigned index)
 {
     if (is8Bit())
-        return WTF::reverseFind(characters8(), m_length, c, index);
-    return WTF::reverseFind(characters16(), m_length, c, index);
+        return WTF::reverseFind(characters8(), m_length, character, index);
+    return WTF::reverseFind(characters16(), m_length, character, index);
 }
 
 template <typename SearchCharacterType, typename MatchCharacterType>
@@ -1316,100 +1143,48 @@ size_t StringImpl::reverseFind(StringImpl* matchString, unsigned index)
     return reverseFindInner(characters16(), matchString->characters16(), index, ourLength, matchLength);
 }
 
-template <typename SearchCharacterType, typename MatchCharacterType>
-ALWAYS_INLINE static size_t reverseFindIgnoringCaseInner(const SearchCharacterType* searchCharacters, const MatchCharacterType* matchCharacters, unsigned index, unsigned length, unsigned matchLength)
+ALWAYS_INLINE static bool equalInner(const StringImpl& string, unsigned startOffset, const char* matchString, unsigned matchLength)
 {
-    // delta is the number of additional times to test; delta == 0 means test only once.
-    unsigned delta = std::min(index, length - matchLength);
+    ASSERT(matchLength <= string.length());
+    ASSERT(startOffset + matchLength <= string.length());
 
-    // keep looping until we match
-    while (!equalCompatibilityCaseless(searchCharacters + delta, matchCharacters, matchLength)) {
-        if (!delta)
-            return notFound;
-        --delta;
-    }
-    return delta;
+    if (string.is8Bit())
+        return equal(string.characters8() + startOffset, reinterpret_cast<const LChar*>(matchString), matchLength);
+    return equal(string.characters16() + startOffset, reinterpret_cast<const LChar*>(matchString), matchLength);
 }
 
-size_t StringImpl::reverseFindIgnoringCase(StringImpl* matchString, unsigned index)
+ALWAYS_INLINE static bool equalInner(const StringImpl& string, unsigned startOffset, const StringImpl& matchString)
 {
-    // Check for null or empty string to match against
-    if (!matchString)
-        return notFound;
-    unsigned matchLength = matchString->length();
-    unsigned ourLength = length();
-    if (!matchLength)
-        return std::min(index, ourLength);
-
-    // Check index & matchLength are in range.
-    if (matchLength > ourLength)
-        return notFound;
-
-    if (is8Bit()) {
-        if (matchString->is8Bit())
-            return reverseFindIgnoringCaseInner(characters8(), matchString->characters8(), index, ourLength, matchLength);
-        return reverseFindIgnoringCaseInner(characters8(), matchString->characters16(), index, ourLength, matchLength);
-    }
-
-    if (matchString->is8Bit())
-        return reverseFindIgnoringCaseInner(characters16(), matchString->characters8(), index, ourLength, matchLength);
-
-    return reverseFindIgnoringCaseInner(characters16(), matchString->characters16(), index, ourLength, matchLength);
-}
-
-ALWAYS_INLINE static bool equalInner(const StringImpl* stringImpl, unsigned startOffset, const char* matchString, unsigned matchLength, bool caseSensitive)
-{
-    ASSERT(stringImpl);
-    ASSERT(matchLength <= stringImpl->length());
-    ASSERT(startOffset + matchLength <= stringImpl->length());
-
-    if (caseSensitive) {
-        if (stringImpl->is8Bit())
-            return equal(stringImpl->characters8() + startOffset, reinterpret_cast<const LChar*>(matchString), matchLength);
-        return equal(stringImpl->characters16() + startOffset, reinterpret_cast<const LChar*>(matchString), matchLength);
-    }
-    if (stringImpl->is8Bit())
-        return equalCompatibilityCaseless(stringImpl->characters8() + startOffset, reinterpret_cast<const LChar*>(matchString), matchLength);
-    return equalCompatibilityCaseless(stringImpl->characters16() + startOffset, reinterpret_cast<const LChar*>(matchString), matchLength);
-}
-
-ALWAYS_INLINE static bool equalInner(const StringImpl& stringImpl, unsigned startOffset, const StringImpl& matchString)
-{
-    if (startOffset > stringImpl.length())
+    if (startOffset > string.length())
         return false;
-    if (matchString.length() > stringImpl.length())
+    if (matchString.length() > string.length())
         return false;
-    if (matchString.length() + startOffset > stringImpl.length())
+    if (matchString.length() + startOffset > string.length())
         return false;
 
-    if (stringImpl.is8Bit()) {
+    if (string.is8Bit()) {
         if (matchString.is8Bit())
-            return equal(stringImpl.characters8() + startOffset, matchString.characters8(), matchString.length());
-        return equal(stringImpl.characters8() + startOffset, matchString.characters16(), matchString.length());
+            return equal(string.characters8() + startOffset, matchString.characters8(), matchString.length());
+        return equal(string.characters8() + startOffset, matchString.characters16(), matchString.length());
     }
     if (matchString.is8Bit())
-        return equal(stringImpl.characters16() + startOffset, matchString.characters8(), matchString.length());
-    return equal(stringImpl.characters16() + startOffset, matchString.characters16(), matchString.length());
+        return equal(string.characters16() + startOffset, matchString.characters8(), matchString.length());
+    return equal(string.characters16() + startOffset, matchString.characters16(), matchString.length());
 }
 
-bool StringImpl::startsWith(const StringImpl* str) const
+bool StringImpl::startsWith(const StringImpl* string) const
 {
-    if (!str)
-        return false;
-    return ::WTF::startsWith(*this, *str);
+    return string && ::WTF::startsWith(*this, *string);
 }
 
-bool StringImpl::startsWith(const StringImpl& str) const
+bool StringImpl::startsWith(const StringImpl& string) const
 {
-    return ::WTF::startsWith(*this, str);
+    return ::WTF::startsWith(*this, string);
 }
 
 bool StringImpl::startsWithIgnoringASCIICase(const StringImpl* prefix) const
 {
-    if (!prefix)
-        return false;
-
-    return ::WTF::startsWithIgnoringASCIICase(*this, *prefix);
+    return prefix && ::WTF::startsWithIgnoringASCIICase(*this, *prefix);
 }
 
 bool StringImpl::startsWithIgnoringASCIICase(const StringImpl& prefix) const
@@ -1422,12 +1197,9 @@ bool StringImpl::startsWith(UChar character) const
     return m_length && (*this)[0] == character;
 }
 
-bool StringImpl::startsWith(const char* matchString, unsigned matchLength, bool caseSensitive) const
+bool StringImpl::startsWith(const char* matchString, unsigned matchLength) const
 {
-    ASSERT(matchLength);
-    if (matchLength > length())
-        return false;
-    return equalInner(this, 0, matchString, matchLength, caseSensitive);
+    return matchLength <= length() && equalInner(*this, 0, matchString, matchLength);
 }
 
 bool StringImpl::hasInfixStartingAt(const StringImpl& matchString, unsigned startOffset) const
@@ -1437,10 +1209,7 @@ bool StringImpl::hasInfixStartingAt(const StringImpl& matchString, unsigned star
 
 bool StringImpl::endsWith(StringImpl* suffix)
 {
-    if (!suffix)
-        return false;
-
-    return ::WTF::endsWith(*this, *suffix);
+    return suffix && ::WTF::endsWith(*this, *suffix);
 }
 
 bool StringImpl::endsWith(StringImpl& suffix)
@@ -1448,22 +1217,9 @@ bool StringImpl::endsWith(StringImpl& suffix)
     return ::WTF::endsWith(*this, suffix);
 }
 
-bool StringImpl::endsWith(StringImpl* matchString, bool caseSensitive)
-{
-    ASSERT(matchString);
-    if (m_length >= matchString->m_length) {
-        unsigned start = m_length - matchString->m_length;
-        return (caseSensitive ? find(matchString, start) : findIgnoringCase(matchString, start)) == start;
-    }
-    return false;
-}
-
 bool StringImpl::endsWithIgnoringASCIICase(const StringImpl* suffix) const
 {
-    if (!suffix)
-        return false;
-
-    return ::WTF::endsWithIgnoringASCIICase(*this, *suffix);
+    return suffix && ::WTF::endsWithIgnoringASCIICase(*this, *suffix);
 }
 
 bool StringImpl::endsWithIgnoringASCIICase(const StringImpl& suffix) const
@@ -1476,66 +1232,59 @@ bool StringImpl::endsWith(UChar character) const
     return m_length && (*this)[m_length - 1] == character;
 }
 
-bool StringImpl::endsWith(const char* matchString, unsigned matchLength, bool caseSensitive) const
+bool StringImpl::endsWith(const char* matchString, unsigned matchLength) const
 {
-    ASSERT(matchLength);
-    if (matchLength > length())
-        return false;
-    unsigned startOffset = length() - matchLength;
-    return equalInner(this, startOffset, matchString, matchLength, caseSensitive);
+    return matchLength <= length() && equalInner(*this, length() - matchLength, matchString, matchLength);
 }
 
 bool StringImpl::hasInfixEndingAt(const StringImpl& matchString, unsigned endOffset) const
 {
-    if (endOffset < matchString.length())
-        return false;
-    return equalInner(*this, endOffset - matchString.length(), matchString);
+    return endOffset >= matchString.length() && equalInner(*this, endOffset - matchString.length(), matchString);
 }
 
-Ref<StringImpl> StringImpl::replace(UChar oldC, UChar newC)
+Ref<StringImpl> StringImpl::replace(UChar target, UChar replacement)
 {
-    if (oldC == newC)
+    if (target == replacement)
         return *this;
     unsigned i;
     for (i = 0; i != m_length; ++i) {
-        UChar c = is8Bit() ? m_data8[i] : m_data16[i];
-        if (c == oldC)
+        UChar character = is8Bit() ? m_data8[i] : m_data16[i];
+        if (character == target)
             break;
     }
     if (i == m_length)
         return *this;
 
     if (is8Bit()) {
-        if (oldC > 0xff)
-            // Looking for a 16 bit char in an 8 bit string, we're done.
+        if (target > 0xFF) {
+            // Looking for a 16-bit character in an 8-bit string, so we're done.
             return *this;
+        }
 
-        if (newC <= 0xff) {
+        if (replacement <= 0xFF) {
             LChar* data;
-            LChar oldChar = static_cast<LChar>(oldC);
-            LChar newChar = static_cast<LChar>(newC);
+            LChar oldChar = static_cast<LChar>(target);
+            LChar newChar = static_cast<LChar>(replacement);
 
             auto newImpl = createUninitializedInternalNonEmpty(m_length, data);
 
             for (i = 0; i != m_length; ++i) {
-                LChar ch = m_data8[i];
-                if (ch == oldChar)
-                    ch = newChar;
-                data[i] = ch;
+                LChar character = m_data8[i];
+                if (character == oldChar)
+                    character = newChar;
+                data[i] = character;
             }
             return newImpl;
         }
 
-        // There is the possibility we need to up convert from 8 to 16 bit,
-        // create a 16 bit string for the result.
         UChar* data;
         auto newImpl = createUninitializedInternalNonEmpty(m_length, data);
 
         for (i = 0; i != m_length; ++i) {
-            UChar ch = m_data8[i];
-            if (ch == oldC)
-                ch = newC;
-            data[i] = ch;
+            UChar character = m_data8[i];
+            if (character == target)
+                character = replacement;
+            data[i] = character;
         }
 
         return newImpl;
@@ -1545,56 +1294,50 @@ Ref<StringImpl> StringImpl::replace(UChar oldC, UChar newC)
     auto newImpl = createUninitializedInternalNonEmpty(m_length, data);
 
     for (i = 0; i != m_length; ++i) {
-        UChar ch = m_data16[i];
-        if (ch == oldC)
-            ch = newC;
-        data[i] = ch;
+        UChar character = m_data16[i];
+        if (character == target)
+            character = replacement;
+        data[i] = character;
     }
     return newImpl;
 }
 
-Ref<StringImpl> StringImpl::replace(unsigned position, unsigned lengthToReplace, StringImpl* str)
+Ref<StringImpl> StringImpl::replace(unsigned position, unsigned lengthToReplace, StringImpl* string)
 {
     position = std::min(position, length());
     lengthToReplace = std::min(lengthToReplace, length() - position);
-    unsigned lengthToInsert = str ? str->length() : 0;
+    unsigned lengthToInsert = string ? string->length() : 0;
     if (!lengthToReplace && !lengthToInsert)
         return *this;
 
     if ((length() - lengthToReplace) >= (std::numeric_limits<unsigned>::max() - lengthToInsert))
         CRASH();
 
-    if (is8Bit() && (!str || str->is8Bit())) {
+    if (is8Bit() && (!string || string->is8Bit())) {
         LChar* data;
         auto newImpl = createUninitialized(length() - lengthToReplace + lengthToInsert, data);
-        memcpy(data, m_data8, position * sizeof(LChar));
-        if (str)
-            memcpy(data + position, str->m_data8, lengthToInsert * sizeof(LChar));
-        memcpy(data + position + lengthToInsert, m_data8 + position + lengthToReplace,
-               (length() - position - lengthToReplace) * sizeof(LChar));
+        copyCharacters(data, m_data8, position);
+        if (string)
+            copyCharacters(data + position, string->m_data8, lengthToInsert);
+        copyCharacters(data + position + lengthToInsert, m_data8 + position + lengthToReplace, length() - position - lengthToReplace);
         return newImpl;
     }
     UChar* data;
     auto newImpl = createUninitialized(length() - lengthToReplace + lengthToInsert, data);
     if (is8Bit())
-        for (unsigned i = 0; i < position; ++i)
-            data[i] = m_data8[i];
+        copyCharacters(data, m_data8, position);
     else
-        memcpy(data, m_data16, position * sizeof(UChar));
-    if (str) {
-        if (str->is8Bit())
-            for (unsigned i = 0; i < lengthToInsert; ++i)
-                data[i + position] = str->m_data8[i];
+        copyCharacters(data, m_data16, position);
+    if (string) {
+        if (string->is8Bit())
+            copyCharacters(data + position, string->m_data8, lengthToInsert);
         else
-            memcpy(data + position, str->m_data16, lengthToInsert * sizeof(UChar));
-    }
-    if (is8Bit()) {
-        for (unsigned i = 0; i < length() - position - lengthToReplace; ++i)
-            data[i + position + lengthToInsert] = m_data8[i + position + lengthToReplace];
-    } else {
-        memcpy(data + position + lengthToInsert, characters16() + position + lengthToReplace,
-            (length() - position - lengthToReplace) * sizeof(UChar));
+            copyCharacters(data + position, string->m_data16, lengthToInsert);
     }
+    if (is8Bit())
+        copyCharacters(data + position + lengthToInsert, m_data8 + position + lengthToReplace, length() - position - lengthToReplace);
+    else
+        copyCharacters(data + position + lengthToInsert, m_data16 + position + lengthToReplace, length() - position - lengthToReplace);
     return newImpl;
 }
 
@@ -1602,10 +1345,8 @@ Ref<StringImpl> StringImpl::replace(UChar pattern, StringImpl* replacement)
 {
     if (!replacement)
         return *this;
-
     if (replacement->is8Bit())
         return replace(pattern, replacement->m_data8, replacement->length());
-
     return replace(pattern, replacement->m_data16, replacement->length());
 }
 
@@ -1648,15 +1389,15 @@ Ref<StringImpl> StringImpl::replace(UChar pattern, const LChar* replacement, uns
 
         while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) {
             srcSegmentLength = srcSegmentEnd - srcSegmentStart;
-            memcpy(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength * sizeof(LChar));
+            copyCharacters(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength);
             dstOffset += srcSegmentLength;
-            memcpy(data + dstOffset, replacement, repStrLength * sizeof(LChar));
+            copyCharacters(data + dstOffset, replacement, repStrLength);
             dstOffset += repStrLength;
             srcSegmentStart = srcSegmentEnd + 1;
         }
 
         srcSegmentLength = m_length - srcSegmentStart;
-        memcpy(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength * sizeof(LChar));
+        copyCharacters(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength);
 
         ASSERT(dstOffset + srcSegmentLength == newImpl.get().length());
 
@@ -1668,18 +1409,17 @@ Ref<StringImpl> StringImpl::replace(UChar pattern, const LChar* replacement, uns
 
     while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) {
         srcSegmentLength = srcSegmentEnd - srcSegmentStart;
-        memcpy(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength * sizeof(UChar));
+        copyCharacters(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength);
 
         dstOffset += srcSegmentLength;
-        for (unsigned i = 0; i < repStrLength; ++i)
-            data[i + dstOffset] = replacement[i];
+        copyCharacters(data + dstOffset, replacement, repStrLength);
 
         dstOffset += repStrLength;
         srcSegmentStart = srcSegmentEnd + 1;
     }
 
     srcSegmentLength = m_length - srcSegmentStart;
-    memcpy(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength * sizeof(UChar));
+    copyCharacters(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength);
 
     ASSERT(dstOffset + srcSegmentLength == newImpl.get().length());
 
@@ -1725,19 +1465,17 @@ Ref<StringImpl> StringImpl::replace(UChar pattern, const UChar* replacement, uns
 
         while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) {
             srcSegmentLength = srcSegmentEnd - srcSegmentStart;
-            for (unsigned i = 0; i < srcSegmentLength; ++i)
-                data[i + dstOffset] = m_data8[i + srcSegmentStart];
+            copyCharacters(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength);
 
             dstOffset += srcSegmentLength;
-            memcpy(data + dstOffset, replacement, repStrLength * sizeof(UChar));
+            copyCharacters(data + dstOffset, replacement, repStrLength);
 
             dstOffset += repStrLength;
             srcSegmentStart = srcSegmentEnd + 1;
         }
 
         srcSegmentLength = m_length - srcSegmentStart;
-        for (unsigned i = 0; i < srcSegmentLength; ++i)
-            data[i + dstOffset] = m_data8[i + srcSegmentStart];
+        copyCharacters(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength);
 
         ASSERT(dstOffset + srcSegmentLength == newImpl.get().length());
 
@@ -1749,17 +1487,17 @@ Ref<StringImpl> StringImpl::replace(UChar pattern, const UChar* replacement, uns
 
     while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) {
         srcSegmentLength = srcSegmentEnd - srcSegmentStart;
-        memcpy(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength * sizeof(UChar));
+        copyCharacters(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength);
 
         dstOffset += srcSegmentLength;
-        memcpy(data + dstOffset, replacement, repStrLength * sizeof(UChar));
+        copyCharacters(data + dstOffset, replacement, repStrLength);
 
         dstOffset += repStrLength;
         srcSegmentStart = srcSegmentEnd + 1;
     }
 
     srcSegmentLength = m_length - srcSegmentStart;
-    memcpy(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength * sizeof(UChar));
+    copyCharacters(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength);
 
     ASSERT(dstOffset + srcSegmentLength == newImpl.get().length());
 
@@ -1818,15 +1556,15 @@ Ref<StringImpl> StringImpl::replace(StringImpl* pattern, StringImpl* replacement
         auto newImpl = createUninitialized(newSize, data);
         while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) {
             srcSegmentLength = srcSegmentEnd - srcSegmentStart;
-            memcpy(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength * sizeof(LChar));
+            copyCharacters(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength);
             dstOffset += srcSegmentLength;
-            memcpy(data + dstOffset, replacement->m_data8, repStrLength * sizeof(LChar));
+            copyCharacters(data + dstOffset, replacement->m_data8, repStrLength);
             dstOffset += repStrLength;
             srcSegmentStart = srcSegmentEnd + patternLength;
         }
 
         srcSegmentLength = m_length - srcSegmentStart;
-        memcpy(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength * sizeof(LChar));
+        copyCharacters(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength);
 
         ASSERT(dstOffset + srcSegmentLength == newImpl.get().length());
 
@@ -1839,20 +1577,18 @@ Ref<StringImpl> StringImpl::replace(StringImpl* pattern, StringImpl* replacement
         srcSegmentLength = srcSegmentEnd - srcSegmentStart;
         if (srcIs8Bit) {
             // Case 3.
-            for (unsigned i = 0; i < srcSegmentLength; ++i)
-                data[i + dstOffset] = m_data8[i + srcSegmentStart];
+            copyCharacters(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength);
         } else {
             // Case 2 & 4.
-            memcpy(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength * sizeof(UChar));
+            copyCharacters(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength);
         }
         dstOffset += srcSegmentLength;
         if (replacementIs8Bit) {
             // Cases 2 & 3.
-            for (unsigned i = 0; i < repStrLength; ++i)
-                data[i + dstOffset] = replacement->m_data8[i];
+            copyCharacters(data + dstOffset, replacement->m_data8, repStrLength);
         } else {
             // Case 4
-            memcpy(data + dstOffset, replacement->m_data16, repStrLength * sizeof(UChar));
+            copyCharacters(data + dstOffset, replacement->m_data16, repStrLength);
         }
         dstOffset += repStrLength;
         srcSegmentStart = srcSegmentEnd + patternLength;
@@ -1861,11 +1597,10 @@ Ref<StringImpl> StringImpl::replace(StringImpl* pattern, StringImpl* replacement
     srcSegmentLength = m_length - srcSegmentStart;
     if (srcIs8Bit) {
         // Case 3.
-        for (unsigned i = 0; i < srcSegmentLength; ++i)
-            data[i + dstOffset] = m_data8[i + srcSegmentStart];
+        copyCharacters(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength);
     } else {
         // Cases 2 & 4.
-        memcpy(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength * sizeof(UChar));
+        copyCharacters(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength);
     }
 
     ASSERT(dstOffset + srcSegmentLength == newImpl.get().length());
@@ -1878,8 +1613,7 @@ bool equal(const StringImpl* a, const StringImpl* b)
     return equalCommon(a, b);
 }
 
-template <typename CharType>
-inline bool equalInternal(const StringImpl* a, const CharType* b, unsigned length)
+template<typename CharacterType> inline bool equalInternal(const StringImpl* a, const CharacterType* b, unsigned length)
 {
     if (!a)
         return !b;
@@ -1954,11 +1688,7 @@ bool equalIgnoringNullity(StringImpl* a, StringImpl* b)
 
 bool equalIgnoringASCIICase(const StringImpl* a, const StringImpl* b)
 {
-    if (a == b)
-        return true;
-    if (!a || !b)
-        return false;
-    return equalIgnoringASCIICaseCommon(*a, *b);
+    return a == b || (a && b && equalIgnoringASCIICase(*a, *b));
 }
 
 bool equalIgnoringASCIICaseNonNull(const StringImpl* a, const StringImpl* b)
@@ -1971,7 +1701,7 @@ bool equalIgnoringASCIICaseNonNull(const StringImpl* a, const StringImpl* b)
 UCharDirection StringImpl::defaultWritingDirection(bool* hasStrongDirectionality)
 {
     for (unsigned i = 0; i < m_length; ++i) {
-        UCharDirection charDirection = u_charDirection(is8Bit() ? m_data8[i] : m_data16[i]);
+        auto charDirection = u_charDirection(is8Bit() ? m_data8[i] : m_data16[i]);
         if (charDirection == U_LEFT_TO_RIGHT) {
             if (hasStrongDirectionality)
                 *hasStrongDirectionality = true;
@@ -2013,13 +1743,13 @@ size_t StringImpl::sizeInBytes() const
     return size + sizeof(*this);
 }
 
-// Helper to write a three-byte UTF-8 code point to the buffer, caller must check room is available.
-static inline void putUTF8Triple(char*& buffer, UChar ch)
+// Helper to write a three-byte UTF-8 code point into the buffer; caller must ensure room is available.
+static inline void putUTF8Triple(char*& buffer, UChar character)
 {
-    ASSERT(ch >= 0x0800);
-    *buffer++ = static_cast<char>(((ch >> 12) & 0x0F) | 0xE0);
-    *buffer++ = static_cast<char>(((ch >> 6) & 0x3F) | 0x80);
-    *buffer++ = static_cast<char>((ch & 0x3F) | 0x80);
+    ASSERT(character >= 0x0800);
+    *buffer++ = static_cast<char>(((character >> 12) & 0x0F) | 0xE0);
+    *buffer++ = static_cast<char>(((character >> 6) & 0x3F) | 0x80);
+    *buffer++ = static_cast<char>((character & 0x3F) | 0x80);
 }
 
 bool StringImpl::utf8Impl(const UChar* characters, unsigned length, char*& buffer, size_t bufferSize, ConversionMode mode)
index 130866c..eaf295f 100644 (file)
@@ -33,6 +33,7 @@
 #include <wtf/MathExtras.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/Vector.h>
+#include <wtf/text/ASCIIFastPath.h>
 #include <wtf/text/ConversionMode.h>
 #include <wtf/text/StringCommon.h>
 #include <wtf/text/StringMalloc.h>
@@ -57,7 +58,6 @@ class SymbolImpl;
 class SymbolRegistry;
 
 struct CStringTranslator;
-template<typename> struct BufferFromStaticDataTranslator;
 struct HashAndUTF8CharactersTranslator;
 struct LCharBufferTranslator;
 struct StringHash;
@@ -66,22 +66,21 @@ struct UCharBufferTranslator;
 
 template<typename> class RetainPtr;
 
+template<typename> struct BufferFromStaticDataTranslator;
 template<typename> struct HashAndCharactersTranslator;
 
-enum TextCaseSensitivity {
-    TextCaseSensitive,
-    TextCaseInsensitive
-};
+// Define STRING_STATS to 1 turn on runtime statistics for string sizes and memory usage.
+#define STRING_STATS 0
 
 typedef bool (*CharacterMatchFunctionPtr)(UChar);
 typedef bool (*IsWhiteSpaceFunctionPtr)(UChar);
 
-// Define STRING_STATS to 1 turn on run time statistics of string sizes and memory usage
-#define STRING_STATS 0
+template<bool isSpecialCharacter(UChar), typename CharacterType> bool isAllSpecialCharacters(const CharacterType*, size_t length);
 
 #if STRING_STATS
+
 struct StringStats {
-    inline void add8BitString(unsigned length, bool isSubString = false)
+    void add8BitString(unsigned length, bool isSubString = false)
     {
         ++m_totalNumberStrings;
         ++m_number8BitStrings;
@@ -89,7 +88,7 @@ struct StringStats {
             m_total8BitData += length;
     }
 
-    inline void add16BitString(unsigned length, bool isSubString = false)
+    void add16BitString(unsigned length, bool isSubString = false)
     {
         ++m_totalNumberStrings;
         ++m_number16BitStrings;
@@ -120,7 +119,9 @@ struct StringStats {
 #define STRING_STATS_REMOVE_STRING(string) StringImpl::stringStats().removeString(string)
 #define STRING_STATS_REF_STRING(string) ++StringImpl::stringStats().m_refCalls;
 #define STRING_STATS_DEREF_STRING(string) ++StringImpl::stringStats().m_derefCalls;
+
 #else
+
 #define STRING_STATS_ADD_8BIT_STRING(length) ((void)0)
 #define STRING_STATS_ADD_8BIT_STRING2(length, isSubString) ((void)0)
 #define STRING_STATS_ADD_16BIT_STRING(length) ((void)0)
@@ -129,42 +130,18 @@ struct StringStats {
 #define STRING_STATS_REMOVE_STRING(string) ((void)0)
 #define STRING_STATS_REF_STRING(string) ((void)0)
 #define STRING_STATS_DEREF_STRING(string) ((void)0)
+
 #endif
 
 class StringImplShape {
     WTF_MAKE_NONCOPYABLE(StringImplShape);
 protected:
-    StringImplShape(unsigned refCount, unsigned length, const LChar* data8, unsigned hashAndFlags)
-        : m_refCount(refCount)
-        , m_length(length)
-        , m_data8(data8)
-        , m_hashAndFlags(hashAndFlags)
-    { }
-
-    StringImplShape(unsigned refCount, unsigned length, const UChar* data16, unsigned hashAndFlags)
-        : m_refCount(refCount)
-        , m_length(length)
-        , m_data16(data16)
-        , m_hashAndFlags(hashAndFlags)
-    { }
+    StringImplShape(unsigned refCount, unsigned length, const LChar*, unsigned hashAndFlags);
+    StringImplShape(unsigned refCount, unsigned length, const UChar*, unsigned hashAndFlags);
 
     enum ConstructWithConstExprTag { ConstructWithConstExpr };
-    
-    template<unsigned characterCount>
-    constexpr StringImplShape(unsigned refCount, unsigned length, const char (&characters)[characterCount], unsigned hashAndFlags, ConstructWithConstExprTag)
-        : m_refCount(refCount)
-        , m_length(length)
-        , m_data8Char(characters)
-        , m_hashAndFlags(hashAndFlags)
-    { }
-    
-    template<unsigned characterCount>
-    constexpr StringImplShape(unsigned refCount, unsigned length, const char16_t (&characters)[characterCount], unsigned hashAndFlags, ConstructWithConstExprTag)
-        : m_refCount(refCount)
-        , m_length(length)
-        , m_data16Char(characters)
-        , m_hashAndFlags(hashAndFlags)
-    { }
+    template<unsigned characterCount> constexpr StringImplShape(unsigned refCount, unsigned length, const char (&characters)[characterCount], unsigned hashAndFlags, ConstructWithConstExprTag);
+    template<unsigned characterCount> constexpr StringImplShape(unsigned refCount, unsigned length, const char16_t (&characters)[characterCount], unsigned hashAndFlags, ConstructWithConstExprTag);
 
     unsigned m_refCount;
     unsigned m_length;
@@ -179,28 +156,33 @@ protected:
     mutable unsigned m_hashAndFlags;
 };
 
+// FIXME: Use of StringImpl and const is rather confused.
+// The actual string inside a StringImpl is immutable, so you can't modify a string using a StringImpl&.
+// We could mark every member function const and always use "const StringImpl&" and "const StringImpl*".
+// Or we could say that "const" doesn't make sense at all and use "StringImpl&" and "StringImpl*" everywhere.
+// Right now we use a mix of both, which makes code more confusing and has no benefit.
+
 class StringImpl : private StringImplShape {
     WTF_MAKE_NONCOPYABLE(StringImpl); WTF_MAKE_STRING_ALLOCATED;
+
+    friend class AtomicStringImpl;
+    friend class JSC::LLInt::Data;
+    friend class JSC::LLIntOffsetsExtractor;
+    friend class PrivateSymbolImpl;
+    friend class RegisteredSymbolImpl;
+    friend class SymbolImpl;
+
     friend struct WTF::CStringTranslator;
-    template<typename CharacterType> friend struct WTF::HashAndCharactersTranslator;
     friend struct WTF::HashAndUTF8CharactersTranslator;
-    template<typename CharacterType> friend struct WTF::BufferFromStaticDataTranslator;
     friend struct WTF::LCharBufferTranslator;
     friend struct WTF::SubstringTranslator;
     friend struct WTF::UCharBufferTranslator;
-    friend class JSC::LLInt::Data;
-    friend class JSC::LLIntOffsetsExtractor;
-    friend class AtomicStringImpl;
-    friend class SymbolImpl;
-    friend class PrivateSymbolImpl;
-    friend class RegisteredSymbolImpl;
-    
+
+    template<typename> friend struct WTF::BufferFromStaticDataTranslator;
+    template<typename> friend struct WTF::HashAndCharactersTranslator;
+
 public:
-    enum BufferOwnership {
-        BufferInternal,
-        BufferOwned,
-        BufferSubstring,
-    };
+    enum BufferOwnership { BufferInternal, BufferOwned, BufferSubstring };
 
     // The bottom 6 bits in the hash are flags.
     static constexpr const unsigned s_flagCount = 6;
@@ -222,94 +204,23 @@ private:
         StringSymbol = s_hashFlagStringKindIsSymbol, // symbol, non-atomic
     };
 
-    // FIXME: there has to be a less hacky way to do this.
+    // Create a normal 8-bit string with internal storage (BufferInternal).
     enum Force8Bit { Force8BitConstructor };
-    // Create a normal 8-bit string with internal storage (BufferInternal)
-    StringImpl(unsigned length, Force8Bit)
-        : StringImplShape(s_refCountIncrement, length, tailPointer<LChar>(), s_hashFlag8BitBuffer | StringNormal | BufferInternal)
-    {
-        ASSERT(m_data8);
-        ASSERT(m_length);
+    StringImpl(unsigned length, Force8Bit);
 
-        STRING_STATS_ADD_8BIT_STRING(m_length);
-    }
-
-    // Create a normal 16-bit string with internal storage (BufferInternal)
-    StringImpl(unsigned length)
-        : StringImplShape(s_refCountIncrement, length, tailPointer<UChar>(), StringNormal | BufferInternal)
-    {
-        ASSERT(m_data16);
-        ASSERT(m_length);
-
-        STRING_STATS_ADD_16BIT_STRING(m_length);
-    }
-
-    // Create a StringImpl adopting ownership of the provided buffer (BufferOwned)
-    StringImpl(MallocPtr<LChar> characters, unsigned length)
-        : StringImplShape(s_refCountIncrement, length, characters.leakPtr(), s_hashFlag8BitBuffer | StringNormal | BufferOwned)
-    {
-        ASSERT(m_data8);
-        ASSERT(m_length);
-
-        STRING_STATS_ADD_8BIT_STRING(m_length);
-    }
+    // Create a normal 16-bit string with internal storage (BufferInternal).
+    explicit StringImpl(unsigned length);
 
+    // Create a StringImpl adopting ownership of the provided buffer (BufferOwned).
+    StringImpl(MallocPtr<LChar>, unsigned length);
+    StringImpl(MallocPtr<UChar>, unsigned length);
     enum ConstructWithoutCopyingTag { ConstructWithoutCopying };
-    StringImpl(const UChar* characters, unsigned length, ConstructWithoutCopyingTag)
-        : StringImplShape(s_refCountIncrement, length, characters, StringNormal | BufferInternal)
-    {
-        ASSERT(m_data16);
-        ASSERT(m_length);
-
-        STRING_STATS_ADD_16BIT_STRING(m_length);
-    }
-
-    StringImpl(const LChar* characters, unsigned length, ConstructWithoutCopyingTag)
-        : StringImplShape(s_refCountIncrement, length, characters, s_hashFlag8BitBuffer | StringNormal | BufferInternal)
-    {
-        ASSERT(m_data8);
-        ASSERT(m_length);
-
-        STRING_STATS_ADD_8BIT_STRING(m_length);
-    }
-
-    // Create a StringImpl adopting ownership of the provided buffer (BufferOwned)
-    StringImpl(MallocPtr<UChar> characters, unsigned length)
-        : StringImplShape(s_refCountIncrement, length, characters.leakPtr(), StringNormal | BufferOwned)
-    {
-        ASSERT(m_data16);
-        ASSERT(m_length);
-
-        STRING_STATS_ADD_16BIT_STRING(m_length);
-    }
+    StringImpl(const UChar*, unsigned length, ConstructWithoutCopyingTag);
+    StringImpl(const LChar*, unsigned length, ConstructWithoutCopyingTag);
 
-    // Used to create new strings that are a substring of an existing 8-bit StringImpl (BufferSubstring)
-    StringImpl(const LChar* characters, unsigned length, Ref<StringImpl>&& base)
-        : StringImplShape(s_refCountIncrement, length, characters, s_hashFlag8BitBuffer | StringNormal | BufferSubstring)
-    {
-        ASSERT(is8Bit());
-        ASSERT(m_data8);
-        ASSERT(m_length);
-        ASSERT(base->bufferOwnership() != BufferSubstring);
-
-        substringBuffer() = &base.leakRef();
-
-        STRING_STATS_ADD_8BIT_STRING2(m_length, true);
-    }
-
-    // Used to create new strings that are a substring of an existing 16-bit StringImpl (BufferSubstring)
-    StringImpl(const UChar* characters, unsigned length, Ref<StringImpl>&& base)
-        : StringImplShape(s_refCountIncrement, length, characters, StringNormal | BufferSubstring)
-    {
-        ASSERT(!is8Bit());
-        ASSERT(m_data16);
-        ASSERT(m_length);
-        ASSERT(base->bufferOwnership() != BufferSubstring);
-
-        substringBuffer() = &base.leakRef();
-
-        STRING_STATS_ADD_16BIT_STRING2(m_length, true);
-    }
+    // Used to create new strings that are a substring of an existing StringImpl (BufferSubstring).
+    StringImpl(const LChar*, unsigned length, Ref<StringImpl>&&);
+    StringImpl(const UChar*, unsigned length, Ref<StringImpl>&&);
 
 public:
     WTF_EXPORT_STRING_API static void destroy(StringImpl*);
@@ -317,71 +228,26 @@ public:
     WTF_EXPORT_STRING_API static Ref<StringImpl> create(const UChar*, unsigned length);
     WTF_EXPORT_STRING_API static Ref<StringImpl> create(const LChar*, unsigned length);
     WTF_EXPORT_STRING_API static Ref<StringImpl> create8BitIfPossible(const UChar*, unsigned length);
-    template<size_t inlineCapacity>
-    static Ref<StringImpl> create8BitIfPossible(const Vector<UChar, inlineCapacity>& vector)
-    {
-        return create8BitIfPossible(vector.data(), vector.size());
-    }
+    template<size_t inlineCapacity> static Ref<StringImpl> create8BitIfPossible(const Vector<UChar, inlineCapacity>&);
     WTF_EXPORT_STRING_API static Ref<StringImpl> create8BitIfPossible(const UChar*);
 
-    ALWAYS_INLINE static Ref<StringImpl> create(const char* s, unsigned length) { return create(reinterpret_cast<const LChar*>(s), length); }
+    ALWAYS_INLINE static Ref<StringImpl> create(const char* characters, unsigned length) { return create(reinterpret_cast<const LChar*>(characters), length); }
     WTF_EXPORT_STRING_API static Ref<StringImpl> create(const LChar*);
-    ALWAYS_INLINE static Ref<StringImpl> create(const char* s) { return create(reinterpret_cast<const LChar*>(s)); }
-
-    static ALWAYS_INLINE Ref<StringImpl> createSubstringSharingImpl(StringImpl& rep, unsigned offset, unsigned length)
-    {
-        ASSERT(length <= rep.length());
+    ALWAYS_INLINE static Ref<StringImpl> create(const char* string) { return create(reinterpret_cast<const LChar*>(string)); }
 
-        if (!length)
-            return *empty();
+    static Ref<StringImpl> createSubstringSharingImpl(StringImpl&, unsigned offset, unsigned length);
 
-        auto* ownerRep = ((rep.bufferOwnership() == BufferSubstring) ? rep.substringBuffer() : &rep);
+    template<unsigned characterCount> static Ref<StringImpl> createFromLiteral(const char (&)[characterCount]);
 
-        // We allocate a buffer that contains both the StringImpl struct as well as the pointer to the owner string.
-        auto* stringImpl = static_cast<StringImpl*>(stringMalloc(allocationSize<StringImpl*>(1)));
-        if (rep.is8Bit())
-            return adoptRef(*new (NotNull, stringImpl) StringImpl(rep.m_data8 + offset, length, *ownerRep));
-        return adoptRef(*new (NotNull, stringImpl) StringImpl(rep.m_data16 + offset, length, *ownerRep));
-    }
-
-    template<unsigned characterCount>
-    ALWAYS_INLINE static Ref<StringImpl> createFromLiteral(const char (&characters)[characterCount])
-    {
-        COMPILE_ASSERT(characterCount > 1, StringImplFromLiteralNotEmpty);
-        COMPILE_ASSERT((characterCount - 1 <= ((unsigned(~0) - sizeof(StringImpl)) / sizeof(LChar))), StringImplFromLiteralCannotOverflow);
+    // FIXME: Replace calls to these overloads of createFromLiteral to createWithoutCopying instead.
+    WTF_EXPORT_STRING_API static Ref<StringImpl> createFromLiteral(const char*, unsigned length);
+    WTF_EXPORT_STRING_API static Ref<StringImpl> createFromLiteral(const char*);
 
-        return createWithoutCopying(reinterpret_cast<const LChar*>(characters), characterCount - 1);
-    }
-
-    // FIXME: Transition off of these functions to createWithoutCopying instead.
-    WTF_EXPORT_STRING_API static Ref<StringImpl> createFromLiteral(const char* characters, unsigned length);
-    WTF_EXPORT_STRING_API static Ref<StringImpl> createFromLiteral(const char* characters);
-
-    WTF_EXPORT_STRING_API static Ref<StringImpl> createWithoutCopying(const UChar* characters, unsigned length);
-    WTF_EXPORT_STRING_API static Ref<StringImpl> createWithoutCopying(const LChar* characters, unsigned length);
-
-    WTF_EXPORT_STRING_API static Ref<StringImpl> createUninitialized(unsigned length, LChar*& data);
-    WTF_EXPORT_STRING_API static Ref<StringImpl> createUninitialized(unsigned length, UChar*& data);
-    template <typename T> static ALWAYS_INLINE RefPtr<StringImpl> tryCreateUninitialized(unsigned length, T*& output)
-    {
-        if (!length) {
-            output = nullptr;
-            return empty();
-        }
-
-        if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(T))) {
-            output = nullptr;
-            return nullptr;
-        }
-        StringImpl* resultImpl = static_cast<StringImpl*>(tryStringMalloc(allocationSize<T>(length)));
-        if (!resultImpl) {
-            output = nullptr;
-            return nullptr;
-        }
-        output = resultImpl->tailPointer<T>();
-
-        return constructInternal<T>(resultImpl, length);
-    }
+    WTF_EXPORT_STRING_API static Ref<StringImpl> createWithoutCopying(const UChar*, unsigned length);
+    WTF_EXPORT_STRING_API static Ref<StringImpl> createWithoutCopying(const LChar*, unsigned length);
+    WTF_EXPORT_STRING_API static Ref<StringImpl> createUninitialized(unsigned length, LChar*&);
+    WTF_EXPORT_STRING_API static Ref<StringImpl> createUninitialized(unsigned length, UChar*&);
+    template<typename CharacterType> static RefPtr<StringImpl> tryCreateUninitialized(unsigned length, CharacterType*&);
 
     // Reallocate the StringImpl. The originalString must be only owned by the Ref,
     // and the buffer ownership must be BufferInternal. Just like the input pointer of realloc(),
@@ -396,83 +262,30 @@ public:
     static unsigned maskStringKind() { return s_hashMaskStringKind; }
     static unsigned dataOffset() { return OBJECT_OFFSETOF(StringImpl, m_data8); }
 
-    template<typename CharType, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
-    static Ref<StringImpl> adopt(StringVector<CharType, inlineCapacity, OverflowHandler, minCapacity>&& vector)
-    {
-        if (size_t size = vector.size()) {
-            ASSERT(vector.data());
-            if (size > std::numeric_limits<unsigned>::max())
-                CRASH();
-            return adoptRef(*new StringImpl(vector.releaseBuffer(), size));
-        }
-        return *empty();
-    }
+    template<typename CharacterType, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
+    static Ref<StringImpl> adopt(StringVector<CharacterType, inlineCapacity, OverflowHandler, minCapacity>&&);
 
     WTF_EXPORT_STRING_API static Ref<StringImpl> adopt(StringBuffer<UChar>&&);
     WTF_EXPORT_STRING_API static Ref<StringImpl> adopt(StringBuffer<LChar>&&);
 
     unsigned length() const { return m_length; }
     static ptrdiff_t lengthMemoryOffset() { return OBJECT_OFFSETOF(StringImpl, m_length); }
-    bool is8Bit() const { return m_hashAndFlags & s_hashFlag8BitBuffer; }
+    bool isEmpty() const { return !m_length; }
 
+    bool is8Bit() const { return m_hashAndFlags & s_hashFlag8BitBuffer; }
     ALWAYS_INLINE const LChar* characters8() const { ASSERT(is8Bit()); return m_data8; }
     ALWAYS_INLINE const UChar* characters16() const { ASSERT(!is8Bit()); return m_data16; }
 
-    template <typename CharType>
-    ALWAYS_INLINE const CharType *characters() const;
+    template<typename CharacterType> const CharacterType* characters() const;
 
-    size_t cost() const
-    {
-        // For substrings, return the cost of the base string.
-        if (bufferOwnership() == BufferSubstring)
-            return substringBuffer()->cost();
-
-        // Note: we must not alter the m_hashAndFlags field in instances of StaticStringImpl.
-        // We ensure this by pre-setting the s_hashFlagDidReportCost bit in all instances of
-        // StaticStringImpl. As a result, StaticStringImpl instances will always return a cost of
-        // 0 here and avoid modifying m_hashAndFlags.
-        if (m_hashAndFlags & s_hashFlagDidReportCost)
-            return 0;
-
-        m_hashAndFlags |= s_hashFlagDidReportCost;
-        size_t result = m_length;
-        if (!is8Bit())
-            result <<= 1;
-        return result;
-    }
-    
-    size_t costDuringGC()
-    {
-        if (isStatic())
-            return 0;
-        
-        if (bufferOwnership() == BufferSubstring)
-            return divideRoundedUp(substringBuffer()->costDuringGC(), refCount());
-        
-        size_t result = m_length;
-        if (!is8Bit())
-            result <<= 1;
-        return divideRoundedUp(result, refCount());
-    }
+    size_t cost() const;
+    size_t costDuringGC();
 
     WTF_EXPORT_STRING_API size_t sizeInBytes() const;
 
-    StringKind stringKind() const { return static_cast<StringKind>(m_hashAndFlags & s_hashMaskStringKind); }
     bool isSymbol() const { return m_hashAndFlags & s_hashFlagStringKindIsSymbol; }
     bool isAtomic() const { return m_hashAndFlags & s_hashFlagStringKindIsAtomic; }
-
-    void setIsAtomic(bool isAtomic)
-    {
-        ASSERT(!isStatic());
-        ASSERT(!isSymbol());
-        if (isAtomic) {
-            m_hashAndFlags |= s_hashFlagStringKindIsAtomic;
-            ASSERT(stringKind() == StringAtomic);
-        } else {
-            m_hashAndFlags &= ~s_hashFlagStringKindIsAtomic;
-            ASSERT(stringKind() == StringNormal);
-        }
-    }
+    void setIsAtomic(bool);
 
 #if STRING_STATS
     bool isSubString() const { return bufferOwnership() == BufferSubstring; }
@@ -489,44 +302,15 @@ private:
     // The high bits of 'hash' are always empty, but we prefer to store our flags
     // in the low bits because it makes them slightly more efficient to access.
     // So, we shift left and right when setting and getting our hash code.
-    void setHash(unsigned hash) const
-    {
-        ASSERT(!hasHash());
-        ASSERT(!isStatic());
-        // Multiple clients assume that StringHasher is the canonical string hash function.
-        ASSERT(hash == (is8Bit() ? StringHasher::computeHashAndMaskTop8Bits(m_data8, m_length) : StringHasher::computeHashAndMaskTop8Bits(m_data16, m_length)));
-        ASSERT(!(hash & (s_flagMask << (8 * sizeof(hash) - s_flagCount)))); // Verify that enough high bits are empty.
-        
-        hash <<= s_flagCount;
-        ASSERT(!(hash & m_hashAndFlags)); // Verify that enough low bits are empty after shift.
-        ASSERT(hash); // Verify that 0 is a valid sentinel hash value.
-
-        m_hashAndFlags |= hash; // Store hash with flags in low bits.
-    }
+    void setHash(unsigned) const;
 
-    unsigned rawHash() const
-    {
-        return m_hashAndFlags >> s_flagCount;
-    }
+    unsigned rawHash() const { return m_hashAndFlags >> s_flagCount; }
 
 public:
-    bool hasHash() const
-    {
-        return rawHash() != 0;
-    }
-
-    unsigned existingHash() const
-    {
-        ASSERT(hasHash());
-        return rawHash();
-    }
+    bool hasHash() const { return !!rawHash(); }
 
-    unsigned hash() const
-    {
-        if (hasHash())
-            return existingHash();
-        return hashSlowCase();
-    }
+    unsigned existingHash() const { ASSERT(hasHash()); return rawHash(); }
+    unsigned hash() const { return hasHash() ? rawHash() : hashSlowCase(); }
 
     WTF_EXPORT_PRIVATE unsigned concurrentHash() const;
 
@@ -535,40 +319,12 @@ public:
 
     bool isStatic() const { return m_refCount & s_refCountFlagIsStaticString; }
 
-    inline size_t refCount() const
-    {
-        return m_refCount / s_refCountIncrement;
-    }
-    
-    inline bool hasOneRef() const
-    {
-        return m_refCount == s_refCountIncrement;
-    }
-    
-    // This method is useful for assertions.
-    inline bool hasAtLeastOneRef() const
-    {
-        return !!m_refCount;
-    }
-
-    inline void ref()
-    {
-        STRING_STATS_REF_STRING(*this);
+    size_t refCount() const { return m_refCount / s_refCountIncrement; }
+    bool hasOneRef() const { return m_refCount == s_refCountIncrement; }
+    bool hasAtLeastOneRef() const { return m_refCount; } // For assertions.
 
-        m_refCount += s_refCountIncrement;
-    }
-
-    inline void deref()
-    {
-        STRING_STATS_DEREF_STRING(*this);
-
-        unsigned tempRefCount = m_refCount - s_refCountIncrement;
-        if (!tempRefCount) {
-            StringImpl::destroy(this);
-            return;
-        }
-        m_refCount = tempRefCount;
-    }
+    void ref();
+    void deref();
 
     class StaticStringImpl : private StringImplShape {
         WTF_MAKE_NONCOPYABLE(StaticStringImpl);
@@ -600,64 +356,29 @@ public:
         //       StringImpl::hash() only sets a new hash iff !hasHash().
         //       Additionally, StringImpl::setHash() asserts hasHash() and !isStatic().
 
-        template<unsigned characterCount>
-        constexpr StaticStringImpl(const char (&characters)[characterCount], StringKind stringKind = StringNormal)
-            : StringImplShape(s_refCountFlagIsStaticString, characterCount - 1, characters,
-                s_hashFlag8BitBuffer | s_hashFlagDidReportCost | stringKind | BufferInternal | (StringHasher::computeLiteralHashAndMaskTop8Bits(characters) << s_flagCount), ConstructWithConstExpr)
-        {
-        }
-
-        template<unsigned characterCount>
-        constexpr StaticStringImpl(const char16_t (&characters)[characterCount], StringKind stringKind = StringNormal)
-            : StringImplShape(s_refCountFlagIsStaticString, characterCount - 1, characters,
-                s_hashFlagDidReportCost | stringKind | BufferInternal | (StringHasher::computeLiteralHashAndMaskTop8Bits(characters) << s_flagCount), ConstructWithConstExpr)
-        {
-        }
-
-        operator StringImpl&()
-        {
-            return *reinterpret_cast<StringImpl*>(this);
-        }
+        template<unsigned characterCount> constexpr StaticStringImpl(const char (&characters)[characterCount], StringKind = StringNormal);
+        template<unsigned characterCount> constexpr StaticStringImpl(const char16_t (&characters)[characterCount], StringKind = StringNormal);
+        operator StringImpl&();
     };
 
     WTF_EXPORTDATA static StaticStringImpl s_atomicEmptyString;
     ALWAYS_INLINE static StringImpl* empty() { return reinterpret_cast<StringImpl*>(&s_atomicEmptyString); }
 
     // FIXME: Does this really belong in StringImpl?
-    template <typename T> static void copyChars(T* destination, const T* source, unsigned numCharacters)
-    {
-        if (numCharacters == 1) {
-            *destination = *source;
-            return;
-        }
-        memcpy(destination, source, numCharacters * sizeof(T));
-    }
-
-    ALWAYS_INLINE static void copyChars(UChar* destination, const LChar* source, unsigned numCharacters)
-    {
-        for (unsigned i = 0; i < numCharacters; ++i)
-            destination[i] = source[i];
-    }
+    template<typename CharacterType> static void copyCharacters(CharacterType* destination, const CharacterType* source, unsigned numCharacters);
+    static void copyCharacters(UChar* destination, const LChar* source, unsigned numCharacters);
 
     // Some string features, like refcounting and the atomicity flag, are not
     // thread-safe. We achieve thread safety by isolation, giving each thread
     // its own copy of the string.
     Ref<StringImpl> isolatedCopy() const;
 
-    WTF_EXPORT_STRING_API Ref<StringImpl> substring(unsigned pos, unsigned len = UINT_MAX);
+    WTF_EXPORT_STRING_API Ref<StringImpl> substring(unsigned position, unsigned length = std::numeric_limits<unsigned>::max());
 
-    UChar at(unsigned i) const
-    {
-        ASSERT_WITH_SECURITY_IMPLICATION(i < m_length);
-        if (is8Bit())
-            return m_data8[i];
-        return m_data16[i];
-    }
+    UChar at(unsigned) const;
     UChar operator[](unsigned i) const { return at(i); }
     WTF_EXPORT_STRING_API UChar32 characterStartingAt(unsigned);
 
-    WTF_EXPORT_STRING_API bool containsOnlyWhitespace();
-
     int toIntStrict(bool* ok = 0, int base = 10);
     unsigned toUIntStrict(bool* ok = 0, int base = 10);
     int64_t toInt64Strict(bool* ok = 0, int base = 10);
@@ -692,49 +413,44 @@ public:
     Ref<StringImpl> simplifyWhiteSpace(IsWhiteSpaceFunctionPtr);
 
     Ref<StringImpl> removeCharacters(CharacterMatchFunctionPtr);
-    template <typename CharType>
-    ALWAYS_INLINE Ref<StringImpl> removeCharacters(const CharType* characters, CharacterMatchFunctionPtr);
+    template<typename CharacterType> Ref<StringImpl> removeCharacters(const CharacterType*, CharacterMatchFunctionPtr);
+
+    bool isAllASCII() const;
+    bool isAllLatin1() const;
+    template<bool isSpecialCharacter(UChar)> bool isAllSpecialCharacters() const;
 
     size_t find(LChar character, unsigned start = 0);
     size_t find(char character, unsigned start = 0);
     size_t find(UChar character, unsigned start = 0);
     WTF_EXPORT_STRING_API size_t find(CharacterMatchFunctionPtr, unsigned index = 0);
     size_t find(const LChar*, unsigned index = 0);
-    ALWAYS_INLINE size_t find(const char* s, unsigned index = 0) { return find(reinterpret_cast<const LChar*>(s), index); }
+    ALWAYS_INLINE size_t find(const char* string, unsigned index = 0) { return find(reinterpret_cast<const LChar*>(string), index); }
     WTF_EXPORT_STRING_API size_t find(StringImpl*);
     WTF_EXPORT_STRING_API size_t find(StringImpl*, unsigned index);
-    size_t findIgnoringCase(const LChar*, unsigned index = 0);
-    ALWAYS_INLINE size_t findIgnoringCase(const char* s, unsigned index = 0) { return findIgnoringCase(reinterpret_cast<const LChar*>(s), index); }
-    WTF_EXPORT_STRING_API size_t findIgnoringCase(StringImpl*, unsigned index = 0);
     WTF_EXPORT_STRING_API size_t findIgnoringASCIICase(const StringImpl&) const;
     WTF_EXPORT_STRING_API size_t findIgnoringASCIICase(const StringImpl&, unsigned startOffset) const;
     WTF_EXPORT_STRING_API size_t findIgnoringASCIICase(const StringImpl*) const;
     WTF_EXPORT_STRING_API size_t findIgnoringASCIICase(const StringImpl*, unsigned startOffset) const;
 
-    WTF_EXPORT_STRING_API size_t reverseFind(UChar, unsigned index = UINT_MAX);
-    WTF_EXPORT_STRING_API size_t reverseFind(StringImpl*, unsigned index = UINT_MAX);
-    WTF_EXPORT_STRING_API size_t reverseFindIgnoringCase(StringImpl*, unsigned index = UINT_MAX);
+    WTF_EXPORT_STRING_API size_t reverseFind(UChar, unsigned index = std::numeric_limits<unsigned>::max());
+    WTF_EXPORT_STRING_API size_t reverseFind(StringImpl*, unsigned index = std::numeric_limits<unsigned>::max());
 
     WTF_EXPORT_STRING_API bool startsWith(const StringImpl*) const;
     WTF_EXPORT_STRING_API bool startsWith(const StringImpl&) const;
     WTF_EXPORT_STRING_API bool startsWithIgnoringASCIICase(const StringImpl*) const;
     WTF_EXPORT_STRING_API bool startsWithIgnoringASCIICase(const StringImpl&) const;
-    bool startsWith(StringImpl* str, bool caseSensitive) { return caseSensitive ? startsWith(str) : (reverseFindIgnoringCase(str, 0) == 0); }
     WTF_EXPORT_STRING_API bool startsWith(UChar) const;
-    WTF_EXPORT_STRING_API bool startsWith(const char*, unsigned matchLength, bool caseSensitive) const;
-    template<unsigned matchLength>
-    bool startsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const { return startsWith(prefix, matchLength - 1, caseSensitive); }
+    WTF_EXPORT_STRING_API bool startsWith(const char*, unsigned matchLength) const;
+    template<unsigned matchLength> bool startsWith(const char (&prefix)[matchLength]) const { return startsWith(prefix, matchLength - 1); }
     WTF_EXPORT_STRING_API bool hasInfixStartingAt(const StringImpl&, unsigned startOffset) const;
 
     WTF_EXPORT_STRING_API bool endsWith(StringImpl*);
     WTF_EXPORT_STRING_API bool endsWith(StringImpl&);
     WTF_EXPORT_STRING_API bool endsWithIgnoringASCIICase(const StringImpl*) const;
     WTF_EXPORT_STRING_API bool endsWithIgnoringASCIICase(const StringImpl&) const;
-    WTF_EXPORT_STRING_API bool endsWith(StringImpl*, bool caseSensitive);
     WTF_EXPORT_STRING_API bool endsWith(UChar) const;
-    WTF_EXPORT_STRING_API bool endsWith(const char*, unsigned matchLength, bool caseSensitive) const;
-    template<unsigned matchLength>
-    bool endsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const { return endsWith(prefix, matchLength - 1, caseSensitive); }
+    WTF_EXPORT_STRING_API bool endsWith(const char*, unsigned matchLength) const;
+    template<unsigned matchLength> bool endsWith(const char (&prefix)[matchLength]) const { return endsWith(prefix, matchLength - 1); }
     WTF_EXPORT_STRING_API bool hasInfixEndingAt(const StringImpl&, unsigned endOffset) const;
 
     WTF_EXPORT_STRING_API Ref<StringImpl> replace(UChar, UChar);
@@ -743,13 +459,14 @@ public:
     WTF_EXPORT_STRING_API Ref<StringImpl> replace(UChar, const LChar*, unsigned replacementLength);
     Ref<StringImpl> replace(UChar, const UChar*, unsigned replacementLength);
     WTF_EXPORT_STRING_API Ref<StringImpl> replace(StringImpl*, StringImpl*);
-    WTF_EXPORT_STRING_API Ref<StringImpl> replace(unsigned index, unsigned len, StringImpl*);
+    WTF_EXPORT_STRING_API Ref<StringImpl> replace(unsigned index, unsigned length, StringImpl*);
 
     WTF_EXPORT_STRING_API UCharDirection defaultWritingDirection(bool* hasStrongDirectionality = nullptr);
 
 #if USE(CF)
     RetainPtr<CFStringRef> createCFString();
 #endif
+
 #ifdef __OBJC__
     WTF_EXPORT_STRING_API operator NSString *();
 #endif
@@ -760,110 +477,40 @@ public:
 
     BufferOwnership bufferOwnership() const { return static_cast<BufferOwnership>(m_hashAndFlags & s_hashMaskBufferOwnership); }
     
-    void assertCaged() const
-    {
-        if (!ASSERT_DISABLED)
-            releaseAssertCaged();
-    }
-    
+    void assertCaged() const;
     WTF_EXPORT_PRIVATE void releaseAssertCaged() const;
 
 protected:
     ~StringImpl();
 
+    // Used to create new symbol string that holds an existing [[Description]] string as a substring buffer (BufferSubstring).
     enum CreateSymbolTag { CreateSymbol };
-
-    // Used to create new symbol strings that holds existing 8-bit [[Description]] string as a substring buffer (BufferSubstring).
-    StringImpl(CreateSymbolTag, const LChar* characters, unsigned length)
-        : StringImplShape(s_refCountIncrement, length, characters, s_hashFlag8BitBuffer | StringSymbol | BufferSubstring)
-    {
-        ASSERT(is8Bit());
-        ASSERT(m_data8);
-        STRING_STATS_ADD_8BIT_STRING2(m_length, true);
-    }
-
-    // Used to create new symbol strings that holds existing 16-bit [[Description]] string as a substring buffer (BufferSubstring).
-    StringImpl(CreateSymbolTag, const UChar* characters, unsigned length)
-        : StringImplShape(s_refCountIncrement, length, characters, StringSymbol | BufferSubstring)
-    {
-        ASSERT(!is8Bit());
-        ASSERT(m_data16);
-        STRING_STATS_ADD_16BIT_STRING2(m_length, true);
-    }
+    StringImpl(CreateSymbolTag, const LChar*, unsigned length);
+    StringImpl(CreateSymbolTag, const UChar*, unsigned length);
 
     // Null symbol.
-    StringImpl(CreateSymbolTag)
-        : StringImplShape(s_refCountIncrement, 0, empty()->characters8(), s_hashFlag8BitBuffer | StringSymbol | BufferSubstring)
-    {
-        ASSERT(is8Bit());
-        ASSERT(m_data8);
-        STRING_STATS_ADD_8BIT_STRING2(m_length, true);
-    }
-
-    template<typename T>
-    static size_t allocationSize(Checked<size_t> tailElementCount)
-    {
-        return (tailOffset<T>() + tailElementCount * sizeof(T)).unsafeGet();
-    }
-
-    template<typename T>
-    static size_t tailOffset()
-    {
-#if COMPILER(MSVC)
-        // MSVC doesn't support alignof yet.
-        return roundUpToMultipleOf<sizeof(T)>(sizeof(StringImpl));
-#else
-        return roundUpToMultipleOf<alignof(T)>(offsetof(StringImpl, m_hashAndFlags) + sizeof(StringImpl::m_hashAndFlags));
-#endif
-    }
+    explicit StringImpl(CreateSymbolTag);
 
 private:
-    bool requiresCopy() const
-    {
-        if (bufferOwnership() != BufferInternal)
-            return true;
-
-        if (is8Bit())
-            return m_data8 == tailPointer<LChar>();
-        return m_data16 == tailPointer<UChar>();
-    }
-
-    template<typename T>
-    const T* tailPointer() const
-    {
-        return reinterpret_cast_ptr<const T*>(reinterpret_cast<const uint8_t*>(this) + tailOffset<T>());
-    }
-
-    template<typename T>
-    T* tailPointer()
-    {
-        return reinterpret_cast_ptr<T*>(reinterpret_cast<uint8_t*>(this) + tailOffset<T>());
-    }
-
-    StringImpl* const& substringBuffer() const
-    {
-        ASSERT(bufferOwnership() == BufferSubstring);
-
-        return *tailPointer<StringImpl*>();
-    }
+    template<typename> static size_t allocationSize(Checked<size_t> tailElementCount);
+    template<typename> static size_t tailOffset();
 
-    StringImpl*& substringBuffer()
-    {
-        ASSERT(bufferOwnership() == BufferSubstring);
-
-        return *tailPointer<StringImpl*>();
-    }
+    bool requiresCopy() const;
+    template<typename T> const T* tailPointer() const;
+    template<typename T> T* tailPointer();
+    StringImpl* const& substringBuffer() const;
+    StringImpl*& substringBuffer();
 
     enum class CaseConvertType { Upper, Lower };
-    template<CaseConvertType type, typename CharacterType> static Ref<StringImpl> convertASCIICase(StringImpl&, const CharacterType*, unsigned);
-
-    template <class UCharPredicate> Ref<StringImpl> stripMatchedCharacters(UCharPredicate);
-    template <typename CharType, class UCharPredicate> Ref<StringImpl> simplifyMatchedCharactersToSpace(UCharPredicate);
-    template <typename CharType> static Ref<StringImpl> constructInternal(StringImpl*, unsigned);
-    template <typename CharType> static Ref<StringImpl> createUninitializedInternal(unsigned, CharType*&);
-    template <typename CharType> static Ref<StringImpl> createUninitializedInternalNonEmpty(unsigned, CharType*&);
-    template <typename CharType> static Ref<StringImpl> reallocateInternal(Ref<StringImpl>&&, unsigned, CharType*&);
-    template <typename CharType> static Ref<StringImpl> createInternal(const CharType*, unsigned);
+    template<CaseConvertType, typename CharacterType> static Ref<StringImpl> convertASCIICase(StringImpl&, const CharacterType*, unsigned);
+
+    template<typename UCharPredicate> Ref<StringImpl> stripMatchedCharacters(UCharPredicate);
+    template<typename CharacterType, typename UCharPredicate> Ref<StringImpl> simplifyMatchedCharactersToSpace(UCharPredicate);
+    template<typename CharacterType> static Ref<StringImpl> constructInternal(StringImpl&, unsigned);
+    template<typename CharacterType> static Ref<StringImpl> createUninitializedInternal(unsigned, CharacterType*&);
+    template<typename CharacterType> static Ref<StringImpl> createUninitializedInternalNonEmpty(unsigned, CharacterType*&);
+    template<typename CharacterType> static Ref<StringImpl> reallocateInternal(Ref<StringImpl>&&, unsigned, CharacterType*&);
+    template<typename CharacterType> static Ref<StringImpl> createInternal(const CharacterType*, unsigned);
     WTF_EXPORT_PRIVATE NEVER_INLINE unsigned hashSlowCase() const;
 
     // The bottom bit in the ref count indicates a static (immortal) string.
@@ -875,13 +522,7 @@ private:
 #endif
 
 public:
-#ifndef NDEBUG
-    void assertHashIsCorrect() const
-    {
-        ASSERT(hasHash());
-        ASSERT(existingHash() == StringHasher::computeHashAndMaskTop8Bits(characters8(), length()));
-    }
-#endif
+    void assertHashIsCorrect() const;
 };
 
 using StaticStringImpl = StringImpl::StaticStringImpl;
@@ -889,27 +530,15 @@ using StaticStringImpl = StringImpl::StaticStringImpl;
 static_assert(sizeof(StringImpl) == sizeof(StaticStringImpl), "");
 
 #if !ASSERT_DISABLED
-// StringImpls created from StaticStringImpl will ASSERT
-// in the generic ValueCheck<T>::checkConsistency
-// as they are not allocated by stringMalloc.
-// We don't currently have any way to detect that case
+
+// StringImpls created from StaticStringImpl will ASSERT in the generic ValueCheck<T>::checkConsistency
+// as they are not allocated by stringMalloc. We don't currently have any way to detect that case
 // so we ignore the consistency check for all StringImpl*.
-template<> struct
-ValueCheck<StringImpl*> {
+template<> struct ValueCheck<StringImpl*> {
     static void checkConsistency(const StringImpl*) { }
 };
-#endif
-
-template <>
-ALWAYS_INLINE Ref<StringImpl> StringImpl::constructInternal<LChar>(StringImpl* impl, unsigned length) { return adoptRef(*new (NotNull, impl) StringImpl(length, Force8BitConstructor)); }
-template <>
-ALWAYS_INLINE Ref<StringImpl> StringImpl::constructInternal<UChar>(StringImpl* impl, unsigned length) { return adoptRef(*new (NotNull, impl) StringImpl(length)); }
-
-template <>
-ALWAYS_INLINE const LChar* StringImpl::characters<LChar>() const { return characters8(); }
 
-template <>
-ALWAYS_INLINE const UChar* StringImpl::characters<UChar>() const { return characters16(); }
+#endif
 
 WTF_EXPORT_STRING_API bool equal(const StringImpl*, const StringImpl*);
 WTF_EXPORT_STRING_API bool equal(const StringImpl*, const LChar*);
@@ -934,7 +563,60 @@ WTF_EXPORT_STRING_API bool equalIgnoringASCIICaseNonNull(const StringImpl*, cons
 template<unsigned length> bool equalLettersIgnoringASCIICase(const StringImpl&, const char (&lowercaseLetters)[length]);
 template<unsigned length> bool equalLettersIgnoringASCIICase(const StringImpl*, const char (&lowercaseLetters)[length]);
 
-inline size_t find(const LChar* characters, unsigned length, CharacterMatchFunctionPtr matchFunction, unsigned index = 0)
+size_t find(const LChar*, unsigned length, CharacterMatchFunctionPtr, unsigned index = 0);
+size_t find(const UChar*, unsigned length, CharacterMatchFunctionPtr, unsigned index = 0);
+
+template<typename CharacterType> size_t reverseFindLineTerminator(const CharacterType*, unsigned length, unsigned index = std::numeric_limits<unsigned>::max());
+template<typename CharacterType> size_t reverseFind(const CharacterType*, unsigned length, CharacterType matchCharacter, unsigned index = std::numeric_limits<unsigned>::max());
+size_t reverseFind(const UChar*, unsigned length, LChar matchCharacter, unsigned index = std::numeric_limits<unsigned>::max());
+size_t reverseFind(const LChar*, unsigned length, UChar matchCharacter, unsigned index = std::numeric_limits<unsigned>::max());
+
+template<size_t inlineCapacity> bool equalIgnoringNullity(const Vector<UChar, inlineCapacity>&, StringImpl*);
+
+template<typename CharacterType1, typename CharacterType2> int codePointCompare(const CharacterType1*, unsigned length1, const CharacterType2*, unsigned length2);
+int codePointCompare(const StringImpl*, const StringImpl*);
+
+// FIXME: Should rename this to make clear it uses the Unicode definition of whitespace.
+// Most WebKit callers don't want that would use isASCIISpace or isHTMLSpace instead.
+bool isSpaceOrNewline(UChar);
+
+template<typename CharacterType> unsigned lengthOfNullTerminatedString(const CharacterType*);
+
+// StringHash is the default hash for StringImpl* and RefPtr<StringImpl>
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<StringImpl*> {
+    typedef StringHash Hash;
+};
+template<> struct DefaultHash<RefPtr<StringImpl>> {
+    typedef StringHash Hash;
+};
+
+#define MAKE_STATIC_STRING_IMPL(characters) ([] { \
+        static StaticStringImpl impl(characters); \
+        return &impl; \
+    }())
+
+template<> ALWAYS_INLINE Ref<StringImpl> StringImpl::constructInternal<LChar>(StringImpl& string, unsigned length)
+{
+    return adoptRef(*new (NotNull, &string) StringImpl { length, Force8BitConstructor });
+}
+
+template<> ALWAYS_INLINE Ref<StringImpl> StringImpl::constructInternal<UChar>(StringImpl& string, unsigned length)
+{
+    return adoptRef(*new (NotNull, &string) StringImpl { length });
+}
+
+template<> ALWAYS_INLINE const LChar* StringImpl::characters<LChar>() const
+{
+    return characters8();
+}
+
+template<> ALWAYS_INLINE const UChar* StringImpl::characters<UChar>() const
+{
+    return characters16();
+}
+
+inline size_t find(const LChar* characters, unsigned length, CharacterMatchFunctionPtr matchFunction, unsigned index)
 {
     while (index < length) {
         if (matchFunction(characters[index]))
@@ -944,7 +626,7 @@ inline size_t find(const LChar* characters, unsigned length, CharacterMatchFunct
     return notFound;
 }
 
-inline size_t find(const UChar* characters, unsigned length, CharacterMatchFunctionPtr matchFunction, unsigned index = 0)
+inline size_t find(const UChar* characters, unsigned length, CharacterMatchFunctionPtr matchFunction, unsigned index)
 {
     while (index < length) {
         if (matchFunction(characters[index]))
@@ -954,24 +636,22 @@ inline size_t find(const UChar* characters, unsigned length, CharacterMatchFunct
     return notFound;
 }
 
-template<typename CharacterType>
-inline size_t reverseFindLineTerminator(const CharacterType* characters, unsigned length, unsigned index = UINT_MAX)
+template<typename CharacterType> inline size_t reverseFindLineTerminator(const CharacterType* characters, unsigned length, unsigned index)
 {
     if (!length)
         return notFound;
     if (index >= length)
         index = length - 1;
-    CharacterType c = characters[index];
-    while ((c != '\n') && (c != '\r')) {
+    auto character = characters[index];
+    while (character != '\n' && character != '\r') {
         if (!index--)
             return notFound;
-        c = characters[index];
+        character = characters[index];
     }
     return index;
 }
 
-template<typename CharacterType>
-inline size_t reverseFind(const CharacterType* characters, unsigned length, CharacterType matchCharacter, unsigned index = UINT_MAX)
+template<typename CharacterType> inline size_t reverseFind(const CharacterType* characters, unsigned length, CharacterType matchCharacter, unsigned index)
 {
     if (!length)
         return notFound;
@@ -984,12 +664,12 @@ inline size_t reverseFind(const CharacterType* characters, unsigned length, Char
     return index;
 }
 
-ALWAYS_INLINE size_t reverseFind(const UChar* characters, unsigned length, LChar matchCharacter, unsigned index = UINT_MAX)
+ALWAYS_INLINE size_t reverseFind(const UChar* characters, unsigned length, LChar matchCharacter, unsigned index)
 {
     return reverseFind(characters, length, static_cast<UChar>(matchCharacter), index);
 }
 
-inline size_t reverseFind(const LChar* characters, unsigned length, UChar matchCharacter, unsigned index = UINT_MAX)
+inline size_t reverseFind(const LChar* characters, unsigned length, UChar matchCharacter, unsigned index)
 {
     if (matchCharacter & ~0xFF)
         return notFound;
@@ -1021,45 +701,30 @@ template<size_t inlineCapacity> inline bool equalIgnoringNullity(const Vector<UC
 }
 
 template<typename CharacterType1, typename CharacterType2>
-inline int codePointCompare(unsigned l1, unsigned l2, const CharacterType1* c1, const CharacterType2* c2)
-{
-    const unsigned lmin = l1 < l2 ? l1 : l2;
-    unsigned pos = 0;
-    while (pos < lmin && *c1 == *c2) {
-        ++c1;
-        ++c2;
-        ++pos;
+inline int codePointCompare(const CharacterType1* characters1, unsigned length1, const CharacterType2* characters2, unsigned length2)
+{
+    unsigned commonLength = std::min(length1, length2);
+
+    unsigned position = 0;
+    while (position < commonLength && *characters1 == *characters2) {
+        ++characters1;
+        ++characters2;
+        ++position;
     }
 
-    if (pos < lmin)
-        return (c1[0] > c2[0]) ? 1 : -1;
+    if (position < commonLength)
+        return (characters1[0] > characters2[0]) ? 1 : -1;
 
-    if (l1 == l2)
+    if (length1 == length2)
         return 0;
-
-    return (l1 > l2) ? 1 : -1;
-}
-
-inline int codePointCompare8(const StringImpl* string1, const StringImpl* string2)
-{
-    return codePointCompare(string1->length(), string2->length(), string1->characters8(), string2->characters8());
-}
-
-inline int codePointCompare16(const StringImpl* string1, const StringImpl* string2)
-{
-    return codePointCompare(string1->length(), string2->length(), string1->characters16(), string2->characters16());
-}
-
-inline int codePointCompare8To16(const StringImpl* string1, const StringImpl* string2)
-{
-    return codePointCompare(string1->length(), string2->length(), string1->characters8(), string2->characters16());
+    return (length1 > length2) ? 1 : -1;
 }
 
 inline int codePointCompare(const StringImpl* string1, const StringImpl* string2)
 {
+    // FIXME: Should null strings compare as less than empty strings rather than equal to them?
     if (!string1)
         return (string2 && string2->length()) ? -1 : 0;
-
     if (!string2)
         return string1->length() ? 1 : 0;
 
@@ -1067,23 +732,22 @@ inline int codePointCompare(const StringImpl* string1, const StringImpl* string2
     bool string2Is8Bit = string2->is8Bit();
     if (string1Is8Bit) {
         if (string2Is8Bit)
-            return codePointCompare8(string1, string2);
-        return codePointCompare8To16(string1, string2);
+            return codePointCompare(string1->characters8(), string1->length(), string2->characters8(), string2->length());
+        return codePointCompare(string1->characters8(), string1->length(), string2->characters16(), string2->length());
     }
     if (string2Is8Bit)
-        return -codePointCompare8To16(string2, string1);
-    return codePointCompare16(string1, string2);
+        return codePointCompare(string1->characters16(), string1->length(), string2->characters8(), string2->length());
+    return codePointCompare(string1->characters16(), string1->length(), string2->characters16(), string2->length());
 }
 
-inline bool isSpaceOrNewline(UChar c)
+inline bool isSpaceOrNewline(UChar character)
 {
     // Use isASCIISpace() for basic Latin-1.
     // This will include newlines, which aren't included in Unicode DirWS.
-    return c <= 0x7F ? isASCIISpace(c) : u_charDirection(c) == U_WHITE_SPACE_NEUTRAL;
+    return isASCII(character) ? isASCIISpace(character) : u_charDirection(character) == U_WHITE_SPACE_NEUTRAL;
 }
 
-template<typename CharacterType>
-inline unsigned lengthOfNullTerminatedString(const CharacterType* string)
+template<typename CharacterType> inline unsigned lengthOfNullTerminatedString(const CharacterType* string)
 {
     ASSERT(string);
     size_t length = 0;
@@ -1094,6 +758,38 @@ inline unsigned lengthOfNullTerminatedString(const CharacterType* string)
     return static_cast<unsigned>(length);
 }
 
+inline StringImplShape::StringImplShape(unsigned refCount, unsigned length, const LChar* data8, unsigned hashAndFlags)
+    : m_refCount(refCount)
+    , m_length(length)
+    , m_data8(data8)
+    , m_hashAndFlags(hashAndFlags)
+{
+}
+
+inline StringImplShape::StringImplShape(unsigned refCount, unsigned length, const UChar* data16, unsigned hashAndFlags)
+    : m_refCount(refCount)
+    , m_length(length)
+    , m_data16(data16)
+    , m_hashAndFlags(hashAndFlags)
+{
+}
+
+template<unsigned characterCount> inline constexpr StringImplShape::StringImplShape(unsigned refCount, unsigned length, const char (&characters)[characterCount], unsigned hashAndFlags, ConstructWithConstExprTag)
+    : m_refCount(refCount)
+    , m_length(length)
+    , m_data8Char(characters)
+    , m_hashAndFlags(hashAndFlags)
+{
+}
+
+template<unsigned characterCount> inline constexpr StringImplShape::StringImplShape(unsigned refCount, unsigned length, const char16_t (&characters)[characterCount], unsigned hashAndFlags, ConstructWithConstExprTag)
+    : m_refCount(refCount)
+    , m_length(length)
+    , m_data16Char(characters)
+    , m_hashAndFlags(hashAndFlags)
+{
+}
+
 inline Ref<StringImpl> StringImpl::isolatedCopy() const
 {
     if (!requiresCopy()) {
@@ -1107,14 +803,385 @@ inline Ref<StringImpl> StringImpl::isolatedCopy() const
     return create(m_data16, m_length);
 }
 
-// StringHash is the default hash for StringImpl* and RefPtr<StringImpl>
-template<typename T> struct DefaultHash;
-template<> struct DefaultHash<StringImpl*> {
-    typedef StringHash Hash;
-};
-template<> struct DefaultHash<RefPtr<StringImpl>> {
-    typedef StringHash Hash;
-};
+inline bool StringImpl::isAllASCII() const
+{
+    if (is8Bit())
+        return charactersAreAllASCII(characters8(), length());
+    return charactersAreAllASCII(characters16(), length());
+}
+
+inline bool StringImpl::isAllLatin1() const
+{
+    if (is8Bit())
+        return true;
+    auto* characters = characters16();
+    UChar ored = 0;
+    for (size_t i = 0; i < length(); ++i)
+        ored |= characters[i];
+    return !(ored & 0xFF00);
+}
+
+template<bool isSpecialCharacter(UChar), typename CharacterType> inline bool isAllSpecialCharacters(const CharacterType* characters, size_t length)
+{
+    for (size_t i = 0; i < length; ++i) {
+        if (!isSpecialCharacter(characters[i]))
+            return false;
+    }
+    return true;
+}
+
+template<bool isSpecialCharacter(UChar)> inline bool StringImpl::isAllSpecialCharacters() const
+{
+    if (is8Bit())
+        return WTF::isAllSpecialCharacters<isSpecialCharacter>(characters8(), length());
+    return WTF::isAllSpecialCharacters<isSpecialCharacter>(characters16(), length());
+}
+
+inline StringImpl::StringImpl(unsigned length, Force8Bit)
+    : StringImplShape(s_refCountIncrement, length, tailPointer<LChar>(), s_hashFlag8BitBuffer | StringNormal | BufferInternal)
+{
+    ASSERT(m_data8);
+    ASSERT(m_length);
+
+    STRING_STATS_ADD_8BIT_STRING(m_length);
+}
+
+inline StringImpl::StringImpl(unsigned length)
+    : StringImplShape(s_refCountIncrement, length, tailPointer<UChar>(), StringNormal | BufferInternal)
+{
+    ASSERT(m_data16);
+    ASSERT(m_length);
+
+    STRING_STATS_ADD_16BIT_STRING(m_length);
+}
+
+inline StringImpl::StringImpl(MallocPtr<LChar> characters, unsigned length)
+    : StringImplShape(s_refCountIncrement, length, characters.leakPtr(), s_hashFlag8BitBuffer | StringNormal | BufferOwned)
+{
+    ASSERT(m_data8);
+    ASSERT(m_length);
+
+    STRING_STATS_ADD_8BIT_STRING(m_length);
+}
+
+inline StringImpl::StringImpl(const UChar* characters, unsigned length, ConstructWithoutCopyingTag)
+    : StringImplShape(s_refCountIncrement, length, characters, StringNormal | BufferInternal)
+{
+    ASSERT(m_data16);
+    ASSERT(m_length);
+
+    STRING_STATS_ADD_16BIT_STRING(m_length);
+}
+
+inline StringImpl::StringImpl(const LChar* characters, unsigned length, ConstructWithoutCopyingTag)
+    : StringImplShape(s_refCountIncrement, length, characters, s_hashFlag8BitBuffer | StringNormal | BufferInternal)
+{
+    ASSERT(m_data8);
+    ASSERT(m_length);
+
+    STRING_STATS_ADD_8BIT_STRING(m_length);
+}
+
+inline StringImpl::StringImpl(MallocPtr<UChar> characters, unsigned length)
+    : StringImplShape(s_refCountIncrement, length, characters.leakPtr(), StringNormal | BufferOwned)
+{
+    ASSERT(m_data16);
+    ASSERT(m_length);
+
+    STRING_STATS_ADD_16BIT_STRING(m_length);
+}
+
+inline StringImpl::StringImpl(const LChar* characters, unsigned length, Ref<StringImpl>&& base)
+    : StringImplShape(s_refCountIncrement, length, characters, s_hashFlag8BitBuffer | StringNormal | BufferSubstring)
+{
+    ASSERT(is8Bit());
+    ASSERT(m_data8);
+    ASSERT(m_length);
+    ASSERT(base->bufferOwnership() != BufferSubstring);
+
+    substringBuffer() = &base.leakRef();
+
+    STRING_STATS_ADD_8BIT_STRING2(m_length, true);
+}
+
+inline StringImpl::StringImpl(const UChar* characters, unsigned length, Ref<StringImpl>&& base)
+    : StringImplShape(s_refCountIncrement, length, characters, StringNormal | BufferSubstring)
+{
+    ASSERT(!is8Bit());
+    ASSERT(m_data16);
+    ASSERT(m_length);
+    ASSERT(base->bufferOwnership() != BufferSubstring);
+
+    substringBuffer() = &base.leakRef();
+
+    STRING_STATS_ADD_16BIT_STRING2(m_length, true);
+}
+
+template<size_t inlineCapacity> inline Ref<StringImpl> StringImpl::create8BitIfPossible(const Vector<UChar, inlineCapacity>& vector)
+{
+    return create8BitIfPossible(vector.data(), vector.size());
+}
+
+ALWAYS_INLINE Ref<StringImpl> StringImpl::createSubstringSharingImpl(StringImpl& rep, unsigned offset, unsigned length)
+{
+    ASSERT(length <= rep.length());
+
+    if (!length)
+        return *empty();
+
+    auto* ownerRep = ((rep.bufferOwnership() == BufferSubstring) ? rep.substringBuffer() : &rep);
+
+    // We allocate a buffer that contains both the StringImpl struct as well as the pointer to the owner string.
+    auto* stringImpl = static_cast<StringImpl*>(stringMalloc(allocationSize<StringImpl*>(1)));
+    if (rep.is8Bit())
+        return adoptRef(*new (NotNull, stringImpl) StringImpl(rep.m_data8 + offset, length, *ownerRep));
+    return adoptRef(*new (NotNull, stringImpl) StringImpl(rep.m_data16 + offset, length, *ownerRep));
+}
+
+template<unsigned characterCount> ALWAYS_INLINE Ref<StringImpl> StringImpl::createFromLiteral(const char (&characters)[characterCount])
+{
+    COMPILE_ASSERT(characterCount > 1, StringImplFromLiteralNotEmpty);
+    COMPILE_ASSERT((characterCount - 1 <= ((unsigned(~0) - sizeof(StringImpl)) / sizeof(LChar))), StringImplFromLiteralCannotOverflow);
+
+    return createWithoutCopying(reinterpret_cast<const LChar*>(characters), characterCount - 1);
+}
+
+template<typename CharacterType> ALWAYS_INLINE RefPtr<StringImpl> StringImpl::tryCreateUninitialized(unsigned length, CharacterType*& output)
+{
+    if (!length) {
+        output = nullptr;
+        return empty();
+    }
+
+    if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(CharacterType))) {
+        output = nullptr;
+        return nullptr;
+    }
+    auto* result = static_cast<StringImpl*>(tryStringMalloc(allocationSize<CharacterType>(length)));
+    if (!result) {
+        output = nullptr;
+        return nullptr;
+    }
+    output = result->tailPointer<CharacterType>();
+
+    return constructInternal<CharacterType>(*result, length);
+}
+
+template<typename CharacterType, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity>
+inline Ref<StringImpl> StringImpl::adopt(StringVector<CharacterType, inlineCapacity, OverflowHandler, minCapacity>&& vector)
+{
+    if (size_t size = vector.size()) {
+        ASSERT(vector.data());
+        if (size > std::numeric_limits<unsigned>::max())
+            CRASH();
+        return adoptRef(*new StringImpl(vector.releaseBuffer(), size));
+    }
+    return *empty();
+}
+
+inline size_t StringImpl::cost() const
+{
+    // For substrings, return the cost of the base string.
+    if (bufferOwnership() == BufferSubstring)
+        return substringBuffer()->cost();
+
+    // Note: we must not alter the m_hashAndFlags field in instances of StaticStringImpl.
+    // We ensure this by pre-setting the s_hashFlagDidReportCost bit in all instances of
+    // StaticStringImpl. As a result, StaticStringImpl instances will always return a cost of
+    // 0 here and avoid modifying m_hashAndFlags.
+    if (m_hashAndFlags & s_hashFlagDidReportCost)
+        return 0;
+
+    m_hashAndFlags |= s_hashFlagDidReportCost;
+    size_t result = m_length;
+    if (!is8Bit())
+        result <<= 1;
+    return result;
+}
+
+inline size_t StringImpl::costDuringGC()
+{
+    if (isStatic())
+        return 0;
+
+    if (bufferOwnership() == BufferSubstring)
+        return divideRoundedUp(substringBuffer()->costDuringGC(), refCount());
+
+    size_t result = m_length;
+    if (!is8Bit())
+        result <<= 1;
+    return divideRoundedUp(result, refCount());
+}
+
+inline void StringImpl::setIsAtomic(bool isAtomic)
+{
+    ASSERT(!isStatic());
+    ASSERT(!isSymbol());
+    if (isAtomic)
+        m_hashAndFlags |= s_hashFlagStringKindIsAtomic;
+    else
+        m_hashAndFlags &= ~s_hashFlagStringKindIsAtomic;
+}
+
+inline void StringImpl::setHash(unsigned hash) const
+{
+    // The high bits of 'hash' are always empty, but we prefer to store our flags
+    // in the low bits because it makes them slightly more efficient to access.
+    // So, we shift left and right when setting and getting our hash code.
+
+    ASSERT(!hasHash());
+    ASSERT(!isStatic());
+    // Multiple clients assume that StringHasher is the canonical string hash function.
+    ASSERT(hash == (is8Bit() ? StringHasher::computeHashAndMaskTop8Bits(m_data8, m_length) : StringHasher::computeHashAndMaskTop8Bits(m_data16, m_length)));
+    ASSERT(!(hash & (s_flagMask << (8 * sizeof(hash) - s_flagCount)))); // Verify that enough high bits are empty.
+
+    hash <<= s_flagCount;
+    ASSERT(!(hash & m_hashAndFlags)); // Verify that enough low bits are empty after shift.
+    ASSERT(hash); // Verify that 0 is a valid sentinel hash value.
+
+    m_hashAndFlags |= hash; // Store hash with flags in low bits.
+}
+
+inline void StringImpl::ref()
+{
+    STRING_STATS_REF_STRING(*this);
+
+    m_refCount += s_refCountIncrement;
+}
+
+inline void StringImpl::deref()
+{
+    STRING_STATS_DEREF_STRING(*this);
+
+    unsigned tempRefCount = m_refCount - s_refCountIncrement;
+    if (!tempRefCount) {
+        StringImpl::destroy(this);
+        return;
+    }
+    m_refCount = tempRefCount;
+}
+
+template<typename CharacterType> inline void StringImpl::copyCharacters(CharacterType* destination, const CharacterType* source, unsigned numCharacters)
+{
+    if (numCharacters == 1) {
+        *destination = *source;
+        return;
+    }
+    memcpy(destination, source, numCharacters * sizeof(CharacterType));
+}
+
+ALWAYS_INLINE void StringImpl::copyCharacters(UChar* destination, const LChar* source, unsigned numCharacters)
+{
+    for (unsigned i = 0; i < numCharacters; ++i)
+        destination[i] = source[i];
+}
+
+inline UChar StringImpl::at(unsigned i) const
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(i < m_length);
+    return is8Bit() ? m_data8[i] : m_data16[i];
+}
+
+inline void StringImpl::assertCaged() const
+{
+    if (!ASSERT_DISABLED)
+        releaseAssertCaged();
+}
+
+inline StringImpl::StringImpl(CreateSymbolTag, const LChar* characters, unsigned length)
+    : StringImplShape(s_refCountIncrement, length, characters, s_hashFlag8BitBuffer | StringSymbol | BufferSubstring)
+{
+    ASSERT(is8Bit());
+    ASSERT(m_data8);
+    STRING_STATS_ADD_8BIT_STRING2(m_length, true);
+}
+
+inline StringImpl::StringImpl(CreateSymbolTag, const UChar* characters, unsigned length)
+    : StringImplShape(s_refCountIncrement, length, characters, StringSymbol | BufferSubstring)
+{
+    ASSERT(!is8Bit());
+    ASSERT(m_data16);
+    STRING_STATS_ADD_16BIT_STRING2(m_length, true);
+}
+
+inline StringImpl::StringImpl(CreateSymbolTag)
+    : StringImplShape(s_refCountIncrement, 0, empty()->characters8(), s_hashFlag8BitBuffer | StringSymbol | BufferSubstring)
+{
+    ASSERT(is8Bit());
+    ASSERT(m_data8);
+    STRING_STATS_ADD_8BIT_STRING2(m_length, true);
+}
+
+template<typename T> inline size_t StringImpl::allocationSize(Checked<size_t> tailElementCount)
+{
+    return (tailOffset<T>() + tailElementCount * sizeof(T)).unsafeGet();
+}
+
+template<typename T> inline size_t StringImpl::tailOffset()
+{
+#if COMPILER(MSVC)
+    // MSVC doesn't support alignof yet.
+    return roundUpToMultipleOf<sizeof(T)>(sizeof(StringImpl));
+#else
+    return roundUpToMultipleOf<alignof(T)>(offsetof(StringImpl, m_hashAndFlags) + sizeof(StringImpl::m_hashAndFlags));
+#endif
+}
+
+inline bool StringImpl::requiresCopy() const
+{
+    if (bufferOwnership() != BufferInternal)
+        return true;
+
+    if (is8Bit())
+        return m_data8 == tailPointer<LChar>();
+    return m_data16 == tailPointer<UChar>();
+}
+
+template<typename T> inline const T* StringImpl::tailPointer() const
+{
+    return reinterpret_cast_ptr<const T*>(reinterpret_cast<const uint8_t*>(this) + tailOffset<T>());
+}
+
+template<typename T> inline T* StringImpl::tailPointer()
+{
+    return reinterpret_cast_ptr<T*>(reinterpret_cast<uint8_t*>(this) + tailOffset<T>());
+}
+
+inline StringImpl* const& StringImpl::substringBuffer() const
+{
+    ASSERT(bufferOwnership() == BufferSubstring);
+
+    return *tailPointer<StringImpl*>();
+}
+
+inline StringImpl*& StringImpl::substringBuffer()
+{
+    ASSERT(bufferOwnership() == BufferSubstring);
+
+    return *tailPointer<StringImpl*>();
+}
+
+inline void StringImpl::assertHashIsCorrect() const
+{
+    ASSERT(existingHash() == StringHasher::computeHashAndMaskTop8Bits(characters8(), length()));
+}
+
+template<unsigned characterCount> inline constexpr StringImpl::StaticStringImpl::StaticStringImpl(const char (&characters)[characterCount], StringKind stringKind)
+    : StringImplShape(s_refCountFlagIsStaticString, characterCount - 1, characters,
+        s_hashFlag8BitBuffer | s_hashFlagDidReportCost | stringKind | BufferInternal | (StringHasher::computeLiteralHashAndMaskTop8Bits(characters) << s_flagCount), ConstructWithConstExpr)
+{
+}
+
+template<unsigned characterCount> inline constexpr StringImpl::StaticStringImpl::StaticStringImpl(const char16_t (&characters)[characterCount], StringKind stringKind)
+    : StringImplShape(s_refCountFlagIsStaticString, characterCount - 1, characters,
+        s_hashFlagDidReportCost | stringKind | BufferInternal | (StringHasher::computeLiteralHashAndMaskTop8Bits(characters) << s_flagCount), ConstructWithConstExpr)
+{
+}
+
+inline StringImpl::StaticStringImpl::operator StringImpl&()
+{
+    return *reinterpret_cast<StringImpl*>(this);
+}
 
 inline bool equalIgnoringASCIICase(const StringImpl& a, const StringImpl& b)
 {
@@ -1151,19 +1218,10 @@ template<unsigned length> inline bool equalLettersIgnoringASCIICase(const String
     return string && equalLettersIgnoringASCIICase(*string, lowercaseLetters);
 }
 
-#define MAKE_STATIC_STRING_IMPL(characters) ([] { \
-        static StaticStringImpl impl(characters); \
-        return &impl; \
-    }())
-
-
 } // namespace WTF
 
 using WTF::StringImpl;
 using WTF::StaticStringImpl;
 using WTF::equal;
-using WTF::TextCaseSensitivity;
-using WTF::TextCaseSensitive;
-using WTF::TextCaseInsensitive;
 
 #endif
index 2a2255a..1813ec3 100644 (file)
@@ -451,16 +451,16 @@ inline bool StringView::contains(UChar character) const
 inline void StringView::getCharactersWithUpconvert(LChar* destination) const
 {
     ASSERT(is8Bit());
-    StringImpl::copyChars(destination, characters8(), m_length);
+    StringImpl::copyCharacters(destination, characters8(), m_length);
 }
 
 inline void StringView::getCharactersWithUpconvert(UChar* destination) const
 {
     if (is8Bit()) {
-        StringImpl::copyChars(destination, characters8(), m_length);
+        StringImpl::copyCharacters(destination, characters8(), m_length);
         return;
     }
-    StringImpl::copyChars(destination, characters16(), m_length);
+    StringImpl::copyCharacters(destination, characters16(), m_length);
 }
 
 inline StringView::UpconvertedCharacters::UpconvertedCharacters(const StringView& string)
index 0e99502..fe28fb6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * (C) 1999 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
  * Copyright (C) 2007-2009 Torch Mobile, Inc.
  *
  * This library is free software; you can redistribute it and/or
@@ -48,12 +48,10 @@ String::String(const UChar* characters, unsigned length)
 }
 
 // Construct a string with UTF-16 data, from a null-terminated source.
-String::String(const UChar* str)
+String::String(const UChar* nullTerminatedString)
 {
-    if (!str)
-        return;
-
-    m_impl = StringImpl::create(str, lengthOfNullTerminatedString(str));
+    if (nullTerminatedString)
+        m_impl = StringImpl::create(nullTerminatedString, lengthOfNullTerminatedString(nullTerminatedString));
 }
 
 // Construct a string with latin1 data.
@@ -69,17 +67,17 @@ String::String(const char* characters, unsigned length)
         m_impl = StringImpl::create(reinterpret_cast<const LChar*>(characters), length);
 }
 
-// Construct a string with latin1 data, from a null-terminated source.
-String::String(const LChar* characters)
+// Construct a string with Latin-1 data, from a null-terminated source.
+String::String(const LChar* nullTerminatedString)
 {
-    if (characters)
-        m_impl = StringImpl::create(characters);
+    if (nullTerminatedString)
+        m_impl = StringImpl::create(nullTerminatedString);
 }
 
-String::String(const char* characters)
+String::String(const char* nullTerminatedString)
 {
-    if (characters)
-        m_impl = StringImpl::create(reinterpret_cast<const LChar*>(characters));
+    if (nullTerminatedString)
+        m_impl = StringImpl::create(reinterpret_cast<const LChar*>(nullTerminatedString));
 }
 
 String::String(ASCIILiteral characters)
@@ -87,35 +85,36 @@ String::String(ASCIILiteral characters)
 {
 }
 
-void String::append(const String& str)
+void String::append(const String& otherString)
 {
     // FIXME: This is extremely inefficient. So much so that we might want to take this out of String's API.
 
-    if (str.isEmpty())
-       return;
-
-    if (str.m_impl) {
-        if (m_impl) {
-            if (m_impl->is8Bit() && str.m_impl->is8Bit()) {
-                LChar* data;
-                if (str.length() > std::numeric_limits<unsigned>::max() - m_impl->length())
-                    CRASH();
-                auto newImpl = StringImpl::createUninitialized(m_impl->length() + str.length(), data);
-                memcpy(data, m_impl->characters8(), m_impl->length() * sizeof(LChar));
-                memcpy(data + m_impl->length(), str.characters8(), str.length() * sizeof(LChar));
-                m_impl = WTFMove(newImpl);
-                return;
-            }
-            UChar* data;
-            if (str.length() > std::numeric_limits<unsigned>::max() - m_impl->length())
-                CRASH();
-            auto newImpl = StringImpl::createUninitialized(m_impl->length() + str.length(), data);
-            StringView(*m_impl).getCharactersWithUpconvert(data);
-            StringView(str).getCharactersWithUpconvert(data + m_impl->length());
-            m_impl = WTFMove(newImpl);
-        } else
-            m_impl = str.m_impl;
+    if (!m_impl) {
+        m_impl = otherString.m_impl;
+        return;
     }
+
+    if (otherString.isEmpty())
+        return;
+
+    auto length = m_impl->length();
+    auto otherLength = otherString.m_impl->length();
+    if (otherLength > std::numeric_limits<unsigned>::max() - length)
+        CRASH();
+
+    if (m_impl->is8Bit() && otherString.m_impl->is8Bit()) {
+        LChar* data;
+        auto newImpl = StringImpl::createUninitialized(length + otherLength, data);
+        StringImpl::copyCharacters(data, m_impl->characters8(), length);
+        StringImpl::copyCharacters(data + length, otherString.m_impl->characters8(), otherLength);
+        m_impl = WTFMove(newImpl);
+        return;
+    }
+    UChar* data;
+    auto newImpl = StringImpl::createUninitialized(length + otherLength, data);
+    StringView(*m_impl).getCharactersWithUpconvert(data);
+    StringView(*otherString.m_impl).getCharactersWithUpconvert(data + length);
+    m_impl = WTFMove(newImpl);
 }
 
 void String::append(LChar character)
@@ -134,7 +133,7 @@ void String::append(LChar character)
         CRASH();
     LChar* data;
     auto newImpl = StringImpl::createUninitialized(m_impl->length() + 1, data);
-    memcpy(data, m_impl->characters8(), m_impl->length());
+    StringImpl::copyCharacters(data, m_impl->characters8(), m_impl->length());
     data[m_impl->length()] = character;
     m_impl = WTFMove(newImpl);
 }
@@ -227,8 +226,8 @@ void String::append(const LChar* charactersToAppend, unsigned lengthToAppend)
             CRASH();
         LChar* data;
         auto newImpl = StringImpl::createUninitialized(strLength + lengthToAppend, data);
-        StringImpl::copyChars(data, m_impl->characters8(), strLength);
-        StringImpl::copyChars(data + strLength, charactersToAppend, lengthToAppend);
+        StringImpl::copyCharacters(data, m_impl->characters8(), strLength);
+        StringImpl::copyCharacters(data + strLength, charactersToAppend, lengthToAppend);
         m_impl = WTFMove(newImpl);
         return;
     }
@@ -237,8 +236,8 @@ void String::append(const LChar* charactersToAppend, unsigned lengthToAppend)
         CRASH();
     UChar* data;
     auto newImpl = StringImpl::createUninitialized(length() + lengthToAppend, data);
-    StringImpl::copyChars(data, m_impl->characters16(), strLength);
-    StringImpl::copyChars(data + strLength, charactersToAppend, lengthToAppend);
+    StringImpl::copyCharacters(data, m_impl->characters16(), strLength);
+    StringImpl::copyCharacters(data + strLength, charactersToAppend, lengthToAppend);
     m_impl = WTFMove(newImpl);
 }
 
@@ -264,10 +263,10 @@ void String::append(const UChar* charactersToAppend, unsigned lengthToAppend)
     UChar* data;
     auto newImpl = StringImpl::createUninitialized(strLength + lengthToAppend, data);
     if (m_impl->is8Bit())
-        StringImpl::copyChars(data, characters8(), strLength);
+        StringImpl::copyCharacters(data, characters8(), strLength);
     else
-        StringImpl::copyChars(data, characters16(), strLength);
-    StringImpl::copyChars(data + strLength, charactersToAppend, lengthToAppend);
+        StringImpl::copyCharacters(data, characters16(), strLength);
+    StringImpl::copyCharacters(data + strLength, charactersToAppend, lengthToAppend);
     m_impl = WTFMove(newImpl);
 }
 
@@ -285,41 +284,33 @@ void String::truncate(unsigned position)
         m_impl = m_impl->substring(0, position);
 }
 
-template <typename CharacterType>
-inline void String::removeInternal(const CharacterType* characters, unsigned position, int lengthToRemove)
+template<typename CharacterType> inline void String::removeInternal(const CharacterType* characters, unsigned position, unsigned lengthToRemove)
 {
     CharacterType* data;
     auto newImpl = StringImpl::createUninitialized(length() - lengthToRemove, data);
-    memcpy(data, characters, position * sizeof(CharacterType));
-    memcpy(data + position, characters + position + lengthToRemove,
-        (length() - lengthToRemove - position) * sizeof(CharacterType));
-
+    StringImpl::copyCharacters(data, characters, position);
+    StringImpl::copyCharacters(data + position, characters + position + lengthToRemove, length() - lengthToRemove - position);
     m_impl = WTFMove(newImpl);
 }
 
-void String::remove(unsigned position, int lengthToRemove)
+void String::remove(unsigned position, unsigned lengthToRemove)
 {
-    if (lengthToRemove <= 0)
+    if (!lengthToRemove)
         return;
-    if (position >= length())
+    auto length = this->length();
+    if (position >= length)
         return;
-    if (static_cast<unsigned>(lengthToRemove) > length() - position)
-        lengthToRemove = length() - position;
-
-    if (is8Bit()) {
+    lengthToRemove = std::min(lengthToRemove, length - position);
+    if (is8Bit())
         removeInternal(characters8(), position, lengthToRemove);
-
-        return;
-    }
-
-    removeInternal(characters16(), position, lengthToRemove);
+    else
+        removeInternal(characters16(), position, lengthToRemove);
 }
 
-String String::substring(unsigned pos, unsigned len) const
+String String::substring(unsigned position, unsigned length) const
 {
-    if (!m_impl) 
-        return String();
-    return m_impl->substring(pos, len);
+    // FIXME: Should this function, and the many others like it, be inlined?
+    return m_impl ? m_impl->substring(position, length) : String { };
 }
 
 String String::substringSharingImpl(unsigned offset, unsigned length) const
@@ -332,100 +323,95 @@ String String::substringSharingImpl(unsigned offset, unsigned length) const
 
     if (!offset && length == stringLength)
         return *this;
-    return String(StringImpl::createSubstringSharingImpl(*m_impl, offset, length));
+    return StringImpl::createSubstringSharingImpl(*m_impl, offset, length);
 }
 
 String String::convertToASCIILowercase() const
 {
     // FIXME: Should this function, and the many others like it, be inlined?
-    if (!m_impl)
-        return String();
-    return m_impl->convertToASCIILowercase();
+    return m_impl ? m_impl->convertToASCIILowercase() : String { };
 }
 
 String String::convertToASCIIUppercase() const
 {
     // FIXME: Should this function, and the many others like it, be inlined?
-    if (!m_impl)
-        return String();
-    return m_impl->convertToASCIIUppercase();
+    return m_impl ? m_impl->convertToASCIIUppercase() : String { };
 }
 
 String String::convertToLowercaseWithoutLocale() const
 {
-    if (!m_impl)
-        return String();
-    return m_impl->convertToLowercaseWithoutLocale();
+    // FIXME: Should this function, and the many others like it, be inlined?
+    return m_impl ? m_impl->convertToLowercaseWithoutLocale() : String { };
 }
 
 String String::convertToLowercaseWithoutLocaleStartingAtFailingIndex8Bit(unsigned failingIndex) const
 {
-    if (!m_impl)
-        return String();
-    return m_impl->convertToLowercaseWithoutLocaleStartingAtFailingIndex8Bit(failingIndex);
+    // FIXME: Should this function, and the many others like it, be inlined?
+    return m_impl ? m_impl->convertToLowercaseWithoutLocaleStartingAtFailingIndex8Bit(failingIndex) : String { };
 }
 
 String String::convertToUppercaseWithoutLocale() const
 {
-    if (!m_impl)
-        return String();
-    return m_impl->convertToUppercaseWithoutLocale();
+    // FIXME: Should this function, and the many others like it, be inlined?
+    return m_impl ? m_impl->convertToUppercaseWithoutLocale() : String { };
 }
 
 String String::convertToLowercaseWithLocale(const AtomicString& localeIdentifier) const
 {
-    if (!m_impl)
-        return String();
-    return m_impl->convertToLowercaseWithLocale(localeIdentifier);
+    // FIXME: Should this function, and the many others like it, be inlined?
+    return m_impl ? m_impl->convertToLowercaseWithLocale(localeIdentifier) : String { };
 }
 
 String String::convertToUppercaseWithLocale(const AtomicString& localeIdentifier) const
 {
-    if (!m_impl)
-        return String();
-    return m_impl->convertToUppercaseWithLocale(localeIdentifier);
+    // FIXME: Should this function, and the many others like it, be inlined?
+    return m_impl ? m_impl->convertToUppercaseWithLocale(localeIdentifier) : String { };
 }
 
 String String::stripWhiteSpace() const
 {
-    if (!m_impl)
-        return String();
-    return m_impl->stripWhiteSpace();
+    // FIXME: Should this function, and the many others like it, be inlined?
+    // FIXME: This function needs a new name. For one thing, "whitespace" is a single
+    // word so the "s" should be lowercase. For another, it's not clear from this name
+    // that the function uses the Unicode definition of whitespace. Most WebKit callers
+    // don't want that and eventually we should consider deleting this.
+    return m_impl ? m_impl->stripWhiteSpace() : String { };
 }
 
 String String::stripWhiteSpace(IsWhiteSpaceFunctionPtr isWhiteSpace) const
 {
-    if (!m_impl)
-        return String();
-    return m_impl->stripWhiteSpace(isWhiteSpace);
+    // FIXME: Should this function, and the many others like it, be inlined?
+    // FIXME: This function needs a new name. It strips leading and trailing
+    // characters that match a predicate; not necessarily "white space".
+    return m_impl ? m_impl->stripWhiteSpace(isWhiteSpace) : String { };
 }
 
 String String::simplifyWhiteSpace() const
 {
-    if (!m_impl)
-        return String();
-    return m_impl->simplifyWhiteSpace();
+    // FIXME: Should this function, and the many others like it, be inlined?
+    // FIXME: This function needs a new name. For one thing, "whitespace" is a single
+    // word so the "s" should be lowercase. For another, it's not clear from this name
+    // that the function uses the Unicode definition of whitespace. Most WebKit callers
+    // don't want that and eventually we should consider deleting this.
+    return m_impl ? m_impl->simplifyWhiteSpace() : String { };
 }
 
 String String::simplifyWhiteSpace(IsWhiteSpaceFunctionPtr isWhiteSpace) const
 {
-    if (!m_impl)
-        return String();
-    return m_impl->simplifyWhiteSpace(isWhiteSpace);
+    // FIXME: Should this function, and the many others like it, be inlined?
+    return m_impl ? m_impl->simplifyWhiteSpace(isWhiteSpace) : String { };
 }
 
 String String::removeCharacters(CharacterMatchFunctionPtr findMatch) const
 {
-    if (!m_impl)
-        return String();
-    return m_impl->removeCharacters(findMatch);
+    // FIXME: Should this function, and the many others like it, be inlined?
+    return m_impl ? m_impl->removeCharacters(findMatch) : String { };
 }
 
 String String::foldCase() const
 {
-    if (!m_impl)
-        return String();
-    return m_impl->foldCase();
+    // FIXME: Should this function, and the many others like it, be inlined?
+    return m_impl ? m_impl->foldCase() : String { };
 }
 
 bool String::percentage(int& result) const
@@ -465,8 +451,7 @@ Vector<UChar> String::charactersWithNullTermination() const
     return result;
 }
 
-WTF_ATTRIBUTE_PRINTF(1, 0)
-static String createWithFormatAndArguments(const char *format, va_list args)
+WTF_ATTRIBUTE_PRINTF(1, 0) static String createWithFormatAndArguments(const char *format, va_list args)
 {
     va_list argsCopy;
     va_copy(argsCopy, args);
@@ -478,14 +463,12 @@ static String createWithFormatAndArguments(const char *format, va_list args)
 
 #if USE(CF) && !OS(WINDOWS)
     if (strstr(format, "%@")) {
-        RetainPtr<CFStringRef> cfFormat = adoptCF(CFStringCreateWithCString(kCFAllocatorDefault, format, kCFStringEncodingUTF8));
-
-        RetainPtr<CFStringRef> result = adoptCF(CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, nullptr, cfFormat.get(), args));
-
+        auto cfFormat = adoptCF(CFStringCreateWithCString(kCFAllocatorDefault, format, kCFStringEncodingUTF8));
+        auto result = adoptCF(CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, nullptr, cfFormat.get(), args));
         va_end(args);
         return result.get();
     }
-#endif // USE(CF) && !OS(WINDOWS)
+#endif
 
     // Do the format once to get the length.
 #if COMPILER(MSVC)
@@ -497,7 +480,7 @@ static String createWithFormatAndArguments(const char *format, va_list args)
     va_end(args);
 
     if (result == 0)
-        return String("");
+        return emptyString();
     if (result < 0)
         return String();
 
@@ -527,7 +510,6 @@ String String::format(const char *format, ...)
     va_start(args, format);
     String result = createWithFormatAndArguments(format, args);
     va_end(args);
-    
     return result;
 }
 
@@ -700,11 +682,11 @@ float String::toFloat(bool* ok) const
 }
 
 #if COMPILER_SUPPORTS(CXX_REFERENCE_QUALIFIED_FUNCTIONS)
+
 String String::isolatedCopy() const &
 {
-    if (!m_impl)
-        return String();
-    return m_impl->isolatedCopy();
+    // FIXME: Should this function, and the many others like it, be inlined?
+    return m_impl ? m_impl->isolatedCopy() : String { };
 }
 
 String String::isolatedCopy() &&
@@ -712,36 +694,27 @@ String String::isolatedCopy() &&
     if (isSafeToSendToAnotherThread()) {
         // Since we know that our string is a temporary that will be destroyed
         // we can just steal the m_impl from it, thus avoiding a copy.
-        return String(WTFMove(*this));
+        return { WTFMove(*this) };
     }
 
-    if (!m_impl)
-        return String();
-
-    return m_impl->isolatedCopy();
+    return m_impl ? m_impl->isolatedCopy() : String { };
 }
+
 #else
+
 String String::isolatedCopy() const
 {
-    if (!m_impl)
-        return String();
-    return m_impl->isolatedCopy();
+    // FIXME: Should this function, and the many others like it, be inlined?
+    return m_impl ? m_impl->isolatedCopy() : String { };
 }
+
 #endif
 
 bool String::isSafeToSendToAnotherThread() const
 {
-    if (!impl())
-        return true;
-    if (isEmpty())
-        return true;
     // AtomicStrings are not safe to send between threads as ~StringImpl()
     // will try to remove them from the wrong AtomicStringTable.
-    if (impl()->isAtomic())
-        return false;
-    if (impl()->hasOneRef())
-        return true;
-    return false;
+    return isEmpty() || (m_impl->hasOneRef() && !m_impl->isAtomic());
 }
 
 void String::split(const String& separator, bool allowEmptyEntries, Vector<String>& result) const
@@ -848,10 +821,7 @@ CString String::latin1() const
 
 CString String::utf8(ConversionMode mode) const
 {
-    if (!m_impl)
-        return CString("", 0);
-    
-    return m_impl->utf8(mode);
+    return m_impl ? m_impl->utf8(mode) : CString { "", 0 };
 }
 
 CString String::utf8() const
@@ -880,7 +850,7 @@ String String::make16BitFrom8BitSource(const LChar* source, size_t length)
     UChar* destination;
     String result = String::createUninitialized(length, destination);
     
-    StringImpl::copyChars(destination, source, length);
+    StringImpl::copyCharacters(destination, source, length);
     
     return result;
 }
@@ -949,8 +919,8 @@ static bool isCharacterAllowedInBase(UChar c, int base)
     return false;
 }
 
-template <typename IntegralType, typename CharType>
-static inline IntegralType toIntegralType(const CharType* data, size_t length, bool* ok, int base)
+template<typename IntegralType, typename CharacterType>
+static inline IntegralType toIntegralType(const CharacterType* data, size_t length, bool* ok, int base)
 {
     static const IntegralType integralMax = std::numeric_limits<IntegralType>::max();
     static const bool isSigned = std::numeric_limits<IntegralType>::is_signed;
@@ -984,7 +954,7 @@ static inline IntegralType toIntegralType(const CharType* data, size_t length, b
     while (length && isCharacterAllowedInBase(*data, base)) {
         --length;
         IntegralType digitValue;
-        CharType c = *data;
+        auto c = *data;
         if (isASCIIDigit(c))
             digitValue = c - '0';
         else if (c >= 'a')
@@ -1025,8 +995,8 @@ bye:
     return isOk ? value : 0;
 }
 
-template <typename CharType>
-static unsigned lengthOfCharactersAsInteger(const CharType* data, size_t length)
+template<typename CharacterType>
+static unsigned lengthOfCharactersAsInteger(const CharacterType* data, size_t length)
 {
     size_t i = 0;
 
@@ -1151,8 +1121,8 @@ intptr_t charactersToIntPtr(const UChar* data, size_t length, bool* ok)
 
 enum TrailingJunkPolicy { DisallowTrailingJunk, AllowTrailingJunk };
 
-template <typename CharType, TrailingJunkPolicy policy>
-static inline double toDoubleType(const CharType* data, size_t length, bool* ok, size_t& parsedLength)
+template<typename CharacterType, TrailingJunkPolicy policy>
+static inline double toDoubleType(const CharacterType* data, size_t length, bool* ok, size_t& parsedLength)
 {
     size_t leadingSpacesLength = 0;
     while (leadingSpacesLength < length && isASCIISpace(data[leadingSpacesLength]))
@@ -1212,14 +1182,14 @@ float charactersToFloat(const UChar* data, size_t length, size_t& parsedLength)
 const String& emptyString()
 {
     static NeverDestroyed<String> emptyString(StringImpl::empty());
-
     return emptyString;
 }
 
 } // namespace WTF
 
 #ifndef NDEBUG
-// For use in the debugger
+
+// For use in the debugger.
 String* string(const char*);
 Vector<char> asciiDebug(StringImpl* impl);
 Vector<char> asciiDebug(String& string);
@@ -1231,7 +1201,7 @@ void String::show() const
 
 String* string(const char* s)
 {
-    // leaks memory!
+    // Intentionally leaks memory!
     return new String(s);
 }
 
index 3a97b16..2f29aa5 100644 (file)
@@ -27,7 +27,6 @@
 
 #include <stdarg.h>
 #include <wtf/Function.h>
-#include <wtf/text/ASCIIFastPath.h>
 #include <wtf/text/IntegerToStringConversion.h>
 #include <wtf/text/StringImpl.h>
 
@@ -80,7 +79,7 @@ enum TrailingZerosTruncatingPolicy { KeepTrailingZeros, TruncateTrailingZeros };
 class String {
 public:
     // Construct a null string, distinguishable from an empty string.
-    String() { }
+    String() = default;
 
     // Construct a string with UTF-16 data.
     WTF_EXPORT_STRING_API String(const UChar* characters, unsigned length);
@@ -125,22 +124,16 @@ public:
     // Construct a string from a constant string literal.
     // This constructor is the "big" version, as it put the length in the function call and generate bigger code.
     enum ConstructFromLiteralTag { ConstructFromLiteral };
-    template<unsigned characterCount>
-    String(const char (&characters)[characterCount], ConstructFromLiteralTag) : m_impl(StringImpl::createFromLiteral<characterCount>(characters)) { }
-
-    // We have to declare the copy constructor and copy assignment operator as well, otherwise
-    // they'll be implicitly deleted by adding the move constructor and move assignment operator.
-    String(const String& other)
-        : m_impl(other.m_impl)
-    { }
-    String(String&& other)
-        : m_impl(WTFMove(other.m_impl))
-    { }
-    String& operator=(const String& other) { m_impl = other.m_impl; return *this; }
-    String& operator=(String&& other) { m_impl = WTFMove(other.m_impl); return *this; }
-
-    // Inline the destructor.
-    ALWAYS_INLINE ~String() { }
+    template<unsigned characterCount> String(const char (&characters)[characterCount], ConstructFromLiteralTag) : m_impl(StringImpl::createFromLiteral<characterCount>(characters)) { }
+
+    // FIXME: Why do we have to define these explicitly given that we just want the default versions?
+    // We have verified empirically that we do.
+    String(const String&) = default;
+    String(String&&) = default;
+    String& operator=(const String&) = default;
+    String& operator=(String&&) = default;
+
+    ALWAYS_INLINE ~String() = default;
 
     void swap(String& o) { m_impl.swap(o.m_impl); }
 
@@ -150,46 +143,21 @@ public:
     static String adopt(StringVector<CharacterType, inlineCapacity, OverflowHandler, minCapacity>&& vector) { return StringImpl::adopt(WTFMove(vector)); }
 
     bool isNull() const { return !m_impl; }
-    bool isEmpty() const { return !m_impl || !m_impl->length(); }
+    bool isEmpty() const { return !m_impl || m_impl->isEmpty(); }
 
     StringImpl* impl() const { return m_impl.get(); }
     RefPtr<StringImpl> releaseImpl() { return WTFMove(m_impl); }
 
-    unsigned length() const
-    {
-        if (!m_impl)
-            return 0;
-        return m_impl->length();
-    }
-
-    const LChar* characters8() const
-    {
-        if (!m_impl)
-            return 0;
-        ASSERT(m_impl->is8Bit());
-        return m_impl->characters8();
-    }
-
-    const UChar* characters16() const
-    {
-        if (!m_impl)
-            return 0;
-        ASSERT(!m_impl->is8Bit());
-        return m_impl->characters16();
-    }
+    unsigned length() const { return m_impl ? m_impl->length() : 0; }
+    const LChar* characters8() const { return m_impl ? m_impl->characters8() : nullptr; }
+    const UChar* characters16() const { return m_impl ? m_impl->characters16() : nullptr; }
 
     // Return characters8() or characters16() depending on CharacterType.
-    template <typename CharacterType>
-    inline const CharacterType* characters() const;
+    template<typename CharacterType> const CharacterType* characters() const;
 
     bool is8Bit() const { return m_impl->is8Bit(); }
 
-    unsigned sizeInBytes() const
-    {
-        if (!m_impl)
-            return 0;
-        return m_impl->length() * (is8Bit() ? sizeof(LChar) : sizeof(UChar));
-    }
+    unsigned sizeInBytes() const { return m_impl ? m_impl->length() * (is8Bit() ? sizeof(LChar) : sizeof(UChar)) : 0; }
 
     WTF_EXPORT_STRING_API CString ascii() const;
     WTF_EXPORT_STRING_API CString latin1() const;
@@ -197,16 +165,11 @@ public:
     WTF_EXPORT_STRING_API CString utf8(ConversionMode) const;
     WTF_EXPORT_STRING_API CString utf8() const;
 
-    UChar at(unsigned index) const
-    {
-        if (!m_impl || index >= m_impl->length())
-            return 0;
-        return (*m_impl)[index];
-    }
-    UChar operator[](unsigned index) const { return at(index); }
+    UChar characterAt(unsigned index) const;
+    UChar operator[](unsigned index) const { return characterAt(index); }
 
     WTF_EXPORT_STRING_API static String number(int);
-    WTF_EXPORT_STRING_API static String number(unsigned int);
+    WTF_EXPORT_STRING_API static String number(unsigned);
     WTF_EXPORT_STRING_API static String number(long);
     WTF_EXPORT_STRING_API static String number(unsigned long);
     WTF_EXPORT_STRING_API static String number(long long);
@@ -219,119 +182,64 @@ public:
     WTF_EXPORT_STRING_API static String numberToStringFixedWidth(double, unsigned decimalPlaces);
 
     // Find a single character or string, also with match function & latin1 forms.
-    size_t find(UChar c, unsigned start = 0) const
-        { return m_impl ? m_impl->find(c, start) : notFound; }
-
-    size_t find(const String& str) const
-        { return m_impl ? m_impl->find(str.impl()) : notFound; }
-    size_t find(const String& str, unsigned start) const
-        { return m_impl ? m_impl->find(str.impl(), start) : notFound; }
-    size_t findIgnoringASCIICase(const String& str) const
-        { return m_impl ? m_impl->findIgnoringASCIICase(str.impl()) : notFound; }
-    size_t findIgnoringASCIICase(const String& str, unsigned startOffset) const
-        { return m_impl ? m_impl->findIgnoringASCIICase(str.impl(), startOffset) : notFound; }
-
-    size_t find(CharacterMatchFunctionPtr matchFunction, unsigned start = 0) const
-        { return m_impl ? m_impl->find(matchFunction, start) : notFound; }
-    size_t find(const LChar* str, unsigned start = 0) const
-        { return m_impl ? m_impl->find(str, start) : notFound; }
+    size_t find(UChar character, unsigned start = 0) const { return m_impl ? m_impl->find(character, start) : notFound; }
+
+    size_t find(const String& string) const { return m_impl ? m_impl->find(string.impl()) : notFound; }
+    size_t find(const String& string, unsigned start) const { return m_impl ? m_impl->find(string.impl(), start) : notFound; }
+    size_t findIgnoringASCIICase(const String& string) const { return m_impl ? m_impl->findIgnoringASCIICase(string.impl()) : notFound; }
+    size_t findIgnoringASCIICase(const String& string, unsigned startOffset) const { return m_impl ? m_impl->findIgnoringASCIICase(string.impl(), startOffset) : notFound; }
+
+    size_t find(CharacterMatchFunctionPtr matchFunction, unsigned start = 0) const { return m_impl ? m_impl->find(matchFunction, start) : notFound; }
+    size_t find(const LChar* string, unsigned start = 0) const { return m_impl ? m_impl->find(string, start) : notFound; }
 
     // Find the last instance of a single character or string.
-    size_t reverseFind(UChar c, unsigned start = UINT_MAX) const
-        { return m_impl ? m_impl->reverseFind(c, start) : notFound; }
-    size_t reverseFind(const String& str, unsigned start = UINT_MAX) const
-        { return m_impl ? m_impl->reverseFind(str.impl(), start) : notFound; }
-
-    // Case insensitive string matching.
-    size_t findIgnoringCase(const LChar* str, unsigned start = 0) const
-        { return m_impl ? m_impl->findIgnoringCase(str, start) : notFound; }
-    size_t findIgnoringCase(const String& str, unsigned start = 0) const
-        { return m_impl ? m_impl->findIgnoringCase(str.impl(), start) : notFound; }
-    size_t reverseFindIgnoringCase(const String& str, unsigned start = UINT_MAX) const
-        { return m_impl ? m_impl->reverseFindIgnoringCase(str.impl(), start) : notFound; }
-
-    // Wrappers for find & reverseFind adding dynamic sensitivity check.
-    size_t find(const LChar* str, unsigned start, bool caseSensitive) const
-        { return caseSensitive ? find(str, start) : findIgnoringCase(str, start); }
-    size_t find(const String& str, unsigned start, bool caseSensitive) const
-        { return caseSensitive ? find(str, start) : findIgnoringCase(str, start); }
-    size_t reverseFind(const String& str, unsigned start, bool caseSensitive) const
-        { return caseSensitive ? reverseFind(str, start) : reverseFindIgnoringCase(str, start); }
+    size_t reverseFind(UChar character, unsigned start = std::numeric_limits<unsigned>::max()) const { return m_impl ? m_impl->reverseFind(character, start) : notFound; }
+    size_t reverseFind(const String& string, unsigned start = std::numeric_limits<unsigned>::max()) const { return m_impl ? m_impl->reverseFind(string.impl(), start) : notFound; }
 
     WTF_EXPORT_STRING_API Vector<UChar> charactersWithNullTermination() const;
 
-    WTF_EXPORT_STRING_API UChar32 characterStartingAt(unsigned) const; // Ditto.
-
-    bool contains(UChar c) const { return find(c) != notFound; }
-    bool contains(const LChar* str, bool caseSensitive = true, unsigned startOffset = 0) const
-        { return find(str, startOffset, caseSensitive) != notFound; }
-    bool contains(const String& str) const
-        { return find(str) != notFound; }
-    bool contains(const String& str, bool caseSensitive, unsigned startOffset = 0) const
-        { return find(str, startOffset, caseSensitive) != notFound; }
-    bool containsIgnoringASCIICase(const String& str) const
-        { return findIgnoringASCIICase(str) != notFound; }
-    bool containsIgnoringASCIICase(const String& str, unsigned startOffset) const
-        { return findIgnoringASCIICase(str, startOffset) != notFound; }
-
-    bool startsWith(const String& s) const
-        { return m_impl ? m_impl->startsWith(s.impl()) : s.isEmpty(); }
-    bool startsWithIgnoringASCIICase(const String& s) const
-        { return m_impl ? m_impl->startsWithIgnoringASCIICase(s.impl()) : s.isEmpty(); }
-    bool startsWith(const String& s, bool caseSensitive) const
-        { return m_impl ? m_impl->startsWith(s.impl(), caseSensitive) : s.isEmpty(); }
-    bool startsWith(UChar character) const
-        { return m_impl ? m_impl->startsWith(character) : false; }
-    template<unsigned matchLength>
-    bool startsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const
-        { return m_impl ? m_impl->startsWith<matchLength>(prefix, caseSensitive) : !matchLength; }
-    bool hasInfixStartingAt(const String& prefix, unsigned startOffset) const
-        { return m_impl && prefix.impl() ? m_impl->hasInfixStartingAt(*prefix.impl(), startOffset) : false; }
-
-    bool endsWith(const String& s) const
-        { return m_impl ? m_impl->endsWith(s.impl()) : s.isEmpty(); }
-    bool endsWithIgnoringASCIICase(const String& s) const
-        { return m_impl ? m_impl->endsWithIgnoringASCIICase(s.impl()) : s.isEmpty(); }
-    bool endsWith(const String& s, bool caseSensitive) const
-        { return m_impl ? m_impl->endsWith(s.impl(), caseSensitive) : s.isEmpty(); }
-    bool endsWith(UChar character) const
-        { return m_impl ? m_impl->endsWith(character) : false; }
+    WTF_EXPORT_STRING_API UChar32 characterStartingAt(unsigned) const;
+
+    bool contains(UChar character) const { return find(character) != notFound; }
+    bool contains(const LChar* string) const { return find(string) != notFound; }
+    bool contains(const String& string) const { return find(string) != notFound; }
+    bool containsIgnoringASCIICase(const String& string) const { return findIgnoringASCIICase(string) != notFound; }
+    bool containsIgnoringASCIICase(const String& string, unsigned startOffset) const { return findIgnoringASCIICase(string, startOffset) != notFound; }
+
+    bool startsWith(const String& string) const { return m_impl ? m_impl->startsWith(string.impl()) : string.isEmpty(); }
+    bool startsWithIgnoringASCIICase(const String& string) const { return m_impl ? m_impl->startsWithIgnoringASCIICase(string.impl()) : string.isEmpty(); }
+    bool startsWith(UChar character) const { return m_impl && m_impl->startsWith(character); }
+    template<unsigned matchLength> bool startsWith(const char (&prefix)[matchLength]) const { return m_impl ? m_impl->startsWith<matchLength>(prefix) : !matchLength; }
+    bool hasInfixStartingAt(const String& prefix, unsigned startOffset) const { return m_impl && prefix.impl() && m_impl->hasInfixStartingAt(*prefix.impl(), startOffset); }
+
+    bool endsWith(const String& string) const { return m_impl ? m_impl->endsWith(string.impl()) : string.isEmpty(); }
+    bool endsWithIgnoringASCIICase(const String& string) const { return m_impl ? m_impl->endsWithIgnoringASCIICase(string.impl()) : string.isEmpty(); }
+    bool endsWith(UChar character) const { return m_impl && m_impl->endsWith(character); }
     bool endsWith(char character) const { return endsWith(static_cast<UChar>(character)); }
-    template<unsigned matchLength>
-    bool endsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const
-        { return m_impl ? m_impl->endsWith<matchLength>(prefix, caseSensitive) : !matchLength; }
-    bool hasInfixEndingAt(const String& suffix, unsigned endOffset) const
-        { return m_impl && suffix.impl() ? m_impl->hasInfixEndingAt(*suffix.impl(), endOffset) : false; }
+    template<unsigned matchLength> bool endsWith(const char (&prefix)[matchLength]) const { return m_impl ? m_impl->endsWith<matchLength>(prefix) : !matchLength; }
+    bool hasInfixEndingAt(const String& suffix, unsigned endOffset) const { return m_impl && suffix.impl() && m_impl->hasInfixEndingAt(*suffix.impl(), endOffset); }
 
     WTF_EXPORT_STRING_API void append(const String&);
     WTF_EXPORT_STRING_API void append(LChar);
-    void append(char c) { append(static_cast<LChar>(c)); };
+    void append(char character) { append(static_cast<LChar>(character)); };
     WTF_EXPORT_STRING_API void append(UChar);
     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);
+    WTF_EXPORT_STRING_API void insert(const String&, unsigned position);
 
-    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; }
-    String& replace(const String& a, const String& b) { if (m_impl) m_impl = m_impl->replace(a.impl(), b.impl()); return *this; }
-    String& replace(unsigned index, unsigned len, const String& b) { if (m_impl) m_impl = m_impl->replace(index, len, b.impl()); return *this; }
+    String& replace(UChar target, UChar replacement);
+    String& replace(UChar target, const String& replacement);
+    String& replace(const String& target, const String& replacement);
+    String& replace(unsigned start, unsigned length, const String& replacement);
+    template<unsigned characterCount> String& replaceWithLiteral(UChar target, const char (&replacement)[characterCount]);
 
-    template<unsigned characterCount>
-    ALWAYS_INLINE String& replaceWithLiteral(UChar a, const char (&characters)[characterCount])
-    {
-        if (m_impl)
-            m_impl = m_impl->replace(a, characters, characterCount - 1);
+    WTF_EXPORT_STRING_API void truncate(unsigned length);
+    WTF_EXPORT_STRING_API void remove(unsigned position, unsigned length = 1);
 
-        return *this;
-    }
-
-    WTF_EXPORT_STRING_API void truncate(unsigned len);
-    WTF_EXPORT_STRING_API void remove(unsigned pos, int len = 1);
-
-    WTF_EXPORT_STRING_API String substring(unsigned pos, unsigned len = UINT_MAX) const;
-    WTF_EXPORT_STRING_API String substringSharingImpl(unsigned pos, unsigned len = UINT_MAX) const;
-    String left(unsigned len) const { return substring(0, len); }
-    String right(unsigned len) const { return substring(length() - len, len); }
+    WTF_EXPORT_STRING_API String substring(unsigned position, unsigned length = std::numeric_limits<unsigned>::max()) const;
+    WTF_EXPORT_STRING_API String substringSharingImpl(unsigned position, unsigned length = std::numeric_limits<unsigned>::max()) const;
+    String left(unsigned length) const { return substring(0, length); }
+    String right(unsigned length) const { return substring(this->length() - length, length); }
 
     WTF_EXPORT_STRING_API String convertToASCIILowercase() const;
     WTF_EXPORT_STRING_API String convertToASCIIUppercase() const;
@@ -347,7 +255,6 @@ public:
     WTF_EXPORT_STRING_API String simplifyWhiteSpace(IsWhiteSpaceFunctionPtr) const;
 
     WTF_EXPORT_STRING_API String removeCharacters(CharacterMatchFunctionPtr) const;
-    template<bool isSpecialCharacter(UChar)> bool isAllSpecialCharacters() const;
 
     // Returns the string with case folded for case insensitive comparison.
     // Use convertToASCIILowercase instead if ASCII case insensitive comparison is desired.
@@ -358,35 +265,18 @@ public:
 
     // Returns an uninitialized string. The characters needs to be written
     // into the buffer returned in data before the returned string is used.
-    // Failure to do this will have unpredictable results.
     static String createUninitialized(unsigned length, UChar*& data) { return StringImpl::createUninitialized(length, data); }
     static String createUninitialized(unsigned length, LChar*& data) { return StringImpl::createUninitialized(length, data); }
 
     WTF_EXPORT_STRING_API void split(const String& separator, bool allowEmptyEntries, Vector<String>& result) const;
-    void split(const String& separator, Vector<String>& result) const
-    {
-        split(separator, false, result);
-    }
+    void split(const String& separator, Vector<String>& result) const { split(separator, false, result); }
 
     using SplitFunctor = WTF::Function<void(const StringView&)>;
     WTF_EXPORT_STRING_API void split(UChar separator, bool allowEmptyEntries, const SplitFunctor&) const;
     WTF_EXPORT_STRING_API void split(UChar separator, bool allowEmptyEntries, Vector<String>& result) const;
-    void split(UChar separator, Vector<String>& result) const
-    {
-        split(separator, false, result);
-    }
-    Vector<String> split(UChar separator) const
-    {
-        Vector<String> result;
-        split(separator, false, result);
-        return result;
-    }
-    Vector<String> split(const String& separator) const
-    {
-        Vector<String> result;
-        split(separator, false, result);
-        return result;
-    }
+    void split(UChar separator, Vector<String>& result) const { split(separator, false, result); }
+    Vector<String> split(UChar separator) const;
+    Vector<String> split(const String& separator) const;
 
     WTF_EXPORT_STRING_API int toIntStrict(bool* ok = nullptr, int base = 10) const;
     WTF_EXPORT_STRING_API unsigned toUIntStrict(bool* ok = nullptr, int base = 10) const;
@@ -439,11 +329,7 @@ public:
 #endif
 
     WTF_EXPORT_STRING_API static String make8BitFrom16BitSource(const UChar*, size_t);
-    template<size_t inlineCapacity>
-    static String make8BitFrom16BitSource(const Vector<UChar, inlineCapacity>& buffer)
-    {
-        return make8BitFrom16BitSource(buffer.data(), buffer.size());
-    }
+    template<size_t inlineCapacity> static String make8BitFrom16BitSource(const Vector<UChar, inlineCapacity>&);
 
     WTF_EXPORT_STRING_API static String make16BitFrom8BitSource(const LChar*, size_t);
 
@@ -451,28 +337,21 @@ public:
     // the input data contains invalid UTF-8 sequences.
     WTF_EXPORT_STRING_API static String fromUTF8(const LChar*, size_t);
     WTF_EXPORT_STRING_API static String fromUTF8(const LChar*);
-    static String fromUTF8(const char* s, size_t length) { return fromUTF8(reinterpret_cast<const LChar*>(s), length); };
-    static String fromUTF8(const char* s) { return fromUTF8(reinterpret_cast<const LChar*>(s)); };
+    static String fromUTF8(const char* characters, size_t length) { return fromUTF8(reinterpret_cast<const LChar*>(characters), length); };
+    static String fromUTF8(const char* string) { return fromUTF8(reinterpret_cast<const LChar*>(string)); };
     WTF_EXPORT_STRING_API static String fromUTF8(const CString&);
     static String fromUTF8(const Vector<LChar>& characters);
 
     // Tries to convert the passed in string to UTF-8, but will fall back to Latin-1 if the string is not valid UTF-8.
     WTF_EXPORT_STRING_API static String fromUTF8WithLatin1Fallback(const LChar*, size_t);
-    static String fromUTF8WithLatin1Fallback(const char* s, size_t length) { return fromUTF8WithLatin1Fallback(reinterpret_cast<const LChar*>(s), length); };
+    static String fromUTF8WithLatin1Fallback(const char* characters, size_t length) { return fromUTF8WithLatin1Fallback(reinterpret_cast<const LChar*>(characters), length); };
 
     // Determines the writing direction using the Unicode Bidi Algorithm rules P2 and P3.
-    UCharDirection defaultWritingDirection(bool* hasStrongDirectionality = nullptr) const
-    {
-        if (m_impl)
-            return m_impl->defaultWritingDirection(hasStrongDirectionality);
-        if (hasStrongDirectionality)
-            *hasStrongDirectionality = false;
-        return U_LEFT_TO_RIGHT;
-    }
+    UCharDirection defaultWritingDirection(bool* hasStrongDirectionality = nullptr) const;
 
-    bool containsOnlyASCII() const;
-    bool containsOnlyLatin1() const;
-    bool containsOnlyWhitespace() const { return !m_impl || m_impl->containsOnlyWhitespace(); }
+    bool isAllASCII() const { return !m_impl || m_impl->isAllASCII(); }
+    bool isAllLatin1() const { return !m_impl || m_impl->isAllLatin1(); }
+    template<bool isSpecialCharacter(UChar)> bool isAllSpecialCharacters() const { return !m_impl || m_impl->isAllSpecialCharacters<isSpecialCharacter>(); }
 
     // Hash table deleted values, which are only constructed and never copied or destroyed.
     String(WTF::HashTableDeletedValueType) : m_impl(WTF::HashTableDeletedValue) { }
@@ -484,40 +363,16 @@ public:
     WTF_EXPORT_STRING_API void show() const;
 #endif
 
-    // Workaround for a compiler bug. Use operator[] instead.
-    UChar characterAt(unsigned index) const
-    {
-        if (!m_impl || index >= m_impl->length())
-            return 0;
-        return (*m_impl)[index];
-    }
-
     // Turns this String empty if the StringImpl is not referenced by anyone else.
     // This is useful for clearing String-based caches.
-    void clearImplIfNotShared()
-    {
-        if (m_impl && m_impl->hasOneRef())
-            m_impl = nullptr;
-    }
-    
-    void assertCaged() const
-    {
-        if (m_impl)
-            m_impl->assertCaged();
-    }
+    void clearImplIfNotShared();
 
-    void releaseAssertCaged() const
-    {
-        if (m_impl)
-            m_impl->releaseAssertCaged();
-    }
+    void assertCaged() const;
+    void releaseAssertCaged() const;
 
 private:
-    template <typename CharacterType>
-    void removeInternal(const CharacterType*, unsigned, int);
-
-    template <typename CharacterType>
-    void appendInternal(CharacterType);
+    template<typename CharacterType> void removeInternal(const CharacterType*, unsigned, unsigned);
+    template<typename CharacterType> void appendInternal(CharacterType);
 
     RefPtr<StringImpl> m_impl;
 };
@@ -532,7 +387,6 @@ inline bool operator==(const char* a, const String& b) { return equal(reinterpre
 template<size_t inlineCapacity> inline bool operator==(const Vector<char, inlineCapacity>& a, const String& b) { return equal(b.impl(), a.data(), a.size()); }
 template<size_t inlineCapacity> inline bool operator==(const String& a, const Vector<char, inlineCapacity>& b) { return b == a; }
 
-
 inline bool operator!=(const String& a, const String& b) { return !equal(a.impl(), b.impl()); }
 inline bool operator!=(const String& a, const LChar* b) { return !equal(a.impl(), b); }
 inline bool operator!=(const String& a, const char* b) { return !equal(a.impl(), reinterpret_cast<const LChar*>(b)); }
@@ -550,7 +404,7 @@ template<unsigned length> bool startsWithLettersIgnoringASCIICase(const String&,
 inline bool equalIgnoringNullity(const String& a, const String& b) { return equalIgnoringNullity(a.impl(), b.impl()); }
 template<size_t inlineCapacity> inline bool equalIgnoringNullity(const Vector<UChar, inlineCapacity>& a, const String& b) { return equalIgnoringNullity(a, b.impl()); }
 
-inline bool operator!(const String& str) { return str.isNull(); }
+inline bool operator!(const String& string) { return string.isNull(); }
 
 inline void swap(String& a, String& b) { a.swap(b); }
 
@@ -561,81 +415,176 @@ NSString * nsStringNilIfEmpty(const String&);
 
 #endif
 
+WTF_EXPORT_STRING_API int codePointCompare(const String&, const String&);
+bool codePointCompareLessThan(const String&, const String&);
+
+template<typename CharacterType> void appendNumber(Vector<CharacterType>&, unsigned char number);
+
+// Shared global empty string.
+WTF_EXPORT_STRING_API const String& emptyString();
+
+template<typename> struct DefaultHash;
+template<> struct DefaultHash<String> { using Hash = StringHash; };
+template<> struct VectorTraits<String> : SimpleClassVectorTraits { };
+
+class ASCIILiteral {
+public:
+    explicit ASCIILiteral(const char* characters) : m_characters(characters) { }
+    operator const char*() { return m_characters; }
+
+private:
+    const char* m_characters;
+};
+
+template<> struct IntegerToStringConversionTrait<String> {
+    using ReturnType = String;
+    using AdditionalArgumentType = void;
+    static String flush(LChar* characters, unsigned length, void*) { return { characters, length }; }
+};
+
 // Definitions of string operations
 
-inline String::String(StringImpl& impl)
-    : m_impl(&impl)
+inline String::String(StringImpl& string)
+    : m_impl(&string)
 {
 }
 
-inline String::String(StringImpl* impl)
-    : m_impl(impl)
+inline String::String(StringImpl* string)
+    : m_impl(string)
 {
 }
 
-inline String::String(Ref<StringImpl>&& impl)
-    : m_impl(WTFMove(impl))
+inline String::String(Ref<StringImpl>&& string)
+    : m_impl(WTFMove(string))
 {
 }
 
-inline String::String(RefPtr<StringImpl>&& impl)
-    : m_impl(WTFMove(impl))
+inline String::String(RefPtr<StringImpl>&& string)
+    : m_impl(WTFMove(string))
 {
 }
 
-inline String::String(Ref<AtomicStringImpl>&& impl)
-    : m_impl(WTFMove(impl))
+inline String::String(Ref<AtomicStringImpl>&& string)
+    : m_impl(WTFMove(string))
 {
 }
 
-inline String::String(RefPtr<AtomicStringImpl>&& impl)
-    : m_impl(WTFMove(impl))
+inline String::String(RefPtr<AtomicStringImpl>&& string)
+    : m_impl(WTFMove(string))
 {
 }
 
-inline String::String(StaticStringImpl& impl)
-    : m_impl(reinterpret_cast<StringImpl*>(&impl))
+inline String::String(StaticStringImpl& string)
+    : m_impl(reinterpret_cast<StringImpl*>(&string))
 {
 }
 
-inline String::String(StaticStringImpl* impl)
-    : m_impl(reinterpret_cast<StringImpl*>(impl))
+inline String::String(StaticStringImpl* string)
+    : m_impl(reinterpret_cast<StringImpl*>(string))
 {
 }
 
-template<size_t inlineCapacity, typename OverflowHandler>
-String::String(const Vector<UChar, inlineCapacity, OverflowHandler>& vector)
-    : m_impl(vector.size() ? StringImpl::create(vector.data(), vector.size()) : Ref<StringImpl>(*StringImpl::empty()))
+template<size_t inlineCapacity, typename OverflowHandler> String::String(const Vector<UChar, inlineCapacity, OverflowHandler>& vector)
+    : m_impl(vector.size() ? StringImpl::create(vector.data(), vector.size()) : Ref<StringImpl> { *StringImpl::empty() })
 {
 }
 
-template<>
-inline const LChar* String::characters<LChar>() const
+template<> inline const LChar* String::characters<LChar>() const
 {
-    ASSERT(is8Bit());
     return characters8();
 }
 
-template<>
-inline const UChar* String::characters<UChar>() const
+template<> inline const UChar* String::characters<UChar>() const
 {
-    ASSERT(!is8Bit());
     return characters16();
 }
 
-inline bool String::containsOnlyLatin1() const
+inline UChar String::characterAt(unsigned index) const
+{
+    if (!m_impl || index >= m_impl->length())
+        return 0;
+    return (*m_impl)[index];
+}
+
+inline String& String::replace(UChar target, UChar replacement)
 {
-    if (isEmpty())
-        return true;
+    if (m_impl)
+        m_impl = m_impl->replace(target, replacement);
+    return *this;
+}
+
+inline String& String::replace(UChar target, const String& replacement)
+{
+    if (m_impl)
+        m_impl = m_impl->replace(target, replacement.impl());
+    return *this;
+}
+
+inline String& String::replace(const String& target, const String& replacement)
+{
+    if (m_impl)
+        m_impl = m_impl->replace(target.impl(), replacement.impl());
+    return *this;
+}
+
+inline String& String::replace(unsigned start, unsigned length, const String& replacement)
+{
+    if (m_impl)
+        m_impl = m_impl->replace(start, length, replacement.impl());
+    return *this;
+}
 
-    if (is8Bit())
-        return true;
+template<unsigned characterCount> ALWAYS_INLINE String& String::replaceWithLiteral(UChar target, const char (&characters)[characterCount])
+{
+    if (m_impl)
+        m_impl = m_impl->replace(target, characters, characterCount - 1);
+    return *this;
+}
 
-    const UChar* characters = characters16();
-    UChar ored = 0;
-    for (size_t i = 0; i < m_impl->length(); ++i)
-        ored |= characters[i];
-    return !(ored & 0xFF00);
+inline Vector<String> String::split(UChar separator) const
+{
+    Vector<String> result;
+    split(separator, false, result);
+    return result;
+}
+
+inline Vector<String> String::split(const String& separator) const
+{
+    Vector<String> result;
+    split(separator, false, result);
+    return result;
+}
+
+template<size_t inlineCapacity> inline String String::make8BitFrom16BitSource(const Vector<UChar, inlineCapacity>& buffer)
+{
+    return make8BitFrom16BitSource(buffer.data(), buffer.size());
+}
+
+inline UCharDirection String::defaultWritingDirection(bool* hasStrongDirectionality) const
+{
+    if (m_impl)
+        return m_impl->defaultWritingDirection(hasStrongDirectionality);
+    if (hasStrongDirectionality)
+        *hasStrongDirectionality = false;
+    return U_LEFT_TO_RIGHT;
+}
+
+inline void String::clearImplIfNotShared()
+{
+    if (m_impl && m_impl->hasOneRef())
+        m_impl = nullptr;
+}
+
+inline void String::assertCaged() const
+{
+    if (m_impl)
+        m_impl->assertCaged();
+}
+
+inline void String::releaseAssertCaged() const
+{
+    if (m_impl)
+        m_impl->releaseAssertCaged();
 }
 
 #ifdef __OBJC__
@@ -656,19 +605,6 @@ inline NSString * nsStringNilIfEmpty(const String& string)
 
 #endif
 
-inline bool String::containsOnlyASCII() const
-{
-    if (isEmpty())
-        return true;
-
-    if (is8Bit())
-        return charactersAreAllASCII(characters8(), m_impl->length());
-
-    return charactersAreAllASCII(characters16(), m_impl->length());
-}
-
-WTF_EXPORT_STRING_API int codePointCompare(const String&, const String&);
-
 inline bool codePointCompareLessThan(const String& a, const String& b)
 {
     return codePointCompare(a.impl(), b.impl()) < 0;
@@ -697,49 +633,6 @@ inline void appendNumber(Vector<CharacterType>& vector, unsigned char number)
     }
 }
 
-template<bool isSpecialCharacter(UChar), typename CharacterType>
-inline bool isAllSpecialCharacters(const CharacterType* characters, size_t length)
-{
-    for (size_t i = 0; i < length; ++i) {
-        if (!isSpecialCharacter(characters[i]))
-            return false;
-    }
-    return true;
-}
-
-template<bool isSpecialCharacter(UChar)>
-inline bool String::isAllSpecialCharacters() const
-{
-    size_t len = length();
-
-    if (!len)
-        return true;
-
-    if (is8Bit())
-        return WTF::isAllSpecialCharacters<isSpecialCharacter, LChar>(characters8(), len);
-    return WTF::isAllSpecialCharacters<isSpecialCharacter, UChar>(characters16(), len);
-}
-
-// StringHash is the default hash for String
-template<typename T> struct DefaultHash;
-template<> struct DefaultHash<String> {
-    typedef StringHash Hash;
-};
-
-template <> struct VectorTraits<String> : SimpleClassVectorTraits { };
-
-class ASCIILiteral {
-public:
-    explicit ASCIILiteral(const char* characters) : m_characters(characters) { }
-    operator const char*() { return m_characters; }
-
-private:
-    const char* m_characters;
-};
-
-// Shared global empty string.
-WTF_EXPORT_STRING_API const String& emptyString();
-
 inline String String::fromUTF8(const Vector<LChar>& characters)
 {
     if (characters.isEmpty())
@@ -767,38 +660,30 @@ template<unsigned length> inline bool startsWithLettersIgnoringASCIICase(const S
     return startsWithLettersIgnoringASCIICase(string.impl(), lowercaseLetters);
 }
 
-template<> struct IntegerToStringConversionTrait<String> {
-    using ReturnType = String;
-    using AdditionalArgumentType = void;
-    static String flush(LChar* characters, unsigned length, void*) { return { characters, length }; }
-};
-
 } // namespace WTF
 
-using WTF::CString;
+using WTF::ASCIILiteral;
 using WTF::KeepTrailingZeros;
 using WTF::String;
-using WTF::emptyString;
 using WTF::appendNumber;
-using WTF::charactersAreAllASCII;
-using WTF::charactersToIntStrict;
-using WTF::charactersToUIntStrict;
+using WTF::charactersToDouble;
+using WTF::charactersToFloat;
+using WTF::charactersToInt64;
 using WTF::charactersToInt64Strict;
-using WTF::charactersToUInt64Strict;
-using WTF::charactersToIntPtrStrict;
 using WTF::charactersToInt;
-using WTF::charactersToUInt;
-using WTF::charactersToInt64;
-using WTF::charactersToUInt64;
 using WTF::charactersToIntPtr;
-using WTF::charactersToDouble;
-using WTF::charactersToFloat;
+using WTF::charactersToIntPtrStrict;
+using WTF::charactersToIntStrict;
+using WTF::charactersToUInt64;
+using WTF::charactersToUInt64Strict;
+using WTF::charactersToUInt;
+using WTF::charactersToUIntStrict;
+using WTF::emptyString;
 using WTF::equal;
 using WTF::find;
 using WTF::isAllSpecialCharacters;
 using WTF::isSpaceOrNewline;
 using WTF::reverseFind;
-using WTF::ASCIILiteral;
 
 #include <wtf/text/AtomicString.h>
 
index 25a0e1e..b8109d7 100644 (file)
@@ -140,7 +140,7 @@ static UBool uTextLatin1Access(UText* uText, int64_t index, UBool forward)
     }
     uText->chunkLength = static_cast<int32_t>(uText->chunkNativeLimit - uText->chunkNativeStart);
 
-    StringImpl::copyChars(const_cast<UChar*>(uText->chunkContents), static_cast<const LChar*>(uText->context) + uText->chunkNativeStart, static_cast<unsigned>(uText->chunkLength));
+    StringImpl::copyCharacters(const_cast<UChar*>(uText->chunkContents), static_cast<const LChar*>(uText->context) + uText->chunkNativeStart, static_cast<unsigned>(uText->chunkLength));
 
     uText->nativeIndexingLimit = uText->chunkLength;
 
@@ -178,7 +178,7 @@ static int32_t uTextLatin1Extract(UText* uText, int64_t start, int64_t limit, UC
         if (trimmedLength > destCapacity)
             trimmedLength = destCapacity;
 
-        StringImpl::copyChars(dest, static_cast<const LChar*>(uText->context) + start, static_cast<unsigned>(trimmedLength));
+        StringImpl::copyCharacters(dest, static_cast<const LChar*>(uText->context) + start, static_cast<unsigned>(trimmedLength));
     }
 
     if (length < destCapacity) {
@@ -290,7 +290,7 @@ static void textLatin1ContextAwareMoveInPrimaryContext(UText* text, int64_t nati
     text->chunkLength = length < std::numeric_limits<int32_t>::max() ? static_cast<int32_t>(length) : 0;
     text->nativeIndexingLimit = text->chunkLength;
     text->chunkOffset = forward ? 0 : text->chunkLength;
-    StringImpl::copyChars(const_cast<UChar*>(text->chunkContents), static_cast<const LChar*>(text->p) + (text->chunkNativeStart - text->b), static_cast<unsigned>(text->chunkLength));
+    StringImpl::copyCharacters(const_cast<UChar*>(text->chunkContents), static_cast<const LChar*>(text->p) + (text->chunkNativeStart - text->b), static_cast<unsigned>(text->chunkLength));
 }
 
 static void textLatin1ContextAwareSwitchToPrimaryContext(UText* text, int64_t nativeIndex, int64_t nativeLength, UBool forward)
index 09a0983..03be2b3 100644 (file)
@@ -1,3 +1,439 @@
+2017-11-23  Darin Adler  <darin@apple.com>
+
+        Reduce WTF::String operations that do unnecessary Unicode operations instead of ASCII
+        https://bugs.webkit.org/show_bug.cgi?id=179907
+
+        Reviewed by Sam Weinig.
+
+        * Modules/plugins/YouTubePluginReplacement.cpp:
+        (WebCore::hasCaseInsensitivePrefix): Deleted.
+        (WebCore::processAndCreateYouTubeURL): Use startsWithLettersIgnoringASCIICase.
+
+        * Modules/websockets/WebSocketHandshake.cpp:
+        (WebCore::WebSocketHandshake::readHTTPHeaders): Use isAllASCII.
+
+        * accessibility/atk/AccessibilityObjectAtk.cpp:
+        (WebCore::AccessibilityObject::getLengthForTextRange const): Use text().length().
+
+        * accessibility/AXObjectCache.cpp:
+        (WebCore::AXObjectCache::traverseToOffsetInRange): Use isHTMLSpace instead of
+        isSpaceOrNewline since the code is trying to skip collapsible HTML spaces, not
+        arbitrary Unicode whitespace.
+        * accessibility/AccessibilityList.cpp:
+        (WebCore::AccessibilityList::childHasPseudoVisibleListItemMarkers): Use
+        isAllSpecialCharacters<isHTMLSpace> for the same reason as above.
+
+        * accessibility/AccessibilityNodeObject.cpp:
+        (WebCore::AccessibilityNodeObject::isSearchField const): Use containsIgnoringASCIICase.
+
+        * accessibility/AccessibilityObject.cpp:
+        (WebCore::AccessibilityObject::accessibilityObjectContainsText const): Use
+        new findPlainText function exported from TextIterator so this can share the
+        same search matching logic used to find text in webpages.
+        (WebCore::AccessibilityObject::selectText): Use capitalize and its return value
+        rather than makeCapitalize modifying a string in place.
+
+        * accessibility/AccessibilityRenderObject.cpp:
+        (WebCore::objectInclusionFromAltText): Use isAllSpecialCharacters<isHTMLSpace>
+        for the same reason as above.
+        (WebCore::AccessibilityRenderObject::computeAccessibilityIsIgnored const): Ditto.
+
+        * bindings/js/JSDOMConvertStrings.cpp:
+        (WebCore::stringToByteString): Use isAllLatin1.
+
+        * contentextensions/ContentExtensionParser.cpp:
+        (WebCore::ContentExtensions::containsOnlyASCIIWithNoUppercase): Use
+        StringView::codeUnits instead of String::at.
+
+        * contentextensions/ContentExtensionsBackend.cpp:
+        (WebCore::ContentExtensions::ContentExtensionsBackend::actionsForResourceLoad const):
+        Use isAllASCII.
+        * contentextensions/URLFilterParser.cpp:
+        (WebCore::ContentExtensions::URLFilterParser::addPattern): Ditto.
+
+        * css/CSSFontFaceSrcValue.cpp:
+        (WebCore::CSSFontFaceSrcValue::isSupportedFormat const): Use protocolIs and
+        endsWithIgnoringASCIICase.
+
+        * css/DOMCSSNamespace.cpp:
+        (WebCore::valueWithoutImportant): Use endsWithIgnoringASCIICase.
+
+        * css/parser/CSSPropertyParser.cpp:
+        (WebCore::parseGridTemplateAreasRow): Use isAllSpecialCharacters<isCSSSpace>,
+        for the preflight, which matches what the actual parsing code uses.
+
+        * dom/CharacterData.cpp:
+        (WebCore::CharacterData::containsOnlyWhitespace const): Deleted. Callers can
+        efficiently get at the data and do this kind of check on the data directly.
+        * dom/CharacterData.h: Updated for the above.
+
+        * dom/DataTransfer.cpp:
+        (WebCore::normalizeType): Use startsWith since the string is already converted
+        to ASCII lowercase.
+
+        * dom/Position.cpp:
+        (WebCore::Position::leadingWhitespacePosition const): Use isHTMLSpace since
+        since the code is trying to check for collapsible HTML spaces, not general
+        Unicode spaces. Other call sites of isSpaceOrNewline need to be checked for
+        this, but I did not fix them all at this time.
+        (WebCore::Position::trailingWhitespacePosition const): Ditto.
+
+        * editing/Editor.cpp:
+        (WebCore::Editor::editorUIUpdateTimerFired): Use noBreakSpace.
+
+        * editing/FrameSelection.cpp:
+        (WebCore::FrameSelection::debugRenderer const): Use text().length() instead
+        of textLength.
+        (WebCore::FrameSelection::selectionAtWordStart const): Use noBreakSpace.
+        (WebCore::FrameSelection::wordSelectionContainingCaretSelection): Ditto.
+        (WebCore::FrameSelection::actualSelectionAtSentenceStart const): Ditto.
+
+        * editing/TextIterator.cpp:
+        (WebCore::textNodeOffsetInFlow): Use text().length().
+        (WebCore::TextIterator::handleTextNode): Ditto.
+        (WebCore::collapsedSpaceLength): Updated since RenderText::text now returns
+        a reference rather than a pointer.
+        (WebCore::findPlainText): Added. Uses SearchBuffer to search for one string
+        within another. Exported so accessibility code can do this operation.
+        * editing/TextIterator.h: Updated for the above.
+
+        * editing/TypingCommand.cpp:
+        (WebCore::TypingCommand::markMisspellingsAfterTyping): Use noBreakSpace.
+
+        * editing/VisibleUnits.cpp:
+        (WebCore::findStartOfParagraph): Updated since RenderText::text now returns
+        a reference.
+        (WebCore::findEndOfParagraph): Ditto.
+
+        * editing/cocoa/HTMLConverter.mm:
+        (HTMLConverter::_processText): Use String::characterAt instead of String::at.
+        Use capitalize instead of makeCapitalized.
+
+        * editing/cocoa/WebContentReaderCocoa.mm:
+        (WebCore::stripMicrosoftPrefix): Use findIgnoringASCIICase.
+
+        * html/Autofill.cpp:
+        (WebCore::AutofillData::createFromHTMLFormControlElement): Use
+        startsWithLettersIgnoringASCIICase.
+
+        * html/BaseTextInputType.cpp:
+        (WebCore::BaseTextInputType::patternMismatch const): Removed explicit
+        TextCaseSensitive since it now is the default, and needed to touch this anyway
+        because the enumeration is now in a different namespace.
+
+        * html/EmailInputType.cpp:
+        (WebCore::isValidEmailAddress): Updated to use JSC::Yarr::TextCaseInsensitive.
+
+        * html/HTMLObjectElement.cpp:
+        (WebCore::HTMLObjectElement::hasFallbackContent const): Use
+        isAllSpecialCharacters<isHTMLSpace>.
+        (WebCore::HTMLObjectElement::shouldAllowQuickTimeClassIdQuirk): Use
+        startsWithLettersIgnoringASCIICase.
+        (WebCore::HTMLObjectElement::hasValidClassId): Use protocolIs.
+        (WebCore::preventsParentObjectFromExposure): Use isAllSpecialCharacters<isHTMLSpace>.
+
+        * html/parser/HTMLConstructionSite.cpp:
+        (WebCore::HTMLConstructionSite::setCompatibilityModeFromDoctype):
+        Use startsWithLettersIgnoringASCIICase.
+
+        * html/parser/HTMLMetaCharsetParser.cpp:
+        (WebCore::extractCharset): Use findIgnoringASCIICase.
+
+        * html/parser/XSSAuditor.cpp:
+        (WebCore::XSSAuditor::isContainedInRequest): Use containsIgnoringASCIICase.
+
+        * html/track/WebVTTParser.cpp:
+        (WebCore::WebVTTParser::hasRequiredFileIdentifier): Don't pass the length to
+        the String::startsWith function. There has never been a version of that function
+        that takes the length, there is no need to pass the length since the function
+        handles null-terminated strings like the one here, and in the past the length
+        has been getting converted to a boolean making the comparison be case sensitive.
+        Removing the argument entirely leaves it case sensitive.
+
+        * inspector/InspectorNodeFinder.cpp:
+        (WebCore::InspectorNodeFinder::matchesElement): Use startsWithIgnoringASCIICase
+        and endsWithIgnoringASCIICase.
+
+        * inspector/InspectorStyleSheet.cpp:
+        (WebCore::selectorsFromSource): Use JSC::Yarr::TextCaseSensitive.
+
+        * inspector/agents/InspectorDOMAgent.cpp:
+        (WebCore::containsOnlyHTMLWhitespace): Made this a non-member function
+        and reimplemented using isAllSpecialCharacters<isHTMLSpace>().
+        (WebCore::InspectorDOMAgent::innerFirstChild): Use containsOnlyHTMLWhitespace.
+        (WebCore::InspectorDOMAgent::innerNextSibling): Ditto.
+        (WebCore::InspectorDOMAgent::innerPreviousSibling): Ditto.
+        (WebCore::InspectorDOMAgent::innerChildNodeCount): Ditto.
+        (WebCore::InspectorDOMAgent::didInsertDOMNode): Ditto.
+        (WebCore::InspectorDOMAgent::didRemoveDOMNode): Ditto.
+        * inspector/agents/InspectorDOMAgent.h: Updated for above change.
+
+        * loader/appcache/ApplicationCacheStorage.cpp:
+        (WebCore::ApplicationCacheStorage::shouldStoreResourceAsFlatFile):
+        Use startsWithLettersIgnoringASCIICase.
+
+        * page/Base64Utilities.cpp:
+        (WebCore::Base64Utilities::btoa): Use isAllLatin1.
+
+        * page/Frame.cpp:
+        (WebCore::createRegExpForLabels): Removed TextCaseSensitive argument since
+        that is now the default and also used JSC::Yarr::TextCaseInsensitive.
+        (WebCore::matchLabelsAgainstString): More of the same.
+
+        * page/FrameView.cpp:
+        (WebCore::countRenderedCharactersInRenderObjectWithThreshold): Use
+        text().length().
+
+        * page/SecurityOrigin.cpp:
+        (WebCore::isFeedWithNestedProtocolInHTTPFamily): Use
+        startsWithLettersIgnoringASCIICase.
+
+        * page/UserContentURLPattern.cpp:
+        (WebCore::UserContentURLPattern::matchesHost const):
+        Use endsWithIgnoringASCIICase.
+        * page/csp/ContentSecurityPolicySource.cpp:
+        (WebCore::ContentSecurityPolicySource::hostMatches const): Ditto.
+
+        * page/csp/ContentSecurityPolicySourceList.cpp:
+        (WebCore::ContentSecurityPolicySourceList::parseNonceSource):
+        Use startsWithIgnoringASCIICase.
+
+        * page/ios/FrameIOS.mm:
+        (WebCore::Frame::wordsInCurrentParagraph const): Use noBreakSpace.
+
+        * platform/ContentType.cpp:
+        (WebCore::ContentType::parameter const): Use findIgnoringASCIICase.
+
+        * platform/MIMETypeRegistry.cpp:
+        (WebCore::MIMETypeRegistry::isSupportedFontMIMEType): Use
+        startsWithLettersIgnoringASCIICase.
+        (WebCore::MIMETypeRegistry::isSupportedJSONMIMEType): Use
+        mimeType.endsWithIgnoringASCIICase.
+        (WebCore::MIMETypeRegistry::isTextMIMEType): Use
+        startsWithLettersIgnoringASCIICase.
+        (WebCore::MIMETypeRegistry::isXMLMIMEType): Use endsWithIgnoringASCIICase.
+        (WebCore::MIMETypeRegistry::isJavaAppletMIMEType): Use
+        startsWithLettersIgnoringASCIICase.
+        (WebCore::MIMETypeRegistry::canShowMIMEType): Ditto.
+
+        * platform/URL.cpp:
+        (WebCore::isAllASCII): Renamed from containsOnlyASCII.
+        (WebCore::appendEncodedHostname): Use isAllASCII.
+
+        * platform/URLParser.cpp:
+        (WebCore::containsOnlyASCII): Deleted.
+        (WebCore::URLParser::domainToASCII): Use StringImpl::isAllASCII. Changed
+        to take StringImpl& to guarantee we won't keep doing null checks since
+        the caller already checks for null.
+        (WebCore::URLParser::parseHostAndPort): Pass StringImpl&.
+        * platform/URLParser.h: Updated for above.
+
+        * platform/graphics/MediaPlayer.cpp:
+        (WebCore::MediaPlayer::supportsType): Use endsWithIgnoringASCIICase
+        and startsWithLettersIgnoringASCIICase.
+
+        * platform/graphics/avfoundation/CDMPrivateMediaSourceAVFObjC.mm:
+        (WebCore::validKeySystemRE): Use JSC::Yarr::TextCaseInsensitive.
+
+        * platform/graphics/cocoa/FontCacheCoreText.cpp:
+        (WebCore::FontCache::similarFont): Use containsIgnoringASCIICase for
+        the Geeza font special cases.
+
+        * platform/graphics/mac/MediaPlayerPrivateQTKit.mm:
+        (WebCore::shouldRejectMIMEType): Use startsWithLettersIgnoringASCIICase.
+
+        * platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp:
+        (WebCore::GraphicsContext3D::getUnmangledInfoLog): Removed
+        TextCaseSensitive since it now is the default.
+
+        * platform/mac/PublicSuffixMac.mm:
+        (WebCore::topPrivatelyControlledDomain): Use isAllASCII.
+
+        * platform/mac/SSLKeyGeneratorMac.mm:
+        (WebCore::signedPublicKeyAndChallengeString): Use isAllASCII.
+
+        * platform/mac/StringUtilities.mm:
+        (WebCore::stringMatchesWildcardString): Use JSC::Yarr::TextCaseInsensitive.
+
+        * platform/mediastream/RealtimeMediaSourceCenter.cpp:
+        (WebCore::addStringToSHA1): Use isAllASCII.
+
+        * platform/network/CacheValidation.cpp:
+        (WebCore::parseCacheControlDirectives): Use containsIgnoringASCIICase.
+
+        * platform/network/HTTPParsers.cpp:
+        (WebCore::parseHTTPRefresh): Use findIgnoringASCIICase.
+        (WebCore::findCharsetInMediaType): Ditto.
+        (WebCore::parseRange): Use startsWithLettersIgnoringASCIICase.
+
+        * platform/network/curl/AuthenticationChallengeCurl.cpp:
+        (WebCore::AuthenticationChallenge::protectionSpaceFromHandle):
+        Use findIgnoringASCIICase.
+        * platform/network/curl/MultipartHandle.cpp:
+        (WebCore::MultipartHandle::extractBoundary): Ditto.
+        * platform/network/curl/ResourceHandleCurlDelegate.cpp:
+        (WebCore::ResourceHandleCurlDelegate::handleDataURL): Use
+        endsWithIgnoringASCIICase.
+        * platform/network/curl/ResourceResponseCurl.cpp:
+        (WebCore::ResourceResponse::isAppendableHeader): Use
+        startsWithLettersIgnoringASCIICase.
+        (WebCore::ResourceResponse::appendHTTPHeaderField): Ditto.
+
+        * platform/win/ClipboardUtilitiesWin.cpp:
+        (WebCore::extractMarkupFromCFHTML): Use findIgnoringASCIICase.
+        (WebCore::fragmentFromCFHTML): Ditto.
+
+        * rendering/BidiRun.cpp:
+        (WebCore::BidiRun::BidiRun): Use text().length().
+        * rendering/HitTestResult.cpp:
+        (WebCore::HitTestResult::absolutePDFURL const): Use
+        endsWithIgnoringASCIICase.
+        * rendering/InlineFlowBox.cpp:
+        (WebCore::InlineFlowBox::placeBoxRangeInInlineDirection): Use text().length().
+        * rendering/InlineIterator.h:
+        (WebCore::InlineIterator::fastIncrementInTextNode): Ditto.
+        (WebCore::InlineIterator::increment): Dtto.
+        * rendering/InlineTextBox.cpp:
+        (WebCore::InlineTextBox::isLineBreak const): Updated since RenderText::text
+        now returns a StringImpl&.
+        (WebCore::InlineTextBox::selectionStartEnd const): Use text().length().
+        (WebCore::InlineTextBox::text const): Updated since RenderText::text
+        now returns a StringImpl&.
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::constructTextRun): Use text().length().
+        * rendering/RenderBlockFlow.cpp:
+        (WebCore::isVisibleRenderText): Use isAllSpecialCharacters<isHTMLSpace>().
+        (WebCore::RenderBlockFlow::computeInlinePreferredLogicalWidths const):
+        Use the new trimmedPreferredWidths that returns a structure instead of the
+        old one with lots of arguments. Also use text().length().
+        * rendering/RenderBlockLineLayout.cpp:
+        (WebCore::endsWithHTMLSpaces): Renamed and changed to use isHTMLSpace
+        instead of isASCIISpace.
+        (WebCore::reachedEndOfTextRenderer): Use endsWithHTMLSpaces.
+        (WebCore::RenderBlockFlow::computeInlineDirectionPositionsForSegment):
+        Updated for hcanges to RenderText.
+        (WebCore::RenderBlockFlow::handleTrailingSpaces): Ditto.
+        (WebCore::RenderBlockFlow::determineStartPosition): Ditto.
+
+        * rendering/RenderCombineText.cpp:
+        (WebCore::RenderCombineText::combineTextIfNeeded): Use
+        isAllSpecialCharacters<isHTMLSpace>.
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::calculateClipRects const): Ditto.
+
+        * rendering/RenderListBox.cpp:
+        (WebCore::bolder): Added. Helper function.
+        (WebCore::RenderListBox::updateFromElement): Rewrote to
+        only compute the bolder font once rather than for every item.
+        (WebCore::RenderListBox::paintItemForeground): Updated for
+        change to applyTextTransform.
+
+        * rendering/RenderMenuList.cpp:
+        (WebCore::RenderMenuList::adjustInnerStyle): Updated for change
+        to RenderText::text.
+        (RenderMenuList::updateOptionsWidth): Updated for change to
+        applyTextTransform.
+        (RenderMenuList::itemText const): Ditto.
+
+        * rendering/RenderText.cpp:
+        (WebCore::capitalize): Renamed from makeCapitalized. Changed to
+        take and return a String instead of taking a String*.
+        (WebCore::RenderText::RenderText): Use isAllASCII. Also moved
+        initialization of most non-bitfield members to the class definition.
+        (WebCore::RenderText::positionForPoint): Use text().
+        (WebCore::RenderText::widthFromCache const): Ditto.
+        (WebCore::RenderText::hangablePunctuationStartWidth const): Ditto.
+        (WebCore::RenderText::hangablePunctuationEndWidth const): Ditto.
+        (WebCore::RenderText::isHangableStopOrComma): Ditto.
+        (WebCore::RenderText::firstCharacterIndexStrippingSpaces const): Ditto.
+        (WebCore::RenderText::lastCharacterIndexStrippingSpaces const): Ditto.
+        (WebCore::RenderText::trimmedPreferredWidths): Changed to return values
+        in a structure instead of taking lots of arguments.
+        (WebCore::RenderText::computePreferredLogicalWidths): Updated to use
+        the text() function.
+        (WebCore::isAllCollapsibleWhitespace): Added.
+        (WebCore::RenderText::isAllCollapsibleWhitespace const): Updated to
+        use a tighter loop.
+        (WebCore::isAllPossiblyCollapsibleWhitespace): Added.
+        (WebCore::RenderText::containsOnlyHTMLWhitespace const): Updated to
+        use a tighter loop. Renamed from containsOnlyWhitespace.
+        (WebCore::RenderText::setTextWithOffset): Updated to  use text().
+        (WebCore::isInlineFlowOrEmptyText): Rewrote to be easier to read.
+        (WebCore::RenderText::previousCharacter const): Got rid of unneeded
+        null check and simplified.
+        (WebCore::applyTextTransform): Changed to return a String rather
+        than modifying one that is passed in.
+        (WebCore::RenderText::setRenderedText): Updated use of applyTextTransform.
+        (WebCore::RenderText::secureText): More of the same.
+        (WebCore::RenderText::computeCanUseSimplifiedTextMeasuring const): Ditto.
+        (WebCore::RenderText::textWithoutConvertingBackslashToYenSymbol const): Ditto.
+        (WebCore::RenderText::width const): Ditto.
+        (WebCore::RenderText::collectSelectionRectsForLineBoxes): Ditto.
+        (WebCore::RenderText::previousOffset const): Ditto.
+        (WebCore::RenderText::previousOffsetForBackwardDeletion const): Ditto.
+        (WebCore::RenderText::nextOffset const): Ditto.
+        (WebCore::RenderText::computeCanUseSimpleFontCodePath const): Ditto.
+        (WebCore::RenderText::stringView const): Ditto.
+
+        * rendering/RenderText.h: Made some more members private and final.
+        Updated for above, including adding the Widths structure. Got rid of the
+        textLength function, which existed as a workaround before we could mark
+        a function like length final. Made the text function return a StringImpl&,
+        which is good since the m_text string is never null, and so callers end
+        up using StringImpl directly and saving null checks. Removed functions
+        that are not needed, including is8Bit, characters8, characters16,
+        uncheckedCharacterAt, operator[], and isAllASCII.
+
+        * rendering/RenderTextFragment.cpp:
+        (WebCore::RenderTextFragment::setText): Use text().length().
+        * rendering/RenderTextLineBoxes.cpp:
+        (WebCore::RenderTextLineBoxes::caretMaxOffset const): Ditto.
+        (WebCore::RenderTextLineBoxes::positionForPoint const): Ditto.
+        (WebCore::RenderTextLineBoxes::setSelectionState): Ditto.
+        (WebCore::RenderTextLineBoxes::absoluteQuads const): Ditto.
+        * rendering/SimpleLineLayout.cpp:
+        (WebCore::SimpleLineLayout::canUseForFontAndText): Ditto.
+        * rendering/SimpleLineLayoutCoverage.cpp:
+        (WebCore::SimpleLineLayout::textLengthForSubtree): Ditto.
+        (WebCore::SimpleLineLayout::collectNonEmptyLeafRenderBlockFlows): Ditto.
+        * rendering/SimpleLineLayoutFlowContents.cpp:
+        (WebCore::SimpleLineLayout::initializeSegments): Ditto.
+        * rendering/SimpleLineLayoutFunctions.cpp:
+        (WebCore::SimpleLineLayout::textOffsetForPoint): Ditto.
+        * rendering/SimpleLineLayoutFunctions.h:
+        (WebCore::SimpleLineLayout::findCaretMaximumOffset): Ditto.
+        * rendering/line/BreakingContext.h:
+        (WebCore::shouldAddBorderPaddingMargin): Ditto.
+        (WebCore::shouldSkipWhitespaceAfterStartObject): Ditto.
+        (WebCore::iteratorIsBeyondEndOfRenderCombineText): Ditto.
+        (WebCore::textWidth): Ditto.
+        (WebCore::BreakingContext::handleText): Ditto.
+        (WebCore::BreakingContext::optimalLineBreakLocationForTrailingWord): Ditto.
+        * rendering/line/TrailingObjects.cpp:
+        (WebCore::TrailingObjects::updateWhitespaceCollapsingTransitionsForTrailingBoxes): Ditto.
+
+        * rendering/mathml/RenderMathMLFenced.cpp:
+        (WebCore::RenderMathMLFenced::updateFromElement): Removed stray use of "unsigned int".
+
+        * rendering/svg/RenderSVGInlineText.cpp:
+        (WebCore::RenderSVGInlineText::characterStartsNewTextChunk const): Use text().length().
+        (WebCore::RenderSVGInlineText::positionForPoint): Ditto.
+        * rendering/svg/SVGTextLayoutAttributesBuilder.cpp:
+        (WebCore::processRenderSVGInlineText): Ditto.
+        * rendering/svg/SVGTextLayoutEngine.cpp:
+        (WebCore::SVGTextLayoutEngine::currentLogicalCharacterAttributes): Ditto.
+        * rendering/svg/SVGTextQuery.cpp:
+        (WebCore::SVGTextQuery::modifyStartEndPositionsRespectingLigatures const): Ditto.
+
+        * style/RenderTreeUpdater.cpp:
+        (WebCore::RenderTreeUpdater::updateRenderTree): Use isAllSpecialCharacters<isHTMLSpace>.
+        (WebCore::RenderTreeUpdater::textRendererIsNeeded): Ditto.
+
+        * svg/SVGTests.cpp:
+        (WebCore::SVGTests::hasFeatureForLegacyBindings): Use startsWithLettersIgnoringASCIICase.
+        * xml/parser/XMLDocumentParserLibxml2.cpp:
+        (WebCore::shouldAllowExternalLoad): Ditto.
+
 2017-11-23  Zan Dobersek  <zdobersek@igalia.com>
 
         [CoordGraphics] Simplify CoordinatedGraphicsLayer's content buffer updates
index b497adc..c9171dc 100644 (file)
@@ -174,11 +174,6 @@ static YouTubePluginReplacement::KeyValueMap queryKeysAndValues(const String& qu
     return queryDictionary;
 }
     
-static bool hasCaseInsensitivePrefix(const String& input, const String& prefix)
-{
-    return input.startsWith(prefix, false);
-}
-    
 static bool isYouTubeURL(const URL& url)
 {
     String hostName = url.host();
@@ -264,7 +259,7 @@ static URL processAndCreateYouTubeURL(const URL& url, bool& isYouTubeShortenedUR
                 }
             }
         }
-    } else if (hasCaseInsensitivePrefix(path, "/v/") || hasCaseInsensitivePrefix(path, "/e/")) {
+    } else if (startsWithLettersIgnoringASCIICase(path, "/v/") || startsWithLettersIgnoringASCIICase(path, "/e/")) {
         String lastPathComponent = url.lastPathComponent();
         String videoID;
         String pathAfterFirstAmpersand;
index 0ea90f5..7ec2786 100644 (file)
@@ -525,7 +525,7 @@ const char* WebSocketHandshake::readHTTPHeaders(const char* start, const char* e
         if ((headerName == HTTPHeaderName::SecWebSocketExtensions
             || headerName == HTTPHeaderName::SecWebSocketAccept
             || headerName == HTTPHeaderName::SecWebSocketProtocol)
-            && !value.containsOnlyASCII()) {
+            && !value.isAllASCII()) {
             m_failureReason = makeString(name, " header value should only contain ASCII characters");
             return nullptr;
         }
index 2992a09..1df1f05 100644 (file)
@@ -76,6 +76,7 @@
 #include "HTMLLabelElement.h"
 #include "HTMLMeterElement.h"
 #include "HTMLNames.h"
+#include "HTMLParserIdioms.h"
 #include "HTMLTextFormControlElement.h"
 #include "InlineElementBox.h"
 #include "MathMLElement.h"
@@ -1615,14 +1616,14 @@ CharacterOffset AXObjectCache::traverseToOffsetInRange(RefPtr<Range>range, int o
         } else {
             // Ignore space, new line, tag node.
             if (currentLength == 1) {
-                if (isSpaceOrNewline(iterator.text()[0])) {
+                if (isHTMLSpace(iterator.text()[0])) {
                     // If the node has BR tag, we want to set the currentNode to it.
                     int subOffset = iterator.range()->startOffset();
                     Node* childNode = node.traverseToChildAt(subOffset);
                     if (childNode && childNode->renderer() && childNode->renderer()->isBR()) {
                         currentNode = childNode;
                         hasReplacedNodeOrBR = true;
-                    } else if (Element *shadowHost = currentNode->shadowHost()) {
+                    } else if (auto* shadowHost = currentNode->shadowHost()) {
                         // Since we are entering text controls, we should set the currentNode
                         // to be the shadow host when there's no content.
                         if (nodeIsTextControl(shadowHost) && currentNode->isShadowRoot()) {
index 6e301b0..d5db9e2 100644 (file)
@@ -118,7 +118,7 @@ bool AccessibilityList::childHasPseudoVisibleListItemMarkers(RenderObject* listI
     // those renderers as "ignored" objects.
 #if PLATFORM(GTK)
     String text = axObj->textUnderElement();
-    return !text.isEmpty() && !text.containsOnlyWhitespace();
+    return !text.isEmpty() && !text.isAllSpecialCharacters<isHTMLSpace>();
 #else
     return false;
 #endif
index 57d0eac..e94aa94 100644 (file)
@@ -481,12 +481,12 @@ bool AccessibilityNodeObject::isSearchField() const
 
     // Check the node name of the input type, sometimes it's "search".
     const AtomicString& nameAttribute = getAttribute(nameAttr);
-    if (nameAttribute.contains("search", false))
+    if (nameAttribute.containsIgnoringASCIICase("search"))
         return true;
 
     // Check the form action and the name, which will sometimes be "search".
     auto* form = inputElement.form();
-    if (form && (form->name().contains("search", false) || form->action().contains("search", false)))
+    if (form && (form->name().containsIgnoringASCIICase("search") || form->action().containsIgnoringASCIICase("search")))
         return true;
 
     return false;
index 2919142..bd4eb81 100644 (file)
@@ -289,9 +289,9 @@ bool AccessibilityObject::accessibilityObjectContainsText(String* text) const
     // If text is null or empty we return true.
     return !text
         || text->isEmpty()
-        || title().contains(*text, false)
-        || accessibilityDescription().contains(*text, false)
-        || stringValue().contains(*text, false);
+        || findPlainText(title(), *text, CaseInsensitive)
+        || findPlainText(accessibilityDescription(), *text, CaseInsensitive)
+        || findPlainText(stringValue(), *text, CaseInsensitive);
 }
 
 // ARIA marks elements as having their accessible name derive from either their contents, or their author provide name.
@@ -838,8 +838,7 @@ String AccessibilityObject::selectText(AccessibilitySelectTextCriteria* criteria
         if (frame->selection().setSelectedRange(closestStringRange.get(), DOWNSTREAM, true)) {
             switch (activity) {
             case AccessibilitySelectTextActivity::FindAndCapitalize:
-                replacementString = closestString;
-                makeCapitalized(&replacementString, 0);
+                replacementString = capitalize(closestString, ' '); // FIXME: Needs to take locale into account to work correctly.
                 replaceSelection = true;
                 break;
             case AccessibilitySelectTextActivity::FindAndUppercase:
@@ -856,7 +855,7 @@ String AccessibilityObject::selectText(AccessibilitySelectTextCriteria* criteria
                 // (unless we're replacing with an abbreviation.)
                 if (closestString.length() > 0 && replacementString.length() > 2 && replacementString != replacementString.convertToUppercaseWithoutLocale()) {
                     if (closestString[0] == u_toupper(closestString[0]))
-                        makeCapitalized(&replacementString, 0);
+                        replacementString = capitalize(replacementString, ' '); // FIXME: Needs to take locale into account to work correctly.
                     else
                         replacementString = replacementString.convertToLowercaseWithoutLocale(); // FIXME: Needs locale to work correctly.
                 }
index 113fff5..6db9f77 100644 (file)
@@ -1121,7 +1121,7 @@ bool AccessibilityRenderObject::isAllowedChildOfTree() const
 static AccessibilityObjectInclusion objectInclusionFromAltText(const String& altText)
 {
     // Don't ignore an image that has an alt tag.
-    if (!altText.containsOnlyWhitespace())
+    if (!altText.isAllSpecialCharacters<isHTMLSpace>())
         return AccessibilityObjectInclusion::IncludeObject;
     
     // The informal standard is to ignore images with zero-length alt strings.
@@ -1251,7 +1251,7 @@ bool AccessibilityRenderObject::computeAccessibilityIsIgnored() const
         }
 
         // text elements that are just empty whitespace should not be returned
-        return renderText.text()->containsOnlyWhitespace();
+        return renderText.text().isAllSpecialCharacters<isHTMLSpace>();
     }
     
     if (isHeading())
index 17566b1..5933a19 100644 (file)
@@ -197,7 +197,7 @@ unsigned AccessibilityObject::getLengthForTextRange() const
     Node* node = this->node();
     RenderObject* renderer = node ? node->renderer() : nullptr;
     if (is<RenderText>(renderer))
-        textLength = downcast<RenderText>(*renderer).textLength();
+        textLength = downcast<RenderText>(*renderer).text().length();
 
     // Get the text length from the elements under the
     // accessibility object if the value is still zero.
index 69dd4bf..b5438f7 100644 (file)
@@ -34,7 +34,7 @@ using namespace JSC;
 
 static inline String stringToByteString(ExecState& state, JSC::ThrowScope& scope, String&& string)
 {
-    if (!string.containsOnlyLatin1()) {
+    if (!string.isAllLatin1()) {
         throwTypeError(&state, scope);
         return { };
     }
index 37c2ca8..16614c5 100644 (file)
@@ -51,9 +51,8 @@ namespace ContentExtensions {
     
 static bool containsOnlyASCIIWithNoUppercase(const String& domain)
 {
-    for (unsigned i = 0; i < domain.length(); ++i) {
-        UChar c = domain.at(i);
-        if (!isASCII(c) || isASCIIUpper(c))
+    for (auto character : StringView { domain }.codeUnits()) {
+        if (!isASCII(character) || isASCIIUpper(character))
             return false;
     }
     return true;
index 3072101..c0db1b1 100644 (file)
@@ -80,7 +80,7 @@ std::pair<Vector<Action>, Vector<String>> ContentExtensionsBackend::actionsForRe
         return { };
 
     const String& urlString = resourceLoadInfo.resourceURL.string();
-    ASSERT_WITH_MESSAGE(urlString.containsOnlyASCII(), "A decoded URL should only contain ASCII characters. The matching algorithm assumes the input is ASCII.");
+    ASSERT_WITH_MESSAGE(urlString.isAllASCII(), "A decoded URL should only contain ASCII characters. The matching algorithm assumes the input is ASCII.");
     const CString& urlCString = urlString.utf8();
 
     Vector<Action> finalActions;
index 22dfc13..e351e17 100644 (file)
@@ -341,7 +341,7 @@ URLFilterParser::~URLFilterParser() = default;
 
 URLFilterParser::ParseStatus URLFilterParser::addPattern(const String& pattern, bool patternIsCaseSensitive, uint64_t patternId)
 {
-    if (!pattern.containsOnlyASCII())
+    if (!pattern.isAllASCII())
         return NonASCII;
     if (pattern.isEmpty())
         return EmptyPattern;
index 63572c5..8acd9af 100644 (file)
@@ -55,7 +55,7 @@ bool CSSFontFaceSrcValue::isSupportedFormat() const
     // we will also check to see if the URL ends with .eot. If so, we'll assume that we shouldn't load it.
     if (m_format.isEmpty()) {
         // Check for .eot.
-        if (!m_resource.startsWith("data:", false) && m_resource.endsWith(".eot", false))
+        if (!protocolIs(m_resource, "data") && m_resource.endsWithIgnoringASCIICase(".eot"))
             return false;
         return true;
     }
index c6aa786..9135237 100644 (file)
@@ -41,7 +41,7 @@ namespace WebCore {
 
 static String valueWithoutImportant(const String& value)
 {
-    if (!value.endsWith("important", false))
+    if (!value.endsWithIgnoringASCIICase("important"))
         return value;
 
     String newValue = value;
index c167879..99ceed4 100644 (file)
@@ -3254,7 +3254,7 @@ static Vector<String> parseGridTemplateAreasColumnNames(const String& gridRowNam
 
 static bool parseGridTemplateAreasRow(const String& gridRowNames, NamedGridAreaMap& gridAreaMap, const size_t rowCount, size_t& columnCount)
 {
-    if (gridRowNames.isEmpty() || gridRowNames.containsOnlyWhitespace())
+    if (gridRowNames.isAllSpecialCharacters<isCSSSpace>())
         return false;
 
     Vector<String> columnNames = parseGridTemplateAreasColumnNames(gridRowNames);
index e6ee2ac..c3f4b09 100644 (file)
@@ -174,11 +174,6 @@ String CharacterData::nodeValue() const
     return m_data;
 }
 
-bool CharacterData::containsOnlyWhitespace() const
-{
-    return m_data.containsOnlyWhitespace();
-}
-
 ExceptionOr<void> CharacterData::setNodeValue(const String& nodeValue)
 {
     setData(nodeValue);
index e4ad221..1bb1bbe 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
- * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2003-2017 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -39,8 +39,6 @@ public:
     WEBCORE_EXPORT ExceptionOr<void> deleteData(unsigned offset, unsigned count);
     WEBCORE_EXPORT ExceptionOr<void> replaceData(unsigned offset, unsigned count, const String&);
 
-    bool containsOnlyWhitespace() const;
-
     // Like appendData, but optimized for the parser (e.g., no mutation events).
     // Returns how much could be added before length limit was met.
     unsigned parserAppendData(const String& string, unsigned offset, unsigned lengthLimit);
index efa1e9a..6f33326 100644 (file)
@@ -118,11 +118,11 @@ static String normalizeType(const String& type)
         return type;
 
     String lowercaseType = stripLeadingAndTrailingHTMLSpaces(type).convertToASCIILowercase();
-    if (lowercaseType == "text" || lowercaseType.startsWithIgnoringASCIICase("text/plain;"))
+    if (lowercaseType == "text" || lowercaseType.startsWith("text/plain;"))
         return "text/plain";
-    if (lowercaseType == "url" || lowercaseType.startsWithIgnoringASCIICase("text/uri-list;"))
+    if (lowercaseType == "url" || lowercaseType.startsWith("text/uri-list;"))
         return "text/uri-list";
-    if (lowercaseType.startsWithIgnoringASCIICase("text/html;"))
+    if (lowercaseType.startsWith("text/html;"))
         return "text/html";
 
     return lowercaseType;
index 0c6bc25..89a506f 100644 (file)
@@ -32,6 +32,7 @@
 #include "HTMLBodyElement.h"
 #include "HTMLHtmlElement.h"
 #include "HTMLNames.h"
+#include "HTMLParserIdioms.h"
 #include "HTMLTableElement.h"
 #include "InlineElementBox.h"
 #include "InlineIterator.h"
@@ -1141,11 +1142,11 @@ Position Position::leadingWhitespacePosition(EAffinity affinity, bool considerNo
 
     Position prev = previousCharacterPosition(affinity);
     if (prev != *this && inSameEnclosingBlockFlowElement(deprecatedNode(), prev.deprecatedNode()) && is<Text>(*prev.deprecatedNode())) {
-        String string = downcast<Text>(*prev.deprecatedNode()).data();
-        UChar c = string[prev.deprecatedEditingOffset()];
-        if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : deprecatedIsCollapsibleWhitespace(c))
+        UChar c = downcast<Text>(*prev.deprecatedNode()).data()[prev.deprecatedEditingOffset()];
+        if (considerNonCollapsibleWhitespace ? (isHTMLSpace(c) || c == noBreakSpace) : deprecatedIsCollapsibleWhitespace(c)) {
             if (isEditablePosition(prev))
                 return prev;
+        }
     }
 
     return { };
@@ -1162,7 +1163,7 @@ Position Position::trailingWhitespacePosition(EAffinity, bool considerNonCollaps
     UChar c = v.characterAfter();
     // The space must not be in another paragraph and it must be editable.
     if (!isEndOfParagraph(v) && v.next(CannotCrossEditingBoundary).isNotNull())
-        if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : deprecatedIsCollapsibleWhitespace(c))
+        if (considerNonCollapsibleWhitespace ? (isHTMLSpace(c) || c == noBreakSpace) : deprecatedIsCollapsibleWhitespace(c))
             return *this;
     
     return { };
index ba06f79..8a997e4 100644 (file)
@@ -3559,7 +3559,7 @@ void Editor::editorUIUpdateTimerFired()
             UChar32 c = newStart.characterBefore();
             // FIXME: VisiblePosition::characterAfter() and characterBefore() do not emit newlines the same
             // way as TextIterator, so we do an isStartOfParagraph check here.
-            if (isSpaceOrNewline(c) || c == 0xA0 || isStartOfParagraph(newStart)) {
+            if (isSpaceOrNewline(c) || c == noBreakSpace || isStartOfParagraph(newStart)) {
                 startWordSide = RightWordIfOnBoundary;
             }
             newAdjacentWords = VisibleSelection(startOfWord(newStart, startWordSide), endOfWord(newStart, RightWordIfOnBoundary));
index b2073ac..f36e05e 100644 (file)
@@ -1763,7 +1763,7 @@ void FrameSelection::debugRenderer(RenderObject* renderer, bool selected) const
         fprintf(stderr, "%s%s\n", selected ? "==> " : "    ", element.localName().string().utf8().data());
     } else if (is<RenderText>(*renderer)) {
         RenderText& textRenderer = downcast<RenderText>(*renderer);
-        if (!textRenderer.textLength() || !textRenderer.firstTextBox()) {
+        if (textRenderer.text().isEmpty() || !textRenderer.firstTextBox()) {
             fprintf(stderr, "%s#text (empty)\n", selected ? "==> " : "    ");
             return;
         }
@@ -2641,7 +2641,7 @@ bool FrameSelection::selectionAtWordStart() const
         }
         UChar c(pos.characterAfter());
         if (c) {
-            result = isSpaceOrNewline(c) || c == 0xA0 || (u_ispunct(c) && c != ',' && c != '-' && c != '\'');
+            result = isSpaceOrNewline(c) || c == noBreakSpace || (u_ispunct(c) && c != ',' && c != '-' && c != '\'');
             break;
         }
     }
@@ -2686,7 +2686,7 @@ VisibleSelection FrameSelection::wordSelectionContainingCaretSelection(const Vis
 
     if (isEndOfParagraph(endVisiblePosBeforeExpansion)) {
         UChar c(endVisiblePosBeforeExpansion.characterBefore());
-        if (isSpaceOrNewline(c) || c == 0xA0) {
+        if (isSpaceOrNewline(c) || c == noBreakSpace) {
             // End of paragraph with space.
             return VisibleSelection();
         }
@@ -2729,7 +2729,7 @@ VisibleSelection FrameSelection::wordSelectionContainingCaretSelection(const Vis
             return VisibleSelection();
         }
         UChar c(previous.characterAfter());
-        if (isSpaceOrNewline(c) || c == 0xA0) {
+        if (isSpaceOrNewline(c) || c == noBreakSpace) {
             // Space at end of line
             return VisibleSelection();
         }
@@ -2744,7 +2744,7 @@ VisibleSelection FrameSelection::wordSelectionContainingCaretSelection(const Vis
             return VisibleSelection();
         }
         UChar c(previous.characterAfter());
-        if (isSpaceOrNewline(c) || c == 0xA0) {
+        if (isSpaceOrNewline(c) || c == noBreakSpace) {
             // Space at end of line
             return VisibleSelection();
         }
@@ -2764,7 +2764,7 @@ VisibleSelection FrameSelection::wordSelectionContainingCaretSelection(const Vis
     while (endVisiblePos != startVisiblePos) {
         VisiblePosition previous(endVisiblePos.previous());
         UChar c(previous.characterAfter());
-        if (!isSpaceOrNewline(c) && c != 0xA0)
+        if (!isSpaceOrNewline(c) && c != noBreakSpace)
             break;
         endVisiblePos = previous;
     }
@@ -2802,7 +2802,7 @@ bool FrameSelection::actualSelectionAtSentenceStart(const VisibleSelection& sel)
         }
         UChar c(pos.characterAfter());
         if (c) {
-            if (isSpaceOrNewline(c) || c == 0xA0) {
+            if (isSpaceOrNewline(c) || c == noBreakSpace) {
                 sawSpace = true;
             }
             else {
index 5c9f360..3af1acf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004-2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
  * Copyright (C) 2005 Alexey Proskuryakov.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -579,7 +579,7 @@ static unsigned textNodeOffsetInFlow(const Text& firstTextNodeInRange)
     unsigned textOffset = 0;
     for (renderer = renderer->previousSibling(); renderer; renderer = renderer->previousSibling()) {
         if (is<RenderText>(renderer))
-            textOffset += downcast<RenderText>(renderer)->textLength();
+            textOffset += downcast<RenderText>(renderer)->text().length();
     }
     return textOffset;
 }
@@ -640,7 +640,7 @@ bool TextIterator::handleTextNode()
         bool isNewTextNode = m_previousSimpleTextNodeInFlow && m_previousSimpleTextNodeInFlow != &textNode;
         // Simple line layout run positions are all absolute to the parent flow.
         // Offsetting is required when multiple renderers are present.
-        m_accumulatedSimpleTextLengthInFlow += isNewTextNode ? m_previousSimpleTextNodeInFlow->renderer()->text()->length() : 0;
+        m_accumulatedSimpleTextLengthInFlow += isNewTextNode ? m_previousSimpleTextNodeInFlow->renderer()->text().length() : 0;
         m_previousSimpleTextNodeInFlow = &textNode;
 
         unsigned endPosition = (m_node == m_endContainer) ? static_cast<unsigned>(m_endOffset) : rendererText.length();
@@ -1045,7 +1045,7 @@ static bool shouldEmitExtraNewlineForNode(Node& node)
 
 static int collapsedSpaceLength(RenderText& renderer, int textEnd)
 {
-    StringImpl& text = *renderer.text();
+    StringImpl& text = renderer.text();
     unsigned length = text.length();
     for (unsigned i = textEnd; i < length; ++i) {
         if (!renderer.style().isCollapsibleWhiteSpace(text[i]))
@@ -2763,4 +2763,20 @@ Ref<Range> findPlainText(const Range& range, const String& target, FindOptions o
     return rangeForMatch(range, options, matchStart, matchLength, searchForward);
 }
 
+bool findPlainText(const String& document, const String& target, FindOptions options)
+{
+    SearchBuffer buffer { target, options };
+    StringView remainingText { document };
+    while (!remainingText.isEmpty()) {
+        size_t charactersAppended = buffer.append(document);
+        remainingText = remainingText.substring(charactersAppended);
+        if (remainingText.isEmpty())
+            buffer.reachedBreak();
+        size_t matchStartOffset;
+        if (buffer.search(matchStartOffset))
+            return true;
+    }
+    return false;
+}
+
 }
index 23c0b5e..860e74c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004, 2006, 2009, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -38,6 +38,7 @@ namespace WebCore {
 class InlineTextBox;
 class RenderText;
 class RenderTextFragment;
+
 namespace SimpleLineLayout {
 class RunResolver;
 }
@@ -47,6 +48,7 @@ WEBCORE_EXPORT String plainTextReplacingNoBreakSpace(const Range*, TextIteratorB
 Ref<Range> findPlainText(const Range&, const String&, FindOptions);
 WEBCORE_EXPORT Ref<Range> findClosestPlainText(const Range&, const String&, FindOptions, unsigned);
 WEBCORE_EXPORT bool hasAnyPlainText(const Range&, TextIteratorBehavior = TextIteratorDefaultBehavior);
+bool findPlainText(const String& document, const String&, FindOptions); // Lets us use the search algorithm on a string.
 
 // FIXME: Move this somewhere else in the editing directory. It doesn't belong here.
 bool isRendererReplacedElement(RenderObject*);
index 9620bfb..fd79066 100644 (file)
@@ -477,7 +477,7 @@ void TypingCommand::markMisspellingsAfterTyping(ETypingCommand commandType)
         UChar32 c = previous.characterAfter();
         // FIXME: VisiblePosition::characterAfter() and characterBefore() do not emit newlines the same
         // way as TextIterator, so we do an isEndOfParagraph check here.
-        if (isSpaceOrNewline(c) || c == 0xA0 || isEndOfParagraph(previous)) {
+        if (isSpaceOrNewline(c) || c == noBreakSpace || isEndOfParagraph(previous)) {
             startWordSide = RightWordIfOnBoundary;
         }
         VisiblePosition p1 = startOfWord(previous, startWordSide);
index 6abcd4f..cc17dd6 100644 (file)
@@ -1193,7 +1193,7 @@ Node* findStartOfParagraph(Node* startNode, Node* highestRoot, Node* startBlock,
             ASSERT_WITH_SECURITY_IMPLICATION(is<Text>(*n));
             type = Position::PositionIsOffsetInAnchor;
             if (style.preserveNewline()) {
-                StringImpl& text = *downcast<RenderText>(*r).text();
+                StringImpl& text = downcast<RenderText>(*r).text();
                 int i = text.length();
                 int o = offset;
                 if (n == startNode && o < i)
@@ -1257,7 +1257,7 @@ Node* findEndOfParagraph(Node* startNode, Node* highestRoot, Node* stayInsideBlo
             ASSERT_WITH_SECURITY_IMPLICATION(is<Text>(*n));
             type = Position::PositionIsOffsetInAnchor;
             if (style.preserveNewline()) {
-                StringImpl& text = *downcast<RenderText>(*r).text();
+                StringImpl& text = downcast<RenderText>(*r).text();
                 int o = n == startNode ? offset : 0;
                 int length = text.length();
                 for (int i = o; i < length; ++i) {
index 30ad6db..6b1397e 100644 (file)
@@ -2224,7 +2224,7 @@ void HTMLConverter::_processText(CharacterData& characterData)
     bool wasSpace = false;
     if (_caches->propertyValueForNode(characterData, CSSPropertyWhiteSpace).startsWith("pre")) {
         if (textLength && originalString.length() && _flags.isSoft) {
-            unichar c = originalString.at(0);
+            unichar c = originalString.characterAt(0);
             if (c == '\n' || c == '\r' || c == NSParagraphSeparatorCharacter || c == NSLineSeparatorCharacter || c == NSFormFeedCharacter || c == WebNextLineCharacter)
                 rangeToReplace = NSMakeRange(textLength - 1, 1);
         }
@@ -2234,7 +2234,7 @@ void HTMLConverter::_processText(CharacterData& characterData)
         StringBuilder builder;
         LChar noBreakSpaceRepresentation = 0;
         for (unsigned i = 0; i < count; i++) {
-            UChar c = originalString.at(i);
+            UChar c = originalString.characterAt(i);
             bool isWhitespace = c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == 0xc || c == 0x200b;
             if (isWhitespace)
                 wasSpace = (!wasLeading || !suppressLeadingSpace);
@@ -2260,7 +2260,7 @@ void HTMLConverter::_processText(CharacterData& characterData)
     if (outputString.length()) {
         String textTransform = _caches->propertyValueForNode(characterData, CSSPropertyTextTransform);
         if (textTransform == "capitalize")
-            makeCapitalized(&outputString, 0); // FIXME: Needs to take locale into account to work correctly.
+            outputString = capitalize(outputString, ' '); // FIXME: Needs to take locale into account to work correctly.
         else if (textTransform == "uppercase")
             outputString = outputString.convertToUppercaseWithoutLocale(); // FIXME: Needs locale to work correctly.
         else if (textTransform == "lowercase")
index eb28666..6a3fe46 100644 (file)
@@ -312,7 +312,7 @@ static String stripMicrosoftPrefix(const String& string)
     // It's a simple-minded way to ignore the CF_HTML clipboard format, just skipping over the
     // description part and parsing the entire context plus fragment.
     if (string.startsWith("Version:")) {
-        size_t location = string.findIgnoringCase("<html");
+        size_t location = string.findIgnoringASCIICase("<html");
         if (location != notFound)
             return string.substring(location);
     }
index e313419..2f1de9b 100644 (file)
@@ -304,7 +304,7 @@ AutofillData AutofillData::createFromHTMLFormControlElement(const HTMLFormContro
     // 17. If the first eight characters of the indexth token in tokens are not an ASCII case-insensitive
     // match for the string "section-", then jump to the step labeled default.
     const auto& sectionToken = tokens[index];
-    if (!sectionToken.startsWithIgnoringASCIICase("section-"))
+    if (!startsWithLettersIgnoringASCIICase(sectionToken, "section-"))
         return defaultLabel();
 
     // 18. Let section be the indexth token in tokens, converted to ASCII lowercase.
index 56d6709..2bb4331 100644 (file)
@@ -40,12 +40,12 @@ bool BaseTextInputType::isTextType() const
 bool BaseTextInputType::patternMismatch(const String& value) const
 {
     const AtomicString& rawPattern = element().attributeWithoutSynchronization(patternAttr);
-    if (rawPattern.isNull() || value.isEmpty() || !JSC::Yarr::RegularExpression(rawPattern, TextCaseSensitive).isValid())
+    if (rawPattern.isNull() || value.isEmpty() || !JSC::Yarr::RegularExpression(rawPattern).isValid())
         return false;
     String pattern = "^(?:" + rawPattern + ")$";
     int matchLength = 0;
     int valueLength = value.length();
-    int matchOffset = JSC::Yarr::RegularExpression(pattern, TextCaseSensitive).match(value, 0, &matchLength);
+    int matchOffset = JSC::Yarr::RegularExpression(pattern).match(value, 0, &matchLength);
     return matchOffset || matchLength != valueLength;
 }
 
index 31f8aa5..1c27f88 100644 (file)
@@ -43,7 +43,7 @@ static bool isValidEmailAddress(const String& address)
     if (!addressLength)
         return false;
 
-    static NeverDestroyed<const JSC::Yarr::RegularExpression> regExp(emailPattern, TextCaseInsensitive);
+    static NeverDestroyed<const JSC::Yarr::RegularExpression> regExp(emailPattern, JSC::Yarr::TextCaseInsensitive);
 
     int matchLength;
     int matchOffset = regExp.get().match(address, 0, &matchLength);
index c523229..1bc0ee4 100644 (file)
@@ -214,7 +214,7 @@ bool HTMLObjectElement::hasFallbackContent() const
     for (RefPtr<Node> child = firstChild(); child; child = child->nextSibling()) {
         // Ignore whitespace-only text, and <param> tags, any other content is fallback content.
         if (is<Text>(*child)) {
-            if (!downcast<Text>(*child).containsOnlyWhitespace())
+            if (!downcast<Text>(*child).data().isAllSpecialCharacters<isHTMLSpace>())
                 return true;
         } else if (!is<HTMLParamElement>(*child))
             return true;
@@ -238,7 +238,7 @@ bool HTMLObjectElement::shouldAllowQuickTimeClassIdQuirk()
         return false;
 
     for (auto& metaElement : descendantsOfType<HTMLMetaElement>(document())) {
-        if (equalLettersIgnoringASCIICase(metaElement.name(), "generator") && metaElement.content().startsWith("Mac OS X Server Web Services Server", false))
+        if (equalLettersIgnoringASCIICase(metaElement.name(), "generator") && startsWithLettersIgnoringASCIICase(metaElement.content(), "mac os x server web services server"))
             return true;
     }
 
@@ -247,7 +247,7 @@ bool HTMLObjectElement::shouldAllowQuickTimeClassIdQuirk()
     
 bool HTMLObjectElement::hasValidClassId()
 {
-    if (MIMETypeRegistry::isJavaAppletMIMEType(serviceType()) && attributeWithoutSynchronization(classidAttr).startsWith("java:", false))
+    if (MIMETypeRegistry::isJavaAppletMIMEType(serviceType()) && protocolIs(attributeWithoutSynchronization(classidAttr), "java"))
         return true;
     
     if (shouldAllowQuickTimeClassIdQuirk())
@@ -409,7 +409,7 @@ static inline bool preventsParentObjectFromExposure(const Node& child)
     if (is<Element>(child))
         return preventsParentObjectFromExposure(downcast<Element>(child));
     if (is<Text>(child))
-        return !downcast<Text>(child).containsOnlyWhitespace();
+        return !downcast<Text>(child).data().isAllSpecialCharacters<isHTMLSpace>();
     return true;
 }
 
index 774ad54..764e502 100644 (file)
@@ -46,13 +46,11 @@ static const Seconds typeAheadTimeout { 1_s };
 static String stripLeadingWhiteSpace(const String& string)
 {
     unsigned length = string.length();
-
     unsigned i;
     for (i = 0; i < length; ++i) {
-        if (string[i] != noBreakSpace && (string[i] <= 0x7F ? !isASCIISpace(string[i]) : (u_charDirection(string[i]) != U_WHITE_SPACE_NEUTRAL)))
+        if (string[i] != noBreakSpace && !isSpaceOrNewline(string[i]))
             break;
     }
-
     return string.substring(i, length - i);
 }
 
@@ -95,10 +93,6 @@ int TypeAhead::handleEvent(KeyboardEvent* event, MatchModeFlags matchMode)
         int index = (selected < 0 ? 0 : selected) + searchStartOffset;
         index %= optionCount;
 
-        // Compute a case-folded copy of the prefix string before beginning the search for
-        // a matching element. This code uses foldCase to work around the fact that
-        // String::startWith does not fold non-ASCII characters. This code can be changed
-        // to use startWith once that is fixed.
         String prefixWithCaseFolded(prefix.foldCase());
         for (int i = 0; i < optionCount; ++i, index = (index + 1) % optionCount) {
             // Fold the option string and check if its prefix is equal to the folded prefix.
index 1217d9b..023c8fd 100644 (file)
@@ -336,76 +336,76 @@ void HTMLConstructionSite::setCompatibilityModeFromDoctype(const String& name, c
 
     // Check for Quirks Mode.
     if (name != "html"
-        || publicId.startsWith("+//Silmaril//dtd html Pro v0r11 19970101//", false)
-        || publicId.startsWith("-//AdvaSoft Ltd//DTD HTML 3.0 asWedit + extensions//", false)
-        || publicId.startsWith("-//AS//DTD HTML 3.0 asWedit + extensions//", false)
-        || publicId.startsWith("-//IETF//DTD HTML 2.0 Level 1//", false)
-        || publicId.startsWith("-//IETF//DTD HTML 2.0 Level 2//", false)
-        || publicId.startsWith("-//IETF//DTD HTML 2.0 Strict Level 1//", false)
-        || publicId.startsWith("-//IETF//DTD HTML 2.0 Strict Level 2//", false)
-        || publicId.startsWith("-//IETF//DTD HTML 2.0 Strict//", false)
-        || publicId.startsWith("-//IETF//DTD HTML 2.0//", false)
-        || publicId.startsWith("-//IETF//DTD HTML 2.1E//", false)
-        || publicId.startsWith("-//IETF//DTD HTML 3.0//", false)
-        || publicId.startsWith("-//IETF//DTD HTML 3.2 Final//", false)
-        || publicId.startsWith("-//IETF//DTD HTML 3.2//", false)
-        || publicId.startsWith("-//IETF//DTD HTML 3//", false)
-        || publicId.startsWith("-//IETF//DTD HTML Level 0//", false)
-        || publicId.startsWith("-//IETF//DTD HTML Level 1//", false)
-        || publicId.startsWith("-//IETF//DTD HTML Level 2//", false)
-        || publicId.startsWith("-//IETF//DTD HTML Level 3//", false)
-        || publicId.startsWith("-//IETF//DTD HTML Strict Level 0//", false)
-        || publicId.startsWith("-//IETF//DTD HTML Strict Level 1//", false)
-        || publicId.startsWith("-//IETF//DTD HTML Strict Level 2//", false)
-        || publicId.startsWith("-//IETF//DTD HTML Strict Level 3//", false)
-        || publicId.startsWith("-//IETF//DTD HTML Strict//", false)
-        || publicId.startsWith("-//IETF//DTD HTML//", false)
-        || publicId.startsWith("-//Metrius//DTD Metrius Presentational//", false)
-        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 HTML Strict//", false)
-        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 HTML//", false)
-        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 Tables//", false)
-        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 HTML Strict//", false)
-        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 HTML//", false)
-        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 Tables//", false)
-        || publicId.startsWith("-//Netscape Comm. Corp.//DTD HTML//", false)
-        || publicId.startsWith("-//Netscape Comm. Corp.//DTD Strict HTML//", false)
-        || publicId.startsWith("-//O'Reilly and Associates//DTD HTML 2.0//", false)
-        || publicId.startsWith("-//O'Reilly and Associates//DTD HTML Extended 1.0//", false)
-        || publicId.startsWith("-//O'Reilly and Associates//DTD HTML Extended Relaxed 1.0//", false)
-        || publicId.startsWith("-//SoftQuad Software//DTD HoTMetaL PRO 6.0::19990601::extensions to HTML 4.0//", false)
-        || publicId.startsWith("-//SoftQuad//DTD HoTMetaL PRO 4.0::19971010::extensions to HTML 4.0//", false)
-        || publicId.startsWith("-//Spyglass//DTD HTML 2.0 Extended//", false)
-        || publicId.startsWith("-//SQ//DTD HTML 2.0 HoTMetaL + extensions//", false)
-        || publicId.startsWith("-//Sun Microsystems Corp.//DTD HotJava HTML//", false)
-        || publicId.startsWith("-//Sun Microsystems Corp.//DTD HotJava Strict HTML//", false)
-        || publicId.startsWith("-//W3C//DTD HTML 3 1995-03-24//", false)
-        || publicId.startsWith("-//W3C//DTD HTML 3.2 Draft//", false)
-        || publicId.startsWith("-//W3C//DTD HTML 3.2 Final//", false)
-        || publicId.startsWith("-//W3C//DTD HTML 3.2//", false)
-        || publicId.startsWith("-//W3C//DTD HTML 3.2S Draft//", false)
-        || publicId.startsWith("-//W3C//DTD HTML 4.0 Frameset//", false)
-        || publicId.startsWith("-//W3C//DTD HTML 4.0 Transitional//", false)
-        || publicId.startsWith("-//W3C//DTD HTML Experimental 19960712//", false)
-        || publicId.startsWith("-//W3C//DTD HTML Experimental 970421//", false)
-        || publicId.startsWith("-//W3C//DTD W3 HTML//", false)
-        || publicId.startsWith("-//W3O//DTD W3 HTML 3.0//", false)
+        || startsWithLettersIgnoringASCIICase(publicId, "+//silmaril//dtd html pro v0r11 19970101//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//advasoft ltd//dtd html 3.0 aswedit + extensions//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//as//dtd html 3.0 aswedit + extensions//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html 2.0 level 1//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html 2.0 level 2//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html 2.0 strict level 1//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html 2.0 strict level 2//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html 2.0 strict//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html 2.0//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html 2.1e//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html 3.0//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html 3.2 final//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html 3.2//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html 3//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html level 0//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html level 1//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html level 2//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html level 3//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html strict level 0//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html strict level 1//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html strict level 2//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html strict level 3//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html strict//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//ietf//dtd html//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//metrius//dtd metrius presentational//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//microsoft//dtd internet explorer 2.0 html strict//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//microsoft//dtd internet explorer 2.0 html//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//microsoft//dtd internet explorer 2.0 tables//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//microsoft//dtd internet explorer 3.0 html strict//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//microsoft//dtd internet explorer 3.0 html//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//microsoft//dtd internet explorer 3.0 tables//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//netscape comm. corp.//dtd html//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//netscape comm. corp.//dtd strict html//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//o'reilly and associates//dtd html 2.0//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//o'reilly and associates//dtd html extended 1.0//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//o'reilly and associates//dtd html extended relaxed 1.0//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//spyglass//dtd html 2.0 extended//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//sq//dtd html 2.0 hotmetal + extensions//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//sun microsystems corp.//dtd hotjava html//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//sun microsystems corp.//dtd hotjava strict html//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//w3c//dtd html 3 1995-03-24//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//w3c//dtd html 3.2 draft//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//w3c//dtd html 3.2 final//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//w3c//dtd html 3.2//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//w3c//dtd html 3.2s draft//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//w3c//dtd html 4.0 frameset//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//w3c//dtd html 4.0 transitional//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//w3c//dtd html experimental 19960712//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//w3c//dtd html experimental 970421//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//w3c//dtd w3 html//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//w3o//dtd w3 html 3.0//")
         || equalLettersIgnoringASCIICase(publicId, "-//w3o//dtd w3 html strict 3.0//en//")
-        || publicId.startsWith("-//WebTechs//DTD Mozilla HTML 2.0//", false)
-        || publicId.startsWith("-//WebTechs//DTD Mozilla HTML//", false)
+        || startsWithLettersIgnoringASCIICase(publicId, "-//webtechs//dtd mozilla html 2.0//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//webtechs//dtd mozilla html//")
         || equalLettersIgnoringASCIICase(publicId, "-/w3c/dtd html 4.0 transitional/en")
         || equalLettersIgnoringASCIICase(publicId, "html")
         || equalLettersIgnoringASCIICase(systemId, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd")
-        || (systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Frameset//", false))
-        || (systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Transitional//", false))) {
+        || (systemId.isEmpty() && startsWithLettersIgnoringASCIICase(publicId, "-//w3c//dtd html 4.01 frameset//"))
+        || (systemId.isEmpty() && startsWithLettersIgnoringASCIICase(publicId, "-//w3c//dtd html 4.01 transitional//"))) {
         setCompatibilityMode(DocumentCompatibilityMode::QuirksMode);
         return;
     }
 
     // Check for Limited Quirks Mode.
-    if (publicId.startsWith("-//W3C//DTD XHTML 1.0 Frameset//", false)
-        || publicId.startsWith("-//W3C//DTD XHTML 1.0 Transitional//", false)
-        || (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Frameset//", false))
-        || (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Transitional//", false))) {
+    if (startsWithLettersIgnoringASCIICase(publicId, "-//w3c//dtd xhtml 1.0 frameset//")
+        || startsWithLettersIgnoringASCIICase(publicId, "-//w3c//dtd xhtml 1.0 transitional//")
+        || (!systemId.isEmpty() && startsWithLettersIgnoringASCIICase(publicId, "-//w3c//dtd html 4.01 frameset//"))
+        || (!systemId.isEmpty() && startsWithLettersIgnoringASCIICase(publicId, "-//w3c//dtd html 4.01 transitional//"))) {
         setCompatibilityMode(DocumentCompatibilityMode::LimitedQuirksMode);
         return;
     }
index 8a84689..8d33ee6 100644 (file)
@@ -44,7 +44,7 @@ static StringView extractCharset(const String& value)
 {
     unsigned length = value.length();
     for (size_t pos = 0; pos < length; ) {
-        pos = value.find("charset", pos, false);
+        pos = value.findIgnoringASCIICase("charset", pos);
         if (pos == notFound)
             break;
 
index 93ffa5b..a73ed93 100644 (file)
@@ -715,11 +715,11 @@ bool XSSAuditor::isContainedInRequest(const String& decodedSnippet)
 {
     if (decodedSnippet.isEmpty())
         return false;
-    if (m_decodedURL.find(decodedSnippet, 0, false) != notFound)
+    if (m_decodedURL.containsIgnoringASCIICase(decodedSnippet))
         return true;
     if (m_decodedHTTPBodySuffixTree && !m_decodedHTTPBodySuffixTree->mightContain(decodedSnippet))
         return false;
-    return m_decodedHTTPBody.find(decodedSnippet, 0, false) != notFound;
+    return m_decodedHTTPBody.containsIgnoringASCIICase(decodedSnippet);
 }
 
 bool XSSAuditor::isLikelySafeResource(const String& url)
index ace66e5..518ed8b 100644 (file)
@@ -242,7 +242,7 @@ bool WebVTTParser::hasRequiredFileIdentifier(const String& line)
     // A WebVTT file identifier consists of an optional BOM character,
     // the string "WEBVTT" followed by an optional space or tab character,
     // and any number of characters that are not line terminators ...
-    if (!line.startsWith(fileIdentifier, fileIdentifierLength))
+    if (!line.startsWith(fileIdentifier))
         return false;
     if (line.length() > fileIdentifierLength && !isHTMLSpace(line[fileIdentifierLength]))
         return false;
index 59583a9..f92a5d8 100644 (file)
@@ -110,8 +110,8 @@ bool InspectorNodeFinder::matchesElement(const Element& element)
     String nodeName = element.nodeName();
     if ((!m_startTagFound && !m_endTagFound && nodeName.containsIgnoringASCIICase(m_tagNameQuery))
         || (m_startTagFound && m_endTagFound && equalIgnoringASCIICase(nodeName, m_tagNameQuery))
-        || (m_startTagFound && !m_endTagFound && nodeName.startsWith(m_tagNameQuery, false))
-        || (!m_startTagFound && m_endTagFound && nodeName.endsWith(m_tagNameQuery, false)))
+        || (m_startTagFound && !m_endTagFound && nodeName.startsWithIgnoringASCIICase(m_tagNameQuery))
+        || (!m_startTagFound && m_endTagFound && nodeName.endsWithIgnoringASCIICase(m_tagNameQuery)))
         return true;
 
     if (!element.hasAttributes())
index d7e2e93..d2cd85a 100644 (file)
@@ -1098,7 +1098,7 @@ static Ref<Inspector::Protocol::CSS::CSSSelector> buildObjectForSelectorHelper(c
 
 static Ref<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSSelector>> selectorsFromSource(const CSSRuleSourceData* sourceData, const String& sheetText, const CSSSelectorList& selectorList, Element* element)
 {
-    static NeverDestroyed<JSC::Yarr::RegularExpression> comment("/\\*[^]*?\\*/", TextCaseSensitive, JSC::Yarr::MultilineEnabled);
+    static NeverDestroyed<JSC::Yarr::RegularExpression> comment("/\\*[^]*?\\*/", JSC::Yarr::TextCaseSensitive, JSC::Yarr::MultilineEnabled);
 
     auto result = Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSSelector>::create();
     const CSSSelector* selector = selectorList.first();
index e470016..d0869ef 100644 (file)
@@ -60,6 +60,7 @@
 #include "HTMLElement.h"
 #include "HTMLFrameOwnerElement.h"
 #include "HTMLNames.h"
+#include "HTMLParserIdioms.h"
 #include "HTMLScriptElement.h"
 #include "HTMLStyleElement.h"
 #include "HTMLTemplateElement.h"
@@ -1973,10 +1974,16 @@ RefPtr<Inspector::Protocol::DOM::AccessibilityProperties> InspectorDOMAgent::bui
     return WTFMove(value);
 }
 
+static bool containsOnlyHTMLWhitespace(Node* node)
+{
+    // FIXME: Respect ignoreWhitespace setting from inspector front end?
+    return is<Text>(node) && downcast<Text>(*node).data().isAllSpecialCharacters<isHTMLSpace>();
+}
+
 Node* InspectorDOMAgent::innerFirstChild(Node* node)
 {
     node = node->firstChild();
-    while (isWhitespace(node))
+    while (containsOnlyHTMLWhitespace(node))
         node = node->nextSibling();
     return node;
 }
@@ -1985,7 +1992,7 @@ Node* InspectorDOMAgent::innerNextSibling(Node* node)
 {
     do {
         node = node->nextSibling();
-    } while (isWhitespace(node));
+    } while (containsOnlyHTMLWhitespace(node));
     return node;
 }
 
@@ -1993,18 +2000,15 @@ Node* InspectorDOMAgent::innerPreviousSibling(Node* node)
 {
     do {
         node = node->previousSibling();
-    } while (isWhitespace(node));
+    } while (containsOnlyHTMLWhitespace(node));
     return node;
 }
 
 unsigned InspectorDOMAgent::innerChildNodeCount(Node* node)
 {
     unsigned count = 0;
-    Node* child = innerFirstChild(node);
-    while (child) {
-        count++;
-        child = innerNextSibling(child);
-    }
+    for (Node* child = innerFirstChild(node); child; child = innerNextSibling(child))
+        ++count;
     return count;
 }
 
@@ -2018,13 +2022,6 @@ Node* InspectorDOMAgent::innerParentNode(Node* node)
     return node->parentNode();
 }
 
-bool InspectorDOMAgent::isWhitespace(Node* node)
-{
-    // FIXME: Rename to containsOnlyHTMLSpaces?
-    // FIXME: Respect ignoreWhitespace setting from inspector front end?
-    return is<Text>(node) && downcast<Text>(*node).data().containsOnlyWhitespace();
-}
-
 void InspectorDOMAgent::mainFrameDOMContentLoaded()
 {
     // Re-push document once it is loaded.
@@ -2056,7 +2053,7 @@ void InspectorDOMAgent::didCommitLoad(Document* document)
 
 void InspectorDOMAgent::didInsertDOMNode(Node& node)
 {
-    if (isWhitespace(&node))
+    if (containsOnlyHTMLWhitespace(&node))
         return;
 
     // We could be attaching existing subtree. Forget the bindings.
@@ -2085,7 +2082,7 @@ void InspectorDOMAgent::didInsertDOMNode(Node& node)
 
 void InspectorDOMAgent::didRemoveDOMNode(Node& node)
 {
-    if (isWhitespace(&node))
+    if (containsOnlyHTMLWhitespace(&node))
         return;
 
     ContainerNode* parent = node.parentNode();
index 60eb6c7..0afb285 100644 (file)
@@ -203,7 +203,6 @@ public:
     static Node* innerPreviousSibling(Node*);
     static unsigned innerChildNodeCount(Node*);
     static Node* innerParentNode(Node*);
-    static bool isWhitespace(Node*);
 
     Node* assertNode(ErrorString&, int nodeId);
     Element* assertElement(ErrorString&, int nodeId);
index 7be91be..153e884 100644 (file)
@@ -1285,8 +1285,8 @@ void ApplicationCacheStorage::deleteTables()
     
 bool ApplicationCacheStorage::shouldStoreResourceAsFlatFile(ApplicationCacheResource* resource)
 {
-    return resource->response().mimeType().startsWith("audio/", false) 
-        || resource->response().mimeType().startsWith("video/", false);
+    auto& type = resource->response().mimeType();
+    return startsWithLettersIgnoringASCIICase(type, "audio/") || startsWithLettersIgnoringASCIICase(type, "video/");
 }
     
 bool ApplicationCacheStorage::writeDataToUniqueFileInDirectory(SharedBuffer& data, const String& directory, String& path, const String& fileExtension)
index e08a16b..0c613fa 100644 (file)
@@ -35,7 +35,7 @@ ExceptionOr<String> Base64Utilities::btoa(const String& stringToEncode)
     if (stringToEncode.isNull())
         return String();
 
-    if (!stringToEncode.containsOnlyLatin1())
+    if (!stringToEncode.isAllLatin1())
         return Exception { InvalidCharacterError };
 
     return base64Encode(stringToEncode.latin1());
index 3c4d007..e2e1310 100644 (file)
@@ -328,7 +328,7 @@ static JSC::Yarr::RegularExpression createRegExpForLabels(const Vector<String>&
     // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being
     // the same across calls.  We can't do that.
 
-    static NeverDestroyed<JSC::Yarr::RegularExpression> wordRegExp("\\w", TextCaseSensitive);
+    static NeverDestroyed<JSC::Yarr::RegularExpression> wordRegExp("\\w");
     StringBuilder pattern;
     pattern.append('(');
     unsigned int numLabels = labels.size();
@@ -355,7 +355,7 @@ static JSC::Yarr::RegularExpression createRegExpForLabels(const Vector<String>&
             pattern.appendLiteral("\\b");
     }
     pattern.append(')');
-    return JSC::Yarr::RegularExpression(pattern.toString(), TextCaseInsensitive);
+    return JSC::Yarr::RegularExpression(pattern.toString(), JSC::Yarr::TextCaseInsensitive);
 }
 
 String Frame::searchForLabelsAboveCell(const JSC::Yarr::RegularExpression& regExp, HTMLTableCellElement* cell, size_t* resultDistanceFromStartOfCell)
@@ -459,7 +459,7 @@ static String matchLabelsAgainstString(const Vector<String>& labels, const Strin
     String mutableStringToMatch = stringToMatch;
 
     // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
-    replace(mutableStringToMatch, JSC::Yarr::RegularExpression("\\d", TextCaseSensitive), " ");
+    replace(mutableStringToMatch, JSC::Yarr::RegularExpression("\\d"), " ");
     mutableStringToMatch.replace('_', ' ');
     
     JSC::Yarr::RegularExpression regExp = createRegExpForLabels(labels);
index c0c6977..e4e3525 100644 (file)
@@ -2488,7 +2488,7 @@ static unsigned countRenderedCharactersInRenderObjectWithThreshold(const RenderE
     unsigned count = 0;
     for (const RenderObject* descendant = &renderer; descendant; descendant = descendant->nextInPreOrder()) {
         if (is<RenderText>(*descendant)) {
-            count += downcast<RenderText>(*descendant).text()->length();
+            count += downcast<RenderText>(*descendant).text().length();
             if (count >= threshold)
                 break;
         }
index 53c99c5..9d2e5cc 100644 (file)
@@ -331,14 +331,16 @@ bool SecurityOrigin::canReceiveDragData(const SecurityOrigin& dragInitiator) con
 // This function should be removed as an outcome of https://bugs.webkit.org/show_bug.cgi?id=69196
 static bool isFeedWithNestedProtocolInHTTPFamily(const URL& url)
 {
-    const String& urlString = url.string();
-    if (!urlString.startsWith("feed", false))
+    const String& string = url.string();
+    if (!startsWithLettersIgnoringASCIICase(string, "feed"))
         return false;
-
-    return urlString.startsWith("feed://", false) 
-        || urlString.startsWith("feed:http:", false) || urlString.startsWith("feed:https:", false)
-        || urlString.startsWith("feeds:http:", false) || urlString.startsWith("feeds:https:", false)
-        || urlString.startsWith("feedsearch:http:", false) || urlString.startsWith("feedsearch:https:", false);
+    return startsWithLettersIgnoringASCIICase(string, "feed://")
+        || startsWithLettersIgnoringASCIICase(string, "feed:http:")
+        || startsWithLettersIgnoringASCIICase(string, "feed:https:")
+        || startsWithLettersIgnoringASCIICase(string, "feeds:http:")
+        || startsWithLettersIgnoringASCIICase(string, "feeds:https:")
+        || startsWithLettersIgnoringASCIICase(string, "feedsearch:http:")
+        || startsWithLettersIgnoringASCIICase(string, "feedsearch:https:");
 }
 
 bool SecurityOrigin::canDisplay(const URL& url) const
index 4dab547..e1fdc9b 100644 (file)
@@ -138,7 +138,7 @@ bool UserContentURLPattern::matchesHost(const URL& test) const
         return true;
 
     // Check if the domain is a subdomain of our host.
-    if (!host.endsWith(m_host, false))
+    if (!host.endsWithIgnoringASCIICase(m_host))
         return false;
 
     ASSERT(host.length() > m_host.length());
index 59604c6..7a4333d 100644 (file)
@@ -64,9 +64,7 @@ bool ContentSecurityPolicySource::schemeMatches(const URL& url) const
 bool ContentSecurityPolicySource::hostMatches(const URL& url) const
 {
     const String& host = url.host();
-    if (equalIgnoringASCIICase(host, m_host))
-        return true;
-    return m_hostHasWildcard && host.endsWith("." + m_host, false);
+    return equalIgnoringASCIICase(host, m_host) || (m_hostHasWildcard && host.endsWithIgnoringASCIICase("." + m_host));
 
 }
 
index 920ad12..be6dc88 100644 (file)
@@ -437,10 +437,10 @@ static bool isNonceCharacter(UChar c)
 // nonce-value     = base64-value
 bool ContentSecurityPolicySourceList::parseNonceSource(const UChar* begin, const UChar* end)
 {
-    static NeverDestroyed<String> noncePrefix("'nonce-", String::ConstructFromLiteral);
-    if (!StringView(begin, end - begin).startsWithIgnoringASCIICase(noncePrefix.get()))
+    const unsigned noncePrefixLength = 7;
+    if (!StringView(begin, end - begin).startsWithIgnoringASCIICase("'nonce-"))
         return false;
-    const UChar* position = begin + noncePrefix.get().length();
+    const UChar* position = begin + noncePrefixLength;
     const UChar* beginNonceValue = position;
     skipWhile<UChar, isNonceCharacter>(position, end);
     if (position >= end || position == beginNonceValue || *position != '\'')
index b33e869..584f74b 100644 (file)
@@ -119,7 +119,7 @@ NSArray *Frame::wordsInCurrentParagraph() const
     if (!isStartOfParagraph(end)) {
         VisiblePosition previous = end.previous();
         UChar c(previous.characterAfter());
-        if (!iswpunct(c) && !isSpaceOrNewline(c) && c != 0xA0)
+        if (!iswpunct(c) && !isSpaceOrNewline(c) && c != noBreakSpace)
             end = startOfWord(end);
     }
     VisiblePosition start(startOfParagraph(end));
@@ -140,7 +140,7 @@ NSArray *Frame::wordsInCurrentParagraph() const
         if (length > 1 || !isSpaceOrNewline(text[0])) {
             int startOfWordBoundary = 0;
             for (int i = 1; i < length; i++) {
-                if (isSpaceOrNewline(text[i]) || text[i] == 0xA0) {
+                if (isSpaceOrNewline(text[i]) || text[i] == noBreakSpace) {
                     int wordLength = i - startOfWordBoundary;
                     if (wordLength > 0) {
                         RetainPtr<NSString> chunk = text.substring(startOfWordBoundary, wordLength).createNSString();
@@ -160,7 +160,7 @@ NSArray *Frame::wordsInCurrentParagraph() const
     if ([words count] > 0 && isEndOfParagraph(position) && !isStartOfParagraph(position)) {
         VisiblePosition previous = position.previous();
         UChar c(previous.characterAfter());
-        if (!isSpaceOrNewline(c) && c != 0xA0)
+        if (!isSpaceOrNewline(c) && c != noBreakSpace)
             [words removeLastObject];
     }
 
index 9961cdd..ac75e6f 100644 (file)
@@ -62,7 +62,7 @@ String ContentType::parameter(const String& parameterName) const
     // a MIME type can have one or more "param=value" after a semi-colon, and separated from each other by semi-colons
     size_t semi = strippedType.find(';');
     if (semi != notFound) {
-        size_t start = strippedType.find(parameterName, semi + 1, false);
+        size_t start = strippedType.findIgnoringASCIICase(parameterName, semi + 1);
         if (start != notFound) {
             start = strippedType.find('=', start + parameterName.length());
             if (start != notFound) {
index 5bab1bb..a799e87 100644 (file)
@@ -491,15 +491,15 @@ bool MIMETypeRegistry::isSupportedStyleSheetMIMEType(const String& mimeType)
 
 bool MIMETypeRegistry::isSupportedFontMIMEType(const String& mimeType)
 {
-    static const unsigned fontLen = 5;
-    if (!mimeType.startsWithIgnoringASCIICase("font/"))
+    static const unsigned fontLength = 5;
+    if (!startsWithLettersIgnoringASCIICase(mimeType, "font/"))
         return false;
-    String subType = mimeType.substring(fontLen);
-    return equalLettersIgnoringASCIICase(subType, "woff")
-        || equalLettersIgnoringASCIICase(subType, "woff2")
-        || equalLettersIgnoringASCIICase(subType, "otf")
-        || equalLettersIgnoringASCIICase(subType, "ttf")
-        || equalLettersIgnoringASCIICase(subType, "sfnt");
+    auto subtype = StringView { mimeType }.substring(fontLength);
+    return equalLettersIgnoringASCIICase(subtype, "woff")
+        || equalLettersIgnoringASCIICase(subtype, "woff2")
+        || equalLettersIgnoringASCIICase(subtype, "otf")
+        || equalLettersIgnoringASCIICase(subtype, "ttf")
+        || equalLettersIgnoringASCIICase(subtype, "sfnt");
 }
 
 bool MIMETypeRegistry::isSupportedJSONMIMEType(const String& mimeType)
@@ -511,7 +511,7 @@ bool MIMETypeRegistry::isSupportedJSONMIMEType(const String& mimeType)
         return true;
 
     // When detecting +json ensure there is a non-empty type / subtype preceeding the suffix.
-    if (mimeType.endsWith("+json", false) && mimeType.length() >= 8) {
+    if (mimeType.endsWithIgnoringASCIICase("+json") && mimeType.length() >= 8) {
         size_t slashPosition = mimeType.find('/');
         if (slashPosition != notFound && slashPosition > 0 && slashPosition <= mimeType.length() - 6)
             return true;
@@ -556,13 +556,12 @@ bool MIMETypeRegistry::isTextMIMEType(const String& mimeType)
 {
     return isSupportedJavaScriptMIMEType(mimeType)
         || isSupportedJSONMIMEType(mimeType) // Render JSON as text/plain.
-        || (mimeType.startsWith("text/", false)
+        || (startsWithLettersIgnoringASCIICase(mimeType, "text/")
             && !equalLettersIgnoringASCIICase(mimeType, "text/html")
             && !equalLettersIgnoringASCIICase(mimeType, "text/xml")
             && !equalLettersIgnoringASCIICase(mimeType, "text/xsl"));
 }
 
-
 static inline bool isValidXMLMIMETypeChar(UChar c)
 {
     // Valid characters per RFCs 3023 and 2045: 0-9a-zA-Z_-+~!$^{}|.%'`#&*
@@ -575,7 +574,7 @@ bool MIMETypeRegistry::isXMLMIMEType(const String& mimeType)
     if (equalLettersIgnoringASCIICase(mimeType, "text/xml") || equalLettersIgnoringASCIICase(mimeType, "application/xml") || equalLettersIgnoringASCIICase(mimeType, "text/xsl"))
         return true;
 
-    if (!mimeType.endsWith("+xml", false))
+    if (!mimeType.endsWithIgnoringASCIICase("+xml"))
         return false;
 
     size_t slashPosition = mimeType.find('/');
@@ -599,9 +598,9 @@ bool MIMETypeRegistry::isJavaAppletMIMEType(const String& mimeType)
     // of using a hash set.
     // Any of the MIME types below may be followed by any number of specific versions of the JVM,
     // which is why we use startsWith()
-    return mimeType.startsWith("application/x-java-applet", false)
-        || mimeType.startsWith("application/x-java-bean", false)
-        || mimeType.startsWith("application/x-java-vm", false);
+    return startsWithLettersIgnoringASCIICase(mimeType, "application/x-java-applet")
+        || startsWithLettersIgnoringASCIICase(mimeType, "application/x-java-bean")
+        || startsWithLettersIgnoringASCIICase(mimeType, "application/x-java-vm");
 }
 
 bool MIMETypeRegistry::isPDFOrPostScriptMIMEType(const String& mimeType)
@@ -626,7 +625,7 @@ bool MIMETypeRegistry::canShowMIMEType(const String& mimeType)
     if (isSupportedJavaScriptMIMEType(mimeType) || isSupportedJSONMIMEType(mimeType))
         return true;
 
-    if (mimeType.startsWith("text/", false))
+    if (startsWithLettersIgnoringASCIICase(mimeType, "text/"))
         return !isUnsupportedTextMIMEType(mimeType);
 
     return false;
index 2ed44b0..2f355a9 100644 (file)
@@ -396,7 +396,7 @@ bool URL::setProtocol(const String& s)
     return true;
 }
 
-static bool containsOnlyASCII(StringView string)
+static bool isAllASCII(StringView string)
 {
     if (string.is8Bit())
         return charactersAreAllASCII(string.characters8(), string.length());
@@ -412,7 +412,7 @@ static bool appendEncodedHostname(UCharBuffer& buffer, StringView string)
     // For host names bigger than this, we won't do IDN encoding, which is almost certainly OK.
     const unsigned hostnameBufferLength = 2048;
     
-    if (string.length() > hostnameBufferLength || containsOnlyASCII(string)) {
+    if (string.length() > hostnameBufferLength || isAllASCII(string)) {
         append(buffer, string);
         return true;
     }
index ed56045..6728612 100644 (file)
@@ -2538,19 +2538,10 @@ Vector<LChar, URLParser::defaultInlineBufferSize> URLParser::percentDecode(const
     return output;
 }
 
-ALWAYS_INLINE static bool containsOnlyASCII(const String& string)
-{
-    ASSERT(!string.isNull());
-    if (string.is8Bit())
-        return charactersAreAllASCII(string.characters8(), string.length());
-    return charactersAreAllASCII(string.characters16(), string.length());
-}
-
-template<typename CharacterType>
-std::optional<Vector<LChar, URLParser::defaultInlineBufferSize>> URLParser::domainToASCII(const String& domain, const CodePointIterator<CharacterType>& iteratorForSyntaxViolationPosition)
+template<typename CharacterType> std::optional<Vector<LChar, URLParser::defaultInlineBufferSize>> URLParser::domainToASCII(StringImpl& domain, const CodePointIterator<CharacterType>& iteratorForSyntaxViolationPosition)
 {
     Vector<LChar, defaultInlineBufferSize> ascii;
-    if (containsOnlyASCII(domain)) {
+    if (domain.isAllASCII()) {
         size_t length = domain.length();
         if (domain.is8Bit()) {
             const LChar* characters = domain.characters8();
@@ -2767,7 +2758,7 @@ bool URLParser::parseHostAndPort(CodePointIterator<CharacterType> iterator)
         return false;
     if (domain != StringView(percentDecoded.data(), percentDecoded.size()))
         syntaxViolation(hostBegin);
-    auto asciiDomain = domainToASCII(domain, hostBegin);
+    auto asciiDomain = domainToASCII(*domain.impl(), hostBegin);
     if (!asciiDomain || hasForbiddenHostCodePoint(asciiDomain.value()))
         return false;
     Vector<LChar, defaultInlineBufferSize>& asciiDomainValue = asciiDomain.value();
index 1a53c8c..06d01c1 100644 (file)
@@ -97,7 +97,7 @@ private:
     template<typename UnsignedIntegerType> void appendNumberToASCIIBuffer(UnsignedIntegerType);
     template<bool(*isInCodeSet)(UChar32), typename CharacterType> void utf8PercentEncode(const CodePointIterator<CharacterType>&);
     template<typename CharacterType> void utf8QueryEncode(const CodePointIterator<CharacterType>&);
-    template<typename CharacterType> std::optional<Vector<LChar, defaultInlineBufferSize>> domainToASCII(const String&, const CodePointIterator<CharacterType>& iteratorForSyntaxViolationPosition);
+    template<typename CharacterType> std::optional<Vector<LChar, defaultInlineBufferSize>> domainToASCII(StringImpl&, const CodePointIterator<CharacterType>& iteratorForSyntaxViolationPosition);
     template<typename CharacterType> Vector<LChar, defaultInlineBufferSize> percentDecode(const LChar*, size_t, const CodePointIterator<CharacterType>& iteratorForSyntaxViolationPosition);
     static Vector<LChar, defaultInlineBufferSize> percentDecode(const LChar*, size_t);
     static std::optional<String> formURLDecode(StringView input);
diff --git