Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/image/decoders/nsIconDecoder.cpp
Line
Count
Source (jump to first uncovered line)
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
nsIconDecoder::nsIconDecoder(RasterImage* aImage)
19
 : Decoder(aImage)
20
 , mLexer(Transition::To(State::HEADER, ICON_HEADER_SIZE),
21
          Transition::TerminateSuccess())
22
 , mBytesPerRow()   // set by ReadHeader()
23
0
{
24
0
  // Nothing to do
25
0
}
26
27
nsIconDecoder::~nsIconDecoder()
28
0
{ }
29
30
LexerResult
31
nsIconDecoder::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
32
0
{
33
0
  MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
34
0
35
0
  return mLexer.Lex(aIterator, aOnResume,
36
0
                    [=](State aState, const char* aData, size_t aLength) {
37
0
    switch (aState) {
38
0
      case State::HEADER:
39
0
        return ReadHeader(aData);
40
0
      case State::ROW_OF_PIXELS:
41
0
        return ReadRowOfPixels(aData, aLength);
42
0
      case State::FINISH:
43
0
        return Finish();
44
0
      default:
45
0
        MOZ_CRASH("Unknown State");
46
0
    }
47
0
  });
48
0
}
49
50
LexerTransition<nsIconDecoder::State>
51
nsIconDecoder::ReadHeader(const char* aData)
52
0
{
53
0
  // Grab the width and height.
54
0
  uint8_t width  = uint8_t(aData[0]);
55
0
  uint8_t height = uint8_t(aData[1]);
56
0
57
0
  // The input is 32bpp, so we expect 4 bytes of data per pixel.
58
0
  mBytesPerRow = width * 4;
59
0
60
0
  // Post our size to the superclass.
61
0
  PostSize(width, height);
62
0
63
0
  // Icons have alpha.
64
0
  PostHasTransparency();
65
0
66
0
  // If we're doing a metadata decode, we're done.
67
0
  if (IsMetadataDecode()) {
68
0
    return Transition::TerminateSuccess();
69
0
  }
70
0
71
0
  MOZ_ASSERT(!mImageData, "Already have a buffer allocated?");
72
0
  Maybe<SurfacePipe> pipe =
73
0
    SurfacePipeFactory::CreateSurfacePipe(this, Size(), OutputSize(),
74
0
                                          FullFrame(), SurfaceFormat::B8G8R8A8,
75
0
                                          /* aAnimParams */ Nothing(),
76
0
                                          SurfacePipeFlags());
77
0
  if (!pipe) {
78
0
    return Transition::TerminateFailure();
79
0
  }
80
0
81
0
  mPipe = std::move(*pipe);
82
0
83
0
  MOZ_ASSERT(mImageData, "Should have a buffer now");
84
0
85
0
  return Transition::To(State::ROW_OF_PIXELS, mBytesPerRow);
86
0
}
87
88
LexerTransition<nsIconDecoder::State>
89
nsIconDecoder::ReadRowOfPixels(const char* aData, size_t aLength)
90
0
{
91
0
  MOZ_ASSERT(aLength % 4 == 0, "Rows should contain a multiple of four bytes");
92
0
93
0
  auto result = mPipe.WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
94
0
    if (aLength == 0) {
95
0
      return AsVariant(WriteState::NEED_MORE_DATA);  // Done with this row.
96
0
    }
97
0
98
0
    uint32_t pixel;
99
0
    memcpy(&pixel, aData, 4);
100
0
    aData += 4;
101
0
    aLength -= 4;
102
0
103
0
    return AsVariant(pixel);
104
0
  });
105
0
106
0
  MOZ_ASSERT(result != WriteState::FAILURE);
107
0
108
0
  Maybe<SurfaceInvalidRect> invalidRect = mPipe.TakeInvalidRect();
109
0
  if (invalidRect) {
110
0
    PostInvalidation(invalidRect->mInputSpaceRect,
111
0
                     Some(invalidRect->mOutputSpaceRect));
112
0
  }
113
0
114
0
  return result == WriteState::FINISHED
115
0
       ? Transition::To(State::FINISH, 0)
116
0
       : Transition::To(State::ROW_OF_PIXELS, mBytesPerRow);
117
0
}
118
119
LexerTransition<nsIconDecoder::State>
120
nsIconDecoder::Finish()
121
0
{
122
0
  PostFrameStop();
123
0
  PostDecodeDone();
124
0
125
0
  return Transition::TerminateSuccess();
126
0
}
127
128
} // namespace image
129
} // namespace mozilla