/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include BitmapWriteAccess::BitmapWriteAccess(Bitmap& rBitmap) : BitmapReadAccess(rBitmap, BitmapAccessMode::Write) { } BitmapWriteAccess::~BitmapWriteAccess() {} void BitmapWriteAccess::CopyScanline(tools::Long nY, const BitmapReadAccess& rReadAcc) { assert(nY >= 0 && nY < mpBuffer->mnHeight && "y-coordinate in destination out of range!"); SAL_WARN_IF(nY >= rReadAcc.Height(), "vcl", "y-coordinate in source out of range!"); SAL_WARN_IF((!HasPalette() || !rReadAcc.HasPalette()) && (HasPalette() || rReadAcc.HasPalette()), "vcl", "No copying possible between palette bitmap and TC bitmap!"); if ((GetScanlineFormat() == rReadAcc.GetScanlineFormat()) && (GetScanlineSize() >= rReadAcc.GetScanlineSize())) { memcpy(GetScanline(nY), rReadAcc.GetScanline(nY), rReadAcc.GetScanlineSize()); } else { tools::Long nWidth = std::min(mpBuffer->mnWidth, rReadAcc.Width()); if (!ImplFastCopyScanline(nY, *ImplGetBitmapBuffer(), *rReadAcc.ImplGetBitmapBuffer())) { Scanline pScanline = GetScanline(nY); Scanline pScanlineRead = rReadAcc.GetScanline(nY); for (tools::Long nX = 0; nX < nWidth; nX++) SetPixelOnData(pScanline, nX, rReadAcc.GetPixelFromData(pScanlineRead, nX)); } } } void BitmapWriteAccess::CopyScanline(tools::Long nY, ConstScanline aSrcScanline, ScanlineFormat nSrcScanlineFormat, sal_uInt32 nSrcScanlineSize) { const ScanlineFormat nFormat = RemoveScanline(nSrcScanlineFormat); assert(nY >= 0 && nY < mpBuffer->mnHeight && "y-coordinate in destination out of range!"); DBG_ASSERT((HasPalette() && nFormat <= ScanlineFormat::N8BitPal) || (!HasPalette() && nFormat > ScanlineFormat::N8BitPal), "No copying possible between palette and non palette scanlines!"); const sal_uInt32 nCount = std::min(GetScanlineSize(), nSrcScanlineSize); if (!nCount) return; if (GetScanlineFormat() == RemoveScanline(nSrcScanlineFormat)) memcpy(GetScanline(nY), aSrcScanline, nCount); else { if (ImplFastCopyScanline(nY, *ImplGetBitmapBuffer(), aSrcScanline, nSrcScanlineFormat, nSrcScanlineSize)) return; DBG_ASSERT(nFormat != ScanlineFormat::N32BitTcMask, "No support for pixel formats with color masks yet!"); FncGetPixel pFncGetPixel; switch (nFormat) { case ScanlineFormat::N1BitMsbPal: pFncGetPixel = GetPixelForN1BitMsbPal; break; case ScanlineFormat::N1BitLsbPal: pFncGetPixel = GetPixelForN1BitLsbPal; break; case ScanlineFormat::N8BitPal: pFncGetPixel = GetPixelForN8BitPal; break; case ScanlineFormat::N24BitTcBgr: pFncGetPixel = GetPixelForN24BitTcBgr; break; case ScanlineFormat::N24BitTcRgb: pFncGetPixel = GetPixelForN24BitTcRgb; break; case ScanlineFormat::N32BitTcAbgr: if (Bitmap32IsPreMultipled()) pFncGetPixel = GetPixelForN32BitTcAbgr; else pFncGetPixel = GetPixelForN32BitTcXbgr; break; case ScanlineFormat::N32BitTcArgb: if (Bitmap32IsPreMultipled()) pFncGetPixel = GetPixelForN32BitTcArgb; else pFncGetPixel = GetPixelForN32BitTcXrgb; break; case ScanlineFormat::N32BitTcBgra: if (Bitmap32IsPreMultipled()) pFncGetPixel = GetPixelForN32BitTcBgra; else pFncGetPixel = GetPixelForN32BitTcBgrx; break; case ScanlineFormat::N32BitTcRgba: if (Bitmap32IsPreMultipled()) pFncGetPixel = GetPixelForN32BitTcRgba; else pFncGetPixel = GetPixelForN32BitTcRgbx; break; case ScanlineFormat::N32BitTcMask: pFncGetPixel = GetPixelForN32BitTcMask; break; default: assert(false); pFncGetPixel = nullptr; break; } if (pFncGetPixel) { const ColorMask aDummyMask; Scanline pScanline = GetScanline(nY); for (tools::Long nX = 0, nWidth = mpBuffer->mnWidth; nX < nWidth; ++nX) SetPixelOnData(pScanline, nX, pFncGetPixel(aSrcScanline, nX, aDummyMask)); } } } void BitmapWriteAccess::SetLineColor(const Color& rColor) { if (rColor.GetAlpha() == 0) { mpLineColor.reset(); } else { if (HasPalette()) { mpLineColor = BitmapColor(static_cast(GetBestPaletteIndex(rColor))); } else { mpLineColor = BitmapColor(rColor); } } } void BitmapWriteAccess::SetFillColor() { mpFillColor.reset(); } void BitmapWriteAccess::SetFillColor(const Color& rColor) { if (rColor.GetAlpha() == 0) { mpFillColor.reset(); } else { if (HasPalette()) { mpFillColor = BitmapColor(static_cast(GetBestPaletteIndex(rColor))); } else { mpFillColor = BitmapColor(rColor); } } } void BitmapWriteAccess::Erase(const Color& rColor) { // convert the color format from RGB to palette index if needed // TODO: provide and use Erase( BitmapColor& method) BitmapColor aColor = rColor; if (HasPalette()) { aColor = BitmapColor(static_cast(GetBestPaletteIndex(rColor))); } // try fast bitmap method first if (ImplFastEraseBitmap(*mpBuffer, aColor)) return; tools::Rectangle aRect(Point(), maBitmap.GetSizePixel()); if (aRect.IsEmpty()) return; // clear the bitmap by filling the first line pixel by pixel, // then dup the first line over each other line Scanline pFirstScanline = GetScanline(0); const tools::Long nEndX = aRect.Right(); for (tools::Long nX = 0; nX <= nEndX; ++nX) SetPixelOnData(pFirstScanline, nX, rColor); const auto nScanlineSize = GetScanlineSize(); const tools::Long nEndY = aRect.Bottom(); for (tools::Long nY = 1; nY <= nEndY; nY++) { Scanline pDestScanline = GetScanline(nY); memcpy(pDestScanline, pFirstScanline, nScanlineSize); } } void BitmapWriteAccess::DrawLine(const Point& rStart, const Point& rEnd) { if (!mpLineColor) return; const BitmapColor& rLineColor = *mpLineColor; tools::Long nX, nY; if (rStart.X() == rEnd.X()) { // Vertical Line const tools::Long nEndY = rEnd.Y(); nX = rStart.X(); nY = rStart.Y(); if (nEndY > nY) { for (; nY <= nEndY; nY++) SetPixel(nY, nX, rLineColor); } else { for (; nY >= nEndY; nY--) SetPixel(nY, nX, rLineColor); } } else if (rStart.Y() == rEnd.Y()) { // Horizontal Line const tools::Long nEndX = rEnd.X(); nX = rStart.X(); nY = rStart.Y(); if (nEndX > nX) { for (; nX <= nEndX; nX++) SetPixel(nY, nX, rLineColor); } else { for (; nX >= nEndX; nX--) SetPixel(nY, nX, rLineColor); } } else { const tools::Long nDX = std::abs(rEnd.X() - rStart.X()); const tools::Long nDY = std::abs(rEnd.Y() - rStart.Y()); tools::Long nX1; tools::Long nY1; tools::Long nX2; tools::Long nY2; if (nDX >= nDY) { if (rStart.X() < rEnd.X()) { nX1 = rStart.X(); nY1 = rStart.Y(); nX2 = rEnd.X(); nY2 = rEnd.Y(); } else { nX1 = rEnd.X(); nY1 = rEnd.Y(); nX2 = rStart.X(); nY2 = rStart.Y(); } const tools::Long nDYX = (nDY - nDX) << 1; const tools::Long nDY2 = nDY << 1; tools::Long nD = nDY2 - nDX; bool bPos = nY1 < nY2; for (nX = nX1, nY = nY1; nX <= nX2; nX++) { SetPixel(nY, nX, rLineColor); if (nD < 0) nD += nDY2; else { nD += nDYX; if (bPos) nY++; else nY--; } } } else { if (rStart.Y() < rEnd.Y()) { nX1 = rStart.X(); nY1 = rStart.Y(); nX2 = rEnd.X(); nY2 = rEnd.Y(); } else { nX1 = rEnd.X(); nY1 = rEnd.Y(); nX2 = rStart.X(); nY2 = rStart.Y(); } const tools::Long nDYX = (nDX - nDY) << 1; const tools::Long nDY2 = nDX << 1; tools::Long nD = nDY2 - nDY; bool bPos = nX1 < nX2; for (nX = nX1, nY = nY1; nY <= nY2; nY++) { SetPixel(nY, nX, rLineColor); if (nD < 0) nD += nDY2; else { nD += nDYX; if (bPos) nX++; else nX--; } } } } } void BitmapWriteAccess::FillRect(const tools::Rectangle& rRect) { if (!mpFillColor) return; const BitmapColor& rFillColor = *mpFillColor; tools::Rectangle aRect(Point(), maBitmap.GetSizePixel()); aRect.Intersection(rRect); if (aRect.IsEmpty()) return; const tools::Long nStartX = rRect.Left(); const tools::Long nStartY = rRect.Top(); const tools::Long nEndX = rRect.Right(); const tools::Long nEndY = rRect.Bottom(); for (tools::Long nY = nStartY; nY <= nEndY; nY++) { Scanline pScanline = GetScanline(nY); for (tools::Long nX = nStartX; nX <= nEndX; nX++) { SetPixelOnData(pScanline, nX, rFillColor); } } } void BitmapWriteAccess::DrawRect(const tools::Rectangle& rRect) { if (mpFillColor) FillRect(rRect); if (mpLineColor && (!mpFillColor || (*mpFillColor != *mpLineColor))) { DrawLine(rRect.TopLeft(), rRect.TopRight()); DrawLine(rRect.TopRight(), rRect.BottomRight()); DrawLine(rRect.BottomRight(), rRect.BottomLeft()); DrawLine(rRect.BottomLeft(), rRect.TopLeft()); } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */