| OLD | NEW |
| 1 // Copyright 2014 PDFium Authors. All rights reserved. | 1 // Copyright 2014 PDFium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| 6 | 6 |
| 7 #include <limits.h> | 7 #include <limits.h> |
| 8 | 8 |
| 9 #include <algorithm> |
| 10 |
| 9 #include "core/fxge/dib/dib_int.h" | 11 #include "core/fxge/dib/dib_int.h" |
| 10 #include "core/fxge/include/fx_dib.h" | 12 #include "core/fxge/include/fx_dib.h" |
| 11 #include "core/fxge/include/fx_ge.h" | 13 #include "core/fxge/include/fx_ge.h" |
| 12 | 14 |
| 13 namespace { | 15 namespace { |
| 14 | 16 |
| 17 bool SourceSizeWithinLimit(int width, int height) { |
| 18 const int kMaxProgressiveStretchPixels = 1000000; |
| 19 return !height || width < kMaxProgressiveStretchPixels / height; |
| 20 } |
| 21 |
| 15 FXDIB_Format GetStretchedFormat(const CFX_DIBSource& src) { | 22 FXDIB_Format GetStretchedFormat(const CFX_DIBSource& src) { |
| 16 FXDIB_Format format = src.GetFormat(); | 23 FXDIB_Format format = src.GetFormat(); |
| 17 if (format == FXDIB_1bppMask) | 24 if (format == FXDIB_1bppMask) |
| 18 return FXDIB_8bppMask; | 25 return FXDIB_8bppMask; |
| 19 if (format == FXDIB_1bppRgb) | 26 if (format == FXDIB_1bppRgb) |
| 20 return FXDIB_8bppRgb; | 27 return FXDIB_8bppRgb; |
| 21 if (format == FXDIB_8bppRgb && src.GetPalette()) | 28 if (format == FXDIB_8bppRgb && src.GetPalette()) |
| 22 return FXDIB_Rgb; | 29 return FXDIB_Rgb; |
| 23 return format; | 30 return format; |
| 24 } | 31 } |
| (...skipping 738 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 763 } | 770 } |
| 764 } | 771 } |
| 765 break; | 772 break; |
| 766 } | 773 } |
| 767 } | 774 } |
| 768 m_pDestBitmap->ComposeScanline(row - m_DestClip.top, m_pDestScanline, | 775 m_pDestBitmap->ComposeScanline(row - m_DestClip.top, m_pDestScanline, |
| 769 m_pDestMaskScanline); | 776 m_pDestMaskScanline); |
| 770 } | 777 } |
| 771 } | 778 } |
| 772 | 779 |
| 773 CFX_ImageStretcher::CFX_ImageStretcher() | 780 CFX_ImageStretcher::CFX_ImageStretcher(IFX_ScanlineComposer* pDest, |
| 774 : m_pStretchEngine(nullptr), | 781 const CFX_DIBSource* pSource, |
| 775 m_pScanline(nullptr), | 782 int dest_width, |
| 776 m_pMaskScanline(nullptr) {} | 783 int dest_height, |
| 784 const FX_RECT& bitmap_rect, |
| 785 uint32_t flags) |
| 786 : m_pDest(pDest), |
| 787 m_pSource(pSource), |
| 788 m_Flags(flags), |
| 789 m_bFlipX(FALSE), |
| 790 m_bFlipY(FALSE), |
| 791 m_DestWidth(dest_width), |
| 792 m_DestHeight(dest_height), |
| 793 m_ClipRect(bitmap_rect), |
| 794 m_DestFormat(GetStretchedFormat(*pSource)), |
| 795 m_DestBPP(m_DestFormat & 0xff), |
| 796 m_LineIndex(0) {} |
| 777 | 797 |
| 778 CFX_ImageStretcher::~CFX_ImageStretcher() { | 798 CFX_ImageStretcher::~CFX_ImageStretcher() { |
| 779 FX_Free(m_pScanline); | |
| 780 delete m_pStretchEngine; | |
| 781 FX_Free(m_pMaskScanline); | |
| 782 } | 799 } |
| 783 | 800 |
| 784 FX_BOOL CFX_ImageStretcher::Start(IFX_ScanlineComposer* pDest, | 801 FX_BOOL CFX_ImageStretcher::Start() { |
| 785 const CFX_DIBSource* pSource, | 802 if (m_DestWidth == 0 || m_DestHeight == 0) |
| 786 int dest_width, | |
| 787 int dest_height, | |
| 788 const FX_RECT& rect, | |
| 789 uint32_t flags) { | |
| 790 if (dest_width == 0 || dest_height == 0) | |
| 791 return FALSE; | 803 return FALSE; |
| 792 | 804 |
| 793 m_DestFormat = GetStretchedFormat(*pSource); | 805 if (m_pSource->GetFormat() == FXDIB_1bppRgb && m_pSource->GetPalette()) { |
| 794 m_DestBPP = m_DestFormat & 0xff; | |
| 795 m_pDest = pDest; | |
| 796 m_pSource = pSource; | |
| 797 m_DestWidth = dest_width; | |
| 798 m_DestHeight = dest_height; | |
| 799 m_ClipRect = rect; | |
| 800 m_Flags = flags; | |
| 801 | |
| 802 if (pSource->GetFormat() == FXDIB_1bppRgb && pSource->GetPalette()) { | |
| 803 FX_ARGB pal[256]; | 806 FX_ARGB pal[256]; |
| 804 int a0, r0, g0, b0, a1, r1, g1, b1; | 807 int a0, r0, g0, b0, a1, r1, g1, b1; |
| 805 ArgbDecode(pSource->GetPaletteEntry(0), a0, r0, g0, b0); | 808 ArgbDecode(m_pSource->GetPaletteEntry(0), a0, r0, g0, b0); |
| 806 ArgbDecode(pSource->GetPaletteEntry(1), a1, r1, g1, b1); | 809 ArgbDecode(m_pSource->GetPaletteEntry(1), a1, r1, g1, b1); |
| 807 for (int i = 0; i < 256; i++) { | 810 for (int i = 0; i < 256; i++) { |
| 808 int a = a0 + (a1 - a0) * i / 255; | 811 int a = a0 + (a1 - a0) * i / 255; |
| 809 int r = r0 + (r1 - r0) * i / 255; | 812 int r = r0 + (r1 - r0) * i / 255; |
| 810 int g = g0 + (g1 - g0) * i / 255; | 813 int g = g0 + (g1 - g0) * i / 255; |
| 811 int b = b0 + (b1 - b0) * i / 255; | 814 int b = b0 + (b1 - b0) * i / 255; |
| 812 pal[i] = ArgbEncode(a, r, g, b); | 815 pal[i] = ArgbEncode(a, r, g, b); |
| 813 } | 816 } |
| 814 if (!pDest->SetInfo(rect.Width(), rect.Height(), m_DestFormat, pal)) { | 817 if (!m_pDest->SetInfo(m_ClipRect.Width(), m_ClipRect.Height(), m_DestFormat, |
| 818 pal)) { |
| 815 return FALSE; | 819 return FALSE; |
| 816 } | 820 } |
| 817 } else if (pSource->GetFormat() == FXDIB_1bppCmyk && pSource->GetPalette()) { | 821 } else if (m_pSource->GetFormat() == FXDIB_1bppCmyk && |
| 822 m_pSource->GetPalette()) { |
| 818 FX_CMYK pal[256]; | 823 FX_CMYK pal[256]; |
| 819 int c0, m0, y0, k0, c1, m1, y1, k1; | 824 int c0, m0, y0, k0, c1, m1, y1, k1; |
| 820 CmykDecode(pSource->GetPaletteEntry(0), c0, m0, y0, k0); | 825 CmykDecode(m_pSource->GetPaletteEntry(0), c0, m0, y0, k0); |
| 821 CmykDecode(pSource->GetPaletteEntry(1), c1, m1, y1, k1); | 826 CmykDecode(m_pSource->GetPaletteEntry(1), c1, m1, y1, k1); |
| 822 for (int i = 0; i < 256; i++) { | 827 for (int i = 0; i < 256; i++) { |
| 823 int c = c0 + (c1 - c0) * i / 255; | 828 int c = c0 + (c1 - c0) * i / 255; |
| 824 int m = m0 + (m1 - m0) * i / 255; | 829 int m = m0 + (m1 - m0) * i / 255; |
| 825 int y = y0 + (y1 - y0) * i / 255; | 830 int y = y0 + (y1 - y0) * i / 255; |
| 826 int k = k0 + (k1 - k0) * i / 255; | 831 int k = k0 + (k1 - k0) * i / 255; |
| 827 pal[i] = CmykEncode(c, m, y, k); | 832 pal[i] = CmykEncode(c, m, y, k); |
| 828 } | 833 } |
| 829 if (!pDest->SetInfo(rect.Width(), rect.Height(), m_DestFormat, pal)) { | 834 if (!m_pDest->SetInfo(m_ClipRect.Width(), m_ClipRect.Height(), m_DestFormat, |
| 835 pal)) { |
| 830 return FALSE; | 836 return FALSE; |
| 831 } | 837 } |
| 832 } else if (!pDest->SetInfo(rect.Width(), rect.Height(), m_DestFormat, NULL)) { | 838 } else if (!m_pDest->SetInfo(m_ClipRect.Width(), m_ClipRect.Height(), |
| 839 m_DestFormat, nullptr)) { |
| 833 return FALSE; | 840 return FALSE; |
| 834 } | 841 } |
| 835 | 842 |
| 836 if (flags & FXDIB_DOWNSAMPLE) | 843 if (m_Flags & FXDIB_DOWNSAMPLE) |
| 837 return StartQuickStretch(); | 844 return StartQuickStretch(); |
| 838 return StartStretch(); | 845 return StartStretch(); |
| 839 } | 846 } |
| 840 | 847 |
| 841 FX_BOOL CFX_ImageStretcher::Continue(IFX_Pause* pPause) { | 848 FX_BOOL CFX_ImageStretcher::Continue(IFX_Pause* pPause) { |
| 842 if (m_Flags & FXDIB_DOWNSAMPLE) | 849 if (m_Flags & FXDIB_DOWNSAMPLE) |
| 843 return ContinueQuickStretch(pPause); | 850 return ContinueQuickStretch(pPause); |
| 844 return ContinueStretch(pPause); | 851 return ContinueStretch(pPause); |
| 845 } | 852 } |
| 846 | 853 |
| 847 #define MAX_PROGRESSIVE_STRETCH_PIXELS 1000000 | |
| 848 FX_BOOL CFX_ImageStretcher::StartStretch() { | 854 FX_BOOL CFX_ImageStretcher::StartStretch() { |
| 849 m_pStretchEngine = | 855 m_pStretchEngine.reset(new CStretchEngine(m_pDest, m_DestFormat, m_DestWidth, |
| 850 new CStretchEngine(m_pDest, m_DestFormat, m_DestWidth, m_DestHeight, | 856 m_DestHeight, m_ClipRect, m_pSource, |
| 851 m_ClipRect, m_pSource, m_Flags); | 857 m_Flags)); |
| 852 m_pStretchEngine->StartStretchHorz(); | 858 m_pStretchEngine->StartStretchHorz(); |
| 853 if (m_pSource->GetWidth() * m_pSource->GetHeight() < | 859 if (SourceSizeWithinLimit(m_pSource->GetWidth(), m_pSource->GetHeight())) { |
| 854 MAX_PROGRESSIVE_STRETCH_PIXELS) { | 860 m_pStretchEngine->Continue(nullptr); |
| 855 m_pStretchEngine->Continue(NULL); | |
| 856 return FALSE; | 861 return FALSE; |
| 857 } | 862 } |
| 858 return TRUE; | 863 return TRUE; |
| 859 } | 864 } |
| 865 |
| 860 FX_BOOL CFX_ImageStretcher::ContinueStretch(IFX_Pause* pPause) { | 866 FX_BOOL CFX_ImageStretcher::ContinueStretch(IFX_Pause* pPause) { |
| 861 return m_pStretchEngine && m_pStretchEngine->Continue(pPause); | 867 return m_pStretchEngine && m_pStretchEngine->Continue(pPause); |
| 862 } | 868 } |
| 869 |
| 863 FX_BOOL CFX_ImageStretcher::StartQuickStretch() { | 870 FX_BOOL CFX_ImageStretcher::StartQuickStretch() { |
| 864 m_bFlipX = FALSE; | |
| 865 m_bFlipY = FALSE; | |
| 866 if (m_DestWidth < 0) { | 871 if (m_DestWidth < 0) { |
| 867 m_bFlipX = TRUE; | 872 m_bFlipX = TRUE; |
| 868 m_DestWidth = -m_DestWidth; | 873 m_DestWidth = -m_DestWidth; |
| 869 } | 874 } |
| 870 if (m_DestHeight < 0) { | 875 if (m_DestHeight < 0) { |
| 871 m_bFlipY = TRUE; | 876 m_bFlipY = TRUE; |
| 872 m_DestHeight = -m_DestHeight; | 877 m_DestHeight = -m_DestHeight; |
| 873 } | 878 } |
| 874 m_LineIndex = 0; | |
| 875 uint32_t size = m_ClipRect.Width(); | 879 uint32_t size = m_ClipRect.Width(); |
| 876 if (size && m_DestBPP > (int)(INT_MAX / size)) { | 880 if (size && m_DestBPP > (int)(INT_MAX / size)) { |
| 877 return FALSE; | 881 return FALSE; |
| 878 } | 882 } |
| 879 size *= m_DestBPP; | 883 size *= m_DestBPP; |
| 880 m_pScanline = FX_Alloc(uint8_t, (size / 8 + 3) / 4 * 4); | 884 m_pScanline.reset(FX_Alloc(uint8_t, (size / 8 + 3) / 4 * 4)); |
| 881 if (m_pSource->m_pAlphaMask) { | 885 if (m_pSource->m_pAlphaMask) |
| 882 m_pMaskScanline = FX_Alloc(uint8_t, (m_ClipRect.Width() + 3) / 4 * 4); | 886 m_pMaskScanline.reset(FX_Alloc(uint8_t, (m_ClipRect.Width() + 3) / 4 * 4)); |
| 883 } | 887 |
| 884 if (m_pSource->GetWidth() * m_pSource->GetHeight() < | 888 if (SourceSizeWithinLimit(m_pSource->GetWidth(), m_pSource->GetHeight())) { |
| 885 MAX_PROGRESSIVE_STRETCH_PIXELS) { | 889 ContinueQuickStretch(nullptr); |
| 886 ContinueQuickStretch(NULL); | |
| 887 return FALSE; | 890 return FALSE; |
| 888 } | 891 } |
| 889 return TRUE; | 892 return TRUE; |
| 890 } | 893 } |
| 894 |
| 891 FX_BOOL CFX_ImageStretcher::ContinueQuickStretch(IFX_Pause* pPause) { | 895 FX_BOOL CFX_ImageStretcher::ContinueQuickStretch(IFX_Pause* pPause) { |
| 892 if (!m_pScanline) { | 896 if (!m_pScanline) |
| 893 return FALSE; | 897 return FALSE; |
| 894 } | 898 |
| 895 int result_width = m_ClipRect.Width(), result_height = m_ClipRect.Height(); | 899 int result_width = m_ClipRect.Width(); |
| 900 int result_height = m_ClipRect.Height(); |
| 896 int src_height = m_pSource->GetHeight(); | 901 int src_height = m_pSource->GetHeight(); |
| 897 for (; m_LineIndex < result_height; m_LineIndex++) { | 902 for (; m_LineIndex < result_height; m_LineIndex++) { |
| 898 int dest_y, src_y; | 903 int dest_y; |
| 904 int src_y; |
| 899 if (m_bFlipY) { | 905 if (m_bFlipY) { |
| 900 dest_y = result_height - m_LineIndex - 1; | 906 dest_y = result_height - m_LineIndex - 1; |
| 901 src_y = (m_DestHeight - (dest_y + m_ClipRect.top) - 1) * src_height / | 907 src_y = (m_DestHeight - (dest_y + m_ClipRect.top) - 1) * src_height / |
| 902 m_DestHeight; | 908 m_DestHeight; |
| 903 } else { | 909 } else { |
| 904 dest_y = m_LineIndex; | 910 dest_y = m_LineIndex; |
| 905 src_y = (dest_y + m_ClipRect.top) * src_height / m_DestHeight; | 911 src_y = (dest_y + m_ClipRect.top) * src_height / m_DestHeight; |
| 906 } | 912 } |
| 907 if (src_y >= src_height) { | 913 src_y = std::max(std::min(src_y, src_height - 1), 0); |
| 908 src_y = src_height - 1; | 914 |
| 909 } | 915 if (m_pSource->SkipToScanline(src_y, pPause)) |
| 910 if (src_y < 0) { | |
| 911 src_y = 0; | |
| 912 } | |
| 913 if (m_pSource->SkipToScanline(src_y, pPause)) { | |
| 914 return TRUE; | 916 return TRUE; |
| 915 } | 917 |
| 916 m_pSource->DownSampleScanline(src_y, m_pScanline, m_DestBPP, m_DestWidth, | 918 m_pSource->DownSampleScanline(src_y, m_pScanline.get(), m_DestBPP, |
| 917 m_bFlipX, m_ClipRect.left, result_width); | 919 m_DestWidth, m_bFlipX, m_ClipRect.left, |
| 920 result_width); |
| 918 if (m_pMaskScanline) { | 921 if (m_pMaskScanline) { |
| 919 m_pSource->m_pAlphaMask->DownSampleScanline( | 922 m_pSource->m_pAlphaMask->DownSampleScanline( |
| 920 src_y, m_pMaskScanline, 1, m_DestWidth, m_bFlipX, m_ClipRect.left, | 923 src_y, m_pMaskScanline.get(), 1, m_DestWidth, m_bFlipX, |
| 921 result_width); | 924 m_ClipRect.left, result_width); |
| 922 } | 925 } |
| 923 m_pDest->ComposeScanline(dest_y, m_pScanline, m_pMaskScanline); | 926 m_pDest->ComposeScanline(dest_y, m_pScanline.get(), m_pMaskScanline.get()); |
| 924 } | 927 } |
| 925 return FALSE; | 928 return FALSE; |
| 926 } | 929 } |
| OLD | NEW |