tor-browser

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

nsJXLDecoder.cpp (5869B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 *
      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 "ImageLogging.h"  // Must appear first
      8 #include "gfxPlatform.h"
      9 #include "jxl/codestream_header.h"
     10 #include "jxl/decode_cxx.h"
     11 #include "jxl/types.h"
     12 #include "mozilla/TelemetryHistogramEnums.h"
     13 #include "mozilla/gfx/Point.h"
     14 #include "nsJXLDecoder.h"
     15 
     16 #include "RasterImage.h"
     17 #include "SurfacePipeFactory.h"
     18 
     19 using namespace mozilla::gfx;
     20 
     21 namespace mozilla::image {
     22 
     23 #define JXL_TRY(expr)                        \
     24  do {                                       \
     25    JxlDecoderStatus _status = (expr);       \
     26    if (_status != JXL_DEC_SUCCESS) {        \
     27      return Transition::TerminateFailure(); \
     28    }                                        \
     29  } while (0);
     30 
     31 #define JXL_TRY_BOOL(expr)                   \
     32  do {                                       \
     33    bool succeeded = (expr);                 \
     34    if (!succeeded) {                        \
     35      return Transition::TerminateFailure(); \
     36    }                                        \
     37  } while (0);
     38 
     39 static LazyLogModule sJXLLog("JXLDecoder");
     40 
     41 nsJXLDecoder::nsJXLDecoder(RasterImage* aImage)
     42    : Decoder(aImage),
     43      mLexer(Transition::ToUnbuffered(State::FINISHED_JXL_DATA, State::JXL_DATA,
     44                                      SIZE_MAX),
     45             Transition::TerminateSuccess()),
     46      mDecoder(JxlDecoderMake(nullptr)),
     47      mParallelRunner(
     48          JxlThreadParallelRunnerMake(nullptr, PreferredThreadCount())) {
     49  JxlDecoderSubscribeEvents(mDecoder.get(),
     50                            JXL_DEC_BASIC_INFO | JXL_DEC_FULL_IMAGE);
     51  JxlDecoderSetParallelRunner(mDecoder.get(), JxlThreadParallelRunner,
     52                              mParallelRunner.get());
     53 
     54  MOZ_LOG(sJXLLog, LogLevel::Debug,
     55          ("[this=%p] nsJXLDecoder::nsJXLDecoder", this));
     56 }
     57 
     58 nsJXLDecoder::~nsJXLDecoder() {
     59  MOZ_LOG(sJXLLog, LogLevel::Debug,
     60          ("[this=%p] nsJXLDecoder::~nsJXLDecoder", this));
     61 }
     62 
     63 size_t nsJXLDecoder::PreferredThreadCount() {
     64  if (IsMetadataDecode()) {
     65    return 0;  // no additional worker thread
     66  }
     67  return JxlThreadParallelRunnerDefaultNumWorkerThreads();
     68 }
     69 
     70 LexerResult nsJXLDecoder::DoDecode(SourceBufferIterator& aIterator,
     71                                   IResumable* aOnResume) {
     72  // return LexerResult(TerminalState::FAILURE);
     73  MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
     74 
     75  return mLexer.Lex(aIterator, aOnResume,
     76                    [=](State aState, const char* aData, size_t aLength) {
     77                      switch (aState) {
     78                        case State::JXL_DATA:
     79                          return ReadJXLData(aData, aLength);
     80                        case State::FINISHED_JXL_DATA:
     81                          return FinishedJXLData();
     82                      }
     83                      MOZ_CRASH("Unknown State");
     84                    });
     85 };
     86 
     87 LexerTransition<nsJXLDecoder::State> nsJXLDecoder::ReadJXLData(
     88    const char* aData, size_t aLength) {
     89  const uint8_t* input = (const uint8_t*)aData;
     90  size_t length = aLength;
     91  if (mBuffer.length() != 0) {
     92    JXL_TRY_BOOL(mBuffer.append(aData, aLength));
     93    input = mBuffer.begin();
     94    length = mBuffer.length();
     95  }
     96  JXL_TRY(JxlDecoderSetInput(mDecoder.get(), input, length));
     97 
     98  while (true) {
     99    JxlDecoderStatus status = JxlDecoderProcessInput(mDecoder.get());
    100    switch (status) {
    101      case JXL_DEC_ERROR:
    102      default:
    103        return Transition::TerminateFailure();
    104 
    105      case JXL_DEC_NEED_MORE_INPUT: {
    106        size_t remaining = JxlDecoderReleaseInput(mDecoder.get());
    107        mBuffer.clear();
    108        JXL_TRY_BOOL(mBuffer.append(aData + aLength - remaining, remaining));
    109        return Transition::ContinueUnbuffered(State::JXL_DATA);
    110      }
    111 
    112      case JXL_DEC_BASIC_INFO: {
    113        JXL_TRY(JxlDecoderGetBasicInfo(mDecoder.get(), &mInfo));
    114        PostSize(mInfo.xsize, mInfo.ysize);
    115        if (WantsFrameCount()) {
    116          PostFrameCount(/* aFrameCount */ 1);
    117        }
    118        if (mInfo.alpha_bits > 0) {
    119          PostHasTransparency();
    120        }
    121        if (IsMetadataDecode()) {
    122          return Transition::TerminateSuccess();
    123        }
    124        break;
    125      }
    126 
    127      case JXL_DEC_NEED_IMAGE_OUT_BUFFER: {
    128        size_t size = 0;
    129        JxlPixelFormat format{4, JXL_TYPE_UINT8, JXL_LITTLE_ENDIAN, 0};
    130        JXL_TRY(JxlDecoderImageOutBufferSize(mDecoder.get(), &format, &size));
    131 
    132        mOutBuffer.clear();
    133        JXL_TRY_BOOL(mOutBuffer.growBy(size));
    134        JXL_TRY(JxlDecoderSetImageOutBuffer(mDecoder.get(), &format,
    135                                            mOutBuffer.begin(), size));
    136        break;
    137      }
    138 
    139      case JXL_DEC_FULL_IMAGE: {
    140        OrientedIntSize size(mInfo.xsize, mInfo.ysize);
    141        Maybe<SurfacePipe> pipe = SurfacePipeFactory::CreateSurfacePipe(
    142            this, size, OutputSize(), FullFrame(), SurfaceFormat::R8G8B8A8,
    143            SurfaceFormat::OS_RGBA, Nothing(), nullptr, SurfacePipeFlags());
    144        for (uint8_t* rowPtr = mOutBuffer.begin(); rowPtr < mOutBuffer.end();
    145             rowPtr += mInfo.xsize * 4) {
    146          pipe->WriteBuffer(reinterpret_cast<uint32_t*>(rowPtr));
    147        }
    148 
    149        if (Maybe<SurfaceInvalidRect> invalidRect = pipe->TakeInvalidRect()) {
    150          PostInvalidation(invalidRect->mInputSpaceRect,
    151                           Some(invalidRect->mOutputSpaceRect));
    152        }
    153        PostFrameStop();
    154        PostDecodeDone();
    155        return Transition::TerminateSuccess();
    156      }
    157    }
    158  }
    159 }
    160 
    161 LexerTransition<nsJXLDecoder::State> nsJXLDecoder::FinishedJXLData() {
    162  MOZ_ASSERT_UNREACHABLE("Read the entire address space?");
    163  return Transition::TerminateFailure();
    164 }
    165 
    166 }  // namespace mozilla::image