void WebEditorClient::checkSpellingOfString(StringView text, int* misspellingLocation, int* misspellingLength) { *misspellingLocation = -1; *misspellingLength = 0; COMPtr<IWebEditingDelegate> ed; if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get()) return; initViewSpecificSpelling(m_webView); ed->checkSpellingOfString(m_webView, text.upconvertedCharacters(), text.length(), misspellingLocation, misspellingLength); }
void WebEditorClient::checkGrammarOfString(StringView text, Vector<GrammarDetail>& details, int* badGrammarLocation, int* badGrammarLength) { details.clear(); *badGrammarLocation = -1; *badGrammarLength = 0; COMPtr<IWebEditingDelegate> ed; if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get()) return; initViewSpecificSpelling(m_webView); COMPtr<IEnumWebGrammarDetails> enumDetailsObj; if (FAILED(ed->checkGrammarOfString(m_webView, text.upconvertedCharacters(), text.length(), &enumDetailsObj, badGrammarLocation, badGrammarLength))) return; while (true) { ULONG fetched; COMPtr<IWebGrammarDetail> detailObj; if (enumDetailsObj->Next(1, &detailObj, &fetched) != S_OK) break; GrammarDetail detail; if (FAILED(detailObj->length(&detail.length))) continue; if (FAILED(detailObj->location(&detail.location))) continue; BString userDesc; if (FAILED(detailObj->userDescription(&userDesc))) continue; detail.userDescription = String(userDesc, SysStringLen(userDesc)); COMPtr<IEnumSpellingGuesses> enumGuessesObj; if (FAILED(detailObj->guesses(&enumGuessesObj))) continue; while (true) { BString guess; if (enumGuessesObj->Next(1, &guess, &fetched) != S_OK) break; detail.guesses.append(String(guess, SysStringLen(guess))); } details.append(detail); } }
CString TextEncoding::encode(StringView text, UnencodableHandling handling) const { if (!m_name) return CString(); if (text.isEmpty()) return ""; // FIXME: What's the right place to do normalization? // It's a little strange to do it inside the encode function. // Perhaps normalization should be an explicit step done before calling encode. auto upconvertedCharacters = text.upconvertedCharacters(); const UChar* source = upconvertedCharacters; size_t sourceLength = text.length(); Vector<UChar> normalizedCharacters; UErrorCode err = U_ZERO_ERROR; if (unorm_quickCheck(source, sourceLength, UNORM_NFC, &err) != UNORM_YES) { // First try using the length of the original string, since normalization to NFC rarely increases length. normalizedCharacters.grow(sourceLength); int32_t normalizedLength = unorm_normalize(source, sourceLength, UNORM_NFC, 0, normalizedCharacters.data(), sourceLength, &err); if (err == U_BUFFER_OVERFLOW_ERROR) { err = U_ZERO_ERROR; normalizedCharacters.resize(normalizedLength); normalizedLength = unorm_normalize(source, sourceLength, UNORM_NFC, 0, normalizedCharacters.data(), normalizedLength, &err); } ASSERT(U_SUCCESS(err)); source = normalizedCharacters.data(); sourceLength = normalizedLength; } return newTextCodec(*this)->encode(source, sourceLength, handling); }
bool parseManifest(const URL& manifestURL, const char* data, int length, Manifest& manifest) { ASSERT(manifest.explicitURLs.isEmpty()); ASSERT(manifest.onlineWhitelistedURLs.isEmpty()); ASSERT(manifest.fallbackURLs.isEmpty()); manifest.allowAllNetworkRequests = false; Mode mode = Explicit; String s = TextResourceDecoder::create("text/cache-manifest", "UTF-8")->decodeAndFlush(data, length); // Look for the magic signature: "^\xFEFF?CACHE MANIFEST[ \t]?" (the BOM is removed by TextResourceDecoder). // Example: "CACHE MANIFEST #comment" is a valid signature. // Example: "CACHE MANIFEST;V2" is not. if (!s.startsWith("CACHE MANIFEST")) return false; StringView manifestAfterSignature = StringView(s).substring(14); // "CACHE MANIFEST" is 14 characters. auto upconvertedCharacters = manifestAfterSignature.upconvertedCharacters(); const UChar* p = upconvertedCharacters; const UChar* end = p + manifestAfterSignature.length(); if (p < end && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r') return false; // Skip to the end of the line. while (p < end && *p != '\r' && *p != '\n') p++; while (1) { // Skip whitespace while (p < end && (*p == '\n' || *p == '\r' || *p == ' ' || *p == '\t')) p++; if (p == end) break; const UChar* lineStart = p; // Find the end of the line while (p < end && *p != '\r' && *p != '\n') p++; // Check if we have a comment if (*lineStart == '#') continue; // Get rid of trailing whitespace const UChar* tmp = p - 1; while (tmp > lineStart && (*tmp == ' ' || *tmp == '\t')) tmp--; String line(lineStart, tmp - lineStart + 1); if (line == "CACHE:") mode = Explicit; else if (line == "FALLBACK:") mode = Fallback; else if (line == "NETWORK:") mode = OnlineWhitelist; else if (line.endsWith(':')) mode = Unknown; else if (mode == Unknown) continue; else if (mode == Explicit || mode == OnlineWhitelist) { auto upconvertedLineCharacters = StringView(line).upconvertedCharacters(); const UChar* p = upconvertedLineCharacters; const UChar* lineEnd = p + line.length(); // Look for whitespace separating the URL from subsequent ignored tokens. while (p < lineEnd && *p != '\t' && *p != ' ') p++; if (mode == OnlineWhitelist && p - upconvertedLineCharacters == 1 && line[0] == '*') { // Wildcard was found. manifest.allowAllNetworkRequests = true; continue; } URL url(manifestURL, line.substring(0, p - upconvertedLineCharacters)); if (!url.isValid()) continue; if (url.hasFragmentIdentifier()) url.removeFragmentIdentifier(); if (!equalIgnoringASCIICase(url.protocol(), manifestURL.protocol())) continue; if (mode == Explicit && manifestURL.protocolIs("https") && !protocolHostAndPortAreEqual(manifestURL, url)) continue; if (mode == Explicit) manifest.explicitURLs.add(url.string()); else manifest.onlineWhitelistedURLs.append(url); } else if (mode == Fallback) { auto upconvertedLineCharacters = StringView(line).upconvertedCharacters(); const UChar* p = upconvertedLineCharacters; const UChar* lineEnd = p + line.length(); // Look for whitespace separating the two URLs while (p < lineEnd && *p != '\t' && *p != ' ') p++; if (p == lineEnd) { // There was no whitespace separating the URLs. continue; } URL namespaceURL(manifestURL, line.substring(0, p - upconvertedLineCharacters)); if (!namespaceURL.isValid()) continue; if (namespaceURL.hasFragmentIdentifier()) namespaceURL.removeFragmentIdentifier(); if (!protocolHostAndPortAreEqual(manifestURL, namespaceURL)) continue; // Skip whitespace separating fallback namespace from URL. while (p < lineEnd && (*p == '\t' || *p == ' ')) p++; // Look for whitespace separating the URL from subsequent ignored tokens. const UChar* fallbackStart = p; while (p < lineEnd && *p != '\t' && *p != ' ') p++; URL fallbackURL(manifestURL, String(fallbackStart, p - fallbackStart)); if (!fallbackURL.isValid()) continue; if (fallbackURL.hasFragmentIdentifier()) fallbackURL.removeFragmentIdentifier(); if (!protocolHostAndPortAreEqual(manifestURL, fallbackURL)) continue; manifest.fallbackURLs.append(std::make_pair(namespaceURL, fallbackURL)); } else ASSERT_NOT_REACHED(); } return true; }