tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

alpha_dec.c (8294B)


      1 // Copyright 2011 Google Inc. All Rights Reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style license
      4 // that can be found in the COPYING file in the root of the source
      5 // tree. An additional intellectual property rights grant can be found
      6 // in the file PATENTS. All contributing project authors may
      7 // be found in the AUTHORS file in the root of the source tree.
      8 // -----------------------------------------------------------------------------
      9 //
     10 // Alpha-plane decompression.
     11 //
     12 // Author: Skal (pascal.massimino@gmail.com)
     13 
     14 #include <assert.h>
     15 #include <stdlib.h>
     16 
     17 #include "src/dec/alphai_dec.h"
     18 #include "src/dec/vp8_dec.h"
     19 #include "src/dec/vp8i_dec.h"
     20 #include "src/dec/vp8li_dec.h"
     21 #include "src/dec/webpi_dec.h"
     22 #include "src/dsp/dsp.h"
     23 #include "src/utils/quant_levels_dec_utils.h"
     24 #include "src/utils/utils.h"
     25 #include "src/webp/decode.h"
     26 #include "src/webp/format_constants.h"
     27 #include "src/webp/types.h"
     28 
     29 //------------------------------------------------------------------------------
     30 // ALPHDecoder object.
     31 
     32 // Allocates a new alpha decoder instance.
     33 WEBP_NODISCARD static ALPHDecoder* ALPHNew(void) {
     34  ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
     35  return dec;
     36 }
     37 
     38 // Clears and deallocates an alpha decoder instance.
     39 static void ALPHDelete(ALPHDecoder* const dec) {
     40  if (dec != NULL) {
     41    VP8LDelete(dec->vp8l_dec);
     42    dec->vp8l_dec = NULL;
     43    WebPSafeFree(dec);
     44  }
     45 }
     46 
     47 //------------------------------------------------------------------------------
     48 // Decoding.
     49 
     50 // Initialize alpha decoding by parsing the alpha header and decoding the image
     51 // header for alpha data stored using lossless compression.
     52 // Returns false in case of error in alpha header (data too short, invalid
     53 // compression method or filter, error in lossless header data etc).
     54 WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
     55                                   size_t data_size, const VP8Io* const src_io,
     56                                   uint8_t* output) {
     57  int ok = 0;
     58  const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;
     59  const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;
     60  int rsrv;
     61  VP8Io* const io = &dec->io;
     62 
     63  assert(data != NULL && output != NULL && src_io != NULL);
     64 
     65  VP8FiltersInit();
     66  dec->output = output;
     67  dec->width = src_io->width;
     68  dec->height = src_io->height;
     69  assert(dec->width > 0 && dec->height > 0);
     70 
     71  if (data_size <= ALPHA_HEADER_LEN) {
     72    return 0;
     73  }
     74 
     75  dec->method = (data[0] >> 0) & 0x03;
     76  dec->filter = (WEBP_FILTER_TYPE)((data[0] >> 2) & 0x03);
     77  dec->pre_processing = (data[0] >> 4) & 0x03;
     78  rsrv = (data[0] >> 6) & 0x03;
     79  if (dec->method < ALPHA_NO_COMPRESSION ||
     80      dec->method > ALPHA_LOSSLESS_COMPRESSION ||
     81      dec->filter >= WEBP_FILTER_LAST ||
     82      dec->pre_processing > ALPHA_PREPROCESSED_LEVELS ||
     83      rsrv != 0) {
     84    return 0;
     85  }
     86 
     87  // Copy the necessary parameters from src_io to io
     88  if (!VP8InitIo(io)) {
     89    return 0;
     90  }
     91  WebPInitCustomIo(NULL, io);
     92  io->opaque = dec;
     93  io->width = src_io->width;
     94  io->height = src_io->height;
     95 
     96  io->use_cropping = src_io->use_cropping;
     97  io->crop_left = src_io->crop_left;
     98  io->crop_right = src_io->crop_right;
     99  io->crop_top = src_io->crop_top;
    100  io->crop_bottom = src_io->crop_bottom;
    101  // No need to copy the scaling parameters.
    102 
    103  if (dec->method == ALPHA_NO_COMPRESSION) {
    104    const size_t alpha_decoded_size = dec->width * dec->height;
    105    ok = (alpha_data_size >= alpha_decoded_size);
    106  } else {
    107    assert(dec->method == ALPHA_LOSSLESS_COMPRESSION);
    108    ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size);
    109  }
    110 
    111  return ok;
    112 }
    113 
    114 // Decodes, unfilters and dequantizes *at least* 'num_rows' rows of alpha
    115 // starting from row number 'row'. It assumes that rows up to (row - 1) have
    116 // already been decoded.
    117 // Returns false in case of bitstream error.
    118 WEBP_NODISCARD static int ALPHDecode(VP8Decoder* const dec, int row,
    119                                     int num_rows) {
    120  ALPHDecoder* const alph_dec = dec->alph_dec;
    121  const int width = alph_dec->width;
    122  const int height = alph_dec->io.crop_bottom;
    123  if (alph_dec->method == ALPHA_NO_COMPRESSION) {
    124    int y;
    125    const uint8_t* prev_line = dec->alpha_prev_line;
    126    const uint8_t* deltas = dec->alpha_data + ALPHA_HEADER_LEN + row * width;
    127    uint8_t* dst = dec->alpha_plane + row * width;
    128    assert(deltas <= &dec->alpha_data[dec->alpha_data_size]);
    129    assert(WebPUnfilters[alph_dec->filter] != NULL);
    130    for (y = 0; y < num_rows; ++y) {
    131      WebPUnfilters[alph_dec->filter](prev_line, deltas, dst, width);
    132      prev_line = dst;
    133      dst += width;
    134      deltas += width;
    135    }
    136    dec->alpha_prev_line = prev_line;
    137  } else {  // alph_dec->method == ALPHA_LOSSLESS_COMPRESSION
    138    assert(alph_dec->vp8l_dec != NULL);
    139    if (!VP8LDecodeAlphaImageStream(alph_dec, row + num_rows)) {
    140      return 0;
    141    }
    142  }
    143 
    144  if (row + num_rows >= height) {
    145    dec->is_alpha_decoded = 1;
    146  }
    147  return 1;
    148 }
    149 
    150 WEBP_NODISCARD static int AllocateAlphaPlane(VP8Decoder* const dec,
    151                                             const VP8Io* const io) {
    152  const int stride = io->width;
    153  const int height = io->crop_bottom;
    154  const uint64_t alpha_size = (uint64_t)stride * height;
    155  assert(dec->alpha_plane_mem == NULL);
    156  dec->alpha_plane_mem =
    157      (uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane));
    158  if (dec->alpha_plane_mem == NULL) {
    159    return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
    160                       "Alpha decoder initialization failed.");
    161  }
    162  dec->alpha_plane = dec->alpha_plane_mem;
    163  dec->alpha_prev_line = NULL;
    164  return 1;
    165 }
    166 
    167 void WebPDeallocateAlphaMemory(VP8Decoder* const dec) {
    168  assert(dec != NULL);
    169  WebPSafeFree(dec->alpha_plane_mem);
    170  dec->alpha_plane_mem = NULL;
    171  dec->alpha_plane = NULL;
    172  ALPHDelete(dec->alph_dec);
    173  dec->alph_dec = NULL;
    174 }
    175 
    176 //------------------------------------------------------------------------------
    177 // Main entry point.
    178 
    179 WEBP_NODISCARD const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
    180                                                     const VP8Io* const io,
    181                                                     int row, int num_rows) {
    182  const int width = io->width;
    183  const int height = io->crop_bottom;
    184 
    185  assert(dec != NULL && io != NULL);
    186 
    187  if (row < 0 || num_rows <= 0 || row + num_rows > height) {
    188    return NULL;
    189  }
    190 
    191  if (!dec->is_alpha_decoded) {
    192    if (dec->alph_dec == NULL) {    // Initialize decoder.
    193      dec->alph_dec = ALPHNew();
    194      if (dec->alph_dec == NULL) {
    195        VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
    196                    "Alpha decoder initialization failed.");
    197        return NULL;
    198      }
    199      if (!AllocateAlphaPlane(dec, io)) goto Error;
    200      if (!ALPHInit(dec->alph_dec, dec->alpha_data, dec->alpha_data_size,
    201                    io, dec->alpha_plane)) {
    202        VP8LDecoder* const vp8l_dec = dec->alph_dec->vp8l_dec;
    203        VP8SetError(dec,
    204                    (vp8l_dec == NULL) ? VP8_STATUS_OUT_OF_MEMORY
    205                                       : vp8l_dec->status,
    206                    "Alpha decoder initialization failed.");
    207        goto Error;
    208      }
    209      // if we allowed use of alpha dithering, check whether it's needed at all
    210      if (dec->alph_dec->pre_processing != ALPHA_PREPROCESSED_LEVELS) {
    211        dec->alpha_dithering = 0;    // disable dithering
    212      } else {
    213        num_rows = height - row;     // decode everything in one pass
    214      }
    215    }
    216 
    217    assert(dec->alph_dec != NULL);
    218    assert(row + num_rows <= height);
    219    if (!ALPHDecode(dec, row, num_rows)) goto Error;
    220 
    221    if (dec->is_alpha_decoded) {   // finished?
    222      ALPHDelete(dec->alph_dec);
    223      dec->alph_dec = NULL;
    224      if (dec->alpha_dithering > 0) {
    225        uint8_t* const alpha = dec->alpha_plane + io->crop_top * width
    226                             + io->crop_left;
    227        if (!WebPDequantizeLevels(alpha,
    228                                  io->crop_right - io->crop_left,
    229                                  io->crop_bottom - io->crop_top,
    230                                  width, dec->alpha_dithering)) {
    231          goto Error;
    232        }
    233      }
    234    }
    235  }
    236 
    237  // Return a pointer to the current decoded row.
    238  return dec->alpha_plane + row * width;
    239 
    240 Error:
    241  WebPDeallocateAlphaMemory(dec);
    242  return NULL;
    243 }