feat: enable builtin spellchecker (#20692)

* chore: add code required to use chromes spellchecker

* chore: fix linting

* chore: manifests needs buildflags now

* chore: add dictionarySuggestions to the context menu event when the spellchecker is active

* chore: enable by default for windows builds

* chore: add patch to remove incognito usage in the spellchecker

* chore: add dependencies on spellcheck common and flags

* chore: conditionally include spell check panel impl

* chore: fix deps for spellcheck feature flags

* chore: add patch for electron resources

* chore: add dependency on //components/language/core/browser

* chore: patches to make hunspell work on windows

* build: collect hunspell dictionaries into a zip file and publish

* chore: clean up patches

* chore: add docs and set spell checker url method

* chore: fix error handling

* chore: fix hash logic

* build: update hunspell filename generator

* fix: default spellchecker list to the current system locale if we can

* docs: document the language getter

* chore: patch IDS_ resources for linux builds

* feat: add spellcheck webpref flag to disable the builtin spellchecker

* chore: fix docs typo

* chore: clean up spellchecker impl as per feedback

* remove unneeded deps
This commit is contained in:
Samuel Attard 2019-10-31 13:11:51 -07:00 committed by GitHub
parent 23ca7e3733
commit 6bcf67e051
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 560 additions and 10 deletions

View file

@ -319,6 +319,8 @@ step-gn-check: &step-gn-check
gn check out/Default //electron:electron_app gn check out/Default //electron:electron_app
gn check out/Default //electron:manifests gn check out/Default //electron:manifests
gn check out/Default //electron/shell/common/api:mojo gn check out/Default //electron/shell/common/api:mojo
# Check the hunspell filenames
node electron/script/gen-hunspell-filenames.js --check
step-electron-build: &step-electron-build step-electron-build: &step-electron-build
run: run:
@ -534,6 +536,20 @@ step-mksnapshot-store: &step-mksnapshot-store
path: src/out/Default/mksnapshot.zip path: src/out/Default/mksnapshot.zip
destination: mksnapshot.zip destination: mksnapshot.zip
step-hunspell-build: &step-hunspell-build
run:
name: hunspell build
command: |
cd src
if [ "$SKIP_DIST_ZIP" != "1" ]; then
ninja -C out/Default electron:hunspell_dictionaries_zip -j $NUMBER_OF_NINJA_PROCESSES
fi
step-hunspell-store: &step-hunspell-store
store_artifacts:
path: src/out/Default/hunspell_dictionaries.zip
destination: hunspell_dictionaries.zip
step-maybe-generate-breakpad-symbols: &step-maybe-generate-breakpad-symbols step-maybe-generate-breakpad-symbols: &step-maybe-generate-breakpad-symbols
run: run:
name: Generate breakpad symbols name: Generate breakpad symbols
@ -693,7 +709,6 @@ step-minimize-workspace-size-from-checkout: &step-minimize-workspace-size-from-c
rm -rf src/ios rm -rf src/ios
rm -rf src/third_party/blink/web_tests rm -rf src/third_party/blink/web_tests
rm -rf src/third_party/blink/perf_tests rm -rf src/third_party/blink/perf_tests
rm -rf src/third_party/hunspell_dictionaries
rm -rf src/third_party/WebKit/LayoutTests rm -rf src/third_party/WebKit/LayoutTests
# Save the src cache based on the deps hash # Save the src cache based on the deps hash
@ -912,6 +927,10 @@ steps-electron-build: &steps-electron-build
- *step-ffmpeg-build - *step-ffmpeg-build
- *step-ffmpeg-store - *step-ffmpeg-store
# hunspell
- *step-hunspell-build
- *step-hunspell-store
# Save all data needed for a further tests run. # Save all data needed for a further tests run.
- *step-persist-data-for-tests - *step-persist-data-for-tests
@ -990,6 +1009,10 @@ steps-electron-build-with-inline-checkout-for-tests: &steps-electron-build-with-
- *step-ffmpeg-build - *step-ffmpeg-build
- *step-ffmpeg-store - *step-ffmpeg-store
# hunspell
- *step-hunspell-build
- *step-hunspell-store
# Save all data needed for a further tests run. # Save all data needed for a further tests run.
- *step-persist-data-for-tests - *step-persist-data-for-tests
@ -1079,6 +1102,10 @@ steps-electron-build-for-publish: &steps-electron-build-for-publish
- *step-ffmpeg-build - *step-ffmpeg-build
- *step-ffmpeg-store - *step-ffmpeg-store
# hunspell
- *step-hunspell-build
- *step-hunspell-store
# typescript defs # typescript defs
- *step-maybe-generate-typescript-defs - *step-maybe-generate-typescript-defs

View file

@ -1,6 +1,7 @@
import("//build/config/locales.gni") import("//build/config/locales.gni")
import("//build/config/ui.gni") import("//build/config/ui.gni")
import("//build/config/win/manifest.gni") import("//build/config/win/manifest.gni")
import("//components/spellcheck/spellcheck_build_features.gni")
import("//content/public/app/mac_helpers.gni") import("//content/public/app/mac_helpers.gni")
import("//pdf/features.gni") import("//pdf/features.gni")
import("//printing/buildflags/buildflags.gni") import("//printing/buildflags/buildflags.gni")
@ -21,6 +22,7 @@ import("buildflags/buildflags.gni")
import("electron_paks.gni") import("electron_paks.gni")
import("filenames.auto.gni") import("filenames.auto.gni")
import("filenames.gni") import("filenames.gni")
import("filenames.hunspell.gni")
if (is_mac) { if (is_mac) {
import("//build/config/mac/rules.gni") import("//build/config/mac/rules.gni")
@ -358,12 +360,12 @@ source_set("electron_lib") {
"//chrome/app/resources:platform_locale_settings", "//chrome/app/resources:platform_locale_settings",
"//chrome/services/printing/public/mojom", "//chrome/services/printing/public/mojom",
"//components/certificate_transparency", "//components/certificate_transparency",
"//components/language/core/browser",
"//components/net_log", "//components/net_log",
"//components/network_hints/common", "//components/network_hints/common",
"//components/network_hints/renderer", "//components/network_hints/renderer",
"//components/network_session_configurator/common", "//components/network_session_configurator/common",
"//components/prefs", "//components/prefs",
"//components/spellcheck/renderer",
"//components/viz/host", "//components/viz/host",
"//components/viz/service", "//components/viz/service",
"//content/public/browser", "//content/public/browser",
@ -478,6 +480,10 @@ source_set("electron_lib") {
] ]
} }
if (enable_builtin_spellchecker) {
deps += [ "chromium_src:chrome_spellchecker" ]
}
if (is_mac) { if (is_mac) {
deps += [ deps += [
"//components/remote_cocoa/app_shim", "//components/remote_cocoa/app_shim",
@ -1268,9 +1274,14 @@ template("dist_zip") {
"outputs", "outputs",
"testonly", "testonly",
]) ])
flatten = false
if (defined(invoker.flatten)) {
flatten = invoker.flatten
}
args = rebase_path(outputs + [ _runtime_deps_file ], root_build_dir) + [ args = rebase_path(outputs + [ _runtime_deps_file ], root_build_dir) + [
target_cpu, target_cpu,
target_os, target_os,
"$flatten",
] ]
} }
} }
@ -1356,6 +1367,24 @@ dist_zip("electron_mksnapshot_zip") {
] ]
} }
copy("hunspell_dictionaries") {
sources = hunspell_dictionaries + hunspell_licenses
outputs = [
"$target_gen_dir/electron_hunspell/{{source_file_part}}",
]
}
dist_zip("hunspell_dictionaries_zip") {
data_deps = [
":hunspell_dictionaries",
]
flatten = true
outputs = [
"$root_build_dir/hunspell_dictionaries.zip",
]
}
group("electron") { group("electron") {
public_deps = [ public_deps = [
":electron_app", ":electron_app",

View file

@ -91,6 +91,7 @@ build_script:
- ninja -C out/Default electron:electron_dist_zip - ninja -C out/Default electron:electron_dist_zip
- ninja -C out/Default shell_browser_ui_unittests - ninja -C out/Default shell_browser_ui_unittests
- ninja -C out/Default electron:electron_mksnapshot_zip - ninja -C out/Default electron:electron_mksnapshot_zip
- ninja -C out/Default electron:hunspell_dictionaries_zip
- ninja -C out/Default electron:electron_chromedriver_zip - ninja -C out/Default electron:electron_chromedriver_zip
- ninja -C out/Default third_party/electron_node:headers - ninja -C out/Default third_party/electron_node:headers
- appveyor PushArtifact out/Default/dist.zip - appveyor PushArtifact out/Default/dist.zip
@ -100,6 +101,7 @@ build_script:
- 7z a node_headers.zip out\Default\gen\node_headers - 7z a node_headers.zip out\Default\gen\node_headers
- appveyor PushArtifact node_headers.zip - appveyor PushArtifact node_headers.zip
- appveyor PushArtifact out/Default/mksnapshot.zip - appveyor PushArtifact out/Default/mksnapshot.zip
- appveyor PushArtifact out/Default/hunspell_dictionaries.zip
- appveyor PushArtifact out/Default/electron.lib - appveyor PushArtifact out/Default/electron.lib
- ps: >- - ps: >-
if ($env:GN_CONFIG -eq 'release') { if ($env:GN_CONFIG -eq 'release') {

View file

@ -46,13 +46,14 @@ def execute(argv):
raise e raise e
def main(argv): def main(argv):
dist_zip, runtime_deps, target_cpu, target_os = argv dist_zip, runtime_deps, target_cpu, target_os, flatten_val = argv
should_flatten = flatten_val == "true"
dist_files = set() dist_files = set()
with open(runtime_deps) as f: with open(runtime_deps) as f:
for dep in f.readlines(): for dep in f.readlines():
dep = dep.strip() dep = dep.strip()
dist_files.add(dep) dist_files.add(dep)
if sys.platform == 'darwin': if sys.platform == 'darwin' and not should_flatten:
execute(['zip', '-r', '-y', dist_zip] + list(dist_files)) execute(['zip', '-r', '-y', dist_zip] + list(dist_files))
else: else:
with zipfile.ZipFile(dist_zip, 'w', zipfile.ZIP_DEFLATED, allowZip64=True) as z: with zipfile.ZipFile(dist_zip, 'w', zipfile.ZIP_DEFLATED, allowZip64=True) as z:
@ -67,7 +68,7 @@ def main(argv):
basename = os.path.basename(dep) basename = os.path.basename(dep)
dirname = os.path.dirname(dep) dirname = os.path.dirname(dep)
arcname = os.path.join(dirname, 'chrome-sandbox') if basename == 'chrome_sandbox' else dep arcname = os.path.join(dirname, 'chrome-sandbox') if basename == 'chrome_sandbox' else dep
z.write(dep, arcname) z.write(dep, os.path.basename(arcname) if should_flatten else arcname)
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main(sys.argv[1:])) sys.exit(main(sys.argv[1:]))

View file

@ -19,6 +19,7 @@ buildflag_header("buildflags") {
"ENABLE_TTS=$enable_tts", "ENABLE_TTS=$enable_tts",
"ENABLE_COLOR_CHOOSER=$enable_color_chooser", "ENABLE_COLOR_CHOOSER=$enable_color_chooser",
"ENABLE_ELECTRON_EXTENSIONS=$enable_electron_extensions", "ENABLE_ELECTRON_EXTENSIONS=$enable_electron_extensions",
"ENABLE_BUILTIN_SPELLCHECKER=$enable_builtin_spellchecker",
"ENABLE_PICTURE_IN_PICTURE=$enable_picture_in_picture", "ENABLE_PICTURE_IN_PICTURE=$enable_picture_in_picture",
"OVERRIDE_LOCATION_PROVIDER=$enable_fake_location_provider", "OVERRIDE_LOCATION_PROVIDER=$enable_fake_location_provider",
] ]

View file

@ -33,4 +33,7 @@ declare_args() {
# Enable Chrome extensions support. # Enable Chrome extensions support.
enable_electron_extensions = false enable_electron_extensions = false
# Enable Spellchecker support
enable_builtin_spellchecker = true
} }

View file

@ -3,6 +3,7 @@
# found in the LICENSE file. # found in the LICENSE file.
import("//build/config/ui.gni") import("//build/config/ui.gni")
import("//components/spellcheck/spellcheck_build_features.gni")
import("//electron/buildflags/buildflags.gni") import("//electron/buildflags/buildflags.gni")
import("//printing/buildflags/buildflags.gni") import("//printing/buildflags/buildflags.gni")
import("//third_party/widevine/cdm/widevine.gni") import("//third_party/widevine/cdm/widevine.gni")
@ -225,3 +226,52 @@ static_library("chrome") {
] ]
} }
} }
# This source set is just so we don't have to depend on all of //chrome/browser
# You may have to add new files here during the upgrade if //chrome/browser/spellchecker
# gets more files
source_set("chrome_spellchecker") {
sources = [
"//chrome/browser/spellchecker/spell_check_host_chrome_impl.cc",
"//chrome/browser/spellchecker/spell_check_host_chrome_impl.h",
"//chrome/browser/spellchecker/spellcheck_custom_dictionary.cc",
"//chrome/browser/spellchecker/spellcheck_custom_dictionary.h",
"//chrome/browser/spellchecker/spellcheck_factory.cc",
"//chrome/browser/spellchecker/spellcheck_factory.h",
"//chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc",
"//chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h",
"//chrome/browser/spellchecker/spellcheck_language_blacklist_policy_handler.cc",
"//chrome/browser/spellchecker/spellcheck_language_blacklist_policy_handler.h",
"//chrome/browser/spellchecker/spellcheck_language_policy_handler.cc",
"//chrome/browser/spellchecker/spellcheck_language_policy_handler.h",
"//chrome/browser/spellchecker/spellcheck_service.cc",
"//chrome/browser/spellchecker/spellcheck_service.h",
]
if (has_spellcheck_panel) {
sources += [
"//chrome/browser/spellchecker/spell_check_panel_host_impl.cc",
"//chrome/browser/spellchecker/spell_check_panel_host_impl.h",
]
}
if (use_browser_spellchecker) {
sources += [
"//chrome/browser/spellchecker/spelling_request.cc",
"//chrome/browser/spellchecker/spelling_request.h",
]
}
deps = [
"//base:base_static",
"//components/language/core/browser",
"//components/spellcheck:buildflags",
"//components/sync",
]
public_deps = [
"//components/spellcheck/browser",
"//components/spellcheck/common",
"//components/spellcheck/renderer",
]
}

View file

@ -385,6 +385,8 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
* `accessibleTitle` String (optional) - An alternative title string provided only * `accessibleTitle` String (optional) - An alternative title string provided only
to accessibility tools such as screen readers. This string is not directly to accessibility tools such as screen readers. This string is not directly
visible to users. visible to users.
* `spellcheck` Boolean (optional) - Whether to enable the builtin spellchecker.
Default is `true`.
When setting minimum or maximum window size with `minWidth`/`maxWidth`/ When setting minimum or maximum window size with `minWidth`/`maxWidth`/
`minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from `minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from

View file

@ -456,10 +456,38 @@ this session just before normal `preload` scripts run.
Returns `String[]` an array of paths to preload scripts that have been Returns `String[]` an array of paths to preload scripts that have been
registered. registered.
#### `ses.setSpellCheckerLanguages(languages)`
* `languages` String[] - An array of language codes to enable the spellchecker for.
The built in spellchecker does not automatically detect what language a user is typing in. In order for the
spell checker to correctly check their words you must call this API with an array of language codes. You can
get the list of supported language codes with the `ses.availableSpellCheckerLanguages` property.
#### `ses.getSpellCheckerLanguages()`
Returns `String[]` - An array of language codes the spellchecker is enabled for. If this list is empty the spellchecker
will fallback to using `en-US`. By default on launch if this setting is an empty list Electron will try to populate this
setting with the current OS locale. This setting is persisted across restarts.
#### `ses.setSpellCheckerDictionaryDownloadURL(url)`
* `url` String - A base URL for Electron to download hunspell dictionaries from.
By default Electron will download hunspell dictionaries from the Chromium CDN. If you want to override this
behavior you can use this API to point the dictionary downloader at your own hosted version of the hunspell
dictionaries. We publish a `hunspell_dictionaries.zip` file with each release which contains the files you need
to host here.
### Instance Properties ### Instance Properties
The following properties are available on instances of `Session`: The following properties are available on instances of `Session`:
#### `ses.availableSpellCheckerLanguages` _Readonly_
A `String[]` array which consists of all the known available spell checker languages. Providing a language
code to the `setSpellCheckerLanaguages` API that isn't in this array will result in an error.
#### `ses.cookies` _Readonly_ #### `ses.cookies` _Readonly_
A [`Cookies`](cookies.md) object for this session. A [`Cookies`](cookies.md) object for this session.

View file

@ -570,6 +570,9 @@ Returns:
* `titleText` String - Title or alt text of the selection that the context * `titleText` String - Title or alt text of the selection that the context
was invoked on. was invoked on.
* `misspelledWord` String - The misspelled word under the cursor, if any. * `misspelledWord` String - The misspelled word under the cursor, if any.
* `dictionarySuggestions` String[] - An array of suggested words to show the
user to replace the `misspelledWord`. Only available if there is a misspelled
word and spellchecker is enabled.
* `frameCharset` String - The character encoding of the frame on which the * `frameCharset` String - The character encoding of the frame on which the
menu was invoked. menu was invoked.
* `inputFieldType` String - If the context menu was invoked on an input * `inputFieldType` String - If the context menu was invoked on an input

View file

@ -74,6 +74,17 @@ Sets the maximum and minimum layout-based (i.e. non-visual) zoom level.
Sets a provider for spell checking in input fields and text areas. Sets a provider for spell checking in input fields and text areas.
If you want to use this method you must disable the builtin spellchecker when you
construct the window.
```js
const mainWindow = new BrowserWindow({
webPreferences: {
spellcheck: false
}
})
```
The `provider` must be an object that has a `spellCheck` method that accepts The `provider` must be an object that has a `spellCheck` method that accepts
an array of individual words for spellchecking. an array of individual words for spellchecking.
The `spellCheck` function runs asynchronously and calls the `callback` function The `spellCheck` function runs asynchronously and calls the `callback` function

View file

@ -69,4 +69,10 @@
<message name="IDS_PICTURE_IN_PICTURE_PREVIOUS_TRACK_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button invokes previous track action."> <message name="IDS_PICTURE_IN_PICTURE_PREVIOUS_TRACK_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button invokes previous track action.">
Previous track Previous track
</message> </message>
<message name="IDS_SPELLCHECK_DICTIONARY" use_name_for_id="true">
en-US
</message>
<message name="IDS_ACCEPT_LANGUAGES" use_name_for_id="true">
en-US,en
</message>
</grit-part> </grit-part>

60
filenames.hunspell.gni Normal file
View file

@ -0,0 +1,60 @@
hunspell_dictionaries = [
"//third_party/hunspell_dictionaries/af-ZA-3-0.bdic",
"//third_party/hunspell_dictionaries/bg-BG-3-0.bdic",
"//third_party/hunspell_dictionaries/ca-ES-3-0.bdic",
"//third_party/hunspell_dictionaries/cs-CZ-3-0.bdic",
"//third_party/hunspell_dictionaries/cy-GB-1-0.bdic",
"//third_party/hunspell_dictionaries/da-DK-3-0.bdic",
"//third_party/hunspell_dictionaries/de-DE-3-0.bdic",
"//third_party/hunspell_dictionaries/el-GR-3-0.bdic",
"//third_party/hunspell_dictionaries/en-AU-8-0.bdic",
"//third_party/hunspell_dictionaries/en-CA-8-0.bdic",
"//third_party/hunspell_dictionaries/en-GB-8-0.bdic",
"//third_party/hunspell_dictionaries/en-US-8-0.bdic",
"//third_party/hunspell_dictionaries/es-ES-3-0.bdic",
"//third_party/hunspell_dictionaries/et-EE-3-0.bdic",
"//third_party/hunspell_dictionaries/fa-IR-8-0.bdic",
"//third_party/hunspell_dictionaries/fo-FO-3-0.bdic",
"//third_party/hunspell_dictionaries/fr-FR-3-0.bdic",
"//third_party/hunspell_dictionaries/he-IL-3-0.bdic",
"//third_party/hunspell_dictionaries/hi-IN-3-0.bdic",
"//third_party/hunspell_dictionaries/hr-HR-3-0.bdic",
"//third_party/hunspell_dictionaries/hu-HU-3-0.bdic",
"//third_party/hunspell_dictionaries/hy-1-0.bdic",
"//third_party/hunspell_dictionaries/id-ID-3-0.bdic",
"//third_party/hunspell_dictionaries/it-IT-3-0.bdic",
"//third_party/hunspell_dictionaries/ko-3-0.bdic",
"//third_party/hunspell_dictionaries/lt-LT-3-0.bdic",
"//third_party/hunspell_dictionaries/lv-LV-3-0.bdic",
"//third_party/hunspell_dictionaries/nb-NO-3-0.bdic",
"//third_party/hunspell_dictionaries/nl-NL-3-0.bdic",
"//third_party/hunspell_dictionaries/pl-PL-3-0.bdic",
"//third_party/hunspell_dictionaries/pt-BR-3-0.bdic",
"//third_party/hunspell_dictionaries/pt-PT-3-0.bdic",
"//third_party/hunspell_dictionaries/ro-RO-3-0.bdic",
"//third_party/hunspell_dictionaries/ru-RU-3-0.bdic",
"//third_party/hunspell_dictionaries/sh-3-0.bdic",
"//third_party/hunspell_dictionaries/sh-4-0.bdic",
"//third_party/hunspell_dictionaries/sk-SK-3-0.bdic",
"//third_party/hunspell_dictionaries/sl-SI-3-0.bdic",
"//third_party/hunspell_dictionaries/sq-3-0.bdic",
"//third_party/hunspell_dictionaries/sr-3-0.bdic",
"//third_party/hunspell_dictionaries/sr-4-0.bdic",
"//third_party/hunspell_dictionaries/sv-SE-3-0.bdic",
"//third_party/hunspell_dictionaries/ta-IN-3-0.bdic",
"//third_party/hunspell_dictionaries/tg-TG-5-0.bdic",
"//third_party/hunspell_dictionaries/tr-TR-4-0.bdic",
"//third_party/hunspell_dictionaries/uk-UA-3-0.bdic",
"//third_party/hunspell_dictionaries/vi-VN-3-0.bdic",
"//third_party/hunspell_dictionaries/xx-XX-3-0.bdic",
]
hunspell_licenses = [
"//third_party/hunspell_dictionaries/COPYING",
"//third_party/hunspell_dictionaries/COPYING.Apache",
"//third_party/hunspell_dictionaries/COPYING.LESSER",
"//third_party/hunspell_dictionaries/COPYING.LGPL",
"//third_party/hunspell_dictionaries/COPYING.MIT",
"//third_party/hunspell_dictionaries/COPYING.MPL",
"//third_party/hunspell_dictionaries/LICENSE",
]

View file

@ -129,6 +129,9 @@
"node script/gen-filenames.js", "node script/gen-filenames.js",
"python script/check-trailing-whitespace.py --fix", "python script/check-trailing-whitespace.py --fix",
"git add filenames.auto.gni" "git add filenames.auto.gni"
],
"DEPS": [
"node script/gen-hunspell-filenames.js"
] ]
}, },
"dependencies": { "dependencies": {

View file

@ -81,3 +81,5 @@ revert_remove_contentrendererclient_shouldfork.patch
build_win_disable_zc_twophase.patch build_win_disable_zc_twophase.patch
ignore_rc_check.patch ignore_rc_check.patch
build_win_fix_ambiguous_reference_with_msstl.patch build_win_fix_ambiguous_reference_with_msstl.patch
remove_usage_of_incognito_apis_in_the_spellchecker.patch
chore_use_electron_resources_not_chrome_for_spellchecker.patch

View file

@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <sattard@slack-corp.com>
Date: Wed, 23 Oct 2019 14:17:18 -0700
Subject: chore: use electron resources not chrome for spellchecker
spellchecker uses a few IDS_ resources. We need to load these from
Electrons grit header instead of Chromes
diff --git a/chrome/browser/spellchecker/spellcheck_factory.cc b/chrome/browser/spellchecker/spellcheck_factory.cc
index 48ac0a24efde0cb7d3ba71c8b8bdf5178f606e80..e2beefc276098fdc8f1cdab2e0edb8fae4ee67ca 100644
--- a/chrome/browser/spellchecker/spellcheck_factory.cc
+++ b/chrome/browser/spellchecker/spellcheck_factory.cc
@@ -6,7 +6,7 @@
#include "chrome/browser/profiles/incognito_helpers.h"
#include "chrome/browser/spellchecker/spellcheck_service.h"
-#include "chrome/grit/locale_settings.h"
+#include "electron/grit/electron_resources.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
diff --git a/components/language/core/browser/language_prefs.cc b/components/language/core/browser/language_prefs.cc
index d5e4c09e1722232df44b112ce39cdacea03a4710..c6caf7eacd9eed439ab5167e51b9fcce5d6af664 100644
--- a/components/language/core/browser/language_prefs.cc
+++ b/components/language/core/browser/language_prefs.cc
@@ -21,7 +21,7 @@
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
-#include "components/strings/grit/components_locale_settings.h"
+#include "electron/grit/electron_resources.h"
#include "ui/base/l10n/l10n_util.h"
namespace language {

View file

@ -0,0 +1,25 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <sattard@slack-corp.com>
Date: Wed, 23 Oct 2019 11:43:58 -0700
Subject: remove usage of incognito APIs in the spellchecker
chrome::GetBrowserContextRedirectedInIncognito is not available in
Electron nor do we want it to be. We could potentially upstream a
change to move more of //chrome spellchecker logic into //components so
that we can further separate our dependency from //chrome.
diff --git a/chrome/browser/spellchecker/spellcheck_factory.cc b/chrome/browser/spellchecker/spellcheck_factory.cc
index 5253d1f48e188b0339834c876378677b459e718e..48ac0a24efde0cb7d3ba71c8b8bdf5178f606e80 100644
--- a/chrome/browser/spellchecker/spellcheck_factory.cc
+++ b/chrome/browser/spellchecker/spellcheck_factory.cc
@@ -78,7 +78,10 @@ void SpellcheckServiceFactory::RegisterProfilePrefs(
content::BrowserContext* SpellcheckServiceFactory::GetBrowserContextToUse(
content::BrowserContext* context) const {
+ return context;
+#if 0
return chrome::GetBrowserContextRedirectedInIncognito(context);
+#endif
}
bool SpellcheckServiceFactory::ServiceIsNULLWhileTesting() const {

View file

@ -0,0 +1,35 @@
const fs = require('fs')
const path = require('path')
const check = process.argv.includes('--check')
const dictsPath = path.resolve(__dirname, '..', '..', 'third_party', 'hunspell_dictionaries')
const gclientPath = 'third_party/hunspell_dictionaries'
const allFiles = fs.readdirSync(dictsPath)
const dictionaries = allFiles
.filter(file => path.extname(file) === '.bdic')
const licenses = allFiles
.filter(file => file.startsWith('LICENSE') || file.startsWith('COPYING'))
const content = `hunspell_dictionaries = [
${dictionaries.map(f => `"//${path.posix.join(gclientPath, f)}"`).join(',\n ')},
]
hunspell_licenses = [
${licenses.map(f => `"//${path.posix.join(gclientPath, f)}"`).join(',\n ')},
]
`
const filenamesPath = path.resolve(__dirname, '..', 'filenames.hunspell.gni')
if (check) {
const currentContent = fs.readFileSync(filenamesPath, 'utf8')
if (currentContent !== content) {
throw new Error('hunspell filenames need to be regenerated, latest generation does not match current file. Please run node gen-hunspell-filenames.js')
}
} else {
fs.writeFileSync(filenamesPath, content)
}

View file

@ -29,6 +29,7 @@ addAllFiles(path.resolve(__dirname, '../patches'))
// Create Hash // Create Hash
const hasher = crypto.createHash('SHA256') const hasher = crypto.createHash('SHA256')
hasher.update(`HASH_VERSION:${HASH_VERSION}`)
for (const file of filesToHash) { for (const file of filesToHash) {
hasher.update(fs.readFileSync(file)) hasher.update(fs.readFileSync(file))
} }

View file

@ -130,6 +130,7 @@ function assetsForVersion (version, validatingRelease) {
`electron-${version}-win32-arm64.zip`, `electron-${version}-win32-arm64.zip`,
`electron-api.json`, `electron-api.json`,
`electron.d.ts`, `electron.d.ts`,
`hunspell_dictionaries.zip`,
`ffmpeg-${version}-darwin-x64.zip`, `ffmpeg-${version}-darwin-x64.zip`,
`ffmpeg-${version}-linux-arm64.zip`, `ffmpeg-${version}-linux-arm64.zip`,
`ffmpeg-${version}-linux-armv7l.zip`, `ffmpeg-${version}-linux-armv7l.zip`,

View file

@ -106,6 +106,11 @@ def main():
shutil.copy2(os.path.join(OUT_DIR, 'mksnapshot.zip'), mksnapshot_zip) shutil.copy2(os.path.join(OUT_DIR, 'mksnapshot.zip'), mksnapshot_zip)
upload_electron(release, mksnapshot_zip, args) upload_electron(release, mksnapshot_zip, args)
if PLATFORM == 'linux' and get_target_arch() == 'x64':
# Upload the hunspell dictionaries only from the linux x64 build
hunspell_dictionaries_zip = os.path.join(OUT_DIR, 'hunspell_dictionaries.zip')
upload_electron(release, hunspell_dictionaries_zip, args)
if not tag_exists and not args.upload_to_s3: if not tag_exists and not args.upload_to_s3:
# Upload symbols to symbol server. # Upload symbols to symbol server.
run_python_upload_script('upload-symbols.py') run_python_upload_script('upload-symbols.py')

View file

@ -898,9 +898,14 @@ void App::SetPath(gin_helper::ErrorThrower thrower,
bool succeed = false; bool succeed = false;
int key = GetPathConstant(name); int key = GetPathConstant(name);
if (key >= 0) if (key >= 0) {
succeed = succeed =
base::PathService::OverrideAndCreateIfNeeded(key, path, true, false); base::PathService::OverrideAndCreateIfNeeded(key, path, true, false);
if (key == DIR_USER_DATA) {
succeed |= base::PathService::OverrideAndCreateIfNeeded(
chrome::DIR_USER_DATA, path, true, false);
}
}
if (!succeed) if (!succeed)
thrower.ThrowError("Failed to set path"); thrower.ThrowError("Failed to set path");
} }

View file

@ -68,6 +68,12 @@
#include "shell/browser/extensions/atom_extension_system.h" #include "shell/browser/extensions/atom_extension_system.h"
#endif #endif
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
#include "chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h"
#include "components/spellcheck/browser/pref_names.h"
#include "components/spellcheck/common/spellcheck_common.h"
#endif
using content::BrowserThread; using content::BrowserThread;
using content::StoragePartition; using content::StoragePartition;
@ -646,6 +652,42 @@ void Session::Preconnect(const gin_helper::Dictionary& options,
url, num_sockets_to_preconnect)); url, num_sockets_to_preconnect));
} }
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
base::Value Session::GetSpellCheckerLanguages() {
return browser_context_->prefs()
->Get(spellcheck::prefs::kSpellCheckDictionaries)
->Clone();
}
void Session::SetSpellCheckerLanguages(
gin_helper::ErrorThrower thrower,
const std::vector<std::string>& languages) {
base::ListValue language_codes;
for (const std::string& lang : languages) {
std::string code = spellcheck::GetCorrespondingSpellCheckLanguage(lang);
if (code.empty()) {
thrower.ThrowError("Invalid language code provided: \"" + lang +
"\" is not a valid language code");
return;
}
language_codes.AppendString(code);
}
browser_context_->prefs()->Set(spellcheck::prefs::kSpellCheckDictionaries,
language_codes);
}
void SetSpellCheckerDictionaryDownloadURL(gin_helper::ErrorThrower thrower,
const GURL& url) {
if (!url.is_valid()) {
thrower.ThrowError(
"The URL you provided to setSpellCheckerDictionaryDownloadURL is not a "
"valid URL");
return;
}
SpellcheckHunspellDictionary::SetDownloadURLForTesting(url);
}
#endif
// static // static
gin::Handle<Session> Session::CreateFrom(v8::Isolate* isolate, gin::Handle<Session> Session::CreateFrom(v8::Isolate* isolate,
AtomBrowserContext* browser_context) { AtomBrowserContext* browser_context) {
@ -716,6 +758,14 @@ void Session::BuildPrototype(v8::Isolate* isolate,
.SetMethod("getPreloads", &Session::GetPreloads) .SetMethod("getPreloads", &Session::GetPreloads)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
.SetMethod("loadChromeExtension", &Session::LoadChromeExtension) .SetMethod("loadChromeExtension", &Session::LoadChromeExtension)
#endif
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
.SetMethod("getSpellCheckerLanguages", &Session::GetSpellCheckerLanguages)
.SetMethod("setSpellCheckerLanguages", &Session::SetSpellCheckerLanguages)
.SetProperty("availableSpellCheckerLanguages",
&spellcheck::SpellCheckLanguages)
.SetMethod("setSpellCheckerDictionaryDownloadURL",
&SetSpellCheckerDictionaryDownloadURL)
#endif #endif
.SetMethod("preconnect", &Session::Preconnect) .SetMethod("preconnect", &Session::Preconnect)
.SetProperty("cookies", &Session::Cookies) .SetProperty("cookies", &Session::Cookies)

View file

@ -88,6 +88,11 @@ class Session : public gin_helper::TrackableObject<Session>,
v8::Local<v8::Value> NetLog(v8::Isolate* isolate); v8::Local<v8::Value> NetLog(v8::Isolate* isolate);
void Preconnect(const gin_helper::Dictionary& options, void Preconnect(const gin_helper::Dictionary& options,
gin_helper::Arguments* args); gin_helper::Arguments* args);
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
base::Value GetSpellCheckerLanguages();
void SetSpellCheckerLanguages(gin_helper::ErrorThrower thrower,
const std::vector<std::string>& languages);
#endif
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
void LoadChromeExtension(const base::FilePath extension_path); void LoadChromeExtension(const base::FilePath extension_path);

View file

@ -100,6 +100,11 @@
#include "net/ssl/client_cert_store.h" #include "net/ssl/client_cert_store.h"
#endif #endif
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
#include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h" // nogncheck
#include "components/spellcheck/common/spellcheck.mojom.h" // nogncheck
#endif
#if BUILDFLAG(ENABLE_PEPPER_FLASH) #if BUILDFLAG(ENABLE_PEPPER_FLASH)
#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h" #include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
#endif // BUILDFLAG(ENABLE_PEPPER_FLASH) #endif // BUILDFLAG(ENABLE_PEPPER_FLASH)
@ -758,6 +763,18 @@ network::mojom::NetworkContext* AtomBrowserClient::GetSystemNetworkContext() {
return g_browser_process->system_network_context_manager()->GetContext(); return g_browser_process->system_network_context_manager()->GetContext();
} }
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
void AtomBrowserClient::BindHostReceiverForRenderer(
content::RenderProcessHost* render_process_host,
mojo::GenericPendingReceiver receiver) {
if (auto host_receiver = receiver.As<spellcheck::mojom::SpellCheckHost>()) {
SpellCheckHostChromeImpl::Create(render_process_host->GetID(),
std::move(host_receiver));
return;
}
}
#endif
base::Optional<service_manager::Manifest> base::Optional<service_manager::Manifest>
AtomBrowserClient::GetServiceManifestOverlay(base::StringPiece name) { AtomBrowserClient::GetServiceManifestOverlay(base::StringPiece name) {
if (name == content::mojom::kBrowserServiceName) if (name == content::mojom::kBrowserServiceName)

View file

@ -149,6 +149,11 @@ class AtomBrowserClient : public content::ContentBrowserClient,
bool in_memory, bool in_memory,
const base::FilePath& relative_partition_path) override; const base::FilePath& relative_partition_path) override;
network::mojom::NetworkContext* GetSystemNetworkContext() override; network::mojom::NetworkContext* GetSystemNetworkContext() override;
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
void BindHostReceiverForRenderer(
content::RenderProcessHost* render_process_host,
mojo::GenericPendingReceiver receiver) override;
#endif
base::Optional<service_manager::Manifest> GetServiceManifestOverlay( base::Optional<service_manager::Manifest> GetServiceManifestOverlay(
base::StringPiece name) override; base::StringPiece name) override;
content::MediaObserver* GetMediaObserver() override; content::MediaObserver* GetMediaObserver() override;

View file

@ -48,8 +48,6 @@
#include "shell/common/options_switches.h" #include "shell/common/options_switches.h"
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/user_prefs/user_prefs.h"
#include "extensions/browser/browser_context_keyed_service_factories.h" #include "extensions/browser/browser_context_keyed_service_factories.h"
#include "extensions/browser/extension_pref_store.h" #include "extensions/browser/extension_pref_store.h"
#include "extensions/browser/extension_pref_value_map_factory.h" #include "extensions/browser/extension_pref_value_map_factory.h"
@ -63,6 +61,19 @@
#include "shell/common/extensions/atom_extensions_client.h" #include "shell/common/extensions/atom_extensions_client.h"
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) #endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) || \
BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/user_prefs/user_prefs.h"
#endif
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
#include "base/i18n/rtl.h"
#include "components/language/core/browser/language_prefs.h"
#include "components/spellcheck/browser/pref_names.h"
#include "components/spellcheck/common/spellcheck_common.h"
#endif
using content::BrowserThread; using content::BrowserThread;
namespace electron { namespace electron {
@ -102,6 +113,7 @@ AtomBrowserContext::AtomBrowserContext(const std::string& partition,
base::PathService::Get(DIR_APP_DATA, &path_); base::PathService::Get(DIR_APP_DATA, &path_);
path_ = path_.Append(base::FilePath::FromUTF8Unsafe(GetApplicationName())); path_ = path_.Append(base::FilePath::FromUTF8Unsafe(GetApplicationName()));
base::PathService::Override(DIR_USER_DATA, path_); base::PathService::Override(DIR_USER_DATA, path_);
base::PathService::Override(chrome::DIR_USER_DATA, path_);
} }
if (!in_memory && !partition.empty()) if (!in_memory && !partition.empty())
@ -156,7 +168,10 @@ void AtomBrowserContext::InitPrefs() {
ExtensionPrefValueMapFactory::GetForBrowserContext(this), ExtensionPrefValueMapFactory::GetForBrowserContext(this),
IsOffTheRecord()); IsOffTheRecord());
prefs_factory.set_extension_prefs(ext_pref_store); prefs_factory.set_extension_prefs(ext_pref_store);
#endif
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) || \
BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
auto registry = WrapRefCounted(new user_prefs::PrefRegistrySyncable); auto registry = WrapRefCounted(new user_prefs::PrefRegistrySyncable);
#else #else
auto registry = WrapRefCounted(new PrefRegistrySimple); auto registry = WrapRefCounted(new PrefRegistrySimple);
@ -177,13 +192,36 @@ void AtomBrowserContext::InitPrefs() {
extensions::ExtensionPrefs::RegisterProfilePrefs(registry.get()); extensions::ExtensionPrefs::RegisterProfilePrefs(registry.get());
#endif #endif
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
BrowserContextDependencyManager::GetInstance()
->RegisterProfilePrefsForServices(registry.get());
language::LanguagePrefs::RegisterProfilePrefs(registry.get());
#endif
prefs_ = prefs_factory.Create( prefs_ = prefs_factory.Create(
registry.get(), registry.get(),
std::make_unique<PrefStoreDelegate>(weak_factory_.GetWeakPtr())); std::make_unique<PrefStoreDelegate>(weak_factory_.GetWeakPtr()));
prefs_->UpdateCommandLinePrefStore(new ValueMapPrefStore); prefs_->UpdateCommandLinePrefStore(new ValueMapPrefStore);
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) || \
BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
user_prefs::UserPrefs::Set(this, prefs_.get()); user_prefs::UserPrefs::Set(this, prefs_.get());
#endif #endif
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
auto* current_dictionaries =
prefs()->Get(spellcheck::prefs::kSpellCheckDictionaries);
// No configured dictionaries, the default will be en-US
if (current_dictionaries->GetList().size() == 0) {
std::string default_code = spellcheck::GetCorrespondingSpellCheckLanguage(
base::i18n::GetConfiguredLocale());
if (!default_code.empty()) {
base::ListValue language_codes;
language_codes.AppendString(default_code);
prefs()->Set(spellcheck::prefs::kSpellCheckDictionaries, language_codes);
}
}
#endif
} }
void AtomBrowserContext::SetUserAgent(const std::string& user_agent) { void AtomBrowserContext::SetUserAgent(const std::string& user_agent) {

View file

@ -103,6 +103,10 @@
#include "shell/common/extensions/atom_extensions_client.h" #include "shell/common/extensions/atom_extensions_client.h"
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) #endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
#include "chrome/browser/spellchecker/spellcheck_factory.h" // nogncheck
#endif
namespace electron { namespace electron {
namespace { namespace {
@ -442,6 +446,10 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
extensions::electron::EnsureBrowserContextKeyedServiceFactoriesBuilt(); extensions::electron::EnsureBrowserContextKeyedServiceFactoriesBuilt();
#endif #endif
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
SpellcheckServiceFactory::GetInstance();
#endif
// url::Add*Scheme are not threadsafe, this helps prevent data races. // url::Add*Scheme are not threadsafe, this helps prevent data races.
url::LockSchemeRegistries(); url::LockSchemeRegistries();

View file

@ -144,6 +144,9 @@ WebContentsPreferences::WebContentsPreferences(
SetDefaultBoolIfUndefined(options::kScrollBounce, false); SetDefaultBoolIfUndefined(options::kScrollBounce, false);
#endif #endif
SetDefaultBoolIfUndefined(options::kOffscreen, false); SetDefaultBoolIfUndefined(options::kOffscreen, false);
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
SetDefaultBoolIfUndefined(options::kSpellcheck, true);
#endif
// If this is a <webview> tag, and the embedder is offscreen-rendered, then // If this is a <webview> tag, and the embedder is offscreen-rendered, then
// this WebContents is also offscreen-rendered. // this WebContents is also offscreen-rendered.
@ -414,6 +417,12 @@ void WebContentsPreferences::AppendCommandLineSwitches(
if (IsEnabled(options::kNodeIntegrationInSubFrames)) if (IsEnabled(options::kNodeIntegrationInSubFrames))
command_line->AppendSwitch(switches::kNodeIntegrationInSubFrames); command_line->AppendSwitch(switches::kNodeIntegrationInSubFrames);
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
if (IsEnabled(options::kSpellcheck)) {
command_line->AppendSwitch(switches::kEnableSpellcheck);
}
#endif
// We are appending args to a webContents so let's save the current state // We are appending args to a webContents so let's save the current state
// of our preferences object so that during the lifetime of the WebContents // of our preferences object so that during the lifetime of the WebContents
// we can fetch the options used to initally configure the WebContents // we can fetch the options used to initally configure the WebContents

View file

@ -138,6 +138,9 @@ v8::Local<v8::Value> Converter<ContextMenuParamsWithWebContents>::ToV8(
dict.Set("selectionText", params.selection_text); dict.Set("selectionText", params.selection_text);
dict.Set("titleText", params.title_text); dict.Set("titleText", params.title_text);
dict.Set("misspelledWord", params.misspelled_word); dict.Set("misspelledWord", params.misspelled_word);
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
dict.Set("dictionarySuggestions", params.dictionary_suggestions);
#endif
dict.Set("frameCharset", params.frame_charset); dict.Set("frameCharset", params.frame_charset);
dict.Set("inputFieldType", params.input_field_type); dict.Set("inputFieldType", params.input_field_type);
dict.Set("menuSourceType", params.source_type); dict.Set("menuSourceType", params.source_type);

View file

@ -173,6 +173,10 @@ const char kWebGL[] = "webgl";
// navigation. // navigation.
const char kNavigateOnDragDrop[] = "navigateOnDragDrop"; const char kNavigateOnDragDrop[] = "navigateOnDragDrop";
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
const char kSpellcheck[] = "spellcheck";
#endif
#if BUILDFLAG(ENABLE_REMOTE_MODULE) #if BUILDFLAG(ENABLE_REMOTE_MODULE)
const char kEnableRemoteModule[] = "enableRemoteModule"; const char kEnableRemoteModule[] = "enableRemoteModule";
#endif #endif
@ -267,6 +271,10 @@ const char kAuthNegotiateDelegateWhitelist[] =
// If set, include the port in generated Kerberos SPNs. // If set, include the port in generated Kerberos SPNs.
const char kEnableAuthNegotiatePort[] = "enable-auth-negotiate-port"; const char kEnableAuthNegotiatePort[] = "enable-auth-negotiate-port";
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
const char kEnableSpellcheck[] = "enable-spellcheck";
#endif
#if BUILDFLAG(ENABLE_REMOTE_MODULE) #if BUILDFLAG(ENABLE_REMOTE_MODULE)
const char kEnableRemoteModule[] = "enable-remote-module"; const char kEnableRemoteModule[] = "enable-remote-module";
#endif #endif

View file

@ -84,6 +84,10 @@ extern const char kTextAreasAreResizable[];
extern const char kWebGL[]; extern const char kWebGL[];
extern const char kNavigateOnDragDrop[]; extern const char kNavigateOnDragDrop[];
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
extern const char kSpellcheck[];
#endif
#if BUILDFLAG(ENABLE_REMOTE_MODULE) #if BUILDFLAG(ENABLE_REMOTE_MODULE)
extern const char kEnableRemoteModule[]; extern const char kEnableRemoteModule[];
#endif #endif
@ -134,6 +138,10 @@ extern const char kAuthServerWhitelist[];
extern const char kAuthNegotiateDelegateWhitelist[]; extern const char kAuthNegotiateDelegateWhitelist[];
extern const char kEnableAuthNegotiatePort[]; extern const char kEnableAuthNegotiatePort[];
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
extern const char kEnableSpellcheck[];
#endif
#if BUILDFLAG(ENABLE_REMOTE_MODULE) #if BUILDFLAG(ENABLE_REMOTE_MODULE)
extern const char kEnableRemoteModule[]; extern const char kEnableRemoteModule[];
#endif #endif

View file

@ -6,6 +6,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
#include "base/command_line.h" #include "base/command_line.h"
@ -45,6 +46,11 @@
#include <shlobj.h> #include <shlobj.h>
#endif #endif
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
#include "components/spellcheck/renderer/spellcheck.h"
#include "components/spellcheck/renderer/spellcheck_provider.h"
#endif
#if BUILDFLAG(ENABLE_PDF_VIEWER) #if BUILDFLAG(ENABLE_PDF_VIEWER)
#include "shell/common/atom_constants.h" #include "shell/common/atom_constants.h"
#endif // BUILDFLAG(ENABLE_PDF_VIEWER) #endif // BUILDFLAG(ENABLE_PDF_VIEWER)
@ -148,6 +154,11 @@ void RendererClientBase::RenderThreadStarted() {
thread->AddObserver(extensions_renderer_client_->GetDispatcher()); thread->AddObserver(extensions_renderer_client_->GetDispatcher());
#endif #endif
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
if (command_line->HasSwitch(switches::kEnableSpellcheck))
spellcheck_ = std::make_unique<SpellCheck>(&registry_, this);
#endif
blink::WebCustomElement::AddEmbedderCustomElementName("webview"); blink::WebCustomElement::AddEmbedderCustomElementName("webview");
blink::WebCustomElement::AddEmbedderCustomElementName("browserplugin"); blink::WebCustomElement::AddEmbedderCustomElementName("browserplugin");
@ -262,8 +273,37 @@ void RendererClientBase::RenderFrameCreated(
dispatcher->OnRenderFrameCreated(render_frame); dispatcher->OnRenderFrameCreated(render_frame);
#endif #endif
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
auto* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kEnableSpellcheck))
new SpellCheckProvider(render_frame, spellcheck_.get(), this);
#endif
} }
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
void RendererClientBase::BindReceiverOnMainThread(
mojo::GenericPendingReceiver receiver) {
// TODO(crbug.com/977637): Get rid of the use of BinderRegistry here. This is
// only used to bind a spellcheck interface.
std::string interface_name = *receiver.interface_name();
auto pipe = receiver.PassPipe();
registry_.TryBindInterface(interface_name, &pipe);
}
void RendererClientBase::GetInterface(
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) {
// TODO(crbug.com/977637): Get rid of the use of this implementation of
// |service_manager::LocalInterfaceProvider|. This was done only to avoid
// churning spellcheck code while eliminating the "chrome" and
// "chrome_renderer" services. Spellcheck is (and should remain) the only
// consumer of this implementation.
content::RenderThread::Get()->BindHostReceiver(
mojo::GenericPendingReceiver(interface_name, std::move(interface_pipe)));
}
#endif
void RendererClientBase::DidClearWindowObject( void RendererClientBase::DidClearWindowObject(
content::RenderFrame* render_frame) { content::RenderFrame* render_frame) {
// Make sure every page will get a script context created. // Make sure every page will get a script context created.

View file

@ -19,6 +19,13 @@
#include "chrome/renderer/media/chrome_key_systems_provider.h" // nogncheck #include "chrome/renderer/media/chrome_key_systems_provider.h" // nogncheck
#endif #endif
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/local_interface_provider.h"
class SpellCheck;
#endif
namespace network_hints { namespace network_hints {
class PrescientNetworkingDispatcher; class PrescientNetworkingDispatcher;
} }
@ -35,11 +42,24 @@ namespace electron {
class AtomExtensionsRendererClient; class AtomExtensionsRendererClient;
#endif #endif
class RendererClientBase : public content::ContentRendererClient { class RendererClientBase : public content::ContentRendererClient
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
,
public service_manager::LocalInterfaceProvider
#endif
{
public: public:
RendererClientBase(); RendererClientBase();
~RendererClientBase() override; ~RendererClientBase() override;
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
// service_manager::LocalInterfaceProvider implementation.
void GetInterface(const std::string& name,
mojo::ScopedMessagePipeHandle request_handle) override;
void BindReceiverOnMainThread(mojo::GenericPendingReceiver receiver) override;
#endif
virtual void DidCreateScriptContext(v8::Handle<v8::Context> context, virtual void DidCreateScriptContext(v8::Handle<v8::Context> context,
content::RenderFrame* render_frame); content::RenderFrame* render_frame);
virtual void WillReleaseScriptContext(v8::Handle<v8::Context> context, virtual void WillReleaseScriptContext(v8::Handle<v8::Context> context,
@ -108,6 +128,11 @@ class RendererClientBase : public content::ContentRendererClient {
std::string renderer_client_id_; std::string renderer_client_id_;
// An increasing ID used for indentifying an V8 context in this process. // An increasing ID used for indentifying an V8 context in this process.
int64_t next_context_id_ = 0; int64_t next_context_id_ = 0;
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
std::unique_ptr<SpellCheck> spellcheck_;
service_manager::BinderRegistry registry_;
#endif
}; };
} // namespace electron } // namespace electron