Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "nsIconDecoder.h"
8 : #include "RasterImage.h"
9 : #include "SurfacePipeFactory.h"
10 :
11 : using namespace mozilla::gfx;
12 :
13 : namespace mozilla {
14 : namespace image {
15 :
16 : static const uint32_t ICON_HEADER_SIZE = 2;
17 :
18 0 : nsIconDecoder::nsIconDecoder(RasterImage* aImage)
19 : : Decoder(aImage)
20 0 : , mLexer(Transition::To(State::HEADER, ICON_HEADER_SIZE),
21 : Transition::TerminateSuccess())
22 0 : , mBytesPerRow() // set by ReadHeader()
23 : {
24 : // Nothing to do
25 0 : }
26 :
27 0 : nsIconDecoder::~nsIconDecoder()
28 0 : { }
29 :
30 : LexerResult
31 0 : nsIconDecoder::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
32 : {
33 0 : MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
34 :
35 : return mLexer.Lex(aIterator, aOnResume,
36 0 : [=](State aState, const char* aData, size_t aLength) {
37 0 : switch (aState) {
38 : case State::HEADER:
39 0 : return ReadHeader(aData);
40 : case State::ROW_OF_PIXELS:
41 0 : return ReadRowOfPixels(aData, aLength);
42 : case State::FINISH:
43 0 : return Finish();
44 : default:
45 0 : MOZ_CRASH("Unknown State");
46 : }
47 0 : });
48 : }
49 :
50 : LexerTransition<nsIconDecoder::State>
51 0 : nsIconDecoder::ReadHeader(const char* aData)
52 : {
53 : // Grab the width and height.
54 0 : uint8_t width = uint8_t(aData[0]);
55 0 : uint8_t height = uint8_t(aData[1]);
56 :
57 : // The input is 32bpp, so we expect 4 bytes of data per pixel.
58 0 : mBytesPerRow = width * 4;
59 :
60 : // Post our size to the superclass.
61 0 : PostSize(width, height);
62 :
63 : // Icons have alpha.
64 0 : PostHasTransparency();
65 :
66 : // If we're doing a metadata decode, we're done.
67 0 : if (IsMetadataDecode()) {
68 0 : return Transition::TerminateSuccess();
69 : }
70 :
71 0 : MOZ_ASSERT(!mImageData, "Already have a buffer allocated?");
72 : Maybe<SurfacePipe> pipe =
73 0 : SurfacePipeFactory::CreateSurfacePipe(this, 0, Size(), OutputSize(),
74 0 : FullFrame(), SurfaceFormat::B8G8R8A8,
75 0 : SurfacePipeFlags());
76 0 : if (!pipe) {
77 0 : return Transition::TerminateFailure();
78 : }
79 :
80 0 : mPipe = Move(*pipe);
81 :
82 0 : MOZ_ASSERT(mImageData, "Should have a buffer now");
83 :
84 0 : return Transition::To(State::ROW_OF_PIXELS, mBytesPerRow);
85 : }
86 :
87 : LexerTransition<nsIconDecoder::State>
88 0 : nsIconDecoder::ReadRowOfPixels(const char* aData, size_t aLength)
89 : {
90 0 : MOZ_ASSERT(aLength % 4 == 0, "Rows should contain a multiple of four bytes");
91 :
92 0 : auto result = mPipe.WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
93 0 : if (aLength == 0) {
94 0 : return AsVariant(WriteState::NEED_MORE_DATA); // Done with this row.
95 : }
96 :
97 : uint32_t pixel;
98 0 : memcpy(&pixel, aData, 4);
99 0 : aData += 4;
100 0 : aLength -= 4;
101 :
102 0 : return AsVariant(pixel);
103 0 : });
104 :
105 0 : MOZ_ASSERT(result != WriteState::FAILURE);
106 :
107 0 : Maybe<SurfaceInvalidRect> invalidRect = mPipe.TakeInvalidRect();
108 0 : if (invalidRect) {
109 0 : PostInvalidation(invalidRect->mInputSpaceRect,
110 0 : Some(invalidRect->mOutputSpaceRect));
111 : }
112 :
113 : return result == WriteState::FINISHED
114 : ? Transition::To(State::FINISH, 0)
115 0 : : Transition::To(State::ROW_OF_PIXELS, mBytesPerRow);
116 : }
117 :
118 : LexerTransition<nsIconDecoder::State>
119 0 : nsIconDecoder::Finish()
120 : {
121 0 : PostFrameStop();
122 0 : PostDecodeDone();
123 :
124 0 : return Transition::TerminateSuccess();
125 : }
126 :
127 : } // namespace image
128 : } // namespace mozilla
|