| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/exo/data_source.h" |
| |
| #include "base/posix/eintr_wrapper.h" |
| #include "base/task/post_task.h" |
| #include "components/exo/data_source_delegate.h" |
| #include "components/exo/data_source_observer.h" |
| |
| namespace exo { |
| |
| namespace { |
| constexpr char kTextMimeTypeUtf8[] = "text/plain;charset=utf-8"; |
| |
| std::vector<uint8_t> ReadDataOnWorkerThread(base::ScopedFD fd) { |
| constexpr size_t kChunkSize = 1024; |
| std::vector<uint8_t> bytes; |
| while (true) { |
| uint8_t chunk[kChunkSize]; |
| ssize_t bytes_read = HANDLE_EINTR(read(fd.get(), chunk, kChunkSize)); |
| if (bytes_read > 0) { |
| bytes.insert(bytes.end(), chunk, chunk + bytes_read); |
| continue; |
| } |
| if (!bytes_read) |
| return bytes; |
| if (bytes_read < 0) { |
| PLOG(ERROR) << "Failed to read selection data from clipboard"; |
| return std::vector<uint8_t>(); |
| } |
| } |
| } |
| |
| void CreatePipe(base::ScopedFD* read_pipe, base::ScopedFD* write_pipe) { |
| int raw_pipe[2]; |
| PCHECK(0 == pipe(raw_pipe)); |
| read_pipe->reset(raw_pipe[0]); |
| write_pipe->reset(raw_pipe[1]); |
| } |
| } // namespace |
| |
| ScopedDataSource::ScopedDataSource(DataSource* data_source, |
| DataSourceObserver* observer) |
| : data_source_(data_source), observer_(observer) { |
| data_source_->AddObserver(observer_); |
| } |
| |
| ScopedDataSource::~ScopedDataSource() { |
| data_source_->RemoveObserver(observer_); |
| } |
| |
| DataSource::DataSource(DataSourceDelegate* delegate) |
| : delegate_(delegate), |
| cancelled_(false), |
| read_data_weak_ptr_factory_(this) {} |
| |
| DataSource::~DataSource() { |
| delegate_->OnDataSourceDestroying(this); |
| for (DataSourceObserver& observer : observers_) { |
| observer.OnDataSourceDestroying(this); |
| } |
| } |
| |
| void DataSource::AddObserver(DataSourceObserver* observer) { |
| observers_.AddObserver(observer); |
| } |
| |
| void DataSource::RemoveObserver(DataSourceObserver* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| |
| void DataSource::Offer(const std::string& mime_type) { |
| mime_types_.insert(mime_type); |
| } |
| |
| void DataSource::SetActions(const base::flat_set<DndAction>& dnd_actions) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void DataSource::Cancelled() { |
| cancelled_ = true; |
| read_data_weak_ptr_factory_.InvalidateWeakPtrs(); |
| delegate_->OnCancelled(); |
| } |
| |
| void DataSource::ReadData(ReadDataCallback callback) { |
| // This DataSource does not contain text data. |
| if (!mime_types_.count(kTextMimeTypeUtf8) || cancelled_) |
| return; |
| |
| base::ScopedFD read_fd; |
| base::ScopedFD write_fd; |
| CreatePipe(&read_fd, &write_fd); |
| delegate_->OnSend(kTextMimeTypeUtf8, std::move(write_fd)); |
| |
| base::PostTaskWithTraitsAndReplyWithResult( |
| FROM_HERE, |
| {base::MayBlock(), base::TaskPriority::USER_BLOCKING, |
| base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, |
| base::BindOnce(&ReadDataOnWorkerThread, std::move(read_fd)), |
| base::BindOnce(&DataSource::OnDataRead, |
| read_data_weak_ptr_factory_.GetWeakPtr(), |
| std::move(callback))); |
| } |
| |
| void DataSource::OnDataRead(ReadDataCallback callback, |
| const std::vector<uint8_t>& data) { |
| std::move(callback).Run(data); |
| } |
| |
| } // namespace exo |