blob: 9a955ec9b732e3da26eac60958ff988562a545aa [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:
msarett3d9d7a72015-10-21 10:27:10 -070035 return new SkSampledCodec(codec.detach());
36 default:
37 // FIXME: SkSampledCodec is temporarily disabled for other formats
38 // while focusing on the formats that are supported by
39 // BitmapRegionDecoder.
40 return nullptr;
41 }
42}
43
44SkAndroidCodec* SkAndroidCodec::NewFromData(SkData* data) {
45 if (!data) {
46 return nullptr;
47 }
48
49 return NewFromStream(new SkMemoryStream(data));
50}
51
52SkISize SkAndroidCodec::getSampledDimensions(int sampleSize) const {
53 if (!is_valid_sample_size(sampleSize)) {
54 return SkISize::Make(0, 0);
55 }
56
scroggo501b7342015-11-03 07:55:11 -080057 // Fast path for when we are not scaling.
58 if (1 == sampleSize) {
59 return fInfo.dimensions();
60 }
61
msarett3d9d7a72015-10-21 10:27:10 -070062 return this->onGetSampledDimensions(sampleSize);
63}
64
65bool SkAndroidCodec::getSupportedSubset(SkIRect* desiredSubset) const {
66 if (!desiredSubset || !is_valid_subset(*desiredSubset, fInfo.dimensions())) {
67 return false;
68 }
69
70 return this->onGetSupportedSubset(desiredSubset);
71}
72
73SkISize SkAndroidCodec::getSampledSubsetDimensions(int sampleSize, const SkIRect& subset) const {
74 if (!is_valid_sample_size(sampleSize)) {
75 return SkISize::Make(0, 0);
76 }
77
78 // We require that the input subset is a subset that is supported by SkAndroidCodec.
79 // We test this by calling getSupportedSubset() and verifying that no modifications
80 // are made to the subset.
81 SkIRect copySubset = subset;
82 if (!this->getSupportedSubset(&copySubset) || copySubset != subset) {
83 return SkISize::Make(0, 0);
84 }
85
scroggo501b7342015-11-03 07:55:11 -080086 // If the subset is the entire image, for consistency, use getSampledDimensions().
msarett3d9d7a72015-10-21 10:27:10 -070087 if (fInfo.dimensions() == subset.size()) {
scroggo501b7342015-11-03 07:55:11 -080088 return this->getSampledDimensions(sampleSize);
msarett3d9d7a72015-10-21 10:27:10 -070089 }
90
91 // This should perhaps call a virtual function, but currently both of our subclasses
92 // want the same implementation.
93 return SkISize::Make(get_scaled_dimension(subset.width(), sampleSize),
94 get_scaled_dimension(subset.height(), sampleSize));
95}
96
97SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels,
scroggoe95a0682015-11-04 04:31:12 -080098 size_t rowBytes, const AndroidOptions* options) {
msarett3d9d7a72015-10-21 10:27:10 -070099 if (!pixels) {
100 return SkCodec::kInvalidParameters;
101 }
102 if (rowBytes < info.minRowBytes()) {
103 return SkCodec::kInvalidParameters;
104 }
105
106 AndroidOptions defaultOptions;
107 if (!options) {
108 options = &defaultOptions;
109 } else if (options->fSubset) {
110 if (!is_valid_subset(*options->fSubset, fInfo.dimensions())) {
111 return SkCodec::kInvalidParameters;
112 }
scroggo501b7342015-11-03 07:55:11 -0800113
114 if (SkIRect::MakeSize(fInfo.dimensions()) == *options->fSubset) {
115 // The caller wants the whole thing, rather than a subset. Modify
116 // the AndroidOptions passed to onGetAndroidPixels to not specify
117 // a subset.
118 defaultOptions = *options;
119 defaultOptions.fSubset = nullptr;
120 options = &defaultOptions;
121 }
msarett3d9d7a72015-10-21 10:27:10 -0700122 }
123
124 return this->onGetAndroidPixels(info, pixels, rowBytes, *options);
125}
126
127SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels,
128 size_t rowBytes) {
129 return this->getAndroidPixels(info, pixels, rowBytes, nullptr);
130}