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 |