Commit 2e3131b8 authored by Jesse Schettler's avatar Jesse Schettler Committed by Commit Bot

scanning: Add scan-to path to ScanSettings

Add the scan-to path as a field to ScanSettings. When the scan-to
dropdown is added, its selected value will be used to populate the
field.

Bug: 1059779
Change-Id: Ia9d7b0075d96bd4aae535c4d81c656598702c8f8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2499220Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarZentaro Kavanagh <zentaro@chromium.org>
Commit-Queue: Jesse Schettler <jschettler@chromium.org>
Cr-Commit-Position: refs/heads/master@{#822524}
parent e87569a5
...@@ -22,13 +22,17 @@ namespace { ...@@ -22,13 +22,17 @@ namespace {
namespace mojo_ipc = scanning::mojom; namespace mojo_ipc = scanning::mojom;
// Path to the user's "My files" folder, relative to the root directory. // Path to the user's "My files" folder.
constexpr char kMyFilesPath[] = "home/chronos/user/MyFiles"; constexpr char kMyFilesPath[] = "/home/chronos/user/MyFiles";
} // namespace } // namespace
ScanService::ScanService(LorgnetteScannerManager* lorgnette_scanner_manager) ScanService::ScanService(LorgnetteScannerManager* lorgnette_scanner_manager,
: lorgnette_scanner_manager_(lorgnette_scanner_manager) { base::FilePath my_files_path,
base::FilePath google_drive_path)
: lorgnette_scanner_manager_(lorgnette_scanner_manager),
my_files_path_(std::move(my_files_path)),
google_drive_path_(std::move(google_drive_path)) {
DCHECK(lorgnette_scanner_manager_); DCHECK(lorgnette_scanner_manager_);
} }
...@@ -57,8 +61,10 @@ void ScanService::Scan(const base::UnguessableToken& scanner_id, ...@@ -57,8 +61,10 @@ void ScanService::Scan(const base::UnguessableToken& scanner_id,
mojo_ipc::ScanSettingsPtr settings, mojo_ipc::ScanSettingsPtr settings,
ScanCallback callback) { ScanCallback callback) {
const std::string scanner_name = GetScannerName(scanner_id); const std::string scanner_name = GetScannerName(scanner_id);
if (scanner_name.empty()) if (scanner_name.empty() || !FilePathSupported(settings->scan_to_path)) {
std::move(callback).Run(false); std::move(callback).Run(false);
return;
}
base::Time::Now().LocalExplode(&start_time_); base::Time::Now().LocalExplode(&start_time_);
save_failed_ = false; save_failed_ = false;
...@@ -66,7 +72,8 @@ void ScanService::Scan(const base::UnguessableToken& scanner_id, ...@@ -66,7 +72,8 @@ void ScanService::Scan(const base::UnguessableToken& scanner_id,
scanner_name, mojo::ConvertTo<lorgnette::ScanSettings>(settings), scanner_name, mojo::ConvertTo<lorgnette::ScanSettings>(settings),
base::NullCallback(), base::NullCallback(),
base::BindRepeating(&ScanService::OnPageReceived, base::BindRepeating(&ScanService::OnPageReceived,
weak_ptr_factory_.GetWeakPtr(), settings->file_type), weak_ptr_factory_.GetWeakPtr(),
settings->scan_to_path, settings->file_type),
base::BindOnce(&ScanService::OnScanCompleted, base::BindOnce(&ScanService::OnScanCompleted,
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
} }
...@@ -76,8 +83,14 @@ void ScanService::BindInterface( ...@@ -76,8 +83,14 @@ void ScanService::BindInterface(
receiver_.Bind(std::move(pending_receiver)); receiver_.Bind(std::move(pending_receiver));
} }
void ScanService::SetRootDirForTesting(const base::FilePath& root_dir) { void ScanService::SetGoogleDrivePathForTesting(
root_dir_ = root_dir; const base::FilePath& google_drive_path) {
google_drive_path_ = google_drive_path;
}
void ScanService::SetMyFilesPathForTesting(
const base::FilePath& my_files_path) {
my_files_path_ = my_files_path;
} }
void ScanService::Shutdown() { void ScanService::Shutdown() {
...@@ -115,7 +128,8 @@ void ScanService::OnScannerCapabilitiesReceived( ...@@ -115,7 +128,8 @@ void ScanService::OnScannerCapabilitiesReceived(
mojo::ConvertTo<mojo_ipc::ScannerCapabilitiesPtr>(capabilities.value())); mojo::ConvertTo<mojo_ipc::ScannerCapabilitiesPtr>(capabilities.value()));
} }
void ScanService::OnPageReceived(const mojo_ipc::FileType file_type, void ScanService::OnPageReceived(const base::FilePath& scan_to_path,
const mojo_ipc::FileType file_type,
std::string scanned_image, std::string scanned_image,
uint32_t page_number) { uint32_t page_number) {
// TODO(jschettler): Add support for converting the scanned image to other // TODO(jschettler): Add support for converting the scanned image to other
...@@ -131,7 +145,7 @@ void ScanService::OnPageReceived(const mojo_ipc::FileType file_type, ...@@ -131,7 +145,7 @@ void ScanService::OnPageReceived(const mojo_ipc::FileType file_type,
"scan_%02d%02d%02d-%02d%02d%02d_%d.png", start_time_.year, "scan_%02d%02d%02d-%02d%02d%02d_%d.png", start_time_.year,
start_time_.month, start_time_.day_of_month, start_time_.hour, start_time_.month, start_time_.day_of_month, start_time_.hour,
start_time_.minute, start_time_.second, page_number + 1); start_time_.minute, start_time_.second, page_number + 1);
const auto file_path = root_dir_.Append(kMyFilesPath).Append(filename); const auto file_path = scan_to_path.Append(filename);
if (!base::WriteFile(file_path, scanned_image)) { if (!base::WriteFile(file_path, scanned_image)) {
LOG(ERROR) << "Failed to save scanned image: " << file_path.value().c_str(); LOG(ERROR) << "Failed to save scanned image: " << file_path.value().c_str();
save_failed_ = true; save_failed_ = true;
...@@ -142,6 +156,20 @@ void ScanService::OnScanCompleted(ScanCallback callback, bool success) { ...@@ -142,6 +156,20 @@ void ScanService::OnScanCompleted(ScanCallback callback, bool success) {
std::move(callback).Run(success && !save_failed_); std::move(callback).Run(success && !save_failed_);
} }
bool ScanService::FilePathSupported(const base::FilePath& file_path) {
// TODO(jschettler): Remove this check once the path is selected by the user.
if (file_path == base::FilePath(kMyFilesPath))
return true;
if (!file_path.ReferencesParent() &&
(file_path == my_files_path_ || my_files_path_.IsParent(file_path) ||
google_drive_path_.IsParent(file_path))) {
return true;
}
return false;
}
std::string ScanService::GetScannerName( std::string ScanService::GetScannerName(
const base::UnguessableToken& scanner_id) { const base::UnguessableToken& scanner_id) {
const auto it = scanner_names_.find(scanner_id); const auto it = scanner_names_.find(scanner_id);
......
...@@ -30,7 +30,9 @@ class LorgnetteScannerManager; ...@@ -30,7 +30,9 @@ class LorgnetteScannerManager;
// scanner capabilities, and perform scans. // scanner capabilities, and perform scans.
class ScanService : public scanning::mojom::ScanService, public KeyedService { class ScanService : public scanning::mojom::ScanService, public KeyedService {
public: public:
explicit ScanService(LorgnetteScannerManager* lorgnette_scanner_manager); ScanService(LorgnetteScannerManager* lorgnette_scanner_manager,
base::FilePath my_files_path,
base::FilePath google_drive_path);
~ScanService() override; ~ScanService() override;
ScanService(const ScanService&) = delete; ScanService(const ScanService&) = delete;
...@@ -48,8 +50,11 @@ class ScanService : public scanning::mojom::ScanService, public KeyedService { ...@@ -48,8 +50,11 @@ class ScanService : public scanning::mojom::ScanService, public KeyedService {
void BindInterface( void BindInterface(
mojo::PendingReceiver<scanning::mojom::ScanService> pending_receiver); mojo::PendingReceiver<scanning::mojom::ScanService> pending_receiver);
// Sets the root directory to use when saving scanned images for tests. // Sets |google_drive_path_| for tests.
void SetRootDirForTesting(const base::FilePath& root_dir); void SetGoogleDrivePathForTesting(const base::FilePath& google_drive_path);
// Sets |my_files_path_| for tests.
void SetMyFilesPathForTesting(const base::FilePath& my_files_path);
private: private:
// KeyedService: // KeyedService:
...@@ -66,15 +71,23 @@ class ScanService : public scanning::mojom::ScanService, public KeyedService { ...@@ -66,15 +71,23 @@ class ScanService : public scanning::mojom::ScanService, public KeyedService {
const base::Optional<lorgnette::ScannerCapabilities>& capabilities); const base::Optional<lorgnette::ScannerCapabilities>& capabilities);
// Processes each |scanned_image| received after calling // Processes each |scanned_image| received after calling
// LorgnetteScannerManager::Scan(). |file_type| specifies the file type to use // LorgnetteScannerManager::Scan(). |scan_to_path| is where images will be
// when saving scanned images. // saved, and |file_type| specifies the file type to use when saving scanned
void OnPageReceived(const scanning::mojom::FileType file_type, // images.
void OnPageReceived(const base::FilePath& scan_to_path,
const scanning::mojom::FileType file_type,
std::string scanned_image, std::string scanned_image,
uint32_t page_number); uint32_t page_number);
// Processes the final result of calling LorgnetteScannerManager::Scan(). // Processes the final result of calling LorgnetteScannerManager::Scan().
void OnScanCompleted(ScanCallback callback, bool success); void OnScanCompleted(ScanCallback callback, bool success);
// TODO(jschettler): Replace this with a generic helper function when one is
// available.
// Determines whether the service supports saving scanned images to
// |file_path|.
bool FilePathSupported(const base::FilePath& file_path);
// Returns the scanner name corresponding to the given |scanner_id| or an // Returns the scanner name corresponding to the given |scanner_id| or an
// empty string if the name cannot be found. // empty string if the name cannot be found.
std::string GetScannerName(const base::UnguessableToken& scanner_id); std::string GetScannerName(const base::UnguessableToken& scanner_id);
...@@ -90,9 +103,10 @@ class ScanService : public scanning::mojom::ScanService, public KeyedService { ...@@ -90,9 +103,10 @@ class ScanService : public scanning::mojom::ScanService, public KeyedService {
// Unowned. Used to get scanner information and perform scans. // Unowned. Used to get scanner information and perform scans.
LorgnetteScannerManager* lorgnette_scanner_manager_; LorgnetteScannerManager* lorgnette_scanner_manager_;
// The root directory where scanned images are saved. Allows tests to set a // The paths to the user's My files and Google Drive directories. Used to
// different root. // determine if a selected file path is supported.
base::FilePath root_dir_ = base::FilePath("/"); base::FilePath my_files_path_;
base::FilePath google_drive_path_;
// Indicates whether there was a failure to save scanned images. // Indicates whether there was a failure to save scanned images.
bool save_failed_; bool save_failed_;
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include "chrome/browser/chromeos/scanning/scan_service_factory.h" #include "chrome/browser/chromeos/scanning/scan_service_factory.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "chrome/browser/chromeos/drive/drive_integration_service.h"
#include "chrome/browser/chromeos/file_manager/path_util.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/chromeos/scanning/lorgnette_scanner_manager_factory.h" #include "chrome/browser/chromeos/scanning/lorgnette_scanner_manager_factory.h"
#include "chrome/browser/chromeos/scanning/scan_service.h" #include "chrome/browser/chromeos/scanning/scan_service.h"
...@@ -45,8 +47,16 @@ KeyedService* ScanServiceFactory::BuildServiceInstanceFor( ...@@ -45,8 +47,16 @@ KeyedService* ScanServiceFactory::BuildServiceInstanceFor(
return nullptr; return nullptr;
} }
auto* integration_service =
drive::DriveIntegrationServiceFactory::FindForProfile(profile);
bool drive_available = integration_service &&
integration_service->is_enabled() &&
integration_service->IsMounted();
return new ScanService( return new ScanService(
LorgnetteScannerManagerFactory::GetForBrowserContext(context)); LorgnetteScannerManagerFactory::GetForBrowserContext(context),
file_manager::util::GetMyFilesFolderForProfile(profile),
drive_available ? integration_service->GetMountPointPath()
: base::FilePath());
} }
bool ScanServiceFactory::ServiceIsCreatedWithBrowserContext() const { bool ScanServiceFactory::ServiceIsCreatedWithBrowserContext() const {
......
...@@ -28,8 +28,8 @@ namespace { ...@@ -28,8 +28,8 @@ namespace {
namespace mojo_ipc = scanning::mojom; namespace mojo_ipc = scanning::mojom;
// Relative path where scanned images are saved, relative to the root directory. // Path to the user's "My files" folder.
constexpr char kMyFilesPath[] = "home/chronos/user/MyFiles"; constexpr char kMyFilesPath[] = "/home/chronos/user/MyFiles";
// Scanner names used for tests. // Scanner names used for tests.
constexpr char kFirstTestScannerName[] = "Test Scanner 1"; constexpr char kFirstTestScannerName[] = "Test Scanner 1";
...@@ -68,17 +68,10 @@ class ScanServiceTest : public testing::Test { ...@@ -68,17 +68,10 @@ class ScanServiceTest : public testing::Test {
void SetUp() override { void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
ASSERT_TRUE(base::CreateDirectory(saved_image_dir()));
scan_service_.SetRootDirForTesting(temp_dir_.GetPath());
scan_service_.BindInterface( scan_service_.BindInterface(
scan_service_remote_.BindNewPipeAndPassReceiver()); scan_service_remote_.BindNewPipeAndPassReceiver());
} }
// Path to the directory that scanned images are saved in.
base::FilePath saved_image_dir() {
return temp_dir_.GetPath().Append(kMyFilesPath);
}
// Gets scanners by calling ScanService::GetScanners() via the mojo::Remote. // Gets scanners by calling ScanService::GetScanners() via the mojo::Remote.
std::vector<mojo_ipc::ScannerPtr> GetScanners() { std::vector<mojo_ipc::ScannerPtr> GetScanners() {
std::vector<mojo_ipc::ScannerPtr> scanners; std::vector<mojo_ipc::ScannerPtr> scanners;
...@@ -109,13 +102,14 @@ class ScanServiceTest : public testing::Test { ...@@ -109,13 +102,14 @@ class ScanServiceTest : public testing::Test {
} }
protected: protected:
base::ScopedTempDir temp_dir_;
FakeLorgnetteScannerManager fake_lorgnette_scanner_manager_; FakeLorgnetteScannerManager fake_lorgnette_scanner_manager_;
ScanService scan_service_{&fake_lorgnette_scanner_manager_, base::FilePath(),
base::FilePath()};
private: private:
base::test::TaskEnvironment task_environment_{ base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME}; base::test::TaskEnvironment::TimeSource::MOCK_TIME};
base::ScopedTempDir temp_dir_;
ScanService scan_service_{&fake_lorgnette_scanner_manager_};
mojo::Remote<mojo_ipc::ScanService> scan_service_remote_; mojo::Remote<mojo_ipc::ScanService> scan_service_remote_;
}; };
...@@ -199,6 +193,24 @@ TEST_F(ScanServiceTest, ScanWithBadScannerId) { ...@@ -199,6 +193,24 @@ TEST_F(ScanServiceTest, ScanWithBadScannerId) {
Scan(base::UnguessableToken::Create(), mojo_ipc::ScanSettings::New())); Scan(base::UnguessableToken::Create(), mojo_ipc::ScanSettings::New()));
} }
// Test that attempting to scan with an unsupported file path fails.
// Specifically, use a file path with directory navigation (e.g. "..") to verify
// it can't be used to save scanned images to an unsupported path.
TEST_F(ScanServiceTest, ScanWithUnsupportedFilePath) {
fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse(
{kFirstTestScannerName});
fake_lorgnette_scanner_manager_.SetScanResponse("TestData");
auto scanners = GetScanners();
ASSERT_EQ(scanners.size(), 1u);
const base::FilePath my_files_path(kMyFilesPath);
scan_service_.SetMyFilesPathForTesting(my_files_path);
mojo_ipc::ScanSettings settings;
settings.scan_to_path = my_files_path.Append("../../../var/log");
settings.file_type = mojo_ipc::FileType::kPng;
EXPECT_FALSE(Scan(scanners[0]->id, settings.Clone()));
}
// Test that a scan can be performed successfully. // Test that a scan can be performed successfully.
TEST_F(ScanServiceTest, Scan) { TEST_F(ScanServiceTest, Scan) {
fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse( fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse(
...@@ -210,14 +222,16 @@ TEST_F(ScanServiceTest, Scan) { ...@@ -210,14 +222,16 @@ TEST_F(ScanServiceTest, Scan) {
base::Time::Exploded scan_time; base::Time::Exploded scan_time;
// Since we're using mock time, this is deterministic. // Since we're using mock time, this is deterministic.
base::Time::Now().LocalExplode(&scan_time); base::Time::Now().LocalExplode(&scan_time);
base::FilePath saved_scan_path = saved_image_dir().Append( base::FilePath saved_scan_path = temp_dir_.GetPath().Append(
base::StringPrintf("scan_%02d%02d%02d-%02d%02d%02d_1.png", scan_time.year, base::StringPrintf("scan_%02d%02d%02d-%02d%02d%02d_1.png", scan_time.year,
scan_time.month, scan_time.day_of_month, scan_time.month, scan_time.day_of_month,
scan_time.hour, scan_time.minute, scan_time.second)); scan_time.hour, scan_time.minute, scan_time.second));
EXPECT_FALSE(base::PathExists(saved_scan_path)); EXPECT_FALSE(base::PathExists(saved_scan_path));
// Saving scanned images is currently only supported for the PNG file type. // Saving scanned images is currently only supported for the PNG file type.
scan_service_.SetMyFilesPathForTesting(temp_dir_.GetPath());
mojo_ipc::ScanSettings settings; mojo_ipc::ScanSettings settings;
settings.scan_to_path = temp_dir_.GetPath();
settings.file_type = mojo_ipc::FileType::kPng; settings.file_type = mojo_ipc::FileType::kPng;
EXPECT_TRUE(Scan(scanners[0]->id, settings.Clone())); EXPECT_TRUE(Scan(scanners[0]->id, settings.Clone()));
EXPECT_TRUE(base::PathExists(saved_scan_path)); EXPECT_TRUE(base::PathExists(saved_scan_path));
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
module chromeos.scanning.mojom; module chromeos.scanning.mojom;
import "mojo/public/mojom/base/file_path.mojom";
import "mojo/public/mojom/base/string16.mojom"; import "mojo/public/mojom/base/string16.mojom";
import "mojo/public/mojom/base/unguessable_token.mojom"; import "mojo/public/mojom/base/unguessable_token.mojom";
...@@ -68,6 +69,8 @@ struct ScannerCapabilities { ...@@ -68,6 +69,8 @@ struct ScannerCapabilities {
struct ScanSettings { struct ScanSettings {
// The SANE name of the ScanSource from which to scan. // The SANE name of the ScanSource from which to scan.
string source_name; string source_name;
// The location to save scanned images to.
mojo_base.mojom.FilePath scan_to_path;
// The file type to use when saving scanned images. // The file type to use when saving scanned images.
FileType file_type; FileType file_type;
// The color mode with which to scan. // The color mode with which to scan.
......
...@@ -6,6 +6,7 @@ import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; ...@@ -6,6 +6,7 @@ import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
import 'chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom-lite.js'; import 'chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom-lite.js';
import 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-lite.js'; import 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-lite.js';
import 'chrome://resources/mojo/mojo/public/mojom/base/unguessable_token.mojom-lite.js'; import 'chrome://resources/mojo/mojo/public/mojom/base/unguessable_token.mojom-lite.js';
import './file_path.mojom-lite.js';
import './color_mode_select.js'; import './color_mode_select.js';
import './file_type_select.js'; import './file_type_select.js';
import './page_size_select.js'; import './page_size_select.js';
...@@ -224,9 +225,11 @@ Polymer({ ...@@ -224,9 +225,11 @@ Polymer({
this.scanButtonDisabled_ = true; this.scanButtonDisabled_ = true;
// TODO(jschettler): Use the selected file type when ScanService supports // TODO(jschettler): Use the selected file type when ScanService supports
// it. Use the selected page size when the corresponding dropdown is added. // it. Use the selected scan-to path when the corresponding dropdown is
// added.
const settings = { const settings = {
'sourceName': this.selectedSource, 'sourceName': this.selectedSource,
'scanToPath': {'path': '/home/chronos/user/MyFiles'},
'fileType': chromeos.scanning.mojom.FileType.kPng, 'fileType': chromeos.scanning.mojom.FileType.kPng,
'colorMode': colorModeFromString(this.selectedColorMode), 'colorMode': colorModeFromString(this.selectedColorMode),
'pageSize': pageSizeFromString(this.selectedPageSize), 'pageSize': pageSizeFromString(this.selectedPageSize),
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
<!-- Privileged app host contents. --> <!-- Privileged app host contents. -->
<include name="IDR_SCANNING_APP_INDEX_HTML" file="index.html" type="BINDATA" /> <include name="IDR_SCANNING_APP_INDEX_HTML" file="index.html" type="BINDATA" />
<include name="IDR_SCANNING_MOJO_LITE_JS" file="${root_gen_dir}/chromeos/components/scanning/mojom/scanning.mojom-lite.js" use_base_dir="false" type="BINDATA" /> <include name="IDR_SCANNING_MOJO_LITE_JS" file="${root_gen_dir}/chromeos/components/scanning/mojom/scanning.mojom-lite.js" use_base_dir="false" type="BINDATA" />
<include name="IDR_SCANNING_APP_FILE_PATH_MOJO_LITE_JS" file="${root_gen_dir}\mojo\public\mojom\base\file_path.mojom-lite.js" use_base_dir="false" type="BINDATA" />
<include name="IDR_SCANNING_APP_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/scanning_app.js" use_base_dir="false" type="BINDATA"/> <include name="IDR_SCANNING_APP_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/scanning_app.js" use_base_dir="false" type="BINDATA"/>
<include name="IDR_SCANNING_APP_SCAN_TO_SELECT_HTML" file="scan_to_select.html" type="BINDATA"/> <include name="IDR_SCANNING_APP_SCAN_TO_SELECT_HTML" file="scan_to_select.html" type="BINDATA"/>
<include name="IDR_SCANNING_APP_SCAN_TO_SELECT_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/scan_to_select.js" use_base_dir="false" type="BINDATA"/> <include name="IDR_SCANNING_APP_SCAN_TO_SELECT_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/scan_to_select.js" use_base_dir="false" type="BINDATA"/>
......
...@@ -92,6 +92,8 @@ ScanningUI::ScanningUI( ...@@ -92,6 +92,8 @@ ScanningUI::ScanningUI(
html_source->AddResourcePath("scanning.mojom-lite.js", html_source->AddResourcePath("scanning.mojom-lite.js",
IDR_SCANNING_MOJO_LITE_JS); IDR_SCANNING_MOJO_LITE_JS);
html_source->AddResourcePath("file_path.mojom-lite.js",
IDR_SCANNING_APP_FILE_PATH_MOJO_LITE_JS);
AddScanningAppStrings(html_source.get()); AddScanningAppStrings(html_source.get());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment