summaryrefslogtreecommitdiff
path: root/image/decoders/nsICODecoder.h
blob: 46e1377aad04428894aedfe2e57582dbedc00e5b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#ifndef mozilla_image_decoders_nsICODecoder_h
#define mozilla_image_decoders_nsICODecoder_h

#include "StreamingLexer.h"
#include "Decoder.h"
#include "imgFrame.h"
#include "mozilla/gfx/2D.h"
#include "nsBMPDecoder.h"
#include "nsPNGDecoder.h"
#include "ICOFileHeaders.h"

namespace mozilla {
namespace image {

class RasterImage;

enum class ICOState
{
  HEADER,
  DIR_ENTRY,
  SKIP_TO_RESOURCE,
  FOUND_RESOURCE,
  SNIFF_RESOURCE,
  READ_PNG,
  READ_BIH,
  READ_BMP,
  PREPARE_FOR_MASK,
  READ_MASK_ROW,
  FINISH_MASK,
  SKIP_MASK,
  FINISHED_RESOURCE
};

class nsICODecoder : public Decoder
{
public:
  virtual ~nsICODecoder() { }

  /// @return the width of the icon directory entry @aEntry.
  static uint32_t GetRealWidth(const IconDirEntry& aEntry)
  {
    return aEntry.mWidth == 0 ? 256 : aEntry.mWidth;
  }

  /// @return the width of the selected directory entry (mDirEntry).
  uint32_t GetRealWidth() const { return GetRealWidth(mDirEntry); }

  /// @return the height of the icon directory entry @aEntry.
  static uint32_t GetRealHeight(const IconDirEntry& aEntry)
  {
    return aEntry.mHeight == 0 ? 256 : aEntry.mHeight;
  }

  /// @return the height of the selected directory entry (mDirEntry).
  uint32_t GetRealHeight() const { return GetRealHeight(mDirEntry); }

  /// @return the size of the selected directory entry (mDirEntry).
  gfx::IntSize GetRealSize() const
  {
    return gfx::IntSize(GetRealWidth(), GetRealHeight());
  }

  /// @return The offset from the beginning of the ICO to the first resource.
  size_t FirstResourceOffset() const;

  LexerResult DoDecode(SourceBufferIterator& aIterator,
                       IResumable* aOnResume) override;
  nsresult FinishInternal() override;
  nsresult FinishWithErrorInternal() override;

private:
  friend class DecoderFactory;

  // Decoders should only be instantiated via DecoderFactory.
  explicit nsICODecoder(RasterImage* aImage);

  // Writes to the contained decoder and sets the appropriate errors
  // Returns true if there are no errors.
  bool WriteToContainedDecoder(const char* aBuffer, uint32_t aCount);

  // Gets decoder state from the contained decoder so it's visible externally.
  nsresult GetFinalStateFromContainedDecoder();

  /**
   * Verifies that the width and height values in @aBIH are valid and match the
   * values we read from the ICO directory entry. If everything looks OK, the
   * height value in @aBIH is updated to compensate for the AND mask, which the
   * underlying BMP decoder doesn't know about.
   *
   * @return true if the width and height values in @aBIH are valid and correct.
   */
  bool CheckAndFixBitmapSize(int8_t* aBIH);

  // Obtains the number of colors from the BPP, mBPP must be filled in
  uint16_t GetNumColors();

  LexerTransition<ICOState> ReadHeader(const char* aData);
  LexerTransition<ICOState> ReadDirEntry(const char* aData);
  LexerTransition<ICOState> SniffResource(const char* aData);
  LexerTransition<ICOState> ReadPNG(const char* aData, uint32_t aLen);
  LexerTransition<ICOState> ReadBIH(const char* aData);
  LexerTransition<ICOState> ReadBMP(const char* aData, uint32_t aLen);
  LexerTransition<ICOState> PrepareForMask();
  LexerTransition<ICOState> ReadMaskRow(const char* aData);
  LexerTransition<ICOState> FinishMask();
  LexerTransition<ICOState> FinishResource();

  StreamingLexer<ICOState, 32> mLexer; // The lexer.
  RefPtr<Decoder> mContainedDecoder; // Either a BMP or PNG decoder.
  RefPtr<SourceBuffer> mContainedSourceBuffer;  // SourceBuffer for mContainedDecoder.
  UniquePtr<uint8_t[]> mMaskBuffer;    // A temporary buffer for the alpha mask.
  char mBIHraw[bmp::InfoHeaderLength::WIN_ICO]; // The bitmap information header.
  IconDirEntry mDirEntry;              // The dir entry for the selected resource.
  gfx::IntSize mBiggestResourceSize;   // Used to select the intrinsic size.
  gfx::IntSize mBiggestResourceHotSpot; // Used to select the intrinsic size.
  uint16_t mBiggestResourceColorDepth; // Used to select the intrinsic size.
  int32_t mBestResourceDelta;          // Used to select the best resource.
  uint16_t mBestResourceColorDepth;    // Used to select the best resource.
  uint16_t mNumIcons; // Stores the number of icons in the ICO file.
  uint16_t mCurrIcon; // Stores the current dir entry index we are processing.
  uint16_t mBPP;      // The BPP of the resource we're decoding.
  uint32_t mMaskRowSize;  // The size in bytes of each row in the BMP alpha mask.
  uint32_t mCurrMaskLine; // The line of the BMP alpha mask we're processing.
  bool mIsCursor;         // Is this ICO a cursor?
  bool mHasMaskAlpha;     // Did the BMP alpha mask have any transparency?
};

} // namespace image
} // namespace mozilla

#endif // mozilla_image_decoders_nsICODecoder_h