blob: b0a78d0b170c7eb6944a770e7bfeee0a33378010 [file] [log] [blame]
msarett3d9d7a72015-10-21 10:27:10 -07001/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkAndroidCodec.h"
9#include "SkCodec.h"
10#include "SkCodecPriv.h"
11#include "SkSampledCodec.h"
12#include "SkWebpAdapterCodec.h"
13
14static bool is_valid_sample_size(int sampleSize) {
15 // FIXME: As Leon has mentioned elsewhere, surely there is also a maximum sampleSize?
16 return sampleSize > 0;
17}
18
19SkAndroidCodec::SkAndroidCodec(const SkImageInfo& info)
20 : fInfo(info)
21{}
22
23SkAndroidCodec* SkAndroidCodec::NewFromStream(SkStream* stream) {
24 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream));
25 if (nullptr == codec) {
26 return nullptr;
27 }
28
29 switch (codec->getEncodedFormat()) {
30 case kWEBP_SkEncodedFormat:
31 return new SkWebpAdapterCodec((SkWebpCodec*) codec.detach());
32 case kPNG_SkEncodedFormat:
33 case kJPEG_SkEncodedFormat:
msarett33c76232015-11-16 13:43:40 -080034 case kWBMP_SkEncodedFormat:
msarett887e18e2015-11-17 08:46:02 -080035 case kBMP_SkEncodedFormat:
msarett3d9d7a72015-10-21 10:27:10 -070036 return new SkSampledCodec(codec.detach());
37 default:
38 // FIXME: SkSampledCodec is temporarily disabled for other formats
39 // while focusing on the formats that are supported by
40 // BitmapRegionDecoder.
41 return nullptr;
42 }
43}
44
45SkAndroidCodec* SkAndroidCodec::NewFromData(SkData* data) {
46 if (!data) {
47 return nullptr;
48 }
49
50 return NewFromStream(new SkMemoryStream(data));
51}
52
53SkISize SkAndroidCodec::getSampledDimensions(int sampleSize) const {
54 if (!is_valid_sample_size(sampleSize)) {
55 return SkISize::Make(0, 0);
56 }
57
scroggo501b7342015-11-03 07:55:11 -080058 // Fast path for when we are not scaling.
59 if (1 == sampleSize) {
60 return fInfo.dimensions();
61 }
62
msarett3d9d7a72015-10-21 10:27:10 -070063 return this->onGetSampledDimensions(sampleSize);
64}
65
66bool SkAndroidCodec::getSupportedSubset(SkIRect* desiredSubset) const {
67 if (!desiredSubset || !is_valid_subset(*desiredSubset, fInfo.dimensions())) {
68 return false;
69 }
70
71 return this->onGetSupportedSubset(desiredSubset);
72}
73
74SkISize SkAndroidCodec::getSampledSubsetDimensions(int sampleSize, const SkIRect& subset) const {
75 if (!is_valid_sample_size(sampleSize)) {
76 return SkISize::Make(0, 0);
77 }
78
79 // We require that the input subset is a subset that is supported by SkAndroidCodec.
80 // We test this by calling getSupportedSubset() and verifying that no modifications
81 // are made to the subset.
82 SkIRect copySubset = subset;
83 if (!this->getSupportedSubset(&copySubset) || copySubset != subset) {
84 return SkISize::Make(0, 0);
85 }
86
scroggo501b7342015-11-03 07:55:11 -080087 // If the subset is the entire image, for consistency, use getSampledDimensions().
msarett3d9d7a72015-10-21 10:27:10 -070088 if (fInfo.dimensions() == subset.size()) {
scroggo501b7342015-11-03 07:55:11 -080089 return this->getSampledDimensions(sampleSize);
msarett3d9d7a72015-10-21 10:27:10 -070090 }
91
92 // This should perhaps call a virtual function, but currently both of our subclasses
93 // want the same implementation.
94 return SkISize::Make(get_scaled_dimension(subset.width(), sampleSize),
95 get_scaled_dimension(subset.height(), sampleSize));
96}
97
98SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels,
scroggoe95a0682015-11-04 04:31:12 -080099 size_t rowBytes, const AndroidOptions* options) {
msarett3d9d7a72015-10-21 10:27:10 -0700100 if (!pixels) {
101 return SkCodec::kInvalidParameters;
102 }
103 if (rowBytes < info.minRowBytes()) {
104 return SkCodec::kInvalidParameters;
105 }
106
107 AndroidOptions defaultOptions;
108 if (!options) {
109 options = &defaultOptions;
110 } else if (options->fSubset) {
111 if (!is_valid_subset(*options->fSubset, fInfo.dimensions())) {
112 return SkCodec::kInvalidParameters;
113 }
scroggo501b7342015-11-03 07:55:11 -0800114
115 if (SkIRect::MakeSize(fInfo.dimensions()) == *options->fSubset) {
116 // The caller wants the whole thing, rather than a subset. Modify
117 // the AndroidOptions passed to onGetAndroidPixels to not specify
118 // a subset.
119 defaultOptions = *options;
120 defaultOptions.fSubset = nullptr;
121 options = &defaultOptions;
122 }
msarett3d9d7a72015-10-21 10:27:10 -0700123 }
124
125 return this->onGetAndroidPixels(info, pixels, rowBytes, *options);
126}
127
128SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels,
129 size_t rowBytes) {
130 return this->getAndroidPixels(info, pixels, rowBytes, nullptr);
131}