DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (b6d82b1a6b02)

VCS Links

Line Code
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 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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_nsBMPDecoder_h
#define mozilla_image_decoders_nsBMPDecoder_h

#include "BMPHeaders.h"
#include "Decoder.h"
#include "gfxColor.h"
#include "StreamingLexer.h"
#include "mozilla/UniquePtr.h"

namespace mozilla {
namespace image {

namespace bmp {

/// This struct contains the fields from the file header and info header that
/// we use during decoding. (Excluding bitfields fields, which are kept in
/// BitFields.)
struct Header {
  uint32_t mDataOffset;   // Offset to raster data.
  uint32_t mBIHSize;      // Header size.
  int32_t mWidth;         // Image width.
  int32_t mHeight;        // Image height.
  uint16_t mBpp;          // Bits per pixel.
  uint32_t mCompression;  // See struct Compression for valid values.
  uint32_t mImageSize;    // (compressed) image size. Can be 0 if
                          // mCompression==0.
  uint32_t mNumColors;    // Used colors.

  Header()
      : mDataOffset(0),
        mBIHSize(0),
        mWidth(0),
        mHeight(0),
        mBpp(0),
        mCompression(0),
        mImageSize(0),
        mNumColors(0) {}
};

/// An entry in the color table.
struct ColorTableEntry {
  uint8_t mRed;
  uint8_t mGreen;
  uint8_t mBlue;
};

/// All the color-related bitfields for 16bpp and 32bpp images. We use this
/// even for older format BMPs that don't have explicit bitfields.
class BitFields {
  class Value {
    friend class BitFields;

    uint32_t mMask;       // The mask for the value.
    uint8_t mRightShift;  // The amount to right-shift after masking.
    uint8_t mBitWidth;    // The width (in bits) of the value.

    /// Sets the mask (and thus the right-shift and bit-width as well).
    void Set(uint32_t aMask);

   public:
    Value() {
      mMask = 0;
      mRightShift = 0;
      mBitWidth = 0;
    }

    /// Returns true if this channel is used. Only used for alpha.
    bool IsPresent() const { return mMask != 0x0; }

    /// Extracts the single color value from the multi-color value.
    uint8_t Get(uint32_t aVal) const;

    /// Like Get(), but specially for alpha.
    uint8_t GetAlpha(uint32_t aVal, bool& aHasAlphaOut) const;

    /// Specialized versions of Get() for when the bit-width is 5 or 8.
    /// (They will assert if called and the bit-width is not 5 or 8.)
    uint8_t Get5(uint32_t aVal) const;
    uint8_t Get8(uint32_t aVal) const;
  };

 public:
  /// The individual color channels.
  Value mRed;
  Value mGreen;
  Value mBlue;
  Value mAlpha;

  /// Set bitfields to the standard 5-5-5 16bpp values.
  void SetR5G5B5();

  /// Set bitfields to the standard 8-8-8 32bpp values.
  void SetR8G8B8();

  /// Test if bitfields have the standard 5-5-5 16bpp values.
  bool IsR5G5B5() const;

  /// Test if bitfields have the standard 8-8-8 32bpp values.
  bool IsR8G8B8() const;

  /// Read the bitfields from a header. The reading of the alpha mask is
  /// optional.
  void ReadFromHeader(const char* aData, bool aReadAlpha);

  /// Length of the bitfields structure in the BMP file.
  static const size_t LENGTH = 12;
};

}  // namespace bmp

class RasterImage;

/// Decoder for BMP-Files, as used by Windows and OS/2.

class nsBMPDecoder : public Decoder {
 public:
  ~nsBMPDecoder();

  DecoderType GetType() const override { return DecoderType::BMP; }

  /// @return true if this BMP is a valid ICO resource.
  bool IsValidICOResource() const override { return true; }

  /// Obtains the internal output image buffer.
  uint32_t* GetImageData() { return reinterpret_cast<uint32_t*>(mImageData); }

  /// Obtains the length of the internal output image buffer.
  size_t GetImageDataLength() const { return mImageDataLength; }

  /// Obtains the size of the compressed image resource.
  int32_t GetCompressedImageSize() const;

  /// Mark this BMP as being within an ICO file. Only used for testing purposes
  /// because the ICO-specific constructor does this marking automatically.
  void SetIsWithinICO() { mIsWithinICO = true; }

  /// Did the BMP file have alpha data of any kind? (Only use this after the
  /// bitmap has been fully decoded.)
  bool HasTransparency() const { return mDoesHaveTransparency; }

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

 private:
  friend class DecoderFactory;

  enum class State {
    FILE_HEADER,
    INFO_HEADER_SIZE,
    INFO_HEADER_REST,
    BITFIELDS,
    COLOR_TABLE,
    GAP,
    AFTER_GAP,
    PIXEL_ROW,
    RLE_SEGMENT,
    RLE_DELTA,
    RLE_ABSOLUTE
  };

  // This is the constructor used for normal and clipboard BMP images.
  explicit nsBMPDecoder(RasterImage* aImage, bool aForClipboard = false);

  // This is the constructor used for BMP resources in ICO images.
  nsBMPDecoder(RasterImage* aImage, uint32_t aDataOffset);

  // Helper constructor called by the other two.
  nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength,
               bool aForClipboard);

  int32_t AbsoluteHeight() const { return abs(mH.mHeight); }

  uint32_t* RowBuffer();

  void FinishRow();

  LexerTransition<State> ReadFileHeader(const char* aData, size_t aLength);
  LexerTransition<State> ReadInfoHeaderSize(const char* aData, size_t aLength);
  LexerTransition<State> ReadInfoHeaderRest(const char* aData, size_t aLength);
  LexerTransition<State> ReadBitfields(const char* aData, size_t aLength);
  LexerTransition<State> ReadColorTable(const char* aData, size_t aLength);
  LexerTransition<State> SkipGap();
  LexerTransition<State> AfterGap();
  LexerTransition<State> ReadPixelRow(const char* aData);
  LexerTransition<State> ReadRLESegment(const char* aData);
  LexerTransition<State> ReadRLEDelta(const char* aData);
  LexerTransition<State> ReadRLEAbsolute(const char* aData, size_t aLength);

  StreamingLexer<State> mLexer;

  bmp::Header mH;

  // If the BMP is within an ICO file our treatment of it differs slightly.
  bool mIsWithinICO;

  // If the BMP decoded from the clipboard, we don't start with a data offset.
  bool mIsForClipboard;

  bmp::BitFields mBitFields;

  // Might the image have transparency? Determined from the headers during
  // metadata decode. (Does not guarantee the image actually has transparency.)
  bool mMayHaveTransparency;

  // Does the image have transparency? Determined during full decoding, so only
  // use this after that has been completed.
  bool mDoesHaveTransparency;

  uint32_t mNumColors;  // The number of used colors, i.e. the number of
                        // entries in mColors, if it's present.
  UniquePtr<bmp::ColorTableEntry[]>
      mColors;              // The color table, if it's present.
  uint32_t mBytesPerColor;  // 3 or 4, depending on the format

  // The number of bytes prior to the optional gap that have been read. This
  // is used to find the start of the pixel data.
  uint32_t mPreGapLength;

  uint32_t mPixelRowSize;  // The number of bytes per pixel row.

  int32_t mCurrentRow;  // Index of the row of the image that's currently
                        // being decoded: [height,1].
  int32_t mCurrentPos;  // Index into the current line. Used when
                        // doing RLE decoding and when filling in pixels
                        // for truncated files.

  // Only used in RLE_ABSOLUTE state: the number of pixels to read.
  uint32_t mAbsoluteModeNumPixels;
};

}  // namespace image
}  // namespace mozilla

#endif  // mozilla_image_decoders_nsBMPDecoder_h