mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1206836 - When downscaling ICOs, downscale the AND mask as well. r=tn a=KWierso
This commit is contained in:
parent
8b5b12a870
commit
5f0c22c9c2
@ -40,6 +40,7 @@ public:
|
||||
|
||||
// Obtains the internal output image buffer
|
||||
uint32_t* GetImageData();
|
||||
size_t GetImageDataLength() const { return mImageDataLength; }
|
||||
|
||||
// Obtains the size of the compressed image resource
|
||||
int32_t GetCompressedImageSize() const;
|
||||
|
@ -69,6 +69,8 @@ nsICODecoder::nsICODecoder(RasterImage* aImage)
|
||||
, mBPP(0)
|
||||
, mMaskRowSize(0)
|
||||
, mCurrMaskLine(0)
|
||||
, mIsCursor(false)
|
||||
, mHasMaskAlpha(false)
|
||||
{ }
|
||||
|
||||
void
|
||||
@ -542,6 +544,24 @@ nsICODecoder::PrepareForMask()
|
||||
return Transition::Terminate(ICOState::FAILURE);
|
||||
}
|
||||
|
||||
// If we're downscaling, the mask is the wrong size for the surface we've
|
||||
// produced, so we need to downscale the mask into a temporary buffer and then
|
||||
// combine the mask's alpha values with the color values from the image.
|
||||
if (mDownscaler) {
|
||||
MOZ_ASSERT(bmpDecoder->GetImageDataLength() ==
|
||||
mDownscaler->TargetSize().width *
|
||||
mDownscaler->TargetSize().height *
|
||||
sizeof(uint32_t));
|
||||
mMaskBuffer = MakeUnique<uint8_t[]>(bmpDecoder->GetImageDataLength());
|
||||
nsresult rv = mDownscaler->BeginFrame(GetRealSize(),
|
||||
mMaskBuffer.get(),
|
||||
/* aHasAlpha = */ true,
|
||||
/* aFlipVertically = */ true);
|
||||
if (NS_FAILED(rv)) {
|
||||
return Transition::Terminate(ICOState::FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
mCurrMaskLine = GetRealHeight();
|
||||
return Transition::To(ICOState::READ_MASK_ROW, mMaskRowSize);
|
||||
}
|
||||
@ -552,20 +572,34 @@ nsICODecoder::ReadMaskRow(const char* aData)
|
||||
{
|
||||
mCurrMaskLine--;
|
||||
|
||||
nsRefPtr<nsBMPDecoder> bmpDecoder =
|
||||
static_cast<nsBMPDecoder*>(mContainedDecoder.get());
|
||||
|
||||
uint32_t* imageData = bmpDecoder->GetImageData();
|
||||
if (!imageData) {
|
||||
return Transition::Terminate(ICOState::FAILURE);
|
||||
}
|
||||
|
||||
uint8_t sawTransparency = 0;
|
||||
uint32_t* decoded = imageData + mCurrMaskLine * GetRealWidth();
|
||||
uint32_t* decodedRowEnd = decoded + GetRealWidth();
|
||||
|
||||
// Get the mask row we're reading.
|
||||
const uint8_t* mask = reinterpret_cast<const uint8_t*>(aData);
|
||||
const uint8_t* maskRowEnd = mask + mMaskRowSize;
|
||||
|
||||
// Get the corresponding row of the mask buffer (if we're downscaling) or the
|
||||
// decoded image data (if we're not).
|
||||
uint32_t* decoded = nullptr;
|
||||
if (mDownscaler) {
|
||||
// Initialize the row to all white and fully opaque.
|
||||
memset(mDownscaler->RowBuffer(), 0xFF, GetRealWidth() * sizeof(uint32_t));
|
||||
|
||||
decoded = reinterpret_cast<uint32_t*>(mDownscaler->RowBuffer());
|
||||
} else {
|
||||
nsRefPtr<nsBMPDecoder> bmpDecoder =
|
||||
static_cast<nsBMPDecoder*>(mContainedDecoder.get());
|
||||
uint32_t* imageData = bmpDecoder->GetImageData();
|
||||
if (!imageData) {
|
||||
return Transition::Terminate(ICOState::FAILURE);
|
||||
}
|
||||
|
||||
decoded = imageData + mCurrMaskLine * GetRealWidth();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(decoded);
|
||||
uint32_t* decodedRowEnd = decoded + GetRealWidth();
|
||||
|
||||
// Iterate simultaneously through the AND mask and the image data.
|
||||
while (mask < maskRowEnd) {
|
||||
uint8_t idx = *mask++;
|
||||
@ -579,20 +613,57 @@ nsICODecoder::ReadMaskRow(const char* aData)
|
||||
}
|
||||
}
|
||||
|
||||
if (mDownscaler) {
|
||||
mDownscaler->CommitRow();
|
||||
}
|
||||
|
||||
// If any bits are set in sawTransparency, then we know at least one pixel was
|
||||
// transparent.
|
||||
if (sawTransparency) {
|
||||
PostHasTransparency();
|
||||
bmpDecoder->SetHasAlphaData();
|
||||
mHasMaskAlpha = true;
|
||||
}
|
||||
|
||||
if (mCurrMaskLine == 0) {
|
||||
return Transition::To(ICOState::FINISHED_RESOURCE, 0);
|
||||
return Transition::To(ICOState::FINISH_MASK, 0);
|
||||
}
|
||||
|
||||
return Transition::To(ICOState::READ_MASK_ROW, mMaskRowSize);
|
||||
}
|
||||
|
||||
LexerTransition<ICOState>
|
||||
nsICODecoder::FinishMask()
|
||||
{
|
||||
// If we're downscaling, we now have the appropriate alpha values in
|
||||
// mMaskBuffer. We just need to transfer them to the image.
|
||||
if (mDownscaler) {
|
||||
// Retrieve the image data.
|
||||
nsRefPtr<nsBMPDecoder> bmpDecoder =
|
||||
static_cast<nsBMPDecoder*>(mContainedDecoder.get());
|
||||
uint8_t* imageData = reinterpret_cast<uint8_t*>(bmpDecoder->GetImageData());
|
||||
if (!imageData) {
|
||||
return Transition::Terminate(ICOState::FAILURE);
|
||||
}
|
||||
|
||||
// Iterate through the alpha values, copying from mask to image.
|
||||
MOZ_ASSERT(mMaskBuffer);
|
||||
MOZ_ASSERT(bmpDecoder->GetImageDataLength() > 0);
|
||||
for (size_t i = 3 ; i < bmpDecoder->GetImageDataLength() ; i += 4) {
|
||||
imageData[i] = mMaskBuffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
// If the mask contained any transparent pixels, record that fact.
|
||||
if (mHasMaskAlpha) {
|
||||
PostHasTransparency();
|
||||
|
||||
nsRefPtr<nsBMPDecoder> bmpDecoder =
|
||||
static_cast<nsBMPDecoder*>(mContainedDecoder.get());
|
||||
bmpDecoder->SetHasAlphaData();
|
||||
}
|
||||
|
||||
return Transition::To(ICOState::FINISHED_RESOURCE, 0);
|
||||
}
|
||||
|
||||
LexerTransition<ICOState>
|
||||
nsICODecoder::FinishResource()
|
||||
{
|
||||
@ -637,6 +708,8 @@ nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
return PrepareForMask();
|
||||
case ICOState::READ_MASK_ROW:
|
||||
return ReadMaskRow(aData);
|
||||
case ICOState::FINISH_MASK:
|
||||
return FinishMask();
|
||||
case ICOState::SKIP_MASK:
|
||||
return Transition::ContinueUnbuffered(ICOState::SKIP_MASK);
|
||||
case ICOState::FINISHED_RESOURCE:
|
||||
|
@ -34,6 +34,7 @@ enum class ICOState
|
||||
READ_BMP,
|
||||
PREPARE_FOR_MASK,
|
||||
READ_MASK_ROW,
|
||||
FINISH_MASK,
|
||||
SKIP_MASK,
|
||||
FINISHED_RESOURCE
|
||||
};
|
||||
@ -114,10 +115,12 @@ private:
|
||||
LexerTransition<ICOState> ReadBMP(const char* aData, uint32_t aLen);
|
||||
LexerTransition<ICOState> PrepareForMask();
|
||||
LexerTransition<ICOState> ReadMaskRow(const char* aData);
|
||||
LexerTransition<ICOState> FinishMask();
|
||||
LexerTransition<ICOState> FinishResource();
|
||||
|
||||
StreamingLexer<ICOState, 32> mLexer; // The lexer.
|
||||
nsRefPtr<Decoder> mContainedDecoder; // Either a BMP or PNG decoder.
|
||||
UniquePtr<uint8_t[]> mMaskBuffer; // A temporary buffer for the alpha mask.
|
||||
char mBIHraw[40]; // The bitmap information header.
|
||||
IconDirEntry mDirEntry; // The dir entry for the selected resource.
|
||||
IntSize mBiggestResourceSize; // Used to select the intrinsic size.
|
||||
@ -131,6 +134,7 @@ private:
|
||||
uint32_t mMaskRowSize; // The size in bytes of each row in the BMP alpha mask.
|
||||
uint32_t mCurrMaskLine; // The line of the BMP alpha mask we're processing.
|
||||
bool mIsCursor; // Is this ICO a cursor?
|
||||
bool mHasMaskAlpha; // Did the BMP alpha mask have any transparency?
|
||||
};
|
||||
|
||||
} // namespace image
|
||||
|
Loading…
Reference in New Issue
Block a user