blob: 7d91bb871cbad758e8c879f2a1cb87ca31c266ad [file] [log] [blame]
/*
* Copyright 2016 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "cobalt/loader/image/image_data_decoder.h"
#include <algorithm>
#include "base/debug/trace_event.h"
namespace cobalt {
namespace loader {
namespace image {
namespace {
// The capacity of data buffer.
uint32 kMaxBufferSizeBytes = 32 * 1024L;
} // namespace
ImageDataDecoder::ImageDataDecoder(
render_tree::ResourceProvider* resource_provider)
: resource_provider_(resource_provider), state_(kWaitingForHeader) {
CalculatePixelFormat();
}
void ImageDataDecoder::DecodeChunk(const uint8* data, size_t size) {
TRACE_EVENT0("cobalt::loader::image_decoder",
"ImageDataDecoder::DecodeChunk");
size_t offset = 0;
while (offset < size) {
if (state_ == kError) {
// Previous chunk causes an error, so there is nothing to do in here.
return;
}
const uint8* input_bytes;
size_t input_size;
if (data_buffer_.empty()) {
// Nothing in the data_buffer, so no data append needs to be performed.
input_bytes = data + offset;
input_size = size - offset;
offset += input_size;
} else {
size_t fill_buffer_size =
std::min(kMaxBufferSizeBytes - data_buffer_.size(), size - offset);
// Append new data to data_buffer
data_buffer_.insert(
data_buffer_.begin() + static_cast<int64>(data_buffer_.size()),
data + offset, data + offset + fill_buffer_size);
input_bytes = &data_buffer_[0];
input_size = data_buffer_.size();
offset += fill_buffer_size;
}
size_t decoded_size = DecodeChunkInternal(input_bytes, input_size);
size_t undecoded_size = input_size - decoded_size;
if (undecoded_size == 0) {
// Remove all elements from the data_buffer.
data_buffer_.clear();
} else {
data_buffer_.reserve(kMaxBufferSizeBytes);
if (data_buffer_.empty()) {
// data_buffer is empty, so assign the undecoded data to it.
data_buffer_.assign(data + offset - undecoded_size, data + offset);
} else if (decoded_size != 0) {
// data_buffer is not empty, so erase the decoded data from it.
data_buffer_.erase(
data_buffer_.begin(),
data_buffer_.begin() + static_cast<int64>(decoded_size));
}
}
}
}
bool ImageDataDecoder::FinishWithSuccess() {
TRACE_EVENT0("cobalt::loader::image_decoder",
"ImageDataDecoder::FinishWithSuccess");
FinishInternal();
if (state_ != kDone) {
image_data_.reset();
}
return state_ == kDone;
}
void ImageDataDecoder::AllocateImageData(const math::Size& size) {
DCHECK(resource_provider_->AlphaFormatSupported(
render_tree::kAlphaFormatPremultiplied));
image_data_ = resource_provider_->AllocateImageData(
size, pixel_format(), render_tree::kAlphaFormatPremultiplied);
}
void ImageDataDecoder::CalculatePixelFormat() {
pixel_format_ = render_tree::kPixelFormatRGBA8;
if (!resource_provider_->PixelFormatSupported(pixel_format_)) {
pixel_format_ = render_tree::kPixelFormatBGRA8;
}
DCHECK(resource_provider_->PixelFormatSupported(pixel_format_));
}
} // namespace image
} // namespace loader
} // namespace cobalt