From 3f1c018bcc15a8e3360c4afa0c5b6b411a948f6b Mon Sep 17 00:00:00 2001 From: falkTX Date: Tue, 24 Oct 2017 09:28:12 +0200 Subject: [PATCH] Delete the rest of the juce modules --- source/modules/juce_data_structures/Makefile | 119 - .../juce_ApplicationProperties.cpp | 109 - .../juce_ApplicationProperties.h | 132 - .../app_properties/juce_PropertiesFile.cpp | 363 -- .../app_properties/juce_PropertiesFile.h | 252 - .../juce_data_structures.cpp | 44 - .../juce_data_structures.h | 64 - .../undomanager/juce_UndoManager.cpp | 352 -- .../undomanager/juce_UndoManager.h | 246 - .../undomanager/juce_UndoableAction.h | 99 - .../values/juce_CachedValue.cpp | 159 - .../values/juce_CachedValue.h | 312 - .../values/juce_Value.cpp | 242 - .../juce_data_structures/values/juce_Value.h | 243 - .../values/juce_ValueTree.cpp | 1151 ---- .../values/juce_ValueTree.h | 578 -- .../values/juce_ValueTreeSynchroniser.cpp | 242 - .../values/juce_ValueTreeSynchroniser.h | 97 - source/modules/juce_events/Makefile | 123 - .../broadcasters/juce_ActionBroadcaster.cpp | 92 - .../broadcasters/juce_ActionBroadcaster.h | 77 - .../broadcasters/juce_ActionListener.h | 46 - .../broadcasters/juce_AsyncUpdater.cpp | 93 - .../broadcasters/juce_AsyncUpdater.h | 108 - .../broadcasters/juce_ChangeBroadcaster.cpp | 99 - .../broadcasters/juce_ChangeBroadcaster.h | 101 - .../broadcasters/juce_ChangeListener.h | 61 - .../juce_ConnectedChildProcess.cpp | 267 - .../interprocess/juce_ConnectedChildProcess.h | 189 - .../juce_InterprocessConnection.cpp | 362 -- .../juce_InterprocessConnection.h | 207 - .../juce_InterprocessConnectionServer.cpp | 81 - .../juce_InterprocessConnectionServer.h | 104 - source/modules/juce_events/juce_events.cpp | 102 - source/modules/juce_events/juce_events.h | 96 - .../messages/juce_ApplicationBase.cpp | 333 -- .../messages/juce_ApplicationBase.h | 312 - .../messages/juce_CallbackMessage.h | 72 - .../messages/juce_DeletedAtShutdown.cpp | 94 - .../messages/juce_DeletedAtShutdown.h | 63 - .../messages/juce_Initialisation.h | 200 - .../juce_events/messages/juce_Message.h | 62 - .../messages/juce_MessageListener.cpp | 52 - .../messages/juce_MessageListener.h | 68 - .../messages/juce_MessageManager.cpp | 387 -- .../messages/juce_MessageManager.h | 381 -- .../juce_MountedVolumeListChangeDetector.h | 57 - .../messages/juce_NotificationType.h | 39 - .../native/juce_android_Messaging.cpp | 147 - .../native/juce_ios_MessageManager.mm | 103 - .../juce_events/native/juce_linux_EventLoop.h | 55 - .../native/juce_linux_Messaging.cpp | 265 - .../native/juce_mac_MessageManager.mm | 430 -- .../native/juce_osx_MessageQueue.h | 105 - .../native/juce_win32_HiddenMessageWindow.h | 135 - .../native/juce_win32_Messaging.cpp | 232 - .../native/juce_win32_WinRTWrapper.cpp | 26 - .../native/juce_win32_WinRTWrapper.h | 131 - .../juce_events/timers/juce_MultiTimer.cpp | 108 - .../juce_events/timers/juce_MultiTimer.h | 123 - .../modules/juce_events/timers/juce_Timer.cpp | 371 -- .../modules/juce_events/timers/juce_Timer.h | 135 - source/modules/juce_graphics/Makefile | 123 - .../juce_graphics/colour/juce_Colour.cpp | 468 -- .../juce_graphics/colour/juce_Colour.h | 367 -- .../colour/juce_ColourGradient.cpp | 244 - .../colour/juce_ColourGradient.h | 202 - .../juce_graphics/colour/juce_Colours.cpp | 335 -- .../juce_graphics/colour/juce_Colours.h | 109 - .../juce_graphics/colour/juce_FillType.cpp | 153 - .../juce_graphics/colour/juce_FillType.h | 150 - .../juce_graphics/colour/juce_PixelFormats.h | 757 --- .../contexts/juce_GraphicsContext.cpp | 699 --- .../contexts/juce_GraphicsContext.h | 746 --- .../contexts/juce_LowLevelGraphicsContext.h | 101 - ...uce_LowLevelGraphicsPostScriptRenderer.cpp | 540 -- .../juce_LowLevelGraphicsPostScriptRenderer.h | 120 - .../juce_LowLevelGraphicsSoftwareRenderer.cpp | 45 - .../juce_LowLevelGraphicsSoftwareRenderer.h | 56 - .../effects/juce_DropShadowEffect.cpp | 189 - .../effects/juce_DropShadowEffect.h | 110 - .../juce_graphics/effects/juce_GlowEffect.cpp | 58 - .../juce_graphics/effects/juce_GlowEffect.h | 75 - .../effects/juce_ImageEffectFilter.h | 70 - .../fonts/juce_AttributedString.cpp | 356 -- .../fonts/juce_AttributedString.h | 207 - .../fonts/juce_CustomTypeface.cpp | 413 -- .../juce_graphics/fonts/juce_CustomTypeface.h | 165 - .../modules/juce_graphics/fonts/juce_Font.cpp | 722 --- .../modules/juce_graphics/fonts/juce_Font.h | 478 -- .../fonts/juce_GlyphArrangement.cpp | 820 --- .../fonts/juce_GlyphArrangement.h | 327 -- .../juce_graphics/fonts/juce_TextLayout.cpp | 592 -- .../juce_graphics/fonts/juce_TextLayout.h | 195 - .../juce_graphics/fonts/juce_Typeface.cpp | 267 - .../juce_graphics/fonts/juce_Typeface.h | 161 - .../geometry/juce_AffineTransform.cpp | 269 - .../geometry/juce_AffineTransform.h | 279 - .../juce_graphics/geometry/juce_BorderSize.h | 153 - .../juce_graphics/geometry/juce_EdgeTable.cpp | 838 --- .../juce_graphics/geometry/juce_EdgeTable.h | 220 - .../juce_graphics/geometry/juce_Line.h | 428 -- .../juce_graphics/geometry/juce_Path.cpp | 1638 ------ .../juce_graphics/geometry/juce_Path.h | 833 --- .../geometry/juce_PathIterator.cpp | 286 - .../geometry/juce_PathIterator.h | 110 - .../geometry/juce_PathStrokeType.cpp | 745 --- .../geometry/juce_PathStrokeType.h | 205 - .../juce_graphics/geometry/juce_Point.h | 243 - .../juce_graphics/geometry/juce_Rectangle.h | 981 ---- .../geometry/juce_RectangleList.h | 653 --- .../juce_graphics/image_formats/jpglib/README | 385 -- .../image_formats/jpglib/cderror.h | 132 - .../jpglib/changes to libjpeg for JUCE.txt | 16 - .../image_formats/jpglib/jcapimin.c | 280 - .../image_formats/jpglib/jcapistd.c | 161 - .../image_formats/jpglib/jccoefct.c | 449 -- .../image_formats/jpglib/jccolor.c | 459 -- .../image_formats/jpglib/jcdctmgr.c | 387 -- .../image_formats/jpglib/jchuff.c | 909 --- .../image_formats/jpglib/jchuff.h | 52 - .../image_formats/jpglib/jcinit.c | 72 - .../image_formats/jpglib/jcmainct.c | 293 - .../image_formats/jpglib/jcmarker.c | 597 -- .../image_formats/jpglib/jcmaster.c | 590 -- .../image_formats/jpglib/jcomapi.c | 106 - .../image_formats/jpglib/jconfig.h | 59 - .../image_formats/jpglib/jcparam.c | 610 -- .../image_formats/jpglib/jcphuff.c | 833 --- .../image_formats/jpglib/jcprepct.c | 354 -- .../image_formats/jpglib/jcsample.c | 519 -- .../image_formats/jpglib/jctrans.c | 388 -- .../image_formats/jpglib/jdapimin.c | 395 -- .../image_formats/jpglib/jdapistd.c | 275 - .../image_formats/jpglib/jdatasrc.c | 212 - .../image_formats/jpglib/jdcoefct.c | 736 --- .../image_formats/jpglib/jdcolor.c | 396 -- .../juce_graphics/image_formats/jpglib/jdct.h | 182 - .../image_formats/jpglib/jddctmgr.c | 269 - .../image_formats/jpglib/jdhuff.c | 625 -- .../image_formats/jpglib/jdhuff.h | 206 - .../image_formats/jpglib/jdinput.c | 381 -- .../image_formats/jpglib/jdmainct.c | 512 -- .../image_formats/jpglib/jdmarker.c | 1292 ----- .../image_formats/jpglib/jdmaster.c | 557 -- .../image_formats/jpglib/jdmerge.c | 400 -- .../image_formats/jpglib/jdphuff.c | 642 --- .../image_formats/jpglib/jdpostct.c | 290 - .../image_formats/jpglib/jdsample.c | 478 -- .../image_formats/jpglib/jdtrans.c | 143 - .../image_formats/jpglib/jerror.c | 252 - .../image_formats/jpglib/jerror.h | 291 - .../image_formats/jpglib/jfdctflt.c | 168 - .../image_formats/jpglib/jfdctfst.c | 224 - .../image_formats/jpglib/jfdctint.c | 283 - .../image_formats/jpglib/jidctflt.c | 242 - .../image_formats/jpglib/jidctfst.c | 368 -- .../image_formats/jpglib/jidctint.c | 389 -- .../image_formats/jpglib/jidctred.c | 398 -- .../image_formats/jpglib/jinclude.h | 197 - .../image_formats/jpglib/jmemmgr.c | 1118 ---- .../image_formats/jpglib/jmemnobs.c | 109 - .../image_formats/jpglib/jmemsys.h | 203 - .../image_formats/jpglib/jmorecfg.h | 363 -- .../image_formats/jpglib/jpegint.h | 392 -- .../image_formats/jpglib/jpeglib.h | 1096 ---- .../image_formats/jpglib/jquant1.c | 856 --- .../image_formats/jpglib/jquant2.c | 1310 ----- .../image_formats/jpglib/jutils.c | 179 - .../image_formats/jpglib/jversion.h | 14 - .../image_formats/jpglib/transupp.c | 928 --- .../image_formats/jpglib/transupp.h | 135 - .../image_formats/juce_GIFLoader.cpp | 451 -- .../image_formats/juce_JPEGLoader.cpp | 456 -- .../image_formats/juce_PNGLoader.cpp | 605 -- .../image_formats/pnglib/LICENSE | 109 - .../image_formats/pnglib/libpng_readme.txt | 2 - .../juce_graphics/image_formats/pnglib/png.c | 4295 -------------- .../juce_graphics/image_formats/pnglib/png.h | 3292 ----------- .../image_formats/pnglib/pngconf.h | 616 -- .../image_formats/pnglib/pngerror.c | 932 --- .../image_formats/pnglib/pngget.c | 1177 ---- .../image_formats/pnglib/pnginfo.h | 260 - .../image_formats/pnglib/pngmem.c | 277 - .../image_formats/pnglib/pngpread.c | 1291 ----- .../image_formats/pnglib/pngpriv.h | 1904 ------ .../image_formats/pnglib/pngread.c | 4000 ------------- .../image_formats/pnglib/pngrio.c | 118 - .../image_formats/pnglib/pngrtran.c | 5102 ----------------- .../image_formats/pnglib/pngrutil.c | 4459 -------------- .../image_formats/pnglib/pngset.c | 1606 ------ .../image_formats/pnglib/pngstruct.h | 489 -- .../image_formats/pnglib/pngtrans.c | 830 --- .../image_formats/pnglib/pngwio.c | 164 - .../image_formats/pnglib/pngwrite.c | 2331 -------- .../image_formats/pnglib/pngwtran.c | 637 -- .../image_formats/pnglib/pngwutil.c | 3020 ---------- .../juce_graphics/images/juce_Image.cpp | 680 --- .../modules/juce_graphics/images/juce_Image.h | 547 -- .../juce_graphics/images/juce_ImageCache.cpp | 170 - .../juce_graphics/images/juce_ImageCache.h | 126 - .../images/juce_ImageConvolutionKernel.cpp | 297 - .../images/juce_ImageConvolutionKernel.h | 111 - .../images/juce_ImageFileFormat.cpp | 112 - .../images/juce_ImageFileFormat.h | 216 - .../modules/juce_graphics/juce_graphics.cpp | 181 - source/modules/juce_graphics/juce_graphics.h | 147 - .../native/juce_RenderingHelpers.h | 2690 --------- .../native/juce_android_Fonts.cpp | 409 -- .../native/juce_android_GraphicsContext.cpp | 67 - .../native/juce_android_IconHelpers.cpp | 30 - .../native/juce_freetype_Fonts.cpp | 462 -- .../juce_graphics/native/juce_linux_Fonts.cpp | 197 - .../native/juce_linux_IconHelpers.cpp | 30 - .../native/juce_mac_CoreGraphicsContext.h | 115 - .../native/juce_mac_CoreGraphicsContext.mm | 923 --- .../native/juce_mac_CoreGraphicsHelpers.h | 65 - .../juce_graphics/native/juce_mac_Fonts.mm | 1252 ---- .../native/juce_mac_IconHelpers.cpp | 150 - .../juce_win32_Direct2DGraphicsContext.cpp | 830 --- .../juce_win32_Direct2DGraphicsContext.h | 106 - .../juce_win32_DirectWriteTypeLayout.cpp | 460 -- .../native/juce_win32_DirectWriteTypeface.cpp | 327 -- .../juce_graphics/native/juce_win32_Fonts.cpp | 651 --- .../native/juce_win32_IconHelpers.cpp | 30 - .../placement/juce_Justification.h | 190 - .../placement/juce_RectanglePlacement.cpp | 134 - .../placement/juce_RectanglePlacement.h | 173 - source/modules/juce_gui_basics/Makefile | 123 - .../application/juce_Application.cpp | 105 - .../application/juce_Application.h | 192 - .../buttons/juce_ArrowButton.cpp | 52 - .../buttons/juce_ArrowButton.h | 64 - .../juce_gui_basics/buttons/juce_Button.cpp | 699 --- .../juce_gui_basics/buttons/juce_Button.h | 522 -- .../buttons/juce_DrawableButton.cpp | 226 - .../buttons/juce_DrawableButton.h | 191 - .../buttons/juce_HyperlinkButton.cpp | 116 - .../buttons/juce_HyperlinkButton.h | 115 - .../buttons/juce_ImageButton.cpp | 199 - .../buttons/juce_ImageButton.h | 160 - .../buttons/juce_ShapeButton.cpp | 136 - .../buttons/juce_ShapeButton.h | 125 - .../buttons/juce_TextButton.cpp | 78 - .../juce_gui_basics/buttons/juce_TextButton.h | 113 - .../buttons/juce_ToggleButton.cpp | 61 - .../buttons/juce_ToggleButton.h | 89 - .../buttons/juce_ToolbarButton.cpp | 114 - .../buttons/juce_ToolbarButton.h | 97 - .../commands/juce_ApplicationCommandID.h | 91 - .../commands/juce_ApplicationCommandInfo.cpp | 67 - .../commands/juce_ApplicationCommandInfo.h | 189 - .../juce_ApplicationCommandManager.cpp | 319 -- .../commands/juce_ApplicationCommandManager.h | 352 -- .../juce_ApplicationCommandTarget.cpp | 187 - .../commands/juce_ApplicationCommandTarget.h | 243 - .../commands/juce_KeyPressMappingSet.cpp | 419 -- .../commands/juce_KeyPressMappingSet.h | 245 - .../components/juce_CachedComponentImage.h | 71 - .../components/juce_Component.cpp | 3046 ---------- .../components/juce_Component.h | 2376 -------- .../components/juce_ComponentListener.cpp | 38 - .../components/juce_ComponentListener.h | 111 - .../components/juce_Desktop.cpp | 432 -- .../juce_gui_basics/components/juce_Desktop.h | 474 -- .../components/juce_ModalComponentManager.cpp | 318 - .../components/juce_ModalComponentManager.h | 374 -- .../drawables/juce_Drawable.cpp | 282 - .../juce_gui_basics/drawables/juce_Drawable.h | 285 - .../drawables/juce_DrawableComposite.cpp | 334 -- .../drawables/juce_DrawableComposite.h | 163 - .../drawables/juce_DrawableImage.cpp | 302 - .../drawables/juce_DrawableImage.h | 140 - .../drawables/juce_DrawablePath.cpp | 577 -- .../drawables/juce_DrawablePath.h | 145 - .../drawables/juce_DrawableRectangle.cpp | 190 - .../drawables/juce_DrawableRectangle.h | 103 - .../drawables/juce_DrawableShape.cpp | 503 -- .../drawables/juce_DrawableShape.h | 191 - .../drawables/juce_DrawableText.cpp | 379 -- .../drawables/juce_DrawableText.h | 159 - .../drawables/juce_SVGParser.cpp | 1735 ------ ...juce_DirectoryContentsDisplayComponent.cpp | 71 - .../juce_DirectoryContentsDisplayComponent.h | 114 - .../juce_DirectoryContentsList.cpp | 265 - .../filebrowser/juce_DirectoryContentsList.h | 223 - .../filebrowser/juce_FileBrowserComponent.cpp | 613 -- .../filebrowser/juce_FileBrowserComponent.h | 289 - .../filebrowser/juce_FileBrowserListener.h | 57 - .../filebrowser/juce_FileChooser.cpp | 157 - .../filebrowser/juce_FileChooser.h | 205 - .../filebrowser/juce_FileChooserDialogBox.cpp | 276 - .../filebrowser/juce_FileChooserDialogBox.h | 157 - .../filebrowser/juce_FileListComponent.cpp | 262 - .../filebrowser/juce_FileListComponent.h | 93 - .../filebrowser/juce_FilePreviewComponent.h | 65 - .../juce_FileSearchPathListComponent.cpp | 273 - .../juce_FileSearchPathListComponent.h | 116 - .../filebrowser/juce_FileTreeComponent.cpp | 328 -- .../filebrowser/juce_FileTreeComponent.h | 104 - .../filebrowser/juce_FilenameComponent.cpp | 275 - .../filebrowser/juce_FilenameComponent.h | 233 - .../juce_ImagePreviewComponent.cpp | 121 - .../filebrowser/juce_ImagePreviewComponent.h | 66 - .../juce_gui_basics/juce_gui_basics.cpp | 313 - .../modules/juce_gui_basics/juce_gui_basics.h | 306 - .../keyboard/juce_CaretComponent.cpp | 65 - .../keyboard/juce_CaretComponent.h | 80 - .../keyboard/juce_KeyListener.cpp | 35 - .../keyboard/juce_KeyListener.h | 76 - .../keyboard/juce_KeyPress.cpp | 309 - .../juce_gui_basics/keyboard/juce_KeyPress.h | 273 - .../keyboard/juce_KeyboardFocusTraverser.cpp | 134 - .../keyboard/juce_KeyboardFocusTraverser.h | 89 - .../keyboard/juce_ModifierKeys.cpp | 58 - .../keyboard/juce_ModifierKeys.h | 223 - .../keyboard/juce_SystemClipboard.h | 48 - .../keyboard/juce_TextEditorKeyMapper.h | 122 - .../keyboard/juce_TextInputTarget.h | 95 - .../layout/juce_AnimatedPosition.h | 209 - .../layout/juce_AnimatedPositionBehaviours.h | 157 - .../layout/juce_ComponentAnimator.cpp | 345 -- .../layout/juce_ComponentAnimator.h | 161 - .../juce_ComponentBoundsConstrainer.cpp | 297 - .../layout/juce_ComponentBoundsConstrainer.h | 196 - .../layout/juce_ComponentBuilder.cpp | 288 - .../layout/juce_ComponentBuilder.h | 246 - .../layout/juce_ComponentMovementWatcher.cpp | 146 - .../layout/juce_ComponentMovementWatcher.h | 95 - .../layout/juce_ConcertinaPanel.cpp | 458 -- .../layout/juce_ConcertinaPanel.h | 145 - .../juce_gui_basics/layout/juce_FlexBox.cpp | 858 --- .../juce_gui_basics/layout/juce_FlexBox.h | 108 - .../juce_gui_basics/layout/juce_FlexItem.h | 167 - .../juce_gui_basics/layout/juce_Grid.cpp | 1029 ---- .../juce_gui_basics/layout/juce_Grid.h | 182 - .../juce_gui_basics/layout/juce_GridItem.cpp | 186 - .../juce_gui_basics/layout/juce_GridItem.h | 227 - .../layout/juce_GridUnitTests.cpp | 262 - .../layout/juce_GroupComponent.cpp | 73 - .../layout/juce_GroupComponent.h | 111 - .../layout/juce_MultiDocumentPanel.cpp | 514 -- .../layout/juce_MultiDocumentPanel.h | 305 - .../layout/juce_ResizableBorderComponent.cpp | 208 - .../layout/juce_ResizableBorderComponent.h | 195 - .../layout/juce_ResizableCornerComponent.cpp | 106 - .../layout/juce_ResizableCornerComponent.h | 91 - .../layout/juce_ResizableEdgeComponent.cpp | 114 - .../layout/juce_ResizableEdgeComponent.h | 99 - .../juce_gui_basics/layout/juce_ScrollBar.cpp | 435 -- .../juce_gui_basics/layout/juce_ScrollBar.h | 406 -- .../layout/juce_StretchableLayoutManager.cpp | 349 -- .../layout/juce_StretchableLayoutManager.h | 260 - .../juce_StretchableLayoutResizerBar.cpp | 80 - .../layout/juce_StretchableLayoutResizerBar.h | 104 - .../layout/juce_StretchableObjectResizer.cpp | 123 - .../layout/juce_StretchableObjectResizer.h | 101 - .../layout/juce_TabbedButtonBar.cpp | 592 -- .../layout/juce_TabbedButtonBar.h | 371 -- .../layout/juce_TabbedComponent.cpp | 321 -- .../layout/juce_TabbedComponent.h | 225 - .../juce_gui_basics/layout/juce_Viewport.cpp | 593 -- .../juce_gui_basics/layout/juce_Viewport.h | 317 - .../lookandfeel/juce_LookAndFeel.cpp | 154 - .../lookandfeel/juce_LookAndFeel.h | 232 - .../lookandfeel/juce_LookAndFeel_V1.cpp | 574 -- .../lookandfeel/juce_LookAndFeel_V1.h | 102 - .../lookandfeel/juce_LookAndFeel_V2.cpp | 3025 ---------- .../lookandfeel/juce_LookAndFeel_V2.h | 377 -- .../lookandfeel/juce_LookAndFeel_V3.cpp | 644 --- .../lookandfeel/juce_LookAndFeel_V3.h | 97 - .../lookandfeel/juce_LookAndFeel_V4.cpp | 1447 ----- .../lookandfeel/juce_LookAndFeel_V4.h | 242 - .../menus/juce_MenuBarComponent.cpp | 359 -- .../menus/juce_MenuBarComponent.h | 119 - .../menus/juce_MenuBarModel.cpp | 100 - .../juce_gui_basics/menus/juce_MenuBarModel.h | 193 - .../juce_gui_basics/menus/juce_PopupMenu.cpp | 1866 ------ .../juce_gui_basics/menus/juce_PopupMenu.h | 754 --- .../misc/juce_BubbleComponent.cpp | 151 - .../misc/juce_BubbleComponent.h | 185 - .../misc/juce_DropShadower.cpp | 223 - .../juce_gui_basics/misc/juce_DropShadower.h | 80 - .../mouse/juce_ComponentDragger.cpp | 68 - .../mouse/juce_ComponentDragger.h | 100 - .../mouse/juce_DragAndDropContainer.cpp | 533 -- .../mouse/juce_DragAndDropContainer.h | 216 - .../mouse/juce_DragAndDropTarget.h | 153 - .../mouse/juce_FileDragAndDropTarget.h | 105 - .../mouse/juce_LassoComponent.h | 223 - .../mouse/juce_MouseCursor.cpp | 220 - .../juce_gui_basics/mouse/juce_MouseCursor.h | 182 - .../juce_gui_basics/mouse/juce_MouseEvent.cpp | 143 - .../juce_gui_basics/mouse/juce_MouseEvent.h | 442 -- .../mouse/juce_MouseInactivityDetector.cpp | 77 - .../mouse/juce_MouseInactivityDetector.h | 111 - .../mouse/juce_MouseInputSource.cpp | 755 --- .../mouse/juce_MouseInputSource.h | 256 - .../mouse/juce_MouseListener.cpp | 39 - .../mouse/juce_MouseListener.h | 165 - .../mouse/juce_SelectedItemSet.h | 323 -- .../mouse/juce_TextDragAndDropTarget.h | 105 - .../mouse/juce_TooltipClient.h | 85 - .../native/juce_MultiTouchMapper.h | 79 - .../native/juce_android_FileChooser.cpp | 52 - .../native/juce_android_Windowing.cpp | 1070 ---- .../native/juce_ios_UIViewComponentPeer.mm | 1175 ---- .../native/juce_ios_Windowing.mm | 483 -- .../native/juce_linux_FileChooser.cpp | 213 - .../juce_gui_basics/native/juce_linux_X11.cpp | 340 -- .../juce_gui_basics/native/juce_linux_X11.h | 139 - .../native/juce_linux_X11_Clipboard.cpp | 280 - .../native/juce_linux_X11_Windowing.cpp | 4366 -------------- .../native/juce_mac_FileChooser.mm | 280 - .../native/juce_mac_MainMenu.mm | 802 --- .../native/juce_mac_MouseCursor.mm | 214 - .../native/juce_mac_NSViewComponentPeer.mm | 2201 ------- .../native/juce_mac_Windowing.mm | 619 -- .../native/juce_win32_DragAndDrop.cpp | 289 - .../native/juce_win32_FileChooser.cpp | 303 - .../native/juce_win32_Windowing.cpp | 4202 -------------- .../positioning/juce_MarkerList.cpp | 285 - .../positioning/juce_MarkerList.h | 184 - .../positioning/juce_RelativeCoordinate.cpp | 154 - .../positioning/juce_RelativeCoordinate.h | 179 - .../juce_RelativeCoordinatePositioner.cpp | 324 -- .../juce_RelativeCoordinatePositioner.h | 92 - .../juce_RelativeParallelogram.cpp | 141 - .../positioning/juce_RelativeParallelogram.h | 65 - .../positioning/juce_RelativePoint.cpp | 102 - .../positioning/juce_RelativePoint.h | 90 - .../positioning/juce_RelativePointPath.cpp | 299 - .../positioning/juce_RelativePointPath.h | 191 - .../positioning/juce_RelativeRectangle.cpp | 269 - .../positioning/juce_RelativeRectangle.h | 107 - .../juce_BooleanPropertyComponent.cpp | 92 - .../juce_BooleanPropertyComponent.h | 111 - .../juce_ButtonPropertyComponent.cpp | 53 - .../properties/juce_ButtonPropertyComponent.h | 78 - .../juce_ChoicePropertyComponent.cpp | 159 - .../properties/juce_ChoicePropertyComponent.h | 123 - .../properties/juce_PropertyComponent.cpp | 57 - .../properties/juce_PropertyComponent.h | 143 - .../properties/juce_PropertyPanel.cpp | 381 -- .../properties/juce_PropertyPanel.h | 177 - .../juce_SliderPropertyComponent.cpp | 89 - .../properties/juce_SliderPropertyComponent.h | 109 - .../properties/juce_TextPropertyComponent.cpp | 188 - .../properties/juce_TextPropertyComponent.h | 157 - .../juce_gui_basics/widgets/juce_ComboBox.cpp | 658 --- .../juce_gui_basics/widgets/juce_ComboBox.h | 452 -- .../widgets/juce_ImageComponent.cpp | 84 - .../widgets/juce_ImageComponent.h | 78 - .../juce_gui_basics/widgets/juce_Label.cpp | 479 -- .../juce_gui_basics/widgets/juce_Label.h | 355 -- .../juce_gui_basics/widgets/juce_ListBox.cpp | 957 ---- .../juce_gui_basics/widgets/juce_ListBox.h | 602 -- .../widgets/juce_ProgressBar.cpp | 118 - .../widgets/juce_ProgressBar.h | 142 - .../juce_gui_basics/widgets/juce_Slider.cpp | 1633 ------ .../juce_gui_basics/widgets/juce_Slider.h | 946 --- .../widgets/juce_TableHeaderComponent.cpp | 900 --- .../widgets/juce_TableHeaderComponent.h | 459 -- .../widgets/juce_TableListBox.cpp | 488 -- .../widgets/juce_TableListBox.h | 349 -- .../widgets/juce_TextEditor.cpp | 2493 -------- .../juce_gui_basics/widgets/juce_TextEditor.h | 775 --- .../juce_gui_basics/widgets/juce_Toolbar.cpp | 818 --- .../juce_gui_basics/widgets/juce_Toolbar.h | 331 -- .../widgets/juce_ToolbarItemComponent.cpp | 242 - .../widgets/juce_ToolbarItemComponent.h | 205 - .../widgets/juce_ToolbarItemFactory.h | 108 - .../widgets/juce_ToolbarItemPalette.cpp | 113 - .../widgets/juce_ToolbarItemPalette.h | 76 - .../juce_gui_basics/widgets/juce_TreeView.cpp | 1912 ------ .../juce_gui_basics/widgets/juce_TreeView.h | 939 --- .../windows/juce_AlertWindow.cpp | 698 --- .../windows/juce_AlertWindow.h | 490 -- .../windows/juce_CallOutBox.cpp | 267 - .../juce_gui_basics/windows/juce_CallOutBox.h | 186 - .../windows/juce_ComponentPeer.cpp | 581 -- .../windows/juce_ComponentPeer.h | 382 -- .../windows/juce_DialogWindow.cpp | 175 - .../windows/juce_DialogWindow.h | 266 - .../windows/juce_DocumentWindow.cpp | 361 -- .../windows/juce_DocumentWindow.h | 295 - .../windows/juce_NativeMessageBox.h | 220 - .../windows/juce_ResizableWindow.cpp | 628 -- .../windows/juce_ResizableWindow.h | 410 -- .../windows/juce_ThreadWithProgressWindow.cpp | 121 - .../windows/juce_ThreadWithProgressWindow.h | 174 - .../windows/juce_TooltipWindow.cpp | 182 - .../windows/juce_TooltipWindow.h | 144 - .../windows/juce_TopLevelWindow.cpp | 351 -- .../windows/juce_TopLevelWindow.h | 164 - source/modules/juce_gui_extra/Makefile | 119 - .../juce_CPlusPlusCodeTokeniser.cpp | 75 - .../code_editor/juce_CPlusPlusCodeTokeniser.h | 71 - .../juce_CPlusPlusCodeTokeniserFunctions.h | 665 --- .../code_editor/juce_CodeDocument.cpp | 997 ---- .../code_editor/juce_CodeDocument.h | 418 -- .../code_editor/juce_CodeEditorComponent.cpp | 1649 ------ .../code_editor/juce_CodeEditorComponent.h | 435 -- .../code_editor/juce_CodeTokeniser.h | 58 - .../code_editor/juce_LuaCodeTokeniser.cpp | 240 - .../code_editor/juce_LuaCodeTokeniser.h | 64 - .../code_editor/juce_XMLCodeTokeniser.cpp | 173 - .../code_editor/juce_XMLCodeTokeniser.h | 62 - .../documents/juce_FileBasedDocument.cpp | 266 - .../documents/juce_FileBasedDocument.h | 294 - .../embedding/juce_ActiveXControlComponent.h | 128 - .../embedding/juce_NSViewComponent.h | 90 - .../embedding/juce_UIViewComponent.h | 89 - .../embedding/juce_XEmbedComponent.h | 114 - .../modules/juce_gui_extra/juce_gui_extra.cpp | 160 - .../modules/juce_gui_extra/juce_gui_extra.h | 99 - .../misc/juce_AnimatedAppComponent.cpp | 55 - .../misc/juce_AnimatedAppComponent.h | 76 - .../juce_gui_extra/misc/juce_AppleRemote.h | 116 - .../misc/juce_BubbleMessageComponent.cpp | 125 - .../misc/juce_BubbleMessageComponent.h | 130 - .../misc/juce_ColourSelector.cpp | 575 -- .../juce_gui_extra/misc/juce_ColourSelector.h | 171 - .../misc/juce_KeyMappingEditorComponent.cpp | 475 -- .../misc/juce_KeyMappingEditorComponent.h | 134 - .../misc/juce_LiveConstantEditor.cpp | 507 -- .../misc/juce_LiveConstantEditor.h | 314 - .../misc/juce_PreferencesPanel.cpp | 157 - .../misc/juce_PreferencesPanel.h | 147 - .../misc/juce_RecentlyOpenedFilesList.cpp | 152 - .../misc/juce_RecentlyOpenedFilesList.h | 164 - .../juce_gui_extra/misc/juce_SplashScreen.cpp | 102 - .../juce_gui_extra/misc/juce_SplashScreen.h | 155 - .../misc/juce_SystemTrayIconComponent.cpp | 43 - .../misc/juce_SystemTrayIconComponent.h | 105 - .../misc/juce_WebBrowserComponent.h | 154 - .../juce_android_WebBrowserComponent.cpp | 128 - .../native/juce_ios_UIViewComponent.mm | 133 - .../native/juce_linux_X11_SystemTrayIcon.cpp | 149 - .../juce_linux_X11_WebBrowserComponent.cpp | 827 --- .../native/juce_linux_XEmbedComponent.cpp | 685 --- .../native/juce_mac_AppleRemote.mm | 269 - .../juce_mac_CarbonViewWrapperComponent.h | 345 -- .../native/juce_mac_NSViewComponent.mm | 247 - .../native/juce_mac_SystemTrayIcon.cpp | 281 - .../native/juce_mac_WebBrowserComponent.mm | 491 -- .../native/juce_win32_ActiveXComponent.cpp | 458 -- .../native/juce_win32_SystemTrayIcon.cpp | 243 - .../native/juce_win32_WebBrowserComponent.cpp | 439 -- 549 files changed, 216474 deletions(-) delete mode 100644 source/modules/juce_data_structures/Makefile delete mode 100644 source/modules/juce_data_structures/app_properties/juce_ApplicationProperties.cpp delete mode 100644 source/modules/juce_data_structures/app_properties/juce_ApplicationProperties.h delete mode 100644 source/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp delete mode 100644 source/modules/juce_data_structures/app_properties/juce_PropertiesFile.h delete mode 100644 source/modules/juce_data_structures/juce_data_structures.cpp delete mode 100644 source/modules/juce_data_structures/juce_data_structures.h delete mode 100644 source/modules/juce_data_structures/undomanager/juce_UndoManager.cpp delete mode 100644 source/modules/juce_data_structures/undomanager/juce_UndoManager.h delete mode 100644 source/modules/juce_data_structures/undomanager/juce_UndoableAction.h delete mode 100644 source/modules/juce_data_structures/values/juce_CachedValue.cpp delete mode 100644 source/modules/juce_data_structures/values/juce_CachedValue.h delete mode 100644 source/modules/juce_data_structures/values/juce_Value.cpp delete mode 100644 source/modules/juce_data_structures/values/juce_Value.h delete mode 100644 source/modules/juce_data_structures/values/juce_ValueTree.cpp delete mode 100644 source/modules/juce_data_structures/values/juce_ValueTree.h delete mode 100644 source/modules/juce_data_structures/values/juce_ValueTreeSynchroniser.cpp delete mode 100644 source/modules/juce_data_structures/values/juce_ValueTreeSynchroniser.h delete mode 100644 source/modules/juce_events/Makefile delete mode 100644 source/modules/juce_events/broadcasters/juce_ActionBroadcaster.cpp delete mode 100644 source/modules/juce_events/broadcasters/juce_ActionBroadcaster.h delete mode 100644 source/modules/juce_events/broadcasters/juce_ActionListener.h delete mode 100644 source/modules/juce_events/broadcasters/juce_AsyncUpdater.cpp delete mode 100644 source/modules/juce_events/broadcasters/juce_AsyncUpdater.h delete mode 100644 source/modules/juce_events/broadcasters/juce_ChangeBroadcaster.cpp delete mode 100644 source/modules/juce_events/broadcasters/juce_ChangeBroadcaster.h delete mode 100644 source/modules/juce_events/broadcasters/juce_ChangeListener.h delete mode 100644 source/modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp delete mode 100644 source/modules/juce_events/interprocess/juce_ConnectedChildProcess.h delete mode 100644 source/modules/juce_events/interprocess/juce_InterprocessConnection.cpp delete mode 100644 source/modules/juce_events/interprocess/juce_InterprocessConnection.h delete mode 100644 source/modules/juce_events/interprocess/juce_InterprocessConnectionServer.cpp delete mode 100644 source/modules/juce_events/interprocess/juce_InterprocessConnectionServer.h delete mode 100644 source/modules/juce_events/juce_events.cpp delete mode 100644 source/modules/juce_events/juce_events.h delete mode 100644 source/modules/juce_events/messages/juce_ApplicationBase.cpp delete mode 100644 source/modules/juce_events/messages/juce_ApplicationBase.h delete mode 100644 source/modules/juce_events/messages/juce_CallbackMessage.h delete mode 100644 source/modules/juce_events/messages/juce_DeletedAtShutdown.cpp delete mode 100644 source/modules/juce_events/messages/juce_DeletedAtShutdown.h delete mode 100644 source/modules/juce_events/messages/juce_Initialisation.h delete mode 100644 source/modules/juce_events/messages/juce_Message.h delete mode 100644 source/modules/juce_events/messages/juce_MessageListener.cpp delete mode 100644 source/modules/juce_events/messages/juce_MessageListener.h delete mode 100644 source/modules/juce_events/messages/juce_MessageManager.cpp delete mode 100644 source/modules/juce_events/messages/juce_MessageManager.h delete mode 100644 source/modules/juce_events/messages/juce_MountedVolumeListChangeDetector.h delete mode 100644 source/modules/juce_events/messages/juce_NotificationType.h delete mode 100644 source/modules/juce_events/native/juce_android_Messaging.cpp delete mode 100644 source/modules/juce_events/native/juce_ios_MessageManager.mm delete mode 100644 source/modules/juce_events/native/juce_linux_EventLoop.h delete mode 100644 source/modules/juce_events/native/juce_linux_Messaging.cpp delete mode 100644 source/modules/juce_events/native/juce_mac_MessageManager.mm delete mode 100644 source/modules/juce_events/native/juce_osx_MessageQueue.h delete mode 100644 source/modules/juce_events/native/juce_win32_HiddenMessageWindow.h delete mode 100644 source/modules/juce_events/native/juce_win32_Messaging.cpp delete mode 100644 source/modules/juce_events/native/juce_win32_WinRTWrapper.cpp delete mode 100644 source/modules/juce_events/native/juce_win32_WinRTWrapper.h delete mode 100644 source/modules/juce_events/timers/juce_MultiTimer.cpp delete mode 100644 source/modules/juce_events/timers/juce_MultiTimer.h delete mode 100644 source/modules/juce_events/timers/juce_Timer.cpp delete mode 100644 source/modules/juce_events/timers/juce_Timer.h delete mode 100644 source/modules/juce_graphics/Makefile delete mode 100644 source/modules/juce_graphics/colour/juce_Colour.cpp delete mode 100644 source/modules/juce_graphics/colour/juce_Colour.h delete mode 100644 source/modules/juce_graphics/colour/juce_ColourGradient.cpp delete mode 100644 source/modules/juce_graphics/colour/juce_ColourGradient.h delete mode 100644 source/modules/juce_graphics/colour/juce_Colours.cpp delete mode 100644 source/modules/juce_graphics/colour/juce_Colours.h delete mode 100644 source/modules/juce_graphics/colour/juce_FillType.cpp delete mode 100644 source/modules/juce_graphics/colour/juce_FillType.h delete mode 100644 source/modules/juce_graphics/colour/juce_PixelFormats.h delete mode 100644 source/modules/juce_graphics/contexts/juce_GraphicsContext.cpp delete mode 100644 source/modules/juce_graphics/contexts/juce_GraphicsContext.h delete mode 100644 source/modules/juce_graphics/contexts/juce_LowLevelGraphicsContext.h delete mode 100644 source/modules/juce_graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp delete mode 100644 source/modules/juce_graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.h delete mode 100644 source/modules/juce_graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp delete mode 100644 source/modules/juce_graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.h delete mode 100644 source/modules/juce_graphics/effects/juce_DropShadowEffect.cpp delete mode 100644 source/modules/juce_graphics/effects/juce_DropShadowEffect.h delete mode 100644 source/modules/juce_graphics/effects/juce_GlowEffect.cpp delete mode 100644 source/modules/juce_graphics/effects/juce_GlowEffect.h delete mode 100644 source/modules/juce_graphics/effects/juce_ImageEffectFilter.h delete mode 100644 source/modules/juce_graphics/fonts/juce_AttributedString.cpp delete mode 100644 source/modules/juce_graphics/fonts/juce_AttributedString.h delete mode 100644 source/modules/juce_graphics/fonts/juce_CustomTypeface.cpp delete mode 100644 source/modules/juce_graphics/fonts/juce_CustomTypeface.h delete mode 100644 source/modules/juce_graphics/fonts/juce_Font.cpp delete mode 100644 source/modules/juce_graphics/fonts/juce_Font.h delete mode 100644 source/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp delete mode 100644 source/modules/juce_graphics/fonts/juce_GlyphArrangement.h delete mode 100644 source/modules/juce_graphics/fonts/juce_TextLayout.cpp delete mode 100644 source/modules/juce_graphics/fonts/juce_TextLayout.h delete mode 100644 source/modules/juce_graphics/fonts/juce_Typeface.cpp delete mode 100644 source/modules/juce_graphics/fonts/juce_Typeface.h delete mode 100644 source/modules/juce_graphics/geometry/juce_AffineTransform.cpp delete mode 100644 source/modules/juce_graphics/geometry/juce_AffineTransform.h delete mode 100644 source/modules/juce_graphics/geometry/juce_BorderSize.h delete mode 100644 source/modules/juce_graphics/geometry/juce_EdgeTable.cpp delete mode 100644 source/modules/juce_graphics/geometry/juce_EdgeTable.h delete mode 100644 source/modules/juce_graphics/geometry/juce_Line.h delete mode 100644 source/modules/juce_graphics/geometry/juce_Path.cpp delete mode 100644 source/modules/juce_graphics/geometry/juce_Path.h delete mode 100644 source/modules/juce_graphics/geometry/juce_PathIterator.cpp delete mode 100644 source/modules/juce_graphics/geometry/juce_PathIterator.h delete mode 100644 source/modules/juce_graphics/geometry/juce_PathStrokeType.cpp delete mode 100644 source/modules/juce_graphics/geometry/juce_PathStrokeType.h delete mode 100644 source/modules/juce_graphics/geometry/juce_Point.h delete mode 100644 source/modules/juce_graphics/geometry/juce_Rectangle.h delete mode 100644 source/modules/juce_graphics/geometry/juce_RectangleList.h delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/README delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/cderror.h delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/changes to libjpeg for JUCE.txt delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jcapimin.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jcapistd.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jccoefct.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jccolor.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jcdctmgr.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jchuff.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jchuff.h delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jcinit.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jcmainct.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jcmarker.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jcmaster.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jcomapi.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jconfig.h delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jcparam.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jcphuff.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jcprepct.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jcsample.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jctrans.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jdapimin.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jdapistd.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jdatasrc.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jdcoefct.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jdcolor.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jdct.h delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jddctmgr.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jdhuff.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jdhuff.h delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jdinput.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jdmainct.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jdmarker.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jdmaster.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jdmerge.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jdphuff.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jdpostct.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jdsample.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jdtrans.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jerror.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jerror.h delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jfdctflt.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jfdctfst.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jfdctint.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jidctflt.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jidctfst.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jidctint.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jidctred.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jinclude.h delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jmemmgr.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jmemnobs.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jmemsys.h delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jmorecfg.h delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jpegint.h delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jpeglib.h delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jquant1.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jquant2.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jutils.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/jversion.h delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/transupp.c delete mode 100644 source/modules/juce_graphics/image_formats/jpglib/transupp.h delete mode 100644 source/modules/juce_graphics/image_formats/juce_GIFLoader.cpp delete mode 100644 source/modules/juce_graphics/image_formats/juce_JPEGLoader.cpp delete mode 100644 source/modules/juce_graphics/image_formats/juce_PNGLoader.cpp delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/LICENSE delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/libpng_readme.txt delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/png.c delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/png.h delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pngconf.h delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pngerror.c delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pngget.c delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pnginfo.h delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pngmem.c delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pngpread.c delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pngpriv.h delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pngread.c delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pngrio.c delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pngrtran.c delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pngrutil.c delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pngset.c delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pngstruct.h delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pngtrans.c delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pngwio.c delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pngwrite.c delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pngwtran.c delete mode 100644 source/modules/juce_graphics/image_formats/pnglib/pngwutil.c delete mode 100644 source/modules/juce_graphics/images/juce_Image.cpp delete mode 100644 source/modules/juce_graphics/images/juce_Image.h delete mode 100644 source/modules/juce_graphics/images/juce_ImageCache.cpp delete mode 100644 source/modules/juce_graphics/images/juce_ImageCache.h delete mode 100644 source/modules/juce_graphics/images/juce_ImageConvolutionKernel.cpp delete mode 100644 source/modules/juce_graphics/images/juce_ImageConvolutionKernel.h delete mode 100644 source/modules/juce_graphics/images/juce_ImageFileFormat.cpp delete mode 100644 source/modules/juce_graphics/images/juce_ImageFileFormat.h delete mode 100644 source/modules/juce_graphics/juce_graphics.cpp delete mode 100644 source/modules/juce_graphics/juce_graphics.h delete mode 100644 source/modules/juce_graphics/native/juce_RenderingHelpers.h delete mode 100644 source/modules/juce_graphics/native/juce_android_Fonts.cpp delete mode 100644 source/modules/juce_graphics/native/juce_android_GraphicsContext.cpp delete mode 100644 source/modules/juce_graphics/native/juce_android_IconHelpers.cpp delete mode 100644 source/modules/juce_graphics/native/juce_freetype_Fonts.cpp delete mode 100644 source/modules/juce_graphics/native/juce_linux_Fonts.cpp delete mode 100644 source/modules/juce_graphics/native/juce_linux_IconHelpers.cpp delete mode 100644 source/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h delete mode 100644 source/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm delete mode 100644 source/modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h delete mode 100644 source/modules/juce_graphics/native/juce_mac_Fonts.mm delete mode 100644 source/modules/juce_graphics/native/juce_mac_IconHelpers.cpp delete mode 100644 source/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp delete mode 100644 source/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.h delete mode 100644 source/modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp delete mode 100644 source/modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp delete mode 100644 source/modules/juce_graphics/native/juce_win32_Fonts.cpp delete mode 100644 source/modules/juce_graphics/native/juce_win32_IconHelpers.cpp delete mode 100644 source/modules/juce_graphics/placement/juce_Justification.h delete mode 100644 source/modules/juce_graphics/placement/juce_RectanglePlacement.cpp delete mode 100644 source/modules/juce_graphics/placement/juce_RectanglePlacement.h delete mode 100644 source/modules/juce_gui_basics/Makefile delete mode 100644 source/modules/juce_gui_basics/application/juce_Application.cpp delete mode 100644 source/modules/juce_gui_basics/application/juce_Application.h delete mode 100644 source/modules/juce_gui_basics/buttons/juce_ArrowButton.cpp delete mode 100644 source/modules/juce_gui_basics/buttons/juce_ArrowButton.h delete mode 100644 source/modules/juce_gui_basics/buttons/juce_Button.cpp delete mode 100644 source/modules/juce_gui_basics/buttons/juce_Button.h delete mode 100644 source/modules/juce_gui_basics/buttons/juce_DrawableButton.cpp delete mode 100644 source/modules/juce_gui_basics/buttons/juce_DrawableButton.h delete mode 100644 source/modules/juce_gui_basics/buttons/juce_HyperlinkButton.cpp delete mode 100644 source/modules/juce_gui_basics/buttons/juce_HyperlinkButton.h delete mode 100644 source/modules/juce_gui_basics/buttons/juce_ImageButton.cpp delete mode 100644 source/modules/juce_gui_basics/buttons/juce_ImageButton.h delete mode 100644 source/modules/juce_gui_basics/buttons/juce_ShapeButton.cpp delete mode 100644 source/modules/juce_gui_basics/buttons/juce_ShapeButton.h delete mode 100644 source/modules/juce_gui_basics/buttons/juce_TextButton.cpp delete mode 100644 source/modules/juce_gui_basics/buttons/juce_TextButton.h delete mode 100644 source/modules/juce_gui_basics/buttons/juce_ToggleButton.cpp delete mode 100644 source/modules/juce_gui_basics/buttons/juce_ToggleButton.h delete mode 100644 source/modules/juce_gui_basics/buttons/juce_ToolbarButton.cpp delete mode 100644 source/modules/juce_gui_basics/buttons/juce_ToolbarButton.h delete mode 100644 source/modules/juce_gui_basics/commands/juce_ApplicationCommandID.h delete mode 100644 source/modules/juce_gui_basics/commands/juce_ApplicationCommandInfo.cpp delete mode 100644 source/modules/juce_gui_basics/commands/juce_ApplicationCommandInfo.h delete mode 100644 source/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp delete mode 100644 source/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.h delete mode 100644 source/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.cpp delete mode 100644 source/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.h delete mode 100644 source/modules/juce_gui_basics/commands/juce_KeyPressMappingSet.cpp delete mode 100644 source/modules/juce_gui_basics/commands/juce_KeyPressMappingSet.h delete mode 100644 source/modules/juce_gui_basics/components/juce_CachedComponentImage.h delete mode 100644 source/modules/juce_gui_basics/components/juce_Component.cpp delete mode 100644 source/modules/juce_gui_basics/components/juce_Component.h delete mode 100644 source/modules/juce_gui_basics/components/juce_ComponentListener.cpp delete mode 100644 source/modules/juce_gui_basics/components/juce_ComponentListener.h delete mode 100644 source/modules/juce_gui_basics/components/juce_Desktop.cpp delete mode 100644 source/modules/juce_gui_basics/components/juce_Desktop.h delete mode 100644 source/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp delete mode 100644 source/modules/juce_gui_basics/components/juce_ModalComponentManager.h delete mode 100644 source/modules/juce_gui_basics/drawables/juce_Drawable.cpp delete mode 100644 source/modules/juce_gui_basics/drawables/juce_Drawable.h delete mode 100644 source/modules/juce_gui_basics/drawables/juce_DrawableComposite.cpp delete mode 100644 source/modules/juce_gui_basics/drawables/juce_DrawableComposite.h delete mode 100644 source/modules/juce_gui_basics/drawables/juce_DrawableImage.cpp delete mode 100644 source/modules/juce_gui_basics/drawables/juce_DrawableImage.h delete mode 100644 source/modules/juce_gui_basics/drawables/juce_DrawablePath.cpp delete mode 100644 source/modules/juce_gui_basics/drawables/juce_DrawablePath.h delete mode 100644 source/modules/juce_gui_basics/drawables/juce_DrawableRectangle.cpp delete mode 100644 source/modules/juce_gui_basics/drawables/juce_DrawableRectangle.h delete mode 100644 source/modules/juce_gui_basics/drawables/juce_DrawableShape.cpp delete mode 100644 source/modules/juce_gui_basics/drawables/juce_DrawableShape.h delete mode 100644 source/modules/juce_gui_basics/drawables/juce_DrawableText.cpp delete mode 100644 source/modules/juce_gui_basics/drawables/juce_DrawableText.h delete mode 100644 source/modules/juce_gui_basics/drawables/juce_SVGParser.cpp delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsDisplayComponent.cpp delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsDisplayComponent.h delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsList.cpp delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsList.h delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.cpp delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.h delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_FileBrowserListener.h delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_FileChooser.h delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.cpp delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.h delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_FileListComponent.cpp delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_FileListComponent.h delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_FilePreviewComponent.h delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_FileSearchPathListComponent.cpp delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_FileSearchPathListComponent.h delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_FileTreeComponent.cpp delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_FileTreeComponent.h delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_FilenameComponent.cpp delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_FilenameComponent.h delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_ImagePreviewComponent.cpp delete mode 100644 source/modules/juce_gui_basics/filebrowser/juce_ImagePreviewComponent.h delete mode 100644 source/modules/juce_gui_basics/juce_gui_basics.cpp delete mode 100644 source/modules/juce_gui_basics/juce_gui_basics.h delete mode 100644 source/modules/juce_gui_basics/keyboard/juce_CaretComponent.cpp delete mode 100644 source/modules/juce_gui_basics/keyboard/juce_CaretComponent.h delete mode 100644 source/modules/juce_gui_basics/keyboard/juce_KeyListener.cpp delete mode 100644 source/modules/juce_gui_basics/keyboard/juce_KeyListener.h delete mode 100644 source/modules/juce_gui_basics/keyboard/juce_KeyPress.cpp delete mode 100644 source/modules/juce_gui_basics/keyboard/juce_KeyPress.h delete mode 100644 source/modules/juce_gui_basics/keyboard/juce_KeyboardFocusTraverser.cpp delete mode 100644 source/modules/juce_gui_basics/keyboard/juce_KeyboardFocusTraverser.h delete mode 100644 source/modules/juce_gui_basics/keyboard/juce_ModifierKeys.cpp delete mode 100644 source/modules/juce_gui_basics/keyboard/juce_ModifierKeys.h delete mode 100644 source/modules/juce_gui_basics/keyboard/juce_SystemClipboard.h delete mode 100644 source/modules/juce_gui_basics/keyboard/juce_TextEditorKeyMapper.h delete mode 100644 source/modules/juce_gui_basics/keyboard/juce_TextInputTarget.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_AnimatedPosition.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_AnimatedPositionBehaviours.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_ComponentAnimator.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_ComponentBoundsConstrainer.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_ComponentBoundsConstrainer.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_ComponentBuilder.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_ComponentBuilder.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_ComponentMovementWatcher.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_ComponentMovementWatcher.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_ConcertinaPanel.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_ConcertinaPanel.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_FlexBox.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_FlexBox.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_FlexItem.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_Grid.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_Grid.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_GridItem.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_GridItem.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_GridUnitTests.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_GroupComponent.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_GroupComponent.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_MultiDocumentPanel.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_MultiDocumentPanel.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_ResizableBorderComponent.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_ResizableBorderComponent.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_ResizableCornerComponent.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_ResizableCornerComponent.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_ResizableEdgeComponent.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_ResizableEdgeComponent.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_ScrollBar.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_ScrollBar.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_StretchableLayoutManager.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_StretchableLayoutManager.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_StretchableLayoutResizerBar.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_StretchableLayoutResizerBar.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_StretchableObjectResizer.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_StretchableObjectResizer.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_TabbedButtonBar.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_TabbedButtonBar.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_TabbedComponent.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_TabbedComponent.h delete mode 100644 source/modules/juce_gui_basics/layout/juce_Viewport.cpp delete mode 100644 source/modules/juce_gui_basics/layout/juce_Viewport.h delete mode 100644 source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel.cpp delete mode 100644 source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel.h delete mode 100644 source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V1.cpp delete mode 100644 source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V1.h delete mode 100644 source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp delete mode 100644 source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h delete mode 100644 source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V3.cpp delete mode 100644 source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V3.h delete mode 100644 source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V4.cpp delete mode 100644 source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V4.h delete mode 100644 source/modules/juce_gui_basics/menus/juce_MenuBarComponent.cpp delete mode 100644 source/modules/juce_gui_basics/menus/juce_MenuBarComponent.h delete mode 100644 source/modules/juce_gui_basics/menus/juce_MenuBarModel.cpp delete mode 100644 source/modules/juce_gui_basics/menus/juce_MenuBarModel.h delete mode 100644 source/modules/juce_gui_basics/menus/juce_PopupMenu.cpp delete mode 100644 source/modules/juce_gui_basics/menus/juce_PopupMenu.h delete mode 100644 source/modules/juce_gui_basics/misc/juce_BubbleComponent.cpp delete mode 100644 source/modules/juce_gui_basics/misc/juce_BubbleComponent.h delete mode 100644 source/modules/juce_gui_basics/misc/juce_DropShadower.cpp delete mode 100644 source/modules/juce_gui_basics/misc/juce_DropShadower.h delete mode 100644 source/modules/juce_gui_basics/mouse/juce_ComponentDragger.cpp delete mode 100644 source/modules/juce_gui_basics/mouse/juce_ComponentDragger.h delete mode 100644 source/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp delete mode 100644 source/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.h delete mode 100644 source/modules/juce_gui_basics/mouse/juce_DragAndDropTarget.h delete mode 100644 source/modules/juce_gui_basics/mouse/juce_FileDragAndDropTarget.h delete mode 100644 source/modules/juce_gui_basics/mouse/juce_LassoComponent.h delete mode 100644 source/modules/juce_gui_basics/mouse/juce_MouseCursor.cpp delete mode 100644 source/modules/juce_gui_basics/mouse/juce_MouseCursor.h delete mode 100644 source/modules/juce_gui_basics/mouse/juce_MouseEvent.cpp delete mode 100644 source/modules/juce_gui_basics/mouse/juce_MouseEvent.h delete mode 100644 source/modules/juce_gui_basics/mouse/juce_MouseInactivityDetector.cpp delete mode 100644 source/modules/juce_gui_basics/mouse/juce_MouseInactivityDetector.h delete mode 100644 source/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp delete mode 100644 source/modules/juce_gui_basics/mouse/juce_MouseInputSource.h delete mode 100644 source/modules/juce_gui_basics/mouse/juce_MouseListener.cpp delete mode 100644 source/modules/juce_gui_basics/mouse/juce_MouseListener.h delete mode 100644 source/modules/juce_gui_basics/mouse/juce_SelectedItemSet.h delete mode 100644 source/modules/juce_gui_basics/mouse/juce_TextDragAndDropTarget.h delete mode 100644 source/modules/juce_gui_basics/mouse/juce_TooltipClient.h delete mode 100644 source/modules/juce_gui_basics/native/juce_MultiTouchMapper.h delete mode 100644 source/modules/juce_gui_basics/native/juce_android_FileChooser.cpp delete mode 100644 source/modules/juce_gui_basics/native/juce_android_Windowing.cpp delete mode 100644 source/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm delete mode 100644 source/modules/juce_gui_basics/native/juce_ios_Windowing.mm delete mode 100644 source/modules/juce_gui_basics/native/juce_linux_FileChooser.cpp delete mode 100644 source/modules/juce_gui_basics/native/juce_linux_X11.cpp delete mode 100644 source/modules/juce_gui_basics/native/juce_linux_X11.h delete mode 100644 source/modules/juce_gui_basics/native/juce_linux_X11_Clipboard.cpp delete mode 100644 source/modules/juce_gui_basics/native/juce_linux_X11_Windowing.cpp delete mode 100644 source/modules/juce_gui_basics/native/juce_mac_FileChooser.mm delete mode 100644 source/modules/juce_gui_basics/native/juce_mac_MainMenu.mm delete mode 100644 source/modules/juce_gui_basics/native/juce_mac_MouseCursor.mm delete mode 100644 source/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm delete mode 100644 source/modules/juce_gui_basics/native/juce_mac_Windowing.mm delete mode 100644 source/modules/juce_gui_basics/native/juce_win32_DragAndDrop.cpp delete mode 100644 source/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp delete mode 100644 source/modules/juce_gui_basics/native/juce_win32_Windowing.cpp delete mode 100644 source/modules/juce_gui_basics/positioning/juce_MarkerList.cpp delete mode 100644 source/modules/juce_gui_basics/positioning/juce_MarkerList.h delete mode 100644 source/modules/juce_gui_basics/positioning/juce_RelativeCoordinate.cpp delete mode 100644 source/modules/juce_gui_basics/positioning/juce_RelativeCoordinate.h delete mode 100644 source/modules/juce_gui_basics/positioning/juce_RelativeCoordinatePositioner.cpp delete mode 100644 source/modules/juce_gui_basics/positioning/juce_RelativeCoordinatePositioner.h delete mode 100644 source/modules/juce_gui_basics/positioning/juce_RelativeParallelogram.cpp delete mode 100644 source/modules/juce_gui_basics/positioning/juce_RelativeParallelogram.h delete mode 100644 source/modules/juce_gui_basics/positioning/juce_RelativePoint.cpp delete mode 100644 source/modules/juce_gui_basics/positioning/juce_RelativePoint.h delete mode 100644 source/modules/juce_gui_basics/positioning/juce_RelativePointPath.cpp delete mode 100644 source/modules/juce_gui_basics/positioning/juce_RelativePointPath.h delete mode 100644 source/modules/juce_gui_basics/positioning/juce_RelativeRectangle.cpp delete mode 100644 source/modules/juce_gui_basics/positioning/juce_RelativeRectangle.h delete mode 100644 source/modules/juce_gui_basics/properties/juce_BooleanPropertyComponent.cpp delete mode 100644 source/modules/juce_gui_basics/properties/juce_BooleanPropertyComponent.h delete mode 100644 source/modules/juce_gui_basics/properties/juce_ButtonPropertyComponent.cpp delete mode 100644 source/modules/juce_gui_basics/properties/juce_ButtonPropertyComponent.h delete mode 100644 source/modules/juce_gui_basics/properties/juce_ChoicePropertyComponent.cpp delete mode 100644 source/modules/juce_gui_basics/properties/juce_ChoicePropertyComponent.h delete mode 100644 source/modules/juce_gui_basics/properties/juce_PropertyComponent.cpp delete mode 100644 source/modules/juce_gui_basics/properties/juce_PropertyComponent.h delete mode 100644 source/modules/juce_gui_basics/properties/juce_PropertyPanel.cpp delete mode 100644 source/modules/juce_gui_basics/properties/juce_PropertyPanel.h delete mode 100644 source/modules/juce_gui_basics/properties/juce_SliderPropertyComponent.cpp delete mode 100644 source/modules/juce_gui_basics/properties/juce_SliderPropertyComponent.h delete mode 100644 source/modules/juce_gui_basics/properties/juce_TextPropertyComponent.cpp delete mode 100644 source/modules/juce_gui_basics/properties/juce_TextPropertyComponent.h delete mode 100644 source/modules/juce_gui_basics/widgets/juce_ComboBox.cpp delete mode 100644 source/modules/juce_gui_basics/widgets/juce_ComboBox.h delete mode 100644 source/modules/juce_gui_basics/widgets/juce_ImageComponent.cpp delete mode 100644 source/modules/juce_gui_basics/widgets/juce_ImageComponent.h delete mode 100644 source/modules/juce_gui_basics/widgets/juce_Label.cpp delete mode 100644 source/modules/juce_gui_basics/widgets/juce_Label.h delete mode 100644 source/modules/juce_gui_basics/widgets/juce_ListBox.cpp delete mode 100644 source/modules/juce_gui_basics/widgets/juce_ListBox.h delete mode 100644 source/modules/juce_gui_basics/widgets/juce_ProgressBar.cpp delete mode 100644 source/modules/juce_gui_basics/widgets/juce_ProgressBar.h delete mode 100644 source/modules/juce_gui_basics/widgets/juce_Slider.cpp delete mode 100644 source/modules/juce_gui_basics/widgets/juce_Slider.h delete mode 100644 source/modules/juce_gui_basics/widgets/juce_TableHeaderComponent.cpp delete mode 100644 source/modules/juce_gui_basics/widgets/juce_TableHeaderComponent.h delete mode 100644 source/modules/juce_gui_basics/widgets/juce_TableListBox.cpp delete mode 100644 source/modules/juce_gui_basics/widgets/juce_TableListBox.h delete mode 100644 source/modules/juce_gui_basics/widgets/juce_TextEditor.cpp delete mode 100644 source/modules/juce_gui_basics/widgets/juce_TextEditor.h delete mode 100644 source/modules/juce_gui_basics/widgets/juce_Toolbar.cpp delete mode 100644 source/modules/juce_gui_basics/widgets/juce_Toolbar.h delete mode 100644 source/modules/juce_gui_basics/widgets/juce_ToolbarItemComponent.cpp delete mode 100644 source/modules/juce_gui_basics/widgets/juce_ToolbarItemComponent.h delete mode 100644 source/modules/juce_gui_basics/widgets/juce_ToolbarItemFactory.h delete mode 100644 source/modules/juce_gui_basics/widgets/juce_ToolbarItemPalette.cpp delete mode 100644 source/modules/juce_gui_basics/widgets/juce_ToolbarItemPalette.h delete mode 100644 source/modules/juce_gui_basics/widgets/juce_TreeView.cpp delete mode 100644 source/modules/juce_gui_basics/widgets/juce_TreeView.h delete mode 100644 source/modules/juce_gui_basics/windows/juce_AlertWindow.cpp delete mode 100644 source/modules/juce_gui_basics/windows/juce_AlertWindow.h delete mode 100644 source/modules/juce_gui_basics/windows/juce_CallOutBox.cpp delete mode 100644 source/modules/juce_gui_basics/windows/juce_CallOutBox.h delete mode 100644 source/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp delete mode 100644 source/modules/juce_gui_basics/windows/juce_ComponentPeer.h delete mode 100644 source/modules/juce_gui_basics/windows/juce_DialogWindow.cpp delete mode 100644 source/modules/juce_gui_basics/windows/juce_DialogWindow.h delete mode 100644 source/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp delete mode 100644 source/modules/juce_gui_basics/windows/juce_DocumentWindow.h delete mode 100644 source/modules/juce_gui_basics/windows/juce_NativeMessageBox.h delete mode 100644 source/modules/juce_gui_basics/windows/juce_ResizableWindow.cpp delete mode 100644 source/modules/juce_gui_basics/windows/juce_ResizableWindow.h delete mode 100644 source/modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.cpp delete mode 100644 source/modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.h delete mode 100644 source/modules/juce_gui_basics/windows/juce_TooltipWindow.cpp delete mode 100644 source/modules/juce_gui_basics/windows/juce_TooltipWindow.h delete mode 100644 source/modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp delete mode 100644 source/modules/juce_gui_basics/windows/juce_TopLevelWindow.h delete mode 100644 source/modules/juce_gui_extra/Makefile delete mode 100644 source/modules/juce_gui_extra/code_editor/juce_CPlusPlusCodeTokeniser.cpp delete mode 100644 source/modules/juce_gui_extra/code_editor/juce_CPlusPlusCodeTokeniser.h delete mode 100644 source/modules/juce_gui_extra/code_editor/juce_CPlusPlusCodeTokeniserFunctions.h delete mode 100644 source/modules/juce_gui_extra/code_editor/juce_CodeDocument.cpp delete mode 100644 source/modules/juce_gui_extra/code_editor/juce_CodeDocument.h delete mode 100644 source/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp delete mode 100644 source/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.h delete mode 100644 source/modules/juce_gui_extra/code_editor/juce_CodeTokeniser.h delete mode 100644 source/modules/juce_gui_extra/code_editor/juce_LuaCodeTokeniser.cpp delete mode 100644 source/modules/juce_gui_extra/code_editor/juce_LuaCodeTokeniser.h delete mode 100644 source/modules/juce_gui_extra/code_editor/juce_XMLCodeTokeniser.cpp delete mode 100644 source/modules/juce_gui_extra/code_editor/juce_XMLCodeTokeniser.h delete mode 100644 source/modules/juce_gui_extra/documents/juce_FileBasedDocument.cpp delete mode 100644 source/modules/juce_gui_extra/documents/juce_FileBasedDocument.h delete mode 100644 source/modules/juce_gui_extra/embedding/juce_ActiveXControlComponent.h delete mode 100644 source/modules/juce_gui_extra/embedding/juce_NSViewComponent.h delete mode 100644 source/modules/juce_gui_extra/embedding/juce_UIViewComponent.h delete mode 100644 source/modules/juce_gui_extra/embedding/juce_XEmbedComponent.h delete mode 100644 source/modules/juce_gui_extra/juce_gui_extra.cpp delete mode 100644 source/modules/juce_gui_extra/juce_gui_extra.h delete mode 100644 source/modules/juce_gui_extra/misc/juce_AnimatedAppComponent.cpp delete mode 100644 source/modules/juce_gui_extra/misc/juce_AnimatedAppComponent.h delete mode 100644 source/modules/juce_gui_extra/misc/juce_AppleRemote.h delete mode 100644 source/modules/juce_gui_extra/misc/juce_BubbleMessageComponent.cpp delete mode 100644 source/modules/juce_gui_extra/misc/juce_BubbleMessageComponent.h delete mode 100644 source/modules/juce_gui_extra/misc/juce_ColourSelector.cpp delete mode 100644 source/modules/juce_gui_extra/misc/juce_ColourSelector.h delete mode 100644 source/modules/juce_gui_extra/misc/juce_KeyMappingEditorComponent.cpp delete mode 100644 source/modules/juce_gui_extra/misc/juce_KeyMappingEditorComponent.h delete mode 100644 source/modules/juce_gui_extra/misc/juce_LiveConstantEditor.cpp delete mode 100644 source/modules/juce_gui_extra/misc/juce_LiveConstantEditor.h delete mode 100644 source/modules/juce_gui_extra/misc/juce_PreferencesPanel.cpp delete mode 100644 source/modules/juce_gui_extra/misc/juce_PreferencesPanel.h delete mode 100644 source/modules/juce_gui_extra/misc/juce_RecentlyOpenedFilesList.cpp delete mode 100644 source/modules/juce_gui_extra/misc/juce_RecentlyOpenedFilesList.h delete mode 100644 source/modules/juce_gui_extra/misc/juce_SplashScreen.cpp delete mode 100644 source/modules/juce_gui_extra/misc/juce_SplashScreen.h delete mode 100644 source/modules/juce_gui_extra/misc/juce_SystemTrayIconComponent.cpp delete mode 100644 source/modules/juce_gui_extra/misc/juce_SystemTrayIconComponent.h delete mode 100644 source/modules/juce_gui_extra/misc/juce_WebBrowserComponent.h delete mode 100644 source/modules/juce_gui_extra/native/juce_android_WebBrowserComponent.cpp delete mode 100644 source/modules/juce_gui_extra/native/juce_ios_UIViewComponent.mm delete mode 100644 source/modules/juce_gui_extra/native/juce_linux_X11_SystemTrayIcon.cpp delete mode 100644 source/modules/juce_gui_extra/native/juce_linux_X11_WebBrowserComponent.cpp delete mode 100644 source/modules/juce_gui_extra/native/juce_linux_XEmbedComponent.cpp delete mode 100644 source/modules/juce_gui_extra/native/juce_mac_AppleRemote.mm delete mode 100644 source/modules/juce_gui_extra/native/juce_mac_CarbonViewWrapperComponent.h delete mode 100644 source/modules/juce_gui_extra/native/juce_mac_NSViewComponent.mm delete mode 100644 source/modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp delete mode 100644 source/modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm delete mode 100644 source/modules/juce_gui_extra/native/juce_win32_ActiveXComponent.cpp delete mode 100644 source/modules/juce_gui_extra/native/juce_win32_SystemTrayIcon.cpp delete mode 100644 source/modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp diff --git a/source/modules/juce_data_structures/Makefile b/source/modules/juce_data_structures/Makefile deleted file mode 100644 index 999b49d1b..000000000 --- a/source/modules/juce_data_structures/Makefile +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/make -f -# Makefile for juce_data_structures # -# --------------------------------- # -# Created by falkTX -# - -CWD=../.. -MODULENAME=juce_data_structures -include ../Makefile.mk - -# ---------------------------------------------------------------------------------------------------------------------------- - -BUILD_CXX_FLAGS += $(JUCE_DATA_STRUCTURES_FLAGS) -I.. - -# ---------------------------------------------------------------------------------------------------------------------------- - -ifeq ($(MACOS),true) -OBJS = $(OBJDIR)/$(MODULENAME).mm.o -OBJS_posix32 = $(OBJDIR)/$(MODULENAME).mm.posix32.o -OBJS_posix64 = $(OBJDIR)/$(MODULENAME).mm.posix64.o -else -OBJS = $(OBJDIR)/$(MODULENAME).cpp.o -OBJS_posix32 = $(OBJDIR)/$(MODULENAME).cpp.posix32.o -OBJS_posix64 = $(OBJDIR)/$(MODULENAME).cpp.posix64.o -endif -OBJS_win32 = $(OBJDIR)/$(MODULENAME).cpp.win32.o -OBJS_win64 = $(OBJDIR)/$(MODULENAME).cpp.win64.o - -# ---------------------------------------------------------------------------------------------------------------------------- - -all: $(MODULEDIR)/$(MODULENAME).a -posix32: $(MODULEDIR)/$(MODULENAME).posix32.a -posix64: $(MODULEDIR)/$(MODULENAME).posix64.a -win32: $(MODULEDIR)/$(MODULENAME).win32.a -win64: $(MODULEDIR)/$(MODULENAME).win64.a - -# ---------------------------------------------------------------------------------------------------------------------------- - -clean: - rm -f $(OBJDIR)/*.o $(MODULEDIR)/$(MODULENAME)*.a - -debug: - $(MAKE) DEBUG=true - -# ---------------------------------------------------------------------------------------------------------------------------- - -$(MODULEDIR)/$(MODULENAME).a: $(OBJS) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).posix32.a: $(OBJS_posix32) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).posix32.a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).posix64.a: $(OBJS_posix64) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).posix64.a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).win32.a: $(OBJS_win32) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).win32.a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).win64.a: $(OBJS_win64) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).win64.a" - @rm -f $@ - @$(AR) crs $@ $^ - -# ---------------------------------------------------------------------------------------------------------------------------- - -$(OBJDIR)/$(MODULENAME).cpp.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $<" - @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ - -$(OBJDIR)/$(MODULENAME).cpp.%32.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (32bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -c -o $@ - -$(OBJDIR)/$(MODULENAME).cpp.%64.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (64bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -c -o $@ - -# ---------------------------------------------------------------------------------------------------------------------------- - -$(OBJDIR)/$(MODULENAME).mm.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $<" - @$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ - -$(OBJDIR)/$(MODULENAME).mm.%32.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (32bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -ObjC++ -c -o $@ - -$(OBJDIR)/$(MODULENAME).mm.%64.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (64bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -ObjC++ -c -o $@ - -# ---------------------------------------------------------------------------------------------------------------------------- - --include $(OBJS:%.o=%.d) --include $(OBJS_posix32:%.o=%.d) --include $(OBJS_posix64:%.o=%.d) --include $(OBJS_win32:%.o=%.d) --include $(OBJS_win64:%.o=%.d) - -# ---------------------------------------------------------------------------------------------------------------------------- diff --git a/source/modules/juce_data_structures/app_properties/juce_ApplicationProperties.cpp b/source/modules/juce_data_structures/app_properties/juce_ApplicationProperties.cpp deleted file mode 100644 index eca113fb4..000000000 --- a/source/modules/juce_data_structures/app_properties/juce_ApplicationProperties.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -ApplicationProperties::ApplicationProperties() - : commonSettingsAreReadOnly (0) -{ -} - -ApplicationProperties::~ApplicationProperties() -{ - closeFiles(); -} - -//============================================================================== -void ApplicationProperties::setStorageParameters (const PropertiesFile::Options& newOptions) -{ - options = newOptions; -} - -//============================================================================== -void ApplicationProperties::openFiles() -{ - // You need to call setStorageParameters() before trying to get hold of the properties! - jassert (options.applicationName.isNotEmpty()); - - if (options.applicationName.isNotEmpty()) - { - PropertiesFile::Options o (options); - - if (userProps == nullptr) - { - o.commonToAllUsers = false; - userProps = new PropertiesFile (o); - } - - if (commonProps == nullptr) - { - o.commonToAllUsers = true; - commonProps = new PropertiesFile (o); - } - - userProps->setFallbackPropertySet (commonProps); - } -} - -PropertiesFile* ApplicationProperties::getUserSettings() -{ - if (userProps == nullptr) - openFiles(); - - return userProps; -} - -PropertiesFile* ApplicationProperties::getCommonSettings (const bool returnUserPropsIfReadOnly) -{ - if (commonProps == nullptr) - openFiles(); - - if (returnUserPropsIfReadOnly) - { - if (commonSettingsAreReadOnly == 0) - commonSettingsAreReadOnly = commonProps->save() ? -1 : 1; - - if (commonSettingsAreReadOnly > 0) - return userProps; - } - - return commonProps; -} - -bool ApplicationProperties::saveIfNeeded() -{ - return (userProps == nullptr || userProps->saveIfNeeded()) - && (commonProps == nullptr || commonProps->saveIfNeeded()); -} - -void ApplicationProperties::closeFiles() -{ - userProps = nullptr; - commonProps = nullptr; -} - -} // namespace juce diff --git a/source/modules/juce_data_structures/app_properties/juce_ApplicationProperties.h b/source/modules/juce_data_structures/app_properties/juce_ApplicationProperties.h deleted file mode 100644 index faa3817c4..000000000 --- a/source/modules/juce_data_structures/app_properties/juce_ApplicationProperties.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Manages a collection of properties. - - This is a slightly higher-level wrapper for managing PropertiesFile objects. - - It holds two different PropertiesFile objects internally, one for user-specific - settings (stored in your user directory), and one for settings that are common to - all users (stored in a folder accessible to all users). - - The class manages the creation of these files on-demand, allowing access via the - getUserSettings() and getCommonSettings() methods. - - After creating an instance of an ApplicationProperties object, you should first - of all call setStorageParameters() to tell it the parameters to use to create - its files. - - @see PropertiesFile -*/ -class JUCE_API ApplicationProperties -{ -public: - //============================================================================== - /** - Creates an ApplicationProperties object. - - Before using it, you must call setStorageParameters() to give it the info - it needs to create the property files. - */ - ApplicationProperties(); - - /** Destructor. */ - ~ApplicationProperties(); - - //============================================================================== - /** Gives the object the information it needs to create the appropriate properties files. - See the PropertiesFile::Options class for details about what options you need to set. - */ - void setStorageParameters (const PropertiesFile::Options& options); - - /** Returns the current storage parameters. - @see setStorageParameters - */ - const PropertiesFile::Options& getStorageParameters() const noexcept { return options; } - - //============================================================================== - /** Returns the user settings file. - - The first time this is called, it will create and load the properties file. - - Note that when you search the user PropertiesFile for a value that it doesn't contain, - the common settings are used as a second-chance place to look. This is done via the - PropertySet::setFallbackPropertySet() method - by default the common settings are set - to the fallback for the user settings. - - @see getCommonSettings - */ - PropertiesFile* getUserSettings(); - - /** Returns the common settings file. - - The first time this is called, it will create and load the properties file. - - @param returnUserPropsIfReadOnly if this is true, and the common properties file is - read-only (e.g. because the user doesn't have permission to write - to shared files), then this will return the user settings instead, - (like getUserSettings() would do). This is handy if you'd like to - write a value to the common settings, but if that's no possible, - then you'd rather write to the user settings than none at all. - If returnUserPropsIfReadOnly is false, this method will always return - the common settings, even if any changes to them can't be saved. - @see getUserSettings - */ - PropertiesFile* getCommonSettings (bool returnUserPropsIfReadOnly); - - //============================================================================== - /** Saves both files if they need to be saved. - - @see PropertiesFile::saveIfNeeded - */ - bool saveIfNeeded(); - - /** Flushes and closes both files if they are open. - - This flushes any pending changes to disk with PropertiesFile::saveIfNeeded() - and closes both files. They will then be re-opened the next time getUserSettings() - or getCommonSettings() is called. - */ - void closeFiles(); - - -private: - //============================================================================== - PropertiesFile::Options options; - ScopedPointer userProps, commonProps; - int commonSettingsAreReadOnly; - - void openFiles(); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ApplicationProperties) -}; - -} // namespace juce diff --git a/source/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp b/source/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp deleted file mode 100644 index d964fb9cd..000000000 --- a/source/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp +++ /dev/null @@ -1,363 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -namespace PropertyFileConstants -{ - JUCE_CONSTEXPR static const int magicNumber = (int) ByteOrder::littleEndianInt ('P', 'R', 'O', 'P'); - JUCE_CONSTEXPR static const int magicNumberCompressed = (int) ByteOrder::littleEndianInt ('C', 'P', 'R', 'P'); - - JUCE_CONSTEXPR static const char* const fileTag = "PROPERTIES"; - JUCE_CONSTEXPR static const char* const valueTag = "VALUE"; - JUCE_CONSTEXPR static const char* const nameAttribute = "name"; - JUCE_CONSTEXPR static const char* const valueAttribute = "val"; -} - -//============================================================================== -PropertiesFile::Options::Options() - : commonToAllUsers (false), - ignoreCaseOfKeyNames (false), - doNotSave (false), - millisecondsBeforeSaving (3000), - storageFormat (PropertiesFile::storeAsXML), - processLock (nullptr) -{ -} - -File PropertiesFile::Options::getDefaultFile() const -{ - // mustn't have illegal characters in this name.. - jassert (applicationName == File::createLegalFileName (applicationName)); - - #if JUCE_MAC || JUCE_IOS - File dir (commonToAllUsers ? "/Library/" - : "~/Library/"); - - if (osxLibrarySubFolder != "Preferences" && ! osxLibrarySubFolder.startsWith ("Application Support")) - { - /* The PropertiesFile class always used to put its settings files in "Library/Preferences", but Apple - have changed their advice, and now stipulate that settings should go in "Library/Application Support". - - Because older apps would be broken by a silent change in this class's behaviour, you must now - explicitly set the osxLibrarySubFolder value to indicate which path you want to use. - - In newer apps, you should always set this to "Application Support" - or "Application Support/YourSubFolderName". - - If your app needs to load settings files that were created by older versions of juce and - you want to maintain backwards-compatibility, then you can set this to "Preferences". - But.. for better Apple-compliance, the recommended approach would be to write some code that - finds your old settings files in ~/Library/Preferences, moves them to ~/Library/Application Support, - and then uses the new path. - */ - jassertfalse; - - dir = dir.getChildFile ("Application Support"); - } - else - { - dir = dir.getChildFile (osxLibrarySubFolder); - } - - if (folderName.isNotEmpty()) - dir = dir.getChildFile (folderName); - - #elif JUCE_LINUX || JUCE_ANDROID - const File dir (File (commonToAllUsers ? "/var" : "~") - .getChildFile (folderName.isNotEmpty() ? folderName - : ("." + applicationName))); - - #elif JUCE_WINDOWS - File dir (File::getSpecialLocation (commonToAllUsers ? File::commonApplicationDataDirectory - : File::userApplicationDataDirectory)); - - if (dir == File()) - return {}; - - dir = dir.getChildFile (folderName.isNotEmpty() ? folderName - : applicationName); - #endif - - return (filenameSuffix.startsWithChar (L'.') - ? dir.getChildFile (applicationName).withFileExtension (filenameSuffix) - : dir.getChildFile (applicationName + "." + filenameSuffix)); -} - - -//============================================================================== -PropertiesFile::PropertiesFile (const File& f, const Options& o) - : PropertySet (o.ignoreCaseOfKeyNames), - file (f), options (o), - loadedOk (false), needsWriting (false) -{ - reload(); -} - -PropertiesFile::PropertiesFile (const Options& o) - : PropertySet (o.ignoreCaseOfKeyNames), - file (o.getDefaultFile()), options (o), - loadedOk (false), needsWriting (false) -{ - reload(); -} - -bool PropertiesFile::reload() -{ - ProcessScopedLock pl (createProcessLock()); - - if (pl != nullptr && ! pl->isLocked()) - return false; // locking failure.. - - loadedOk = (! file.exists()) || loadAsBinary() || loadAsXml(); - return loadedOk; -} - -PropertiesFile::~PropertiesFile() -{ - saveIfNeeded(); -} - -InterProcessLock::ScopedLockType* PropertiesFile::createProcessLock() const -{ - return options.processLock != nullptr ? new InterProcessLock::ScopedLockType (*options.processLock) : nullptr; -} - -bool PropertiesFile::saveIfNeeded() -{ - const ScopedLock sl (getLock()); - return (! needsWriting) || save(); -} - -bool PropertiesFile::needsToBeSaved() const -{ - const ScopedLock sl (getLock()); - return needsWriting; -} - -void PropertiesFile::setNeedsToBeSaved (const bool needsToBeSaved_) -{ - const ScopedLock sl (getLock()); - needsWriting = needsToBeSaved_; -} - -bool PropertiesFile::save() -{ - const ScopedLock sl (getLock()); - - stopTimer(); - - if (options.doNotSave - || file == File() - || file.isDirectory() - || ! file.getParentDirectory().createDirectory()) - return false; - - if (options.storageFormat == storeAsXML) - return saveAsXml(); - - return saveAsBinary(); -} - -bool PropertiesFile::loadAsXml() -{ - XmlDocument parser (file); - ScopedPointer doc (parser.getDocumentElement (true)); - - if (doc != nullptr && doc->hasTagName (PropertyFileConstants::fileTag)) - { - doc = parser.getDocumentElement(); - - if (doc != nullptr) - { - forEachXmlChildElementWithTagName (*doc, e, PropertyFileConstants::valueTag) - { - const String name (e->getStringAttribute (PropertyFileConstants::nameAttribute)); - - if (name.isNotEmpty()) - { - getAllProperties().set (name, - e->getFirstChildElement() != nullptr - ? e->getFirstChildElement()->createDocument ("", true) - : e->getStringAttribute (PropertyFileConstants::valueAttribute)); - } - } - - return true; - } - - // must be a pretty broken XML file we're trying to parse here, - // or a sign that this object needs an InterProcessLock, - // or just a failure reading the file. This last reason is why - // we don't jassertfalse here. - } - - return false; -} - -bool PropertiesFile::saveAsXml() -{ - XmlElement doc (PropertyFileConstants::fileTag); - const StringPairArray& props = getAllProperties(); - - for (int i = 0; i < props.size(); ++i) - { - XmlElement* const e = doc.createNewChildElement (PropertyFileConstants::valueTag); - e->setAttribute (PropertyFileConstants::nameAttribute, props.getAllKeys() [i]); - - // if the value seems to contain xml, store it as such.. - if (XmlElement* const childElement = XmlDocument::parse (props.getAllValues() [i])) - e->addChildElement (childElement); - else - e->setAttribute (PropertyFileConstants::valueAttribute, props.getAllValues() [i]); - } - - ProcessScopedLock pl (createProcessLock()); - - if (pl != nullptr && ! pl->isLocked()) - return false; // locking failure.. - - if (doc.writeToFile (file, String())) - { - needsWriting = false; - return true; - } - - return false; -} - -bool PropertiesFile::loadAsBinary() -{ - FileInputStream fileStream (file); - - if (fileStream.openedOk()) - { - const int magicNumber = fileStream.readInt(); - - if (magicNumber == PropertyFileConstants::magicNumberCompressed) - { - SubregionStream subStream (&fileStream, 4, -1, false); - GZIPDecompressorInputStream gzip (subStream); - return loadAsBinary (gzip); - } - - if (magicNumber == PropertyFileConstants::magicNumber) - return loadAsBinary (fileStream); - } - - return false; -} - -bool PropertiesFile::loadAsBinary (InputStream& input) -{ - BufferedInputStream in (input, 2048); - - int numValues = in.readInt(); - - while (--numValues >= 0 && ! in.isExhausted()) - { - const String key (in.readString()); - const String value (in.readString()); - - jassert (key.isNotEmpty()); - if (key.isNotEmpty()) - getAllProperties().set (key, value); - } - - return true; -} - -bool PropertiesFile::saveAsBinary() -{ - ProcessScopedLock pl (createProcessLock()); - - if (pl != nullptr && ! pl->isLocked()) - return false; // locking failure.. - - TemporaryFile tempFile (file); - ScopedPointer out (tempFile.getFile().createOutputStream()); - - if (out != nullptr) - { - if (options.storageFormat == storeAsCompressedBinary) - { - out->writeInt (PropertyFileConstants::magicNumberCompressed); - out->flush(); - - out = new GZIPCompressorOutputStream (out.release(), 9, true); - } - else - { - // have you set up the storage option flags correctly? - jassert (options.storageFormat == storeAsBinary); - - out->writeInt (PropertyFileConstants::magicNumber); - } - - const StringPairArray& props = getAllProperties(); - const int numProperties = props.size(); - const StringArray& keys = props.getAllKeys(); - const StringArray& values = props.getAllValues(); - - out->writeInt (numProperties); - - for (int i = 0; i < numProperties; ++i) - { - out->writeString (keys[i]); - out->writeString (values[i]); - } - - out = nullptr; - - if (tempFile.overwriteTargetFileWithTemporary()) - { - needsWriting = false; - return true; - } - } - - return false; -} - -void PropertiesFile::timerCallback() -{ - saveIfNeeded(); -} - -void PropertiesFile::propertyChanged() -{ - sendChangeMessage(); - - needsWriting = true; - - if (options.millisecondsBeforeSaving > 0) - startTimer (options.millisecondsBeforeSaving); - else if (options.millisecondsBeforeSaving == 0) - saveIfNeeded(); -} - -} // namespace juce diff --git a/source/modules/juce_data_structures/app_properties/juce_PropertiesFile.h b/source/modules/juce_data_structures/app_properties/juce_PropertiesFile.h deleted file mode 100644 index 2848c5bb2..000000000 --- a/source/modules/juce_data_structures/app_properties/juce_PropertiesFile.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** Wrapper on a file that stores a list of key/value data pairs. - - Useful for storing application settings, etc. See the PropertySet class for - the interfaces that read and write values. - - Not designed for very large amounts of data, as it keeps all the values in - memory and writes them out to disk lazily when they are changed. - - Because this class derives from ChangeBroadcaster, ChangeListeners can be registered - with it, and these will be signalled when a value changes. - - @see PropertySet -*/ -class JUCE_API PropertiesFile : public PropertySet, - public ChangeBroadcaster, - private Timer -{ -public: - //============================================================================== - enum StorageFormat - { - storeAsBinary, - storeAsCompressedBinary, - storeAsXML - }; - - //============================================================================== - struct JUCE_API Options - { - /** Creates an empty Options structure. - You'll need to fill-in the data members appropriately before using this structure. - */ - Options(); - - /** The name of your application - this is used to help generate the path and filename - at which the properties file will be stored. */ - String applicationName; - - /** The suffix to use for your properties file. - It doesn't really matter what this is - you may want to use ".settings" or - ".properties" or something. If the suffix includes the prefixing dot (for example - ".settings") then the suffix of applicationName will be replaced with your suffix - ("MyApp.exe" -> "MyApp.settings"). If your filenameSuffix does NOT include the dot, - then the suffix will be appended to the applicationName ("MyApp.exe" -> - "MyApp.exe.settings"). - */ - String filenameSuffix; - - /** The name of a subfolder in which you'd like your properties file to live. - See the getDefaultFile() method for more details about how this is used. - */ - String folderName; - - /** If you're using properties files on a Mac, you must set this value - failure to - do so will cause a runtime assertion. - - The PropertiesFile class always used to put its settings files in "Library/Preferences", but Apple - have changed their advice, and now stipulate that settings should go in "Library/Application Support". - - Because older apps would be broken by a silent change in this class's behaviour, you must now - explicitly set the osxLibrarySubFolder value to indicate which path you want to use. - - In newer apps, you should always set this to "Application Support" or - "Application Support/YourSubFolderName". - - If your app needs to load settings files that were created by older versions of juce and - you want to maintain backwards-compatibility, then you can set this to "Preferences". - But.. for better Apple-compliance, the recommended approach would be to write some code that - finds your old settings files in ~/Library/Preferences, moves them to ~/Library/Application Support, - and then uses the new path. - */ - String osxLibrarySubFolder; - - /** If true, the file will be created in a location that's shared between users. - The default constructor initialises this value to false. - */ - bool commonToAllUsers; - - /** If true, this means that property names are matched in a case-insensitive manner. - See the PropertySet constructor for more info. - The default constructor initialises this value to false. - */ - bool ignoreCaseOfKeyNames; - - /** If set to true, this prevents the file from being written to disk. */ - bool doNotSave; - - /** If this is zero or greater, then after a value is changed, the object will wait - for this amount of time and then save the file. If this zero, the file will be - written to disk immediately on being changed (which might be slow, as it'll re-write - synchronously each time a value-change method is called). If it is less than zero, - the file won't be saved until save() or saveIfNeeded() are explicitly called. - The default constructor sets this to a reasonable value of a few seconds, so you - only need to change it if you need a special case. - */ - int millisecondsBeforeSaving; - - /** Specifies whether the file should be written as XML, binary, etc. - The default constructor sets this to storeAsXML, so you only need to set it explicitly - if you want to use a different format. - */ - StorageFormat storageFormat; - - /** An optional InterprocessLock object that will be used to prevent multiple threads or - processes from writing to the file at the same time. The PropertiesFile will keep a - pointer to this object but will not take ownership of it - the caller is responsible for - making sure that the lock doesn't get deleted before the PropertiesFile has been deleted. - The default constructor initialises this value to nullptr, so you don't need to touch it - unless you want to use a lock. - */ - InterProcessLock* processLock; - - /** This can be called to suggest a file that should be used, based on the values - in this structure. - - So on a Mac, this will return a file called: - ~/Library/[osxLibrarySubFolder]/[folderName]/[applicationName].[filenameSuffix] - - On Windows it'll return something like: - C:\\Documents and Settings\\username\\Application Data\\[folderName]\\[applicationName].[filenameSuffix] - - On Linux it'll return - ~/[folderName]/[applicationName].[filenameSuffix] - - If the folderName variable is empty, it'll use the app name for this (or omit the - folder name on the Mac). - - The paths will also vary depending on whether commonToAllUsers is true. - */ - File getDefaultFile() const; - }; - - //============================================================================== - /** Creates a PropertiesFile object. - The file used will be chosen by calling PropertiesFile::Options::getDefaultFile() - for the options provided. To set the file explicitly, use the other constructor. - */ - explicit PropertiesFile (const Options& options); - - /** Creates a PropertiesFile object. - Unlike the other constructor, this one allows you to explicitly set the file that you - want to be used, rather than using the default one. - */ - PropertiesFile (const File& file, - const Options& options); - - /** Destructor. - When deleted, the file will first call saveIfNeeded() to flush any changes to disk. - */ - ~PropertiesFile(); - - //============================================================================== - /** Returns true if this file was created from a valid (or non-existent) file. - If the file failed to load correctly because it was corrupt or had insufficient - access, this will be false. - */ - bool isValidFile() const noexcept { return loadedOk; } - - //============================================================================== - /** This will flush all the values to disk if they've changed since the last - time they were saved. - - Returns false if it fails to write to the file for some reason (maybe because - it's read-only or the directory doesn't exist or something). - - @see save - */ - bool saveIfNeeded(); - - /** This will force a write-to-disk of the current values, regardless of whether - anything has changed since the last save. - - Returns false if it fails to write to the file for some reason (maybe because - it's read-only or the directory doesn't exist or something). - - @see saveIfNeeded - */ - bool save(); - - /** Returns true if the properties have been altered since the last time they were saved. - The file is flagged as needing to be saved when you change a value, but you can - explicitly set this flag with setNeedsToBeSaved(). - */ - bool needsToBeSaved() const; - - /** Explicitly sets the flag to indicate whether the file needs saving or not. - @see needsToBeSaved - */ - void setNeedsToBeSaved (bool needsToBeSaved); - - /** Attempts to reload the settings from the file. */ - bool reload(); - - //============================================================================== - /** Returns the file that's being used. */ - const File& getFile() const noexcept { return file; } - - -protected: - /** @internal */ - void propertyChanged() override; - -private: - //============================================================================== - File file; - Options options; - bool loadedOk, needsWriting; - - typedef const ScopedPointer ProcessScopedLock; - InterProcessLock::ScopedLockType* createProcessLock() const; - - void timerCallback() override; - bool saveAsXml(); - bool saveAsBinary(); - bool loadAsXml(); - bool loadAsBinary(); - bool loadAsBinary (InputStream&); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PropertiesFile) -}; - -} // namespace juce diff --git a/source/modules/juce_data_structures/juce_data_structures.cpp b/source/modules/juce_data_structures/juce_data_structures.cpp deleted file mode 100644 index 5913ca47f..000000000 --- a/source/modules/juce_data_structures/juce_data_structures.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -#ifdef JUCE_DATA_STRUCTURES_H_INCLUDED - /* When you add this cpp file to your project, you mustn't include it in a file where you've - already included any other headers - just put it inside a file on its own, possibly with your config - flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix - header files that the compiler may be using. - */ - #error "Incorrect use of JUCE cpp file" -#endif - -#include "juce_data_structures.h" - -#include "values/juce_Value.cpp" -#include "values/juce_ValueTree.cpp" -#include "values/juce_ValueTreeSynchroniser.cpp" -#include "values/juce_CachedValue.cpp" -#include "undomanager/juce_UndoManager.cpp" -#include "app_properties/juce_ApplicationProperties.cpp" -#include "app_properties/juce_PropertiesFile.cpp" diff --git a/source/modules/juce_data_structures/juce_data_structures.h b/source/modules/juce_data_structures/juce_data_structures.h deleted file mode 100644 index 7856e1917..000000000 --- a/source/modules/juce_data_structures/juce_data_structures.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -/******************************************************************************* - The block below describes the properties of this module, and is read by - the Projucer to automatically generate project code that uses it. - For details about the syntax and how to create or use a module, see the - JUCE Module Format.txt file. - - - BEGIN_JUCE_MODULE_DECLARATION - - ID: juce_data_structures - vendor: juce - version: 5.1.2 - name: JUCE data model helper classes - description: Classes for undo/redo management, and smart data structures. - website: http://www.juce.com/juce - license: GPL/Commercial - - dependencies: juce_events - - END_JUCE_MODULE_DECLARATION - -*******************************************************************************/ - - -#pragma once -#define JUCE_DATA_STRUCTURES_H_INCLUDED - -//============================================================================== -#include - -#include "undomanager/juce_UndoableAction.h" -#include "undomanager/juce_UndoManager.h" -#include "values/juce_Value.h" -#include "values/juce_ValueTree.h" -#include "values/juce_ValueTreeSynchroniser.h" -#include "values/juce_CachedValue.h" -#include "app_properties/juce_PropertiesFile.h" -#include "app_properties/juce_ApplicationProperties.h" diff --git a/source/modules/juce_data_structures/undomanager/juce_UndoManager.cpp b/source/modules/juce_data_structures/undomanager/juce_UndoManager.cpp deleted file mode 100644 index a5a705a32..000000000 --- a/source/modules/juce_data_structures/undomanager/juce_UndoManager.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -struct UndoManager::ActionSet -{ - ActionSet (const String& transactionName) - : name (transactionName), - time (Time::getCurrentTime()) - {} - - bool perform() const - { - for (int i = 0; i < actions.size(); ++i) - if (! actions.getUnchecked(i)->perform()) - return false; - - return true; - } - - bool undo() const - { - for (int i = actions.size(); --i >= 0;) - if (! actions.getUnchecked(i)->undo()) - return false; - - return true; - } - - int getTotalSize() const - { - int total = 0; - - for (int i = actions.size(); --i >= 0;) - total += actions.getUnchecked(i)->getSizeInUnits(); - - return total; - } - - OwnedArray actions; - String name; - Time time; -}; - -//============================================================================== -UndoManager::UndoManager (const int maxNumberOfUnitsToKeep, - const int minimumTransactions) - : totalUnitsStored (0), - nextIndex (0), - newTransaction (true), - reentrancyCheck (false) -{ - setMaxNumberOfStoredUnits (maxNumberOfUnitsToKeep, - minimumTransactions); -} - -UndoManager::~UndoManager() -{ -} - -//============================================================================== -void UndoManager::clearUndoHistory() -{ - transactions.clear(); - totalUnitsStored = 0; - nextIndex = 0; - sendChangeMessage(); -} - -int UndoManager::getNumberOfUnitsTakenUpByStoredCommands() const -{ - return totalUnitsStored; -} - -void UndoManager::setMaxNumberOfStoredUnits (const int maxNumberOfUnitsToKeep, - const int minimumTransactions) -{ - maxNumUnitsToKeep = jmax (1, maxNumberOfUnitsToKeep); - minimumTransactionsToKeep = jmax (1, minimumTransactions); -} - -//============================================================================== -bool UndoManager::perform (UndoableAction* const newAction, const String& actionName) -{ - if (perform (newAction)) - { - if (actionName.isNotEmpty()) - setCurrentTransactionName (actionName); - - return true; - } - - return false; -} - -bool UndoManager::perform (UndoableAction* const newAction) -{ - if (newAction != nullptr) - { - ScopedPointer action (newAction); - - if (reentrancyCheck) - { - jassertfalse; // don't call perform() recursively from the UndoableAction::perform() - // or undo() methods, or else these actions will be discarded! - return false; - } - - if (action->perform()) - { - ActionSet* actionSet = getCurrentSet(); - - if (actionSet != nullptr && ! newTransaction) - { - if (UndoableAction* const lastAction = actionSet->actions.getLast()) - { - if (UndoableAction* const coalescedAction = lastAction->createCoalescedAction (action)) - { - action = coalescedAction; - totalUnitsStored -= lastAction->getSizeInUnits(); - actionSet->actions.removeLast(); - } - } - } - else - { - actionSet = new ActionSet (newTransactionName); - transactions.insert (nextIndex, actionSet); - ++nextIndex; - } - - totalUnitsStored += action->getSizeInUnits(); - actionSet->actions.add (action.release()); - newTransaction = false; - - moveFutureTransactionsToStash(); - dropOldTransactionsIfTooLarge(); - sendChangeMessage(); - return true; - } - } - - return false; -} - -void UndoManager::moveFutureTransactionsToStash() -{ - if (nextIndex < transactions.size()) - { - stashedFutureTransactions.clear(); - - while (nextIndex < transactions.size()) - { - ActionSet* removed = transactions.removeAndReturn (nextIndex); - stashedFutureTransactions.add (removed); - totalUnitsStored -= removed->getTotalSize(); - } - } -} - -void UndoManager::restoreStashedFutureTransactions() -{ - while (nextIndex < transactions.size()) - { - totalUnitsStored -= transactions.getUnchecked (nextIndex)->getTotalSize(); - transactions.remove (nextIndex); - } - - for (int i = 0; i < stashedFutureTransactions.size(); ++i) - { - ActionSet* action = stashedFutureTransactions.removeAndReturn (i); - totalUnitsStored += action->getTotalSize(); - transactions.add (action); - } - - stashedFutureTransactions.clearQuick (false); -} - -void UndoManager::dropOldTransactionsIfTooLarge() -{ - while (nextIndex > 0 - && totalUnitsStored > maxNumUnitsToKeep - && transactions.size() > minimumTransactionsToKeep) - { - totalUnitsStored -= transactions.getFirst()->getTotalSize(); - transactions.remove (0); - --nextIndex; - - // if this fails, then some actions may not be returning - // consistent results from their getSizeInUnits() method - jassert (totalUnitsStored >= 0); - } -} - -void UndoManager::beginNewTransaction() noexcept -{ - beginNewTransaction (String()); -} - -void UndoManager::beginNewTransaction (const String& actionName) noexcept -{ - newTransaction = true; - newTransactionName = actionName; -} - -void UndoManager::setCurrentTransactionName (const String& newName) noexcept -{ - if (newTransaction) - newTransactionName = newName; - else if (ActionSet* action = getCurrentSet()) - action->name = newName; -} - -String UndoManager::getCurrentTransactionName() const noexcept -{ - if (ActionSet* action = getCurrentSet()) - return action->name; - - return newTransactionName; -} - -//============================================================================== -UndoManager::ActionSet* UndoManager::getCurrentSet() const noexcept { return transactions [nextIndex - 1]; } -UndoManager::ActionSet* UndoManager::getNextSet() const noexcept { return transactions [nextIndex]; } - -bool UndoManager::canUndo() const noexcept { return getCurrentSet() != nullptr; } -bool UndoManager::canRedo() const noexcept { return getNextSet() != nullptr; } - -bool UndoManager::undo() -{ - if (const ActionSet* const s = getCurrentSet()) - { - const ScopedValueSetter setter (reentrancyCheck, true); - - if (s->undo()) - --nextIndex; - else - clearUndoHistory(); - - beginNewTransaction(); - sendChangeMessage(); - return true; - } - - return false; -} - -bool UndoManager::redo() -{ - if (const ActionSet* const s = getNextSet()) - { - const ScopedValueSetter setter (reentrancyCheck, true); - - if (s->perform()) - ++nextIndex; - else - clearUndoHistory(); - - beginNewTransaction(); - sendChangeMessage(); - return true; - } - - return false; -} - -String UndoManager::getUndoDescription() const -{ - if (auto* s = getCurrentSet()) - return s->name; - - return {}; -} - -String UndoManager::getRedoDescription() const -{ - if (auto* s = getNextSet()) - return s->name; - - return {}; -} - -Time UndoManager::getTimeOfUndoTransaction() const -{ - if (auto* s = getCurrentSet()) - return s->time; - - return {}; -} - -Time UndoManager::getTimeOfRedoTransaction() const -{ - if (auto* s = getNextSet()) - return s->time; - - return Time::getCurrentTime(); -} - -bool UndoManager::undoCurrentTransactionOnly() -{ - if ((! newTransaction) && undo()) - { - restoreStashedFutureTransactions(); - return true; - } - - return false; -} - -void UndoManager::getActionsInCurrentTransaction (Array& actionsFound) const -{ - if (! newTransaction) - if (const ActionSet* const s = getCurrentSet()) - for (int i = 0; i < s->actions.size(); ++i) - actionsFound.add (s->actions.getUnchecked(i)); -} - -int UndoManager::getNumActionsInCurrentTransaction() const -{ - if (! newTransaction) - if (const ActionSet* const s = getCurrentSet()) - return s->actions.size(); - - return 0; -} - -} // namespace juce diff --git a/source/modules/juce_data_structures/undomanager/juce_UndoManager.h b/source/modules/juce_data_structures/undomanager/juce_UndoManager.h deleted file mode 100644 index 75f3d0f30..000000000 --- a/source/modules/juce_data_structures/undomanager/juce_UndoManager.h +++ /dev/null @@ -1,246 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Manages a list of undo/redo commands. - - An UndoManager object keeps a list of past actions and can use these actions - to move backwards and forwards through an undo history. - - To use it, create subclasses of UndoableAction which perform all the - actions you need, then when you need to actually perform an action, create one - and pass it to the UndoManager's perform() method. - - The manager also uses the concept of 'transactions' to group the actions - together - all actions performed between calls to beginNewTransaction() are - grouped together and are all undone/redone as a group. - - The UndoManager is a ChangeBroadcaster, so listeners can register to be told - when actions are performed or undone. - - @see UndoableAction -*/ -class JUCE_API UndoManager : public ChangeBroadcaster -{ -public: - //============================================================================== - /** Creates an UndoManager. - - @param maxNumberOfUnitsToKeep each UndoableAction object returns a value - to indicate how much storage it takes up - (UndoableAction::getSizeInUnits()), so this - lets you specify the maximum total number of - units that the undomanager is allowed to - keep in memory before letting the older actions - drop off the end of the list. - @param minimumTransactionsToKeep this specifies the minimum number of transactions - that will be kept, even if this involves exceeding - the amount of space specified in maxNumberOfUnitsToKeep - */ - UndoManager (int maxNumberOfUnitsToKeep = 30000, - int minimumTransactionsToKeep = 30); - - /** Destructor. */ - ~UndoManager(); - - //============================================================================== - /** Deletes all stored actions in the list. */ - void clearUndoHistory(); - - /** Returns the current amount of space to use for storing UndoableAction objects. - @see setMaxNumberOfStoredUnits - */ - int getNumberOfUnitsTakenUpByStoredCommands() const; - - /** Sets the amount of space that can be used for storing UndoableAction objects. - - @param maxNumberOfUnitsToKeep each UndoableAction object returns a value - to indicate how much storage it takes up - (UndoableAction::getSizeInUnits()), so this - lets you specify the maximum total number of - units that the undomanager is allowed to - keep in memory before letting the older actions - drop off the end of the list. - @param minimumTransactionsToKeep this specifies the minimum number of transactions - that will be kept, even if this involves exceeding - the amount of space specified in maxNumberOfUnitsToKeep - @see getNumberOfUnitsTakenUpByStoredCommands - */ - void setMaxNumberOfStoredUnits (int maxNumberOfUnitsToKeep, - int minimumTransactionsToKeep); - - //============================================================================== - /** Performs an action and adds it to the undo history list. - - @param action the action to perform - this object will be deleted by - the UndoManager when no longer needed - @returns true if the command succeeds - see UndoableAction::perform - @see beginNewTransaction - */ - bool perform (UndoableAction* action); - - /** Performs an action and also gives it a name. - - @param action the action to perform - this object will be deleted by - the UndoManager when no longer needed - @param actionName if this string is non-empty, the current transaction will be - given this name; if it's empty, the current transaction name will - be left unchanged. See setCurrentTransactionName() - @returns true if the command succeeds - see UndoableAction::perform - @see beginNewTransaction - */ - bool perform (UndoableAction* action, const String& actionName); - - /** Starts a new group of actions that together will be treated as a single transaction. - - All actions that are passed to the perform() method between calls to this - method are grouped together and undone/redone together by a single call to - undo() or redo(). - */ - void beginNewTransaction() noexcept; - - /** Starts a new group of actions that together will be treated as a single transaction. - - All actions that are passed to the perform() method between calls to this - method are grouped together and undone/redone together by a single call to - undo() or redo(). - - @param actionName a description of the transaction that is about to be - performed - */ - void beginNewTransaction (const String& actionName) noexcept; - - /** Changes the name stored for the current transaction. - - Each transaction is given a name when the beginNewTransaction() method is - called, but this can be used to change that name without starting a new - transaction. - */ - void setCurrentTransactionName (const String& newName) noexcept; - - /** Returns the name of the current transaction. - @see setCurrentTransactionName - */ - String getCurrentTransactionName() const noexcept; - - //============================================================================== - /** Returns true if there's at least one action in the list to undo. - @see getUndoDescription, undo, canRedo - */ - bool canUndo() const noexcept; - - /** Returns the name of the transaction that will be rolled-back when undo() is called. - @see undo - */ - String getUndoDescription() const; - - /** Tries to roll-back the last transaction. - @returns true if the transaction can be undone, and false if it fails, or - if there aren't any transactions to undo - */ - bool undo(); - - /** Tries to roll-back any actions that were added to the current transaction. - - This will perform an undo() only if there are some actions in the undo list - that were added after the last call to beginNewTransaction(). - - This is useful because it lets you call beginNewTransaction(), then - perform an operation which may or may not actually perform some actions, and - then call this method to get rid of any actions that might have been done - without it rolling back the previous transaction if nothing was actually - done. - - @returns true if any actions were undone. - */ - bool undoCurrentTransactionOnly(); - - /** Returns a list of the UndoableAction objects that have been performed during the - transaction that is currently open. - - Effectively, this is the list of actions that would be undone if undoCurrentTransactionOnly() - were to be called now. - - The first item in the list is the earliest action performed. - */ - void getActionsInCurrentTransaction (Array& actionsFound) const; - - /** Returns the number of UndoableAction objects that have been performed during the - transaction that is currently open. - @see getActionsInCurrentTransaction - */ - int getNumActionsInCurrentTransaction() const; - - /** Returns the time to which the state would be restored if undo() was to be called. - If an undo isn't currently possible, it'll return Time(). - */ - Time getTimeOfUndoTransaction() const; - - /** Returns the time to which the state would be restored if redo() was to be called. - If a redo isn't currently possible, it'll return Time::getCurrentTime(). - */ - Time getTimeOfRedoTransaction() const; - - //============================================================================== - /** Returns true if there's at least one action in the list to redo. - @see getRedoDescription, redo, canUndo - */ - bool canRedo() const noexcept; - - /** Returns the name of the transaction that will be redone when redo() is called. - @see redo - */ - String getRedoDescription() const; - - /** Tries to redo the last transaction that was undone. - @returns true if the transaction can be redone, and false if it fails, or - if there aren't any transactions to redo - */ - bool redo(); - - -private: - //============================================================================== - struct ActionSet; - friend struct ContainerDeletePolicy; - OwnedArray transactions, stashedFutureTransactions; - String newTransactionName; - int totalUnitsStored, maxNumUnitsToKeep, minimumTransactionsToKeep, nextIndex; - bool newTransaction, reentrancyCheck; - ActionSet* getCurrentSet() const noexcept; - ActionSet* getNextSet() const noexcept; - void moveFutureTransactionsToStash(); - void restoreStashedFutureTransactions(); - void dropOldTransactionsIfTooLarge(); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UndoManager) -}; - -} // namespace juce diff --git a/source/modules/juce_data_structures/undomanager/juce_UndoableAction.h b/source/modules/juce_data_structures/undomanager/juce_UndoableAction.h deleted file mode 100644 index 9b418cd4f..000000000 --- a/source/modules/juce_data_structures/undomanager/juce_UndoableAction.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Used by the UndoManager class to store an action which can be done - and undone. - - @see UndoManager -*/ -class JUCE_API UndoableAction -{ -protected: - /** Creates an action. */ - UndoableAction() noexcept {} - -public: - /** Destructor. */ - virtual ~UndoableAction() {} - - //============================================================================== - /** Overridden by a subclass to perform the action. - - This method is called by the UndoManager, and shouldn't be used directly by - applications. - - Be careful not to make any calls in a perform() method that could call - recursively back into the UndoManager::perform() method - - @returns true if the action could be performed. - @see UndoManager::perform - */ - virtual bool perform() = 0; - - /** Overridden by a subclass to undo the action. - - This method is called by the UndoManager, and shouldn't be used directly by - applications. - - Be careful not to make any calls in an undo() method that could call - recursively back into the UndoManager::perform() method - - @returns true if the action could be undone without any errors. - @see UndoManager::perform - */ - virtual bool undo() = 0; - - //============================================================================== - /** Returns a value to indicate how much memory this object takes up. - - Because the UndoManager keeps a list of UndoableActions, this is used - to work out how much space each one will take up, so that the UndoManager - can work out how many to keep. - - The default value returned here is 10 - units are arbitrary and - don't have to be accurate. - - @see UndoManager::getNumberOfUnitsTakenUpByStoredCommands, - UndoManager::setMaxNumberOfStoredUnits - */ - virtual int getSizeInUnits() { return 10; } - - /** Allows multiple actions to be coalesced into a single action object, to reduce storage space. - - If possible, this method should create and return a single action that does the same job as - this one followed by the supplied action. - - If it's not possible to merge the two actions, the method should return a nullptr. - */ - virtual UndoableAction* createCoalescedAction (UndoableAction* nextAction) { ignoreUnused (nextAction); return nullptr; } -}; - -} // namespace juce diff --git a/source/modules/juce_data_structures/values/juce_CachedValue.cpp b/source/modules/juce_data_structures/values/juce_CachedValue.cpp deleted file mode 100644 index ace2c41de..000000000 --- a/source/modules/juce_data_structures/values/juce_CachedValue.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -#if JUCE_UNIT_TESTS - -class CachedValueTests : public UnitTest -{ -public: - CachedValueTests() : UnitTest ("CachedValues", "Values") {} - - void runTest() override - { - beginTest ("default constructor"); - { - CachedValue cv; - expect (cv.isUsingDefault()); - expect (cv.get() == String()); - } - - beginTest ("without default value"); - { - ValueTree t ("root"); - t.setProperty ("testkey", "testvalue", nullptr); - - CachedValue cv (t, "testkey", nullptr); - - expect (! cv.isUsingDefault()); - expect (cv.get() == "testvalue"); - - cv.resetToDefault(); - - expect (cv.isUsingDefault()); - expect (cv.get() == String()); - } - - beginTest ("with default value"); - { - ValueTree t ("root"); - t.setProperty ("testkey", "testvalue", nullptr); - - CachedValue cv (t, "testkey", nullptr, "defaultvalue"); - - expect (! cv.isUsingDefault()); - expect (cv.get() == "testvalue"); - - cv.resetToDefault(); - - expect (cv.isUsingDefault()); - expect (cv.get() == "defaultvalue"); - } - - beginTest ("with default value (int)"); - { - ValueTree t ("root"); - t.setProperty ("testkey", 23, nullptr); - - CachedValue cv (t, "testkey", nullptr, 34); - - expect (! cv.isUsingDefault()); - expect (cv == 23); - expectEquals (cv.get(), 23); - - cv.resetToDefault(); - - expect (cv.isUsingDefault()); - expect (cv == 34); - } - - beginTest ("with void value"); - { - ValueTree t ("root"); - t.setProperty ("testkey", var(), nullptr); - - CachedValue cv (t, "testkey", nullptr, "defaultvalue"); - - expect (! cv.isUsingDefault()); - expect (cv == ""); - expectEquals (cv.get(), String()); - } - - beginTest ("with non-existent value"); - { - ValueTree t ("root"); - - CachedValue cv (t, "testkey", nullptr, "defaultvalue"); - - expect (cv.isUsingDefault()); - expect (cv == "defaultvalue"); - expect (cv.get() == "defaultvalue"); - } - - beginTest ("with value changing"); - { - ValueTree t ("root"); - t.setProperty ("testkey", "oldvalue", nullptr); - - CachedValue cv (t, "testkey", nullptr, "defaultvalue"); - expect (cv == "oldvalue"); - - t.setProperty ("testkey", "newvalue", nullptr); - expect (cv != "oldvalue"); - expect (cv == "newvalue"); - } - - beginTest ("set value"); - { - ValueTree t ("root"); - t.setProperty ("testkey", 23, nullptr); - - CachedValue cv (t, "testkey", nullptr, 45); - cv = 34; - - expectEquals ((int) t["testkey"], 34); - - cv.resetToDefault(); - expect (cv == 45); - expectEquals (cv.get(), 45); - - expect (t["testkey"] == var()); - } - - beginTest ("reset value"); - { - - } - } -}; - -static CachedValueTests cachedValueTests; - -#endif - -} // namespace juce diff --git a/source/modules/juce_data_structures/values/juce_CachedValue.h b/source/modules/juce_data_structures/values/juce_CachedValue.h deleted file mode 100644 index 7a807df30..000000000 --- a/source/modules/juce_data_structures/values/juce_CachedValue.h +++ /dev/null @@ -1,312 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - This class acts as a typed wrapper around a property inside a ValueTree. - - A CachedValue provides an easy way to read and write a ValueTree property with - a chosen type. So for example a CachedValue allows you to read or write the - property as an int, and a CachedValue lets you work with it as a String. - - It also allows efficient access to the value, by caching a copy of it in the - type that is being used. - - You can give the CachedValue an optional UndoManager which it will use when writing - to the underlying ValueTree. - - If the property inside the ValueTree is missing, the CachedValue will automatically - return an optional default value, which can be specified when initialising the CachedValue. - - To create one, you can either use the constructor to attach the CachedValue to a - ValueTree, or can create an uninitialised CachedValue with its default constructor and - then attach it later with the referTo() methods. - - Common types like String, int, double which can be easily converted to a var should work - out-of-the-box, but if you want to use more complex custom types, you may need to implement - some template specialisations of VariantConverter which this class uses to convert between - the type and the ValueTree's internal var. -*/ -template -class CachedValue : private ValueTree::Listener -{ -public: - //============================================================================== - /** Default constructor. - Creates a default CachedValue not referring to any property. To initialise the - object, call one of the referTo() methods. - */ - CachedValue(); - - /** Constructor. - - Creates a CachedValue referring to a Value property inside a ValueTree. - If you use this constructor, the fallback value will be a default-constructed - instance of Type. - - @param tree The ValueTree containing the property - @param propertyID The identifier of the property - @param undoManager The UndoManager to use when writing to the property - */ - CachedValue (ValueTree& tree, const Identifier& propertyID, - UndoManager* undoManager); - - /** Constructor. - - Creates a default Cached Value referring to a Value property inside a ValueTree, - and specifies a fallback value to use if the property does not exist. - - @param tree The ValueTree containing the property - @param propertyID The identifier of the property - @param undoManager The UndoManager to use when writing to the property - @param defaultToUse The fallback default value to use. - */ - CachedValue (ValueTree& tree, const Identifier& propertyID, - UndoManager* undoManager, const Type& defaultToUse); - - //============================================================================== - /** Returns the current value of the property. If the property does not exist, - returns the fallback default value. - - This is the same as calling get(). - */ - operator Type() const noexcept { return cachedValue; } - - /** Returns the current value of the property. If the property does not exist, - returns the fallback default value. - */ - Type get() const noexcept { return cachedValue; } - - /** Dereference operator. Provides direct access to the property. */ - Type& operator*() noexcept { return cachedValue; } - - /** Dereference operator. Provides direct access to members of the property - if it is of object type. - */ - Type* operator->() noexcept { return &cachedValue; } - - /** Returns true if the current value of the property (or the fallback value) - is equal to other. - */ - template - bool operator== (const OtherType& other) const { return cachedValue == other; } - - /** Returns true if the current value of the property (or the fallback value) - is not equal to other. - */ - template - bool operator!= (const OtherType& other) const { return cachedValue != other; } - - //============================================================================== - /** Returns the current property as a Value object. */ - Value getPropertyAsValue(); - - /** Returns true if the current property does not exist and the CachedValue is using - the fallback default value instead. - */ - bool isUsingDefault() const; - - /** Returns the current fallback default value. */ - Type getDefault() const { return defaultValue; } - - //============================================================================== - /** Sets the property. This will actually modify the property in the referenced ValueTree. */ - CachedValue& operator= (const Type& newValue); - - /** Sets the property. This will actually modify the property in the referenced ValueTree. */ - void setValue (const Type& newValue, UndoManager* undoManagerToUse); - - /** Removes the property from the referenced ValueTree and makes the CachedValue - return the fallback default value instead. - */ - void resetToDefault(); - - /** Removes the property from the referenced ValueTree and makes the CachedValue - return the fallback default value instead. - */ - void resetToDefault (UndoManager* undoManagerToUse); - - /** Resets the fallback default value. */ - void setDefault (const Type& value) { defaultValue = value; } - - //============================================================================== - /** Makes the CachedValue refer to the specified property inside the given ValueTree. */ - void referTo (ValueTree& tree, const Identifier& property, UndoManager* um); - - /** Makes the CachedValue refer to the specified property inside the given ValueTree, - and specifies a fallback value to use if the property does not exist. - */ - void referTo (ValueTree& tree, const Identifier& property, UndoManager* um, const Type& defaultVal); - - /** Force an update in case the referenced property has been changed from elsewhere. - - Note: The CachedValue is a ValueTree::Listener and therefore will be informed of - changes of the referenced property anyway (and update itself). But this may happen - asynchronously. forceUpdateOfCachedValue() forces an update immediately. - */ - void forceUpdateOfCachedValue(); - - //============================================================================== - /** Returns a reference to the ValueTree containing the referenced property. */ - ValueTree& getValueTree() noexcept { return targetTree; } - - /** Returns the property ID of the referenced property. */ - const Identifier& getPropertyID() const noexcept { return targetProperty; } - -private: - //============================================================================== - ValueTree targetTree; - Identifier targetProperty; - UndoManager* undoManager; - Type defaultValue; - Type cachedValue; - - //============================================================================== - void referToWithDefault (ValueTree&, const Identifier&, UndoManager*, const Type&); - Type getTypedValue() const; - - void valueTreePropertyChanged (ValueTree& changedTree, const Identifier& changedProperty) override; - void valueTreeChildAdded (ValueTree&, ValueTree&) override {} - void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override {} - void valueTreeChildOrderChanged (ValueTree&, int, int) override {} - void valueTreeParentChanged (ValueTree&) override {} - - JUCE_DECLARE_NON_COPYABLE (CachedValue) -}; - - -//============================================================================== -template -inline CachedValue::CachedValue() : undoManager (nullptr) {} - -template -inline CachedValue::CachedValue (ValueTree& v, const Identifier& i, UndoManager* um) - : targetTree (v), targetProperty (i), undoManager (um), - defaultValue(), cachedValue (getTypedValue()) -{ - targetTree.addListener (this); -} - -template -inline CachedValue::CachedValue (ValueTree& v, const Identifier& i, UndoManager* um, const Type& defaultToUse) - : targetTree (v), targetProperty (i), undoManager (um), - defaultValue (defaultToUse), cachedValue (getTypedValue()) -{ - targetTree.addListener (this); -} - -template -inline Value CachedValue::getPropertyAsValue() -{ - return targetTree.getPropertyAsValue (targetProperty, undoManager); -} - -template -inline bool CachedValue::isUsingDefault() const -{ - return ! targetTree.hasProperty (targetProperty); -} - -template -inline CachedValue& CachedValue::operator= (const Type& newValue) -{ - setValue (newValue, undoManager); - return *this; -} - -template -inline void CachedValue::setValue (const Type& newValue, UndoManager* undoManagerToUse) -{ - if (cachedValue != newValue || isUsingDefault()) - { - cachedValue = newValue; - targetTree.setProperty (targetProperty, VariantConverter::toVar (newValue), undoManagerToUse); - } -} - -template -inline void CachedValue::resetToDefault() -{ - resetToDefault (undoManager); -} - -template -inline void CachedValue::resetToDefault (UndoManager* undoManagerToUse) -{ - targetTree.removeProperty (targetProperty, undoManagerToUse); - forceUpdateOfCachedValue(); -} - -template -inline void CachedValue::referTo (ValueTree& v, const Identifier& i, UndoManager* um) -{ - referToWithDefault (v, i, um, Type()); -} - -template -inline void CachedValue::referTo (ValueTree& v, const Identifier& i, UndoManager* um, const Type& defaultVal) -{ - referToWithDefault (v, i, um, defaultVal); -} - -template -inline void CachedValue::forceUpdateOfCachedValue() -{ - cachedValue = getTypedValue(); -} - -template -inline void CachedValue::referToWithDefault (ValueTree& v, const Identifier& i, UndoManager* um, const Type& defaultVal) -{ - targetTree.removeListener (this); - targetTree = v; - targetProperty = i; - undoManager = um; - defaultValue = defaultVal; - cachedValue = getTypedValue(); - targetTree.addListener (this); -} - -template -inline Type CachedValue::getTypedValue() const -{ - if (const var* property = targetTree.getPropertyPointer (targetProperty)) - return VariantConverter::fromVar (*property); - - return defaultValue; -} - -template -inline void CachedValue::valueTreePropertyChanged (ValueTree& changedTree, const Identifier& changedProperty) -{ - if (changedProperty == targetProperty && targetTree == changedTree) - forceUpdateOfCachedValue(); -} - -} // namespace juce diff --git a/source/modules/juce_data_structures/values/juce_Value.cpp b/source/modules/juce_data_structures/values/juce_Value.cpp deleted file mode 100644 index b09530fed..000000000 --- a/source/modules/juce_data_structures/values/juce_Value.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -Value::ValueSource::ValueSource() -{ -} - -Value::ValueSource::~ValueSource() -{ - cancelPendingUpdate(); -} - -void Value::ValueSource::handleAsyncUpdate() -{ - sendChangeMessage (true); -} - -void Value::ValueSource::sendChangeMessage (const bool synchronous) -{ - const int numListeners = valuesWithListeners.size(); - - if (numListeners > 0) - { - if (synchronous) - { - const ReferenceCountedObjectPtr localRef (this); - - cancelPendingUpdate(); - - for (int i = numListeners; --i >= 0;) - if (Value* const v = valuesWithListeners[i]) - v->callListeners(); - } - else - { - triggerAsyncUpdate(); - } - } -} - -//============================================================================== -class SimpleValueSource : public Value::ValueSource -{ -public: - SimpleValueSource() - { - } - - SimpleValueSource (const var& initialValue) - : value (initialValue) - { - } - - var getValue() const override - { - return value; - } - - void setValue (const var& newValue) override - { - if (! newValue.equalsWithSameType (value)) - { - value = newValue; - sendChangeMessage (false); - } - } - -private: - var value; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SimpleValueSource) -}; - - -//============================================================================== -Value::Value() : value (new SimpleValueSource()) -{ -} - -Value::Value (ValueSource* const v) : value (v) -{ - jassert (v != nullptr); -} - -Value::Value (const var& initialValue) : value (new SimpleValueSource (initialValue)) -{ -} - -Value::Value (const Value& other) : value (other.value) -{ -} - -Value::Value (Value&& other) noexcept -{ - // moving a Value with listeners will lose those listeners, which - // probably isn't what you wanted to happen! - jassert (other.listeners.size() == 0); - - other.removeFromListenerList(); - value = static_cast&&> (other.value); -} - -Value& Value::operator= (Value&& other) noexcept -{ - // moving a Value with listeners will lose those listeners, which - // probably isn't what you wanted to happen! - jassert (other.listeners.size() == 0); - - other.removeFromListenerList(); - value = static_cast&&> (other.value); - return *this; -} - -Value::~Value() -{ - removeFromListenerList(); -} - -void Value::removeFromListenerList() -{ - if (listeners.size() > 0 && value != nullptr) // may be nullptr after a move operation - value->valuesWithListeners.removeValue (this); -} - -//============================================================================== -var Value::getValue() const -{ - return value->getValue(); -} - -Value::operator var() const -{ - return value->getValue(); -} - -void Value::setValue (const var& newValue) -{ - value->setValue (newValue); -} - -String Value::toString() const -{ - return value->getValue().toString(); -} - -Value& Value::operator= (const var& newValue) -{ - value->setValue (newValue); - return *this; -} - -void Value::referTo (const Value& valueToReferTo) -{ - if (valueToReferTo.value != value) - { - if (listeners.size() > 0) - { - value->valuesWithListeners.removeValue (this); - valueToReferTo.value->valuesWithListeners.add (this); - } - - value = valueToReferTo.value; - callListeners(); - } -} - -bool Value::refersToSameSourceAs (const Value& other) const -{ - return value == other.value; -} - -bool Value::operator== (const Value& other) const -{ - return value == other.value || value->getValue() == other.getValue(); -} - -bool Value::operator!= (const Value& other) const -{ - return value != other.value && value->getValue() != other.getValue(); -} - -//============================================================================== -void Value::addListener (ValueListener* const listener) -{ - if (listener != nullptr) - { - if (listeners.size() == 0) - value->valuesWithListeners.add (this); - - listeners.add (listener); - } -} - -void Value::removeListener (ValueListener* const listener) -{ - listeners.remove (listener); - - if (listeners.size() == 0) - value->valuesWithListeners.removeValue (this); -} - -void Value::callListeners() -{ - if (listeners.size() > 0) - { - Value v (*this); // (create a copy in case this gets deleted by a callback) - listeners.call (&ValueListener::valueChanged, v); - } -} - -OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const Value& value) -{ - return stream << value.toString(); -} - -} // namespace juce diff --git a/source/modules/juce_data_structures/values/juce_Value.h b/source/modules/juce_data_structures/values/juce_Value.h deleted file mode 100644 index e1216da45..000000000 --- a/source/modules/juce_data_structures/values/juce_Value.h +++ /dev/null @@ -1,243 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Represents a shared variant value. - - A Value object contains a reference to a var object, and can get and set its value. - Listeners can be attached to be told when the value is changed. - - The Value class is a wrapper around a shared, reference-counted underlying data - object - this means that multiple Value objects can all refer to the same piece of - data, allowing all of them to be notified when any of them changes it. - - When you create a Value with its default constructor, it acts as a wrapper around a - simple var object, but by creating a Value that refers to a custom subclass of ValueSource, - you can map the Value onto any kind of underlying data. - - Important note! The Value class is not thread-safe! If you're accessing one from - multiple threads, then you'll need to use your own synchronisation around any code - that accesses it. -*/ -class JUCE_API Value -{ -public: - //============================================================================== - /** Creates an empty Value, containing a void var. */ - Value(); - - /** Creates a Value that refers to the same value as another one. - - Note that this doesn't make a copy of the other value - both this and the other - Value will share the same underlying value, so that when either one alters it, both - will see it change. - */ - Value (const Value& other); - - /** Creates a Value that is set to the specified value. */ - explicit Value (const var& initialValue); - - /** Move constructor */ - Value (Value&&) noexcept; - - /** Destructor. */ - ~Value(); - - //============================================================================== - /** Returns the current value. */ - var getValue() const; - - /** Returns the current value. */ - operator var() const; - - /** Returns the value as a string. - This is a shortcut for "myValue.getValue().toString()". - */ - String toString() const; - - /** Sets the current value. - - You can also use operator= to set the value. - - If there are any listeners registered, they will be notified of the - change asynchronously. - */ - void setValue (const var& newValue); - - /** Sets the current value. - - This is the same as calling setValue(). - - If there are any listeners registered, they will be notified of the - change asynchronously. - */ - Value& operator= (const var& newValue); - - /** Move assignment operator */ - Value& operator= (Value&&) noexcept; - - /** Makes this object refer to the same underlying ValueSource as another one. - - Once this object has been connected to another one, changing either one - will update the other. - - Existing listeners will still be registered after you call this method, and - they'll continue to receive messages when the new value changes. - */ - void referTo (const Value& valueToReferTo); - - /** Returns true if this value and the other one are references to the same value. - */ - bool refersToSameSourceAs (const Value& other) const; - - /** Compares two values. - This is a compare-by-value comparison, so is effectively the same as - saying (this->getValue() == other.getValue()). - */ - bool operator== (const Value& other) const; - - /** Compares two values. - This is a compare-by-value comparison, so is effectively the same as - saying (this->getValue() != other.getValue()). - */ - bool operator!= (const Value& other) const; - - //============================================================================== - /** Receives callbacks when a Value object changes. - @see Value::addListener - */ - class JUCE_API Listener - { - public: - Listener() {} - virtual ~Listener() {} - - /** Called when a Value object is changed. - - Note that the Value object passed as a parameter may not be exactly the same - object that you registered the listener with - it might be a copy that refers - to the same underlying ValueSource. To find out, you can call Value::refersToSameSourceAs(). - */ - virtual void valueChanged (Value& value) = 0; - }; - - /** Adds a listener to receive callbacks when the value changes. - - The listener is added to this specific Value object, and not to the shared - object that it refers to. When this object is deleted, all the listeners will - be lost, even if other references to the same Value still exist. So when you're - adding a listener, make sure that you add it to a Value instance that will last - for as long as you need the listener. In general, you'd never want to add a listener - to a local stack-based Value, but more likely to one that's a member variable. - - @see removeListener - */ - void addListener (Listener* listener); - - /** Removes a listener that was previously added with addListener(). */ - void removeListener (Listener* listener); - - - //============================================================================== - /** - Used internally by the Value class as the base class for its shared value objects. - - The Value class is essentially a reference-counted pointer to a shared instance - of a ValueSource object. If you're feeling adventurous, you can create your own custom - ValueSource classes to allow Value objects to represent your own custom data items. - */ - class JUCE_API ValueSource : public ReferenceCountedObject, - private AsyncUpdater - { - public: - ValueSource(); - virtual ~ValueSource(); - - /** Returns the current value of this object. */ - virtual var getValue() const = 0; - - /** Changes the current value. - This must also trigger a change message if the value actually changes. - */ - virtual void setValue (const var& newValue) = 0; - - /** Delivers a change message to all the listeners that are registered with - this value. - - If dispatchSynchronously is true, the method will call all the listeners - before returning; otherwise it'll dispatch a message and make the call later. - */ - void sendChangeMessage (bool dispatchSynchronously); - - protected: - //============================================================================== - friend class Value; - SortedSet valuesWithListeners; - - private: - void handleAsyncUpdate() override; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueSource) - }; - - - //============================================================================== - /** Creates a Value object that uses this valueSource object as its underlying data. */ - explicit Value (ValueSource* valueSource); - - /** Returns the ValueSource that this value is referring to. */ - ValueSource& getValueSource() noexcept { return *value; } - - -private: - //============================================================================== - friend class ValueSource; - ReferenceCountedObjectPtr value; - ListenerList listeners; - - void callListeners(); - void removeFromListenerList(); - - // This is disallowed to avoid confusion about whether it should - // do a by-value or by-reference copy. - Value& operator= (const Value&) JUCE_DELETED_FUNCTION; - - // This declaration prevents accidental construction from an integer of 0, - // which is possible in some compilers via an implicit cast to a pointer. - explicit Value (void*) JUCE_DELETED_FUNCTION; -}; - -/** Writes a Value to an OutputStream as a UTF8 string. */ -OutputStream& JUCE_CALLTYPE operator<< (OutputStream&, const Value&); - -/** This typedef is just for compatibility with old code - newer code should use the Value::Listener class directly. */ -typedef Value::Listener ValueListener; - -} // namespace juce diff --git a/source/modules/juce_data_structures/values/juce_ValueTree.cpp b/source/modules/juce_data_structures/values/juce_ValueTree.cpp deleted file mode 100644 index b1e596e35..000000000 --- a/source/modules/juce_data_structures/values/juce_ValueTree.cpp +++ /dev/null @@ -1,1151 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -class ValueTree::SharedObject : public ReferenceCountedObject -{ -public: - typedef ReferenceCountedObjectPtr Ptr; - - explicit SharedObject (const Identifier& t) noexcept : type (t) - { - } - - SharedObject (const SharedObject& other) - : ReferenceCountedObject(), type (other.type), properties (other.properties) - { - for (int i = 0; i < other.children.size(); ++i) - { - auto child = new SharedObject (*other.children.getObjectPointerUnchecked(i)); - child->parent = this; - children.add (child); - } - } - - ~SharedObject() - { - jassert (parent == nullptr); // this should never happen unless something isn't obeying the ref-counting! - - for (int i = children.size(); --i >= 0;) - { - const Ptr c (children.getObjectPointerUnchecked(i)); - c->parent = nullptr; - children.remove (i); - c->sendParentChangeMessage(); - } - } - - SharedObject* getRoot() noexcept - { - return parent == nullptr ? this : parent->getRoot(); - } - - template - void callListeners (Function fn) const - { - auto numListeners = valueTreesWithListeners.size(); - - if (numListeners == 1) - { - fn (valueTreesWithListeners.getUnchecked(0)->listeners); - } - else if (numListeners > 0) - { - auto listenersCopy = valueTreesWithListeners; - - for (int i = 0; i < numListeners; ++i) - { - auto* v = listenersCopy.getUnchecked(i); - - if (i == 0 || valueTreesWithListeners.contains (v)) - fn (v->listeners); - } - } - } - - template - void callListenersForAllParents (Function fn) const - { - for (auto* t = this; t != nullptr; t = t->parent) - t->callListeners (fn); - } - - void sendPropertyChangeMessage (const Identifier& property, ValueTree::Listener* listenerToExclude = nullptr) - { - ValueTree tree (this); - - callListenersForAllParents ([&] (ListenerList& list) { list.callExcluding (listenerToExclude, &ValueTree::Listener::valueTreePropertyChanged, tree, property); }); - } - - void sendChildAddedMessage (ValueTree child) - { - ValueTree tree (this); - callListenersForAllParents ([&] (ListenerList& list) { list.call (&ValueTree::Listener::valueTreeChildAdded, tree, child); }); - } - - void sendChildRemovedMessage (ValueTree child, int index) - { - ValueTree tree (this); - callListenersForAllParents ([=, &tree, &child] (ListenerList& list) { list.call (&ValueTree::Listener::valueTreeChildRemoved, tree, child, index); }); - } - - void sendChildOrderChangedMessage (int oldIndex, int newIndex) - { - ValueTree tree (this); - callListenersForAllParents ([=, &tree] (ListenerList& list) { list.call (&ValueTree::Listener::valueTreeChildOrderChanged, tree, oldIndex, newIndex); }); - } - - void sendParentChangeMessage() - { - ValueTree tree (this); - - for (int j = children.size(); --j >= 0;) - if (auto* child = children.getObjectPointer (j)) - child->sendParentChangeMessage(); - - callListeners ([&] (ListenerList& list) { list.call (&ValueTree::Listener::valueTreeParentChanged, tree); }); - } - - void setProperty (const Identifier& name, const var& newValue, UndoManager* const undoManager, - ValueTree::Listener* listenerToExclude = nullptr) - { - if (undoManager == nullptr) - { - if (properties.set (name, newValue)) - sendPropertyChangeMessage (name, listenerToExclude); - } - else - { - if (auto* existingValue = properties.getVarPointer (name)) - { - if (*existingValue != newValue) - undoManager->perform (new SetPropertyAction (this, name, newValue, *existingValue, false, false, listenerToExclude)); - } - else - { - undoManager->perform (new SetPropertyAction (this, name, newValue, {}, true, false, listenerToExclude)); - } - } - } - - bool hasProperty (const Identifier& name) const noexcept - { - return properties.contains (name); - } - - void removeProperty (const Identifier& name, UndoManager* const undoManager) - { - if (undoManager == nullptr) - { - if (properties.remove (name)) - sendPropertyChangeMessage (name); - } - else - { - if (properties.contains (name)) - undoManager->perform (new SetPropertyAction (this, name, {}, properties [name], false, true)); - } - } - - void removeAllProperties (UndoManager* const undoManager) - { - if (undoManager == nullptr) - { - while (properties.size() > 0) - { - auto name = properties.getName (properties.size() - 1); - properties.remove (name); - sendPropertyChangeMessage (name); - } - } - else - { - for (int i = properties.size(); --i >= 0;) - undoManager->perform (new SetPropertyAction (this, properties.getName(i), {}, - properties.getValueAt(i), false, true)); - } - } - - void copyPropertiesFrom (const SharedObject& source, UndoManager* const undoManager) - { - for (int i = properties.size(); --i >= 0;) - if (! source.properties.contains (properties.getName (i))) - removeProperty (properties.getName (i), undoManager); - - for (int i = 0; i < source.properties.size(); ++i) - setProperty (source.properties.getName(i), source.properties.getValueAt(i), undoManager); - } - - ValueTree getChildWithName (const Identifier& typeToMatch) const - { - for (auto* s : children) - if (s->type == typeToMatch) - return ValueTree (s); - - return {}; - } - - ValueTree getOrCreateChildWithName (const Identifier& typeToMatch, UndoManager* undoManager) - { - for (auto* s : children) - if (s->type == typeToMatch) - return ValueTree (s); - - auto newObject = new SharedObject (typeToMatch); - addChild (newObject, -1, undoManager); - return ValueTree (newObject); - - } - - ValueTree getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const - { - for (auto* s : children) - if (s->properties[propertyName] == propertyValue) - return ValueTree (s); - - return {}; - } - - bool isAChildOf (const SharedObject* const possibleParent) const noexcept - { - for (auto* p = parent; p != nullptr; p = p->parent) - if (p == possibleParent) - return true; - - return false; - } - - int indexOf (const ValueTree& child) const noexcept - { - return children.indexOf (child.object); - } - - void addChild (SharedObject* child, int index, UndoManager* const undoManager) - { - if (child != nullptr && child->parent != this) - { - if (child != this && ! isAChildOf (child)) - { - // You should always make sure that a child is removed from its previous parent before - // adding it somewhere else - otherwise, it's ambiguous as to whether a different - // undomanager should be used when removing it from its current parent.. - jassert (child->parent == nullptr); - - if (child->parent != nullptr) - { - jassert (child->parent->children.indexOf (child) >= 0); - child->parent->removeChild (child->parent->children.indexOf (child), undoManager); - } - - if (undoManager == nullptr) - { - children.insert (index, child); - child->parent = this; - sendChildAddedMessage (ValueTree (child)); - child->sendParentChangeMessage(); - } - else - { - if (! isPositiveAndBelow (index, children.size())) - index = children.size(); - - undoManager->perform (new AddOrRemoveChildAction (this, index, child)); - } - } - else - { - // You're attempting to create a recursive loop! A node - // can't be a child of one of its own children! - jassertfalse; - } - } - } - - void removeChild (const int childIndex, UndoManager* const undoManager) - { - if (const Ptr child = children.getObjectPointer (childIndex)) - { - if (undoManager == nullptr) - { - children.remove (childIndex); - child->parent = nullptr; - sendChildRemovedMessage (ValueTree (child), childIndex); - child->sendParentChangeMessage(); - } - else - { - undoManager->perform (new AddOrRemoveChildAction (this, childIndex, nullptr)); - } - } - } - - void removeAllChildren (UndoManager* const undoManager) - { - while (children.size() > 0) - removeChild (children.size() - 1, undoManager); - } - - void moveChild (int currentIndex, int newIndex, UndoManager* undoManager) - { - // The source index must be a valid index! - jassert (isPositiveAndBelow (currentIndex, children.size())); - - if (currentIndex != newIndex - && isPositiveAndBelow (currentIndex, children.size())) - { - if (undoManager == nullptr) - { - children.move (currentIndex, newIndex); - sendChildOrderChangedMessage (currentIndex, newIndex); - } - else - { - if (! isPositiveAndBelow (newIndex, children.size())) - newIndex = children.size() - 1; - - undoManager->perform (new MoveChildAction (this, currentIndex, newIndex)); - } - } - } - - void reorderChildren (const OwnedArray& newOrder, UndoManager* undoManager) - { - jassert (newOrder.size() == children.size()); - - for (int i = 0; i < children.size(); ++i) - { - auto* child = newOrder.getUnchecked(i)->object.get(); - - if (children.getObjectPointerUnchecked (i) != child) - { - const int oldIndex = children.indexOf (child); - jassert (oldIndex >= 0); - moveChild (oldIndex, i, undoManager); - } - } - } - - bool isEquivalentTo (const SharedObject& other) const noexcept - { - if (type != other.type - || properties.size() != other.properties.size() - || children.size() != other.children.size() - || properties != other.properties) - return false; - - for (int i = 0; i < children.size(); ++i) - if (! children.getObjectPointerUnchecked(i)->isEquivalentTo (*other.children.getObjectPointerUnchecked(i))) - return false; - - return true; - } - - XmlElement* createXml() const - { - auto xml = new XmlElement (type); - properties.copyToXmlAttributes (*xml); - - // (NB: it's faster to add nodes to XML elements in reverse order) - for (int i = children.size(); --i >= 0;) - xml->prependChildElement (children.getObjectPointerUnchecked(i)->createXml()); - - return xml; - } - - void writeToStream (OutputStream& output) const - { - output.writeString (type.toString()); - output.writeCompressedInt (properties.size()); - - for (int j = 0; j < properties.size(); ++j) - { - output.writeString (properties.getName (j).toString()); - properties.getValueAt(j).writeToStream (output); - } - - output.writeCompressedInt (children.size()); - - for (int i = 0; i < children.size(); ++i) - writeObjectToStream (output, children.getObjectPointerUnchecked(i)); - } - - static void writeObjectToStream (OutputStream& output, const SharedObject* const object) - { - if (object != nullptr) - { - object->writeToStream (output); - } - else - { - output.writeString (String()); - output.writeCompressedInt (0); - output.writeCompressedInt (0); - } - } - - //============================================================================== - struct SetPropertyAction : public UndoableAction - { - SetPropertyAction (SharedObject* const so, const Identifier& propertyName, - const var& newVal, const var& oldVal, bool isAdding, bool isDeleting, - ValueTree::Listener* listenerToExclude = nullptr) - : target (so), name (propertyName), newValue (newVal), oldValue (oldVal), - isAddingNewProperty (isAdding), isDeletingProperty (isDeleting), - excludeListener (listenerToExclude) - { - } - - bool perform() override - { - jassert (! (isAddingNewProperty && target->hasProperty (name))); - - if (isDeletingProperty) - target->removeProperty (name, nullptr); - else - target->setProperty (name, newValue, nullptr, excludeListener); - - return true; - } - - bool undo() override - { - if (isAddingNewProperty) - target->removeProperty (name, nullptr); - else - target->setProperty (name, oldValue, nullptr); - - return true; - } - - int getSizeInUnits() override - { - return (int) sizeof (*this); //xxx should be more accurate - } - - UndoableAction* createCoalescedAction (UndoableAction* nextAction) override - { - if (! (isAddingNewProperty || isDeletingProperty)) - { - if (SetPropertyAction* const next = dynamic_cast (nextAction)) - if (next->target == target && next->name == name - && ! (next->isAddingNewProperty || next->isDeletingProperty)) - return new SetPropertyAction (target, name, next->newValue, oldValue, false, false); - } - - return nullptr; - } - - private: - const Ptr target; - const Identifier name; - const var newValue; - var oldValue; - const bool isAddingNewProperty : 1, isDeletingProperty : 1; - ValueTree::Listener* excludeListener; - - JUCE_DECLARE_NON_COPYABLE (SetPropertyAction) - }; - - //============================================================================== - struct AddOrRemoveChildAction : public UndoableAction - { - AddOrRemoveChildAction (SharedObject* parentObject, int index, SharedObject* newChild) - : target (parentObject), - child (newChild != nullptr ? newChild : parentObject->children.getObjectPointer (index)), - childIndex (index), - isDeleting (newChild == nullptr) - { - jassert (child != nullptr); - } - - bool perform() override - { - if (isDeleting) - target->removeChild (childIndex, nullptr); - else - target->addChild (child, childIndex, nullptr); - - return true; - } - - bool undo() override - { - if (isDeleting) - { - target->addChild (child, childIndex, nullptr); - } - else - { - // If you hit this, it seems that your object's state is getting confused - probably - // because you've interleaved some undoable and non-undoable operations? - jassert (childIndex < target->children.size()); - target->removeChild (childIndex, nullptr); - } - - return true; - } - - int getSizeInUnits() override - { - return (int) sizeof (*this); //xxx should be more accurate - } - - private: - const Ptr target, child; - const int childIndex; - const bool isDeleting; - - JUCE_DECLARE_NON_COPYABLE (AddOrRemoveChildAction) - }; - - //============================================================================== - struct MoveChildAction : public UndoableAction - { - MoveChildAction (SharedObject* parentObject, int fromIndex, int toIndex) noexcept - : parent (parentObject), startIndex (fromIndex), endIndex (toIndex) - { - } - - bool perform() override - { - parent->moveChild (startIndex, endIndex, nullptr); - return true; - } - - bool undo() override - { - parent->moveChild (endIndex, startIndex, nullptr); - return true; - } - - int getSizeInUnits() override - { - return (int) sizeof (*this); //xxx should be more accurate - } - - UndoableAction* createCoalescedAction (UndoableAction* nextAction) override - { - if (auto* next = dynamic_cast (nextAction)) - if (next->parent == parent && next->startIndex == endIndex) - return new MoveChildAction (parent, startIndex, next->endIndex); - - return nullptr; - } - - private: - const Ptr parent; - const int startIndex, endIndex; - - JUCE_DECLARE_NON_COPYABLE (MoveChildAction) - }; - - //============================================================================== - const Identifier type; - NamedValueSet properties; - ReferenceCountedArray children; - SortedSet valueTreesWithListeners; - SharedObject* parent = nullptr; - -private: - SharedObject& operator= (const SharedObject&); - JUCE_LEAK_DETECTOR (SharedObject) -}; - -//============================================================================== -ValueTree::ValueTree() noexcept -{ -} - -#if JUCE_ALLOW_STATIC_NULL_VARIABLES -const ValueTree ValueTree::invalid; -#endif - -ValueTree::ValueTree (const Identifier& type) : object (new ValueTree::SharedObject (type)) -{ - jassert (type.toString().isNotEmpty()); // All objects must be given a sensible type name! -} - -ValueTree::ValueTree (SharedObject* so) noexcept : object (so) -{ -} - -ValueTree::ValueTree (const ValueTree& other) noexcept : object (other.object) -{ -} - -ValueTree& ValueTree::operator= (const ValueTree& other) -{ - if (object != other.object) - { - if (listeners.isEmpty()) - { - object = other.object; - } - else - { - if (object != nullptr) - object->valueTreesWithListeners.removeValue (this); - - if (other.object != nullptr) - other.object->valueTreesWithListeners.add (this); - - object = other.object; - - listeners.call (&ValueTree::Listener::valueTreeRedirected, *this); - } - } - - return *this; -} - -ValueTree::ValueTree (ValueTree&& other) noexcept - : object (static_cast (other.object)) -{ -} - -ValueTree::~ValueTree() -{ - if (listeners.size() > 0 && object != nullptr) - object->valueTreesWithListeners.removeValue (this); -} - -bool ValueTree::operator== (const ValueTree& other) const noexcept -{ - return object == other.object; -} - -bool ValueTree::operator!= (const ValueTree& other) const noexcept -{ - return object != other.object; -} - -bool ValueTree::isEquivalentTo (const ValueTree& other) const -{ - return object == other.object - || (object != nullptr && other.object != nullptr - && object->isEquivalentTo (*other.object)); -} - -ValueTree ValueTree::createCopy() const -{ - return ValueTree (createCopyIfNotNull (object.get())); -} - -bool ValueTree::hasType (const Identifier& typeName) const noexcept -{ - return object != nullptr && object->type == typeName; -} - -Identifier ValueTree::getType() const noexcept -{ - return object != nullptr ? object->type : Identifier(); -} - -ValueTree ValueTree::getParent() const noexcept -{ - return ValueTree (object != nullptr ? object->parent - : static_cast (nullptr)); -} - -ValueTree ValueTree::getRoot() const noexcept -{ - return ValueTree (object != nullptr ? object->getRoot() - : static_cast (nullptr)); -} - -ValueTree ValueTree::getSibling (const int delta) const noexcept -{ - if (object == nullptr || object->parent == nullptr) - return {}; - - const int index = object->parent->indexOf (*this) + delta; - return ValueTree (object->parent->children.getObjectPointer (index)); -} - -static const var& getNullVarRef() noexcept -{ - #if JUCE_ALLOW_STATIC_NULL_VARIABLES - return var::null; - #else - static var nullVar; - return nullVar; - #endif -} - -const var& ValueTree::operator[] (const Identifier& name) const noexcept -{ - return object == nullptr ? getNullVarRef() : object->properties[name]; -} - -const var& ValueTree::getProperty (const Identifier& name) const noexcept -{ - return object == nullptr ? getNullVarRef() : object->properties[name]; -} - -var ValueTree::getProperty (const Identifier& name, const var& defaultReturnValue) const -{ - return object == nullptr ? defaultReturnValue - : object->properties.getWithDefault (name, defaultReturnValue); -} - -const var* ValueTree::getPropertyPointer (const Identifier& name) const noexcept -{ - return object == nullptr ? nullptr - : object->properties.getVarPointer (name); -} - -ValueTree& ValueTree::setProperty (const Identifier& name, const var& newValue, UndoManager* undoManager) -{ - return setPropertyExcludingListener (nullptr, name, newValue, undoManager); -} - -ValueTree& ValueTree::setPropertyExcludingListener (Listener* listenerToExclude, const Identifier& name, const var& newValue, UndoManager* undoManager) -{ - jassert (name.toString().isNotEmpty()); // Must have a valid property name! - jassert (object != nullptr); // Trying to add a property to a null ValueTree will fail! - - if (object != nullptr) - object->setProperty (name, newValue, undoManager, listenerToExclude); - - return *this; -} - -bool ValueTree::hasProperty (const Identifier& name) const noexcept -{ - return object != nullptr && object->hasProperty (name); -} - -void ValueTree::removeProperty (const Identifier& name, UndoManager* const undoManager) -{ - if (object != nullptr) - object->removeProperty (name, undoManager); -} - -void ValueTree::removeAllProperties (UndoManager* const undoManager) -{ - if (object != nullptr) - object->removeAllProperties (undoManager); -} - -int ValueTree::getNumProperties() const noexcept -{ - return object == nullptr ? 0 : object->properties.size(); -} - -Identifier ValueTree::getPropertyName (const int index) const noexcept -{ - return object == nullptr ? Identifier() - : object->properties.getName (index); -} - -void ValueTree::copyPropertiesFrom (const ValueTree& source, UndoManager* const undoManager) -{ - jassert (object != nullptr || source.object == nullptr); // Trying to add properties to a null ValueTree will fail! - - if (source.object == nullptr) - removeAllProperties (undoManager); - else if (object != nullptr) - object->copyPropertiesFrom (*(source.object), undoManager); -} - -int ValueTree::getReferenceCount() const noexcept -{ - return object != nullptr ? object->getReferenceCount() : 0; -} - -//============================================================================== -class ValueTreePropertyValueSource : public Value::ValueSource, - private ValueTree::Listener -{ -public: - ValueTreePropertyValueSource (const ValueTree& vt, const Identifier& prop, UndoManager* um) - : tree (vt), property (prop), undoManager (um) - { - tree.addListener (this); - } - - ~ValueTreePropertyValueSource() - { - tree.removeListener (this); - } - - var getValue() const override { return tree [property]; } - void setValue (const var& newValue) override { tree.setProperty (property, newValue, undoManager); } - -private: - ValueTree tree; - const Identifier property; - UndoManager* const undoManager; - - void valueTreePropertyChanged (ValueTree& changedTree, const Identifier& changedProperty) override - { - if (tree == changedTree && property == changedProperty) - sendChangeMessage (false); - } - - void valueTreeChildAdded (ValueTree&, ValueTree&) override {} - void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override {} - void valueTreeChildOrderChanged (ValueTree&, int, int) override {} - void valueTreeParentChanged (ValueTree&) override {} - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueTreePropertyValueSource) -}; - -Value ValueTree::getPropertyAsValue (const Identifier& name, UndoManager* const undoManager) -{ - return Value (new ValueTreePropertyValueSource (*this, name, undoManager)); -} - -//============================================================================== -int ValueTree::getNumChildren() const noexcept -{ - return object == nullptr ? 0 : object->children.size(); -} - -ValueTree ValueTree::getChild (int index) const -{ - return ValueTree (object != nullptr ? object->children.getObjectPointer (index) - : static_cast (nullptr)); -} - -ValueTree::Iterator::Iterator (const ValueTree& v, bool isEnd) noexcept - : internal (v.object != nullptr ? (isEnd ? v.object->children.end() : v.object->children.begin()) : nullptr) -{} - -ValueTree::Iterator& ValueTree::Iterator::operator++() noexcept -{ - internal = static_cast (internal) + 1; - return *this; -} - -bool ValueTree::Iterator::operator!= (const Iterator& other) const noexcept -{ - return internal != other.internal; -} - -ValueTree ValueTree::Iterator::operator*() const -{ - return ValueTree (*static_cast (internal)); -} - -ValueTree::Iterator ValueTree::begin() const noexcept { return Iterator (*this, false); } -ValueTree::Iterator ValueTree::end() const noexcept { return Iterator (*this, true); } - -ValueTree ValueTree::getChildWithName (const Identifier& type) const -{ - return object != nullptr ? object->getChildWithName (type) : ValueTree(); -} - -ValueTree ValueTree::getOrCreateChildWithName (const Identifier& type, UndoManager* undoManager) -{ - return object != nullptr ? object->getOrCreateChildWithName (type, undoManager) : ValueTree(); -} - -ValueTree ValueTree::getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const -{ - return object != nullptr ? object->getChildWithProperty (propertyName, propertyValue) : ValueTree(); -} - -bool ValueTree::isAChildOf (const ValueTree& possibleParent) const noexcept -{ - return object != nullptr && object->isAChildOf (possibleParent.object); -} - -int ValueTree::indexOf (const ValueTree& child) const noexcept -{ - return object != nullptr ? object->indexOf (child) : -1; -} - -void ValueTree::addChild (const ValueTree& child, int index, UndoManager* const undoManager) -{ - jassert (object != nullptr); // Trying to add a child to a null ValueTree! - - if (object != nullptr) - object->addChild (child.object, index, undoManager); -} - -void ValueTree::removeChild (const int childIndex, UndoManager* const undoManager) -{ - if (object != nullptr) - object->removeChild (childIndex, undoManager); -} - -void ValueTree::removeChild (const ValueTree& child, UndoManager* const undoManager) -{ - if (object != nullptr) - object->removeChild (object->children.indexOf (child.object), undoManager); -} - -void ValueTree::removeAllChildren (UndoManager* const undoManager) -{ - if (object != nullptr) - object->removeAllChildren (undoManager); -} - -void ValueTree::moveChild (int currentIndex, int newIndex, UndoManager* undoManager) -{ - if (object != nullptr) - object->moveChild (currentIndex, newIndex, undoManager); -} - -//============================================================================== -void ValueTree::createListOfChildren (OwnedArray& list) const -{ - jassert (object != nullptr); - - for (int i = 0; i < object->children.size(); ++i) - list.add (new ValueTree (object->children.getObjectPointerUnchecked(i))); -} - -void ValueTree::reorderChildren (const OwnedArray& newOrder, UndoManager* undoManager) -{ - jassert (object != nullptr); - object->reorderChildren (newOrder, undoManager); -} - -//============================================================================== -void ValueTree::addListener (Listener* listener) -{ - if (listener != nullptr) - { - if (listeners.isEmpty() && object != nullptr) - object->valueTreesWithListeners.add (this); - - listeners.add (listener); - } -} - -void ValueTree::removeListener (Listener* listener) -{ - listeners.remove (listener); - - if (listeners.isEmpty() && object != nullptr) - object->valueTreesWithListeners.removeValue (this); -} - -void ValueTree::sendPropertyChangeMessage (const Identifier& property) -{ - if (object != nullptr) - object->sendPropertyChangeMessage (property); -} - -//============================================================================== -XmlElement* ValueTree::createXml() const -{ - return object != nullptr ? object->createXml() : nullptr; -} - -ValueTree ValueTree::fromXml (const XmlElement& xml) -{ - if (! xml.isTextElement()) - { - ValueTree v (xml.getTagName()); - v.object->properties.setFromXmlAttributes (xml); - - forEachXmlChildElement (xml, e) - v.addChild (fromXml (*e), -1, nullptr); - - return v; - } - - // ValueTrees don't have any equivalent to XML text elements! - jassertfalse; - return {}; -} - -String ValueTree::toXmlString() const -{ - const ScopedPointer xml (createXml()); - return xml != nullptr ? xml->createDocument (StringRef()) : String(); -} - -//============================================================================== -void ValueTree::writeToStream (OutputStream& output) const -{ - SharedObject::writeObjectToStream (output, object); -} - -ValueTree ValueTree::readFromStream (InputStream& input) -{ - auto type = input.readString(); - - if (type.isEmpty()) - return {}; - - ValueTree v (type); - - const int numProps = input.readCompressedInt(); - - if (numProps < 0) - { - jassertfalse; // trying to read corrupted data! - return v; - } - - for (int i = 0; i < numProps; ++i) - { - const String name (input.readString()); - - if (name.isNotEmpty()) - { - const var value (var::readFromStream (input)); - v.object->properties.set (name, value); - } - else - { - jassertfalse; // trying to read corrupted data! - } - } - - const int numChildren = input.readCompressedInt(); - v.object->children.ensureStorageAllocated (numChildren); - - for (int i = 0; i < numChildren; ++i) - { - ValueTree child (readFromStream (input)); - - if (! child.isValid()) - return v; - - v.object->children.add (child.object); - child.object->parent = v.object; - } - - return v; -} - -ValueTree ValueTree::readFromData (const void* const data, const size_t numBytes) -{ - MemoryInputStream in (data, numBytes, false); - return readFromStream (in); -} - -ValueTree ValueTree::readFromGZIPData (const void* const data, const size_t numBytes) -{ - MemoryInputStream in (data, numBytes, false); - GZIPDecompressorInputStream gzipStream (in); - return readFromStream (gzipStream); -} - -void ValueTree::Listener::valueTreeRedirected (ValueTree&) {} - -//============================================================================== -#if JUCE_UNIT_TESTS - -class ValueTreeTests : public UnitTest -{ -public: - ValueTreeTests() : UnitTest ("ValueTrees", "Values") {} - - static String createRandomIdentifier (Random& r) - { - char buffer[50] = { 0 }; - const char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-:"; - - for (int i = 1 + r.nextInt (numElementsInArray (buffer) - 2); --i >= 0;) - buffer[i] = chars [r.nextInt (sizeof (chars) - 1)]; - - String result (buffer); - - if (! XmlElement::isValidXmlName (result)) - result = createRandomIdentifier (r); - - return result; - } - - static String createRandomWideCharString (Random& r) - { - juce_wchar buffer[50] = { 0 }; - - for (int i = r.nextInt (numElementsInArray (buffer) - 1); --i >= 0;) - { - if (r.nextBool()) - { - do - { - buffer[i] = (juce_wchar) (1 + r.nextInt (0x10ffff - 1)); - } - while (! CharPointer_UTF16::canRepresent (buffer[i])); - } - else - buffer[i] = (juce_wchar) (1 + r.nextInt (0x7e)); - } - - return CharPointer_UTF32 (buffer); - } - - static ValueTree createRandomTree (UndoManager* undoManager, int depth, Random& r) - { - ValueTree v (createRandomIdentifier (r)); - - for (int i = r.nextInt (10); --i >= 0;) - { - switch (r.nextInt (5)) - { - case 0: v.setProperty (createRandomIdentifier (r), createRandomWideCharString (r), undoManager); break; - case 1: v.setProperty (createRandomIdentifier (r), r.nextInt(), undoManager); break; - case 2: if (depth < 5) v.addChild (createRandomTree (undoManager, depth + 1, r), r.nextInt (v.getNumChildren() + 1), undoManager); break; - case 3: v.setProperty (createRandomIdentifier (r), r.nextBool(), undoManager); break; - case 4: v.setProperty (createRandomIdentifier (r), r.nextDouble(), undoManager); break; - default: break; - } - } - - return v; - } - - void runTest() override - { - beginTest ("ValueTree"); - Random r = getRandom(); - - for (int i = 10; --i >= 0;) - { - MemoryOutputStream mo; - ValueTree v1 (createRandomTree (nullptr, 0, r)); - v1.writeToStream (mo); - - MemoryInputStream mi (mo.getData(), mo.getDataSize(), false); - ValueTree v2 = ValueTree::readFromStream (mi); - expect (v1.isEquivalentTo (v2)); - - ScopedPointer xml1 (v1.createXml()); - ScopedPointer xml2 (v2.createCopy().createXml()); - expect (xml1->isEquivalentTo (xml2, false)); - - ValueTree v4 = v2.createCopy(); - expect (v1.isEquivalentTo (v4)); - } - } -}; - -static ValueTreeTests valueTreeTests; - -#endif - -} // namespace juce diff --git a/source/modules/juce_data_structures/values/juce_ValueTree.h b/source/modules/juce_data_structures/values/juce_ValueTree.h deleted file mode 100644 index d0a66f0cf..000000000 --- a/source/modules/juce_data_structures/values/juce_ValueTree.h +++ /dev/null @@ -1,578 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A powerful tree structure that can be used to hold free-form data, and which can - handle its own undo and redo behaviour. - - A ValueTree contains a list of named properties as var objects, and also holds - any number of sub-trees. - - Create ValueTree objects on the stack, and don't be afraid to copy them around, as - they're simply a lightweight reference to a shared data container. Creating a copy - of another ValueTree simply creates a new reference to the same underlying object - to - make a separate, deep copy of a tree you should explicitly call createCopy(). - - Each ValueTree has a type name, in much the same way as an XmlElement has a tag name, - and much of the structure of a ValueTree is similar to an XmlElement tree. - You can convert a ValueTree to and from an XmlElement, and as long as the XML doesn't - contain text elements, the conversion works well and makes a good serialisation - format. They can also be serialised to a binary format, which is very fast and compact. - - All the methods that change data take an optional UndoManager, which will be used - to track any changes to the object. For this to work, you have to be careful to - consistently always use the same UndoManager for all operations to any node inside - the tree. - - A ValueTree can only be a child of one parent at a time, so if you're moving one from - one tree to another, be careful to always remove it first, before adding it. This - could also mess up your undo/redo chain, so be wary! In a debug build you should hit - assertions if you try to do anything dangerous, but there are still plenty of ways it - could go wrong. - - Note that although the children in a tree have a fixed order, the properties are not - guaranteed to be stored in any particular order, so don't expect that a property's index - will correspond to the order in which the property was added, or that it will remain - constant when other properties are added or removed. - - Listeners can be added to a ValueTree to be told when properies change and when - nodes are added or removed. - - @see var, XmlElement -*/ -class JUCE_API ValueTree -{ -public: - //============================================================================== - /** Creates an empty, invalid ValueTree. - - A ValueTree that is created with this constructor can't actually be used for anything, - it's just a default 'null' ValueTree that can be returned to indicate some sort of failure. - To create a real one, use the constructor that takes a string. - */ - ValueTree() noexcept; - - /** Creates an empty ValueTree with the given type name. - Like an XmlElement, each ValueTree node has a type, which you can access with - getType() and hasType(). - */ - explicit ValueTree (const Identifier& type); - - /** Creates a reference to another ValueTree. */ - ValueTree (const ValueTree&) noexcept; - - /** Makes this object reference another node. */ - ValueTree& operator= (const ValueTree&); - - /** Move constructor */ - ValueTree (ValueTree&&) noexcept; - - /** Destructor. */ - ~ValueTree(); - - /** Returns true if both this and the other tree node refer to the same underlying structure. - Note that this isn't a value comparison - two independently-created trees which - contain identical data are not considered equal. - */ - bool operator== (const ValueTree&) const noexcept; - - /** Returns true if this and the other node refer to different underlying structures. - Note that this isn't a value comparison - two independently-created trees which - contain identical data are not considered equal. - */ - bool operator!= (const ValueTree&) const noexcept; - - /** Performs a deep comparison between the properties and children of two trees. - If all the properties and children of the two trees are the same (recursively), this - returns true. - The normal operator==() only checks whether two trees refer to the same shared data - structure, so use this method if you need to do a proper value comparison. - */ - bool isEquivalentTo (const ValueTree&) const; - - //============================================================================== - /** Returns true if this node refers to some valid data. - It's hard to create an invalid node, but you might get one returned, e.g. by an out-of-range - call to getChild(). - */ - bool isValid() const noexcept { return object != nullptr; } - - /** Returns a deep copy of this tree and all its sub-nodes. */ - ValueTree createCopy() const; - - //============================================================================== - /** Returns the type of this node. - The type is specified when the ValueTree is created. - @see hasType - */ - Identifier getType() const noexcept; - - /** Returns true if the node has this type. - The comparison is case-sensitive. - */ - bool hasType (const Identifier& typeName) const noexcept; - - //============================================================================== - /** Returns the value of a named property. - If no such property has been set, this will return a void variant. - You can also use operator[] to get a property. - @see var, setProperty, getPropertyPointer, hasProperty - */ - const var& getProperty (const Identifier& name) const noexcept; - - /** Returns the value of a named property, or the value of defaultReturnValue - if the property doesn't exist. - You can also use operator[] and getProperty to get a property. - @see var, getProperty, getPropertyPointer, setProperty, hasProperty - */ - var getProperty (const Identifier& name, const var& defaultReturnValue) const; - - /** Returns a pointer to the value of a named property, or nullptr if the property - doesn't exist. - @see var, getProperty, setProperty, hasProperty - */ - const var* getPropertyPointer (const Identifier& name) const noexcept; - - /** Returns the value of a named property. - If no such property has been set, this will return a void variant. This is the same as - calling getProperty(). - @see getProperty - */ - const var& operator[] (const Identifier& name) const noexcept; - - /** Changes a named property of the node. - The name identifier must not be an empty string. - If the undoManager parameter is non-null, its UndoManager::perform() method will be used, - so that this change can be undone. - @see var, getProperty, removeProperty - @returns a reference to the value tree, so that you can daisy-chain calls to this method. - */ - ValueTree& setProperty (const Identifier& name, const var& newValue, UndoManager* undoManager); - - /** Returns true if the node contains a named property. */ - bool hasProperty (const Identifier& name) const noexcept; - - /** Removes a property from the node. - If the undoManager parameter is non-null, its UndoManager::perform() method will be used, - so that this change can be undone. - */ - void removeProperty (const Identifier& name, UndoManager* undoManager); - - /** Removes all properties from the node. - If the undoManager parameter is non-null, its UndoManager::perform() method will be used, - so that this change can be undone. - */ - void removeAllProperties (UndoManager* undoManager); - - /** Returns the total number of properties that the node contains. - @see getProperty. - */ - int getNumProperties() const noexcept; - - /** Returns the identifier of the property with a given index. - Note that properties are not guaranteed to be stored in any particular order, so don't - expect that the index will correspond to the order in which the property was added, or - that it will remain constant when other properties are added or removed. - @see getNumProperties - */ - Identifier getPropertyName (int index) const noexcept; - - /** Returns a Value object that can be used to control and respond to one of the tree's properties. - - The Value object will maintain a reference to this tree, and will use the undo manager when - it needs to change the value. Attaching a Value::Listener to the value object will provide - callbacks whenever the property changes. - */ - Value getPropertyAsValue (const Identifier& name, UndoManager* undoManager); - - /** Overwrites all the properties in this tree with the properties of the source tree. - Any properties that already exist will be updated; and new ones will be added, and - any that are not present in the source tree will be removed. - */ - void copyPropertiesFrom (const ValueTree& source, UndoManager* undoManager); - - //============================================================================== - /** Returns the number of child nodes belonging to this one. - @see getChild - */ - int getNumChildren() const noexcept; - - /** Returns one of this node's child nodes. - If the index is out of range, it'll return an invalid node. (See isValid() to find out - whether a node is valid). - */ - ValueTree getChild (int index) const; - - /** Returns the first child node with the specified type name. - If no such node is found, it'll return an invalid node. (See isValid() to find out - whether a node is valid). - @see getOrCreateChildWithName - */ - ValueTree getChildWithName (const Identifier& type) const; - - /** Returns the first child node with the specified type name, creating and adding - a child with this name if there wasn't already one there. - - The only time this will return an invalid object is when the object that you're calling - the method on is itself invalid. - @see getChildWithName - */ - ValueTree getOrCreateChildWithName (const Identifier& type, UndoManager* undoManager); - - /** Looks for the first child node that has the specified property value. - - This will scan the child nodes in order, until it finds one that has property that matches - the specified value. - - If no such node is found, it'll return an invalid node. (See isValid() to find out - whether a node is valid). - */ - ValueTree getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const; - - /** Adds a child to this node. - - Make sure that the child is removed from any former parent node before calling this, or - you'll hit an assertion. - - If the index is < 0 or greater than the current number of child nodes, the new node will - be added at the end of the list. - - If the undoManager parameter is non-null, its UndoManager::perform() method will be used, - so that this change can be undone. - */ - void addChild (const ValueTree& child, int index, UndoManager* undoManager); - - /** Removes the specified child from this node's child-list. - If the undoManager parameter is non-null, its UndoManager::perform() method will be used, - so that this change can be undone. - */ - void removeChild (const ValueTree& child, UndoManager* undoManager); - - /** Removes a child from this node's child-list. - If the undoManager parameter is non-null, its UndoManager::perform() method will be used, - so that this change can be undone. - */ - void removeChild (int childIndex, UndoManager* undoManager); - - /** Removes all child-nodes from this node. - If the undoManager parameter is non-null, its UndoManager::perform() method will be used, - so that this change can be undone. - */ - void removeAllChildren (UndoManager* undoManager); - - /** Moves one of the children to a different index. - - This will move the child to a specified index, shuffling along any intervening - items as required. So for example, if you have a list of { 0, 1, 2, 3, 4, 5 }, then - calling move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }. - - @param currentIndex the index of the item to be moved. If this isn't a - valid index, then nothing will be done - @param newIndex the index at which you'd like this item to end up. If this - is less than zero, the value will be moved to the end - of the list - @param undoManager the optional UndoManager to use to store this transaction - */ - void moveChild (int currentIndex, int newIndex, UndoManager* undoManager); - - /** Returns true if this node is anywhere below the specified parent node. - This returns true if the node is a child-of-a-child, as well as a direct child. - */ - bool isAChildOf (const ValueTree& possibleParent) const noexcept; - - /** Returns the index of a child item in this parent. - If the child isn't found, this returns -1. - */ - int indexOf (const ValueTree& child) const noexcept; - - /** Returns the parent node that contains this one. - If the node has no parent, this will return an invalid node. (See isValid() to find out - whether a node is valid). - */ - ValueTree getParent() const noexcept; - - /** Recusrively finds the highest-level parent node that contains this one. - If the node has no parent, this will return itself. - */ - ValueTree getRoot() const noexcept; - - /** Returns one of this node's siblings in its parent's child list. - - The delta specifies how far to move through the list, so a value of 1 would return the node - that follows this one, -1 would return the node before it, 0 will return this node itself, etc. - If the requested position is beyond the range of available nodes, this will return an empty ValueTree(). - */ - ValueTree getSibling (int delta) const noexcept; - - //============================================================================== - struct Iterator - { - Iterator (const ValueTree&, bool isEnd) noexcept; - Iterator& operator++() noexcept; - - bool operator!= (const Iterator&) const noexcept; - ValueTree operator*() const; - - private: - void* internal; - }; - - /** Returns a start iterator for the children in this tree. */ - Iterator begin() const noexcept; - - /** Returns an end iterator for the children in this tree. */ - Iterator end() const noexcept; - - //============================================================================== - /** Creates an XmlElement that holds a complete image of this node and all its children. - - If this node is invalid, this may return nullptr. Otherwise, the XML that is produced can - be used to recreate a similar node by calling fromXml(). - - The caller must delete the object that is returned. - - @see fromXml - */ - XmlElement* createXml() const; - - /** Tries to recreate a node from its XML representation. - - This isn't designed to cope with random XML data - for a sensible result, it should only - be fed XML that was created by the createXml() method. - */ - static ValueTree fromXml (const XmlElement& xml); - - /** This returns a string containing an XML representation of the tree. - This is quite handy for debugging purposes, as it provides a quick way to view a tree. - */ - String toXmlString() const; - - //============================================================================== - /** Stores this tree (and all its children) in a binary format. - - Once written, the data can be read back with readFromStream(). - - It's much faster to load/save your tree in binary form than as XML, but - obviously isn't human-readable. - */ - void writeToStream (OutputStream& output) const; - - /** Reloads a tree from a stream that was written with writeToStream(). */ - static ValueTree readFromStream (InputStream& input); - - /** Reloads a tree from a data block that was written with writeToStream(). */ - static ValueTree readFromData (const void* data, size_t numBytes); - - /** Reloads a tree from a data block that was written with writeToStream() and - then zipped using GZIPCompressorOutputStream. - */ - static ValueTree readFromGZIPData (const void* data, size_t numBytes); - - //============================================================================== - /** Listener class for events that happen to a ValueTree. - - To get events from a ValueTree, make your class implement this interface, and use - ValueTree::addListener() and ValueTree::removeListener() to register it. - */ - class JUCE_API Listener - { - public: - /** Destructor. */ - virtual ~Listener() {} - - /** This method is called when a property of this node (or of one of its sub-nodes) has - changed. - - The tree parameter indicates which tree has had its property changed, and the property - parameter indicates the property. - - Note that when you register a listener to a tree, it will receive this callback for - property changes in that tree, and also for any of its children, (recursively, at any depth). - If your tree has sub-trees but you only want to know about changes to the top level tree, - simply check the tree parameter in this callback to make sure it's the tree you're interested in. - */ - virtual void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, - const Identifier& property) = 0; - - /** This method is called when a child sub-tree is added. - - Note that when you register a listener to a tree, it will receive this callback for - child changes in both that tree and any of its children, (recursively, at any depth). - If your tree has sub-trees but you only want to know about changes to the top level tree, - just check the parentTree parameter to make sure it's the one that you're interested in. - */ - virtual void valueTreeChildAdded (ValueTree& parentTree, - ValueTree& childWhichHasBeenAdded) = 0; - - /** This method is called when a child sub-tree is removed. - - Note that when you register a listener to a tree, it will receive this callback for - child changes in both that tree and any of its children, (recursively, at any depth). - If your tree has sub-trees but you only want to know about changes to the top level tree, - just check the parentTree parameter to make sure it's the one that you're interested in. - */ - virtual void valueTreeChildRemoved (ValueTree& parentTree, - ValueTree& childWhichHasBeenRemoved, - int indexFromWhichChildWasRemoved) = 0; - - /** This method is called when a tree's children have been re-shuffled. - - Note that when you register a listener to a tree, it will receive this callback for - child changes in both that tree and any of its children, (recursively, at any depth). - If your tree has sub-trees but you only want to know about changes to the top level tree, - just check the parameter to make sure it's the tree that you're interested in. - */ - virtual void valueTreeChildOrderChanged (ValueTree& parentTreeWhoseChildrenHaveMoved, - int oldIndex, int newIndex) = 0; - - /** This method is called when a tree has been added or removed from a parent node. - - This callback happens when the tree to which the listener was registered is added or - removed from a parent. Unlike the other callbacks, it applies only to the tree to which - the listener is registered, and not to any of its children. - */ - virtual void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged) = 0; - - /** This method is called when a tree is made to point to a different internal shared object. - When operator= is used to make a ValueTree refer to a different object, this callback - will be made. - */ - virtual void valueTreeRedirected (ValueTree& treeWhichHasBeenChanged); - }; - - /** Adds a listener to receive callbacks when this node is changed. - - The listener is added to this specific ValueTree object, and not to the shared - object that it refers to. When this object is deleted, all the listeners will - be lost, even if other references to the same ValueTree still exist. And if you - use the operator= to make this refer to a different ValueTree, any listeners will - begin listening to changes to the new tree instead of the old one. - - When you're adding a listener, make sure that you add it to a ValueTree instance that - will last for as long as you need the listener. In general, you'd never want to add a - listener to a local stack-based ValueTree, and would usually add one to a member variable. - - @see removeListener - */ - void addListener (Listener* listener); - - /** Removes a listener that was previously added with addListener(). */ - void removeListener (Listener* listener); - - /** Changes a named property of the node, but will not notify a specified listener of the change. - @see setProperty - */ - ValueTree& setPropertyExcludingListener (Listener* listenerToExclude, - const Identifier& name, const var& newValue, - UndoManager* undoManager); - - /** Causes a property-change callback to be triggered for the specified property, - calling any listeners that are registered. - */ - void sendPropertyChangeMessage (const Identifier& property); - - //============================================================================== - /** This method uses a comparator object to sort the tree's children into order. - - The object provided must have a method of the form: - @code - int compareElements (const ValueTree& first, const ValueTree& second); - @endcode - - ..and this method must return: - - a value of < 0 if the first comes before the second - - a value of 0 if the two objects are equivalent - - a value of > 0 if the second comes before the first - - To improve performance, the compareElements() method can be declared as static or const. - - @param comparator the comparator to use for comparing elements. - @param undoManager optional UndoManager for storing the changes - @param retainOrderOfEquivalentItems if this is true, then items which the comparator says are - equivalent will be kept in the order in which they currently appear in the array. - This is slower to perform, but may be important in some cases. If it's false, a - faster algorithm is used, but equivalent elements may be rearranged. - */ - template - void sort (ElementComparator& comparator, UndoManager* undoManager, bool retainOrderOfEquivalentItems) - { - if (object != nullptr) - { - OwnedArray sortedList; - createListOfChildren (sortedList); - ComparatorAdapter adapter (comparator); - sortedList.sort (adapter, retainOrderOfEquivalentItems); - reorderChildren (sortedList, undoManager); - } - } - - #if JUCE_ALLOW_STATIC_NULL_VARIABLES - /** An invalid ValueTree that can be used if you need to return one as an error condition, etc. - This invalid object is equivalent to ValueTree created with its default constructor, but - you should always prefer to avoid it and use ValueTree() or {} instead. - */ - static const ValueTree invalid; - #endif - - /** Returns the total number of references to the shared underlying data structure that this - ValueTree is using. - */ - int getReferenceCount() const noexcept; - -private: - //============================================================================== - JUCE_PUBLIC_IN_DLL_BUILD (class SharedObject) - friend class SharedObject; - - ReferenceCountedObjectPtr object; - ListenerList listeners; - - template - struct ComparatorAdapter - { - ComparatorAdapter (ElementComparator& comp) noexcept : comparator (comp) {} - - int compareElements (const ValueTree* const first, const ValueTree* const second) - { - return comparator.compareElements (*first, *second); - } - - private: - ElementComparator& comparator; - JUCE_DECLARE_NON_COPYABLE (ComparatorAdapter) - }; - - void createListOfChildren (OwnedArray&) const; - void reorderChildren (const OwnedArray&, UndoManager*); - - explicit ValueTree (SharedObject*) noexcept; -}; - -} // namespace juce diff --git a/source/modules/juce_data_structures/values/juce_ValueTreeSynchroniser.cpp b/source/modules/juce_data_structures/values/juce_ValueTreeSynchroniser.cpp deleted file mode 100644 index 7e49e712f..000000000 --- a/source/modules/juce_data_structures/values/juce_ValueTreeSynchroniser.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -namespace ValueTreeSynchroniserHelpers -{ - enum ChangeType - { - propertyChanged = 1, - fullSync = 2, - childAdded = 3, - childRemoved = 4, - childMoved = 5, - propertyRemoved = 6 - }; - - static void getValueTreePath (ValueTree v, const ValueTree& topLevelTree, Array& path) - { - while (v != topLevelTree) - { - ValueTree parent (v.getParent()); - - if (! parent.isValid()) - break; - - path.add (parent.indexOf (v)); - v = parent; - } - } - - static void writeHeader (MemoryOutputStream& stream, ChangeType type) - { - stream.writeByte ((char) type); - } - - static void writeHeader (ValueTreeSynchroniser& target, MemoryOutputStream& stream, - ChangeType type, ValueTree v) - { - writeHeader (stream, type); - - Array path; - getValueTreePath (v, target.getRoot(), path); - - stream.writeCompressedInt (path.size()); - - for (int i = path.size(); --i >= 0;) - stream.writeCompressedInt (path.getUnchecked(i)); - } - - static ValueTree readSubTreeLocation (MemoryInputStream& input, ValueTree v) - { - const int numLevels = input.readCompressedInt(); - - if (! isPositiveAndBelow (numLevels, 65536)) // sanity-check - return {}; - - for (int i = numLevels; --i >= 0;) - { - const int index = input.readCompressedInt(); - - if (! isPositiveAndBelow (index, v.getNumChildren())) - return {}; - - v = v.getChild (index); - } - - return v; - } -} - -ValueTreeSynchroniser::ValueTreeSynchroniser (const ValueTree& tree) : valueTree (tree) -{ - valueTree.addListener (this); -} - -ValueTreeSynchroniser::~ValueTreeSynchroniser() -{ - valueTree.removeListener (this); -} - -void ValueTreeSynchroniser::sendFullSyncCallback() -{ - MemoryOutputStream m; - writeHeader (m, ValueTreeSynchroniserHelpers::fullSync); - valueTree.writeToStream (m); - stateChanged (m.getData(), m.getDataSize()); -} - -void ValueTreeSynchroniser::valueTreePropertyChanged (ValueTree& vt, const Identifier& property) -{ - MemoryOutputStream m; - - if (auto* value = vt.getPropertyPointer (property)) - { - ValueTreeSynchroniserHelpers::writeHeader (*this, m, ValueTreeSynchroniserHelpers::propertyChanged, vt); - m.writeString (property.toString()); - value->writeToStream (m); - } - else - { - ValueTreeSynchroniserHelpers::writeHeader (*this, m, ValueTreeSynchroniserHelpers::propertyRemoved, vt); - m.writeString (property.toString()); - } - - stateChanged (m.getData(), m.getDataSize()); -} - -void ValueTreeSynchroniser::valueTreeChildAdded (ValueTree& parentTree, ValueTree& childTree) -{ - const int index = parentTree.indexOf (childTree); - jassert (index >= 0); - - MemoryOutputStream m; - ValueTreeSynchroniserHelpers::writeHeader (*this, m, ValueTreeSynchroniserHelpers::childAdded, parentTree); - m.writeCompressedInt (index); - childTree.writeToStream (m); - stateChanged (m.getData(), m.getDataSize()); -} - -void ValueTreeSynchroniser::valueTreeChildRemoved (ValueTree& parentTree, ValueTree&, int oldIndex) -{ - MemoryOutputStream m; - ValueTreeSynchroniserHelpers::writeHeader (*this, m, ValueTreeSynchroniserHelpers::childRemoved, parentTree); - m.writeCompressedInt (oldIndex); - stateChanged (m.getData(), m.getDataSize()); -} - -void ValueTreeSynchroniser::valueTreeChildOrderChanged (ValueTree& parent, int oldIndex, int newIndex) -{ - MemoryOutputStream m; - ValueTreeSynchroniserHelpers::writeHeader (*this, m, ValueTreeSynchroniserHelpers::childMoved, parent); - m.writeCompressedInt (oldIndex); - m.writeCompressedInt (newIndex); - stateChanged (m.getData(), m.getDataSize()); -} - -void ValueTreeSynchroniser::valueTreeParentChanged (ValueTree&) {} // (No action needed here) - -bool ValueTreeSynchroniser::applyChange (ValueTree& root, const void* data, size_t dataSize, UndoManager* undoManager) -{ - MemoryInputStream input (data, dataSize, false); - - const ValueTreeSynchroniserHelpers::ChangeType type = (ValueTreeSynchroniserHelpers::ChangeType) input.readByte(); - - if (type == ValueTreeSynchroniserHelpers::fullSync) - { - root = ValueTree::readFromStream (input); - return true; - } - - ValueTree v (ValueTreeSynchroniserHelpers::readSubTreeLocation (input, root)); - - if (! v.isValid()) - return false; - - switch (type) - { - case ValueTreeSynchroniserHelpers::propertyChanged: - { - Identifier property (input.readString()); - v.setProperty (property, var::readFromStream (input), undoManager); - return true; - } - - case ValueTreeSynchroniserHelpers::propertyRemoved: - { - Identifier property (input.readString()); - v.removeProperty (property, undoManager); - return true; - } - - case ValueTreeSynchroniserHelpers::childAdded: - { - const int index = input.readCompressedInt(); - v.addChild (ValueTree::readFromStream (input), index, undoManager); - return true; - } - - case ValueTreeSynchroniserHelpers::childRemoved: - { - const int index = input.readCompressedInt(); - - if (isPositiveAndBelow (index, v.getNumChildren())) - { - v.removeChild (index, undoManager); - return true; - } - - jassertfalse; // Either received some corrupt data, or the trees have drifted out of sync - break; - } - - case ValueTreeSynchroniserHelpers::childMoved: - { - const int oldIndex = input.readCompressedInt(); - const int newIndex = input.readCompressedInt(); - - if (isPositiveAndBelow (oldIndex, v.getNumChildren()) - && isPositiveAndBelow (newIndex, v.getNumChildren())) - { - v.moveChild (oldIndex, newIndex, undoManager); - return true; - } - - jassertfalse; // Either received some corrupt data, or the trees have drifted out of sync - break; - } - - default: - jassertfalse; // Seem to have received some corrupt data? - break; - } - - return false; -} - -} // namespace juce diff --git a/source/modules/juce_data_structures/values/juce_ValueTreeSynchroniser.h b/source/modules/juce_data_structures/values/juce_ValueTreeSynchroniser.h deleted file mode 100644 index 42c382360..000000000 --- a/source/modules/juce_data_structures/values/juce_ValueTreeSynchroniser.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - This class can be used to watch for all changes to the state of a ValueTree, - and to convert them to a transmittable binary encoding. - - The purpose of this class is to allow two or more ValueTrees to be remotely - synchronised by transmitting encoded changes over some kind of transport - mechanism. - - To use it, you'll need to implement a subclass of ValueTreeSynchroniser - and implement the stateChanged() method to transmit the encoded change (maybe - via a network or other means) to a remote destination, where it can be - applied to a target tree. -*/ -class JUCE_API ValueTreeSynchroniser : private ValueTree::Listener -{ -public: - /** Creates a ValueTreeSynchroniser that watches the given tree. - - After creating an instance of this class and somehow attaching it to - a target tree, you probably want to call sendFullSyncCallback() to - get them into a common starting state. - */ - ValueTreeSynchroniser (const ValueTree& tree); - - /** Destructor. */ - virtual ~ValueTreeSynchroniser(); - - /** This callback happens when the ValueTree changes and the given state-change message - needs to be applied to any other trees that need to stay in sync with it. - The data is an opaque blob of binary that you should transmit to wherever your - target tree lives, and use applyChange() to apply this to the target tree. - */ - virtual void stateChanged (const void* encodedChange, size_t encodedChangeSize) = 0; - - /** Forces the sending of a full state message, which may be large, as it - encodes the entire ValueTree. - - This will internally invoke stateChanged() with the encoded version of the state. - */ - void sendFullSyncCallback(); - - /** Applies an encoded change to the given destination tree. - - When you implement a receiver for changes that were sent by the stateChanged() - message, this is the function that you'll need to call to apply them to the - target tree that you want to be synced. - */ - static bool applyChange (ValueTree& target, - const void* encodedChangeData, size_t encodedChangeDataSize, - UndoManager* undoManager); - - /** Returns the root ValueTree that is being observed. */ - const ValueTree& getRoot() noexcept { return valueTree; } - -private: - ValueTree valueTree; - - void valueTreePropertyChanged (ValueTree&, const Identifier&) override; - void valueTreeChildAdded (ValueTree&, ValueTree&) override; - void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override; - void valueTreeChildOrderChanged (ValueTree&, int, int) override; - void valueTreeParentChanged (ValueTree&) override; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueTreeSynchroniser) -}; - -} // namespace juce diff --git a/source/modules/juce_events/Makefile b/source/modules/juce_events/Makefile deleted file mode 100644 index 8a77d309d..000000000 --- a/source/modules/juce_events/Makefile +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/make -f -# Makefile for juce_events # -# ------------------------ # -# Created by falkTX -# - -CWD=../.. -MODULENAME=juce_events -include ../Makefile.mk - -# ---------------------------------------------------------------------------------------------------------------------------- - -BUILD_CXX_FLAGS += $(JUCE_EVENTS_FLAGS) -I.. - -ifeq ($(WIN32),true) -BUILD_CXX_FLAGS += -Wno-missing-field-initializers -endif - -# ---------------------------------------------------------------------------------------------------------------------------- - -ifeq ($(MACOS),true) -OBJS = $(OBJDIR)/$(MODULENAME).mm.o -OBJS_posix32 = $(OBJDIR)/$(MODULENAME).mm.posix32.o -OBJS_posix64 = $(OBJDIR)/$(MODULENAME).mm.posix64.o -else -OBJS = $(OBJDIR)/$(MODULENAME).cpp.o -OBJS_posix32 = $(OBJDIR)/$(MODULENAME).cpp.posix32.o -OBJS_posix64 = $(OBJDIR)/$(MODULENAME).cpp.posix64.o -endif -OBJS_win32 = $(OBJDIR)/$(MODULENAME).cpp.win32.o -OBJS_win64 = $(OBJDIR)/$(MODULENAME).cpp.win64.o - -# ---------------------------------------------------------------------------------------------------------------------------- - -all: $(MODULEDIR)/$(MODULENAME).a -posix32: $(MODULEDIR)/$(MODULENAME).posix32.a -posix64: $(MODULEDIR)/$(MODULENAME).posix64.a -win32: $(MODULEDIR)/$(MODULENAME).win32.a -win64: $(MODULEDIR)/$(MODULENAME).win64.a - -# ---------------------------------------------------------------------------------------------------------------------------- - -clean: - rm -f $(OBJDIR)/*.o $(MODULEDIR)/$(MODULENAME)*.a - -debug: - $(MAKE) DEBUG=true - -# ---------------------------------------------------------------------------------------------------------------------------- - -$(MODULEDIR)/$(MODULENAME).a: $(OBJS) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).posix32.a: $(OBJS_posix32) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).posix32.a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).posix64.a: $(OBJS_posix64) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).posix64.a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).win32.a: $(OBJS_win32) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).win32.a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).win64.a: $(OBJS_win64) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).win64.a" - @rm -f $@ - @$(AR) crs $@ $^ - -# ---------------------------------------------------------------------------------------------------------------------------- - -$(OBJDIR)/$(MODULENAME).cpp.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $<" - @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ - -$(OBJDIR)/$(MODULENAME).cpp.%32.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (32bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -c -o $@ - -$(OBJDIR)/$(MODULENAME).cpp.%64.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (64bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -c -o $@ - -# ---------------------------------------------------------------------------------------------------------------------------- - -$(OBJDIR)/$(MODULENAME).mm.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $<" - @$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ - -$(OBJDIR)/$(MODULENAME).mm.%32.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (32bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -ObjC++ -c -o $@ - -$(OBJDIR)/$(MODULENAME).mm.%64.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (64bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -ObjC++ -c -o $@ - -# ---------------------------------------------------------------------------------------------------------------------------- - --include $(OBJS:%.o=%.d) --include $(OBJS_posix32:%.o=%.d) --include $(OBJS_posix64:%.o=%.d) --include $(OBJS_win32:%.o=%.d) --include $(OBJS_win64:%.o=%.d) - -# ---------------------------------------------------------------------------------------------------------------------------- diff --git a/source/modules/juce_events/broadcasters/juce_ActionBroadcaster.cpp b/source/modules/juce_events/broadcasters/juce_ActionBroadcaster.cpp deleted file mode 100644 index 9efb3a9e1..000000000 --- a/source/modules/juce_events/broadcasters/juce_ActionBroadcaster.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -class ActionBroadcaster::ActionMessage : public MessageManager::MessageBase -{ -public: - ActionMessage (const ActionBroadcaster* ab, - const String& messageText, ActionListener* l) noexcept - : broadcaster (const_cast (ab)), - message (messageText), - listener (l) - {} - - void messageCallback() override - { - if (const ActionBroadcaster* const b = broadcaster) - if (b->actionListeners.contains (listener)) - listener->actionListenerCallback (message); - } - -private: - WeakReference broadcaster; - const String message; - ActionListener* const listener; - - JUCE_DECLARE_NON_COPYABLE (ActionMessage) -}; - -//============================================================================== -ActionBroadcaster::ActionBroadcaster() -{ - // are you trying to create this object before or after juce has been intialised?? - jassert (MessageManager::getInstanceWithoutCreating() != nullptr); -} - -ActionBroadcaster::~ActionBroadcaster() -{ - // all event-based objects must be deleted BEFORE juce is shut down! - jassert (MessageManager::getInstanceWithoutCreating() != nullptr); -} - -void ActionBroadcaster::addActionListener (ActionListener* const listener) -{ - const ScopedLock sl (actionListenerLock); - - if (listener != nullptr) - actionListeners.add (listener); -} - -void ActionBroadcaster::removeActionListener (ActionListener* const listener) -{ - const ScopedLock sl (actionListenerLock); - actionListeners.removeValue (listener); -} - -void ActionBroadcaster::removeAllActionListeners() -{ - const ScopedLock sl (actionListenerLock); - actionListeners.clear(); -} - -void ActionBroadcaster::sendActionMessage (const String& message) const -{ - const ScopedLock sl (actionListenerLock); - - for (int i = actionListeners.size(); --i >= 0;) - (new ActionMessage (this, message, actionListeners.getUnchecked(i)))->post(); -} - -} // namespace juce diff --git a/source/modules/juce_events/broadcasters/juce_ActionBroadcaster.h b/source/modules/juce_events/broadcasters/juce_ActionBroadcaster.h deleted file mode 100644 index 3936253a2..000000000 --- a/source/modules/juce_events/broadcasters/juce_ActionBroadcaster.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** Manages a list of ActionListeners, and can send them messages. - - To quickly add methods to your class that can add/remove action - listeners and broadcast to them, you can derive from this. - - @see ActionListener, ChangeListener -*/ -class JUCE_API ActionBroadcaster -{ -public: - //============================================================================== - /** Creates an ActionBroadcaster. */ - ActionBroadcaster(); - - /** Destructor. */ - virtual ~ActionBroadcaster(); - - //============================================================================== - /** Adds a listener to the list. - Trying to add a listener that's already on the list will have no effect. - */ - void addActionListener (ActionListener* listener); - - /** Removes a listener from the list. - If the listener isn't on the list, this won't have any effect. - */ - void removeActionListener (ActionListener* listener); - - /** Removes all listeners from the list. */ - void removeAllActionListeners(); - - //============================================================================== - /** Broadcasts a message to all the registered listeners. - @see ActionListener::actionListenerCallback - */ - void sendActionMessage (const String& message) const; - - -private: - //============================================================================== - class ActionMessage; - friend class ActionMessage; - - SortedSet actionListeners; - CriticalSection actionListenerLock; - - JUCE_DECLARE_WEAK_REFERENCEABLE (ActionBroadcaster) - JUCE_DECLARE_NON_COPYABLE (ActionBroadcaster) -}; - -} // namespace juce diff --git a/source/modules/juce_events/broadcasters/juce_ActionListener.h b/source/modules/juce_events/broadcasters/juce_ActionListener.h deleted file mode 100644 index c16449f7d..000000000 --- a/source/modules/juce_events/broadcasters/juce_ActionListener.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Interface class for delivery of events that are sent by an ActionBroadcaster. - - @see ActionBroadcaster, ChangeListener -*/ -class JUCE_API ActionListener -{ -public: - /** Destructor. */ - virtual ~ActionListener() {} - - /** Overridden by your subclass to receive the callback. - - @param message the string that was specified when the event was triggered - by a call to ActionBroadcaster::sendActionMessage() - */ - virtual void actionListenerCallback (const String& message) = 0; -}; - -} // namespace juce diff --git a/source/modules/juce_events/broadcasters/juce_AsyncUpdater.cpp b/source/modules/juce_events/broadcasters/juce_AsyncUpdater.cpp deleted file mode 100644 index 8d9a20e5a..000000000 --- a/source/modules/juce_events/broadcasters/juce_AsyncUpdater.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -class AsyncUpdater::AsyncUpdaterMessage : public CallbackMessage -{ -public: - AsyncUpdaterMessage (AsyncUpdater& au) : owner (au) {} - - void messageCallback() override - { - if (shouldDeliver.compareAndSetBool (0, 1)) - owner.handleAsyncUpdate(); - } - - AsyncUpdater& owner; - Atomic shouldDeliver; - - JUCE_DECLARE_NON_COPYABLE (AsyncUpdaterMessage) -}; - -//============================================================================== -AsyncUpdater::AsyncUpdater() -{ - activeMessage = new AsyncUpdaterMessage (*this); -} - -AsyncUpdater::~AsyncUpdater() -{ - // You're deleting this object with a background thread while there's an update - // pending on the main event thread - that's pretty dodgy threading, as the callback could - // happen after this destructor has finished. You should either use a MessageManagerLock while - // deleting this object, or find some other way to avoid such a race condition. - jassert ((! isUpdatePending()) - || MessageManager::getInstanceWithoutCreating() == nullptr - || MessageManager::getInstanceWithoutCreating()->currentThreadHasLockedMessageManager()); - - activeMessage->shouldDeliver.set (0); -} - -void AsyncUpdater::triggerAsyncUpdate() -{ - // If you're calling this before (or after) the MessageManager is - // running, then you're not going to get any callbacks! - jassert (MessageManager::getInstanceWithoutCreating() != nullptr); - - if (activeMessage->shouldDeliver.compareAndSetBool (1, 0)) - if (! activeMessage->post()) - cancelPendingUpdate(); // if the message queue fails, this avoids getting - // trapped waiting for the message to arrive -} - -void AsyncUpdater::cancelPendingUpdate() noexcept -{ - activeMessage->shouldDeliver.set (0); -} - -void AsyncUpdater::handleUpdateNowIfNeeded() -{ - // This can only be called by the event thread. - jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); - - if (activeMessage->shouldDeliver.exchange (0) != 0) - handleAsyncUpdate(); -} - -bool AsyncUpdater::isUpdatePending() const noexcept -{ - return activeMessage->shouldDeliver.value != 0; -} - -} // namespace juce diff --git a/source/modules/juce_events/broadcasters/juce_AsyncUpdater.h b/source/modules/juce_events/broadcasters/juce_AsyncUpdater.h deleted file mode 100644 index 7a94a63d6..000000000 --- a/source/modules/juce_events/broadcasters/juce_AsyncUpdater.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Has a callback method that is triggered asynchronously. - - This object allows an asynchronous callback function to be triggered, for - tasks such as coalescing multiple updates into a single callback later on. - - Basically, one or more calls to the triggerAsyncUpdate() will result in the - message thread calling handleAsyncUpdate() as soon as it can. -*/ -class JUCE_API AsyncUpdater -{ -public: - //============================================================================== - /** Creates an AsyncUpdater object. */ - AsyncUpdater(); - - /** Destructor. - If there are any pending callbacks when the object is deleted, these are lost. - */ - virtual ~AsyncUpdater(); - - //============================================================================== - /** Causes the callback to be triggered at a later time. - - This method returns immediately, after which a callback to the - handleAsyncUpdate() method will be made by the message thread as - soon as possible. - - If an update callback is already pending but hasn't happened yet, calling - this method will have no effect. - - It's thread-safe to call this method from any thread, BUT beware of calling - it from a real-time (e.g. audio) thread, because it involves posting a message - to the system queue, which means it may block (and in general will do on - most OSes). - */ - void triggerAsyncUpdate(); - - /** This will stop any pending updates from happening. - - If called after triggerAsyncUpdate() and before the handleAsyncUpdate() - callback happens, this will cancel the handleAsyncUpdate() callback. - - Note that this method simply cancels the next callback - if a callback is already - in progress on a different thread, this won't block until the callback finishes, so - there's no guarantee that the callback isn't still running when the method returns. - */ - void cancelPendingUpdate() noexcept; - - /** If an update has been triggered and is pending, this will invoke it - synchronously. - - Use this as a kind of "flush" operation - if an update is pending, the - handleAsyncUpdate() method will be called immediately; if no update is - pending, then nothing will be done. - - Because this may invoke the callback, this method must only be called on - the main event thread. - */ - void handleUpdateNowIfNeeded(); - - /** Returns true if there's an update callback in the pipeline. */ - bool isUpdatePending() const noexcept; - - //============================================================================== - /** Called back to do whatever your class needs to do. - - This method is called by the message thread at the next convenient time - after the triggerAsyncUpdate() method has been called. - */ - virtual void handleAsyncUpdate() = 0; - -private: - //============================================================================== - class AsyncUpdaterMessage; - friend class ReferenceCountedObjectPtr; - ReferenceCountedObjectPtr activeMessage; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AsyncUpdater) -}; - -} // namespace juce diff --git a/source/modules/juce_events/broadcasters/juce_ChangeBroadcaster.cpp b/source/modules/juce_events/broadcasters/juce_ChangeBroadcaster.cpp deleted file mode 100644 index a816c3d8f..000000000 --- a/source/modules/juce_events/broadcasters/juce_ChangeBroadcaster.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -ChangeBroadcaster::ChangeBroadcaster() noexcept -{ - broadcastCallback.owner = this; -} - -ChangeBroadcaster::~ChangeBroadcaster() -{ -} - -void ChangeBroadcaster::addChangeListener (ChangeListener* const listener) -{ - // Listeners can only be safely added when the event thread is locked - // You can use a MessageManagerLock if you need to call this from another thread. - jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); - - changeListeners.add (listener); -} - -void ChangeBroadcaster::removeChangeListener (ChangeListener* const listener) -{ - // Listeners can only be safely removed when the event thread is locked - // You can use a MessageManagerLock if you need to call this from another thread. - jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); - - changeListeners.remove (listener); -} - -void ChangeBroadcaster::removeAllChangeListeners() -{ - // Listeners can only be safely removed when the event thread is locked - // You can use a MessageManagerLock if you need to call this from another thread. - jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); - - changeListeners.clear(); -} - -void ChangeBroadcaster::sendChangeMessage() -{ - if (changeListeners.size() > 0) - broadcastCallback.triggerAsyncUpdate(); -} - -void ChangeBroadcaster::sendSynchronousChangeMessage() -{ - // This can only be called by the event thread. - jassert (MessageManager::getInstance()->isThisTheMessageThread()); - - broadcastCallback.cancelPendingUpdate(); - callListeners(); -} - -void ChangeBroadcaster::dispatchPendingMessages() -{ - broadcastCallback.handleUpdateNowIfNeeded(); -} - -void ChangeBroadcaster::callListeners() -{ - changeListeners.call (&ChangeListener::changeListenerCallback, this); -} - -//============================================================================== -ChangeBroadcaster::ChangeBroadcasterCallback::ChangeBroadcasterCallback() - : owner (nullptr) -{ -} - -void ChangeBroadcaster::ChangeBroadcasterCallback::handleAsyncUpdate() -{ - jassert (owner != nullptr); - owner->callListeners(); -} - -} // namespace juce diff --git a/source/modules/juce_events/broadcasters/juce_ChangeBroadcaster.h b/source/modules/juce_events/broadcasters/juce_ChangeBroadcaster.h deleted file mode 100644 index beef4e85a..000000000 --- a/source/modules/juce_events/broadcasters/juce_ChangeBroadcaster.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Holds a list of ChangeListeners, and sends messages to them when instructed. - - @see ChangeListener -*/ -class JUCE_API ChangeBroadcaster -{ -public: - //============================================================================== - /** Creates an ChangeBroadcaster. */ - ChangeBroadcaster() noexcept; - - /** Destructor. */ - virtual ~ChangeBroadcaster(); - - //============================================================================== - /** Registers a listener to receive change callbacks from this broadcaster. - Trying to add a listener that's already on the list will have no effect. - */ - void addChangeListener (ChangeListener* listener); - - /** Unregisters a listener from the list. - If the listener isn't on the list, this won't have any effect. - */ - void removeChangeListener (ChangeListener* listener); - - /** Removes all listeners from the list. */ - void removeAllChangeListeners(); - - //============================================================================== - /** Causes an asynchronous change message to be sent to all the registered listeners. - - The message will be delivered asynchronously by the main message thread, so this - method will return immediately. To call the listeners synchronously use - sendSynchronousChangeMessage(). - */ - void sendChangeMessage(); - - /** Sends a synchronous change message to all the registered listeners. - - This will immediately call all the listeners that are registered. For thread-safety - reasons, you must only call this method on the main message thread. - - @see dispatchPendingMessages - */ - void sendSynchronousChangeMessage(); - - /** If a change message has been sent but not yet dispatched, this will call - sendSynchronousChangeMessage() to make the callback immediately. - - For thread-safety reasons, you must only call this method on the main message thread. - */ - void dispatchPendingMessages(); - -private: - //============================================================================== - class ChangeBroadcasterCallback : public AsyncUpdater - { - public: - ChangeBroadcasterCallback(); - void handleAsyncUpdate() override; - - ChangeBroadcaster* owner; - }; - - friend class ChangeBroadcasterCallback; - ChangeBroadcasterCallback broadcastCallback; - ListenerList changeListeners; - - void callListeners(); - - JUCE_DECLARE_NON_COPYABLE (ChangeBroadcaster) -}; - -} // namespace juce diff --git a/source/modules/juce_events/broadcasters/juce_ChangeListener.h b/source/modules/juce_events/broadcasters/juce_ChangeListener.h deleted file mode 100644 index aacaf223c..000000000 --- a/source/modules/juce_events/broadcasters/juce_ChangeListener.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -class ChangeBroadcaster; - -//============================================================================== -/** - Receives change event callbacks that are sent out by a ChangeBroadcaster. - - A ChangeBroadcaster keeps a set of listeners to which it broadcasts a message when - the ChangeBroadcaster::sendChangeMessage() method is called. A subclass of - ChangeListener is used to receive these callbacks. - - Note that the major difference between an ActionListener and a ChangeListener - is that for a ChangeListener, multiple changes will be coalesced into fewer - callbacks, but ActionListeners perform one callback for every event posted. - - @see ChangeBroadcaster, ActionListener -*/ -class JUCE_API ChangeListener -{ -public: - /** Destructor. */ - virtual ~ChangeListener() {} - - /** Your subclass should implement this method to receive the callback. - @param source the ChangeBroadcaster that triggered the callback. - */ - virtual void changeListenerCallback (ChangeBroadcaster* source) = 0; - - - //============================================================================== - #if JUCE_CATCH_DEPRECATED_CODE_MISUSE - // This method's signature has changed to take a ChangeBroadcaster parameter - please update your code! - private: virtual int changeListenerCallback (void*) { return 0; } - #endif -}; - -} // namespace juce diff --git a/source/modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp b/source/modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp deleted file mode 100644 index 9e7070e4d..000000000 --- a/source/modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -enum { magicMastSlaveConnectionHeader = 0x712baf04 }; - -static const char* startMessage = "__ipc_st"; -static const char* killMessage = "__ipc_k_"; -static const char* pingMessage = "__ipc_p_"; -enum { specialMessageSize = 8, defaultTimeoutMs = 8000 }; - -static String getCommandLinePrefix (const String& commandLineUniqueID) -{ - return "--" + commandLineUniqueID + ":"; -} - -//============================================================================== -// This thread sends and receives ping messages every second, so that it -// can find out if the other process has stopped running. -struct ChildProcessPingThread : public Thread, - private AsyncUpdater -{ - ChildProcessPingThread (int timeout) : Thread ("IPC ping"), timeoutMs (timeout) - { - pingReceived(); - } - - static bool isPingMessage (const MemoryBlock& m) noexcept - { - return memcmp (m.getData(), pingMessage, specialMessageSize) == 0; - } - - void pingReceived() noexcept { countdown = timeoutMs / 1000 + 1; } - void triggerConnectionLostMessage() { triggerAsyncUpdate(); } - - virtual bool sendPingMessage (const MemoryBlock&) = 0; - virtual void pingFailed() = 0; - - int timeoutMs; - -private: - Atomic countdown; - - void handleAsyncUpdate() override { pingFailed(); } - - void run() override - { - while (! threadShouldExit()) - { - if (--countdown <= 0 || ! sendPingMessage (MemoryBlock (pingMessage, specialMessageSize))) - { - triggerConnectionLostMessage(); - break; - } - - wait (1000); - } - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildProcessPingThread) -}; - -//============================================================================== -struct ChildProcessMaster::Connection : public InterprocessConnection, - private ChildProcessPingThread -{ - Connection (ChildProcessMaster& m, const String& pipeName, int timeout) - : InterprocessConnection (false, magicMastSlaveConnectionHeader), - ChildProcessPingThread (timeout), - owner (m) - { - if (createPipe (pipeName, timeoutMs)) - startThread (4); - } - - ~Connection() - { - stopThread (10000); - } - -private: - void connectionMade() override {} - void connectionLost() override { owner.handleConnectionLost(); } - - bool sendPingMessage (const MemoryBlock& m) override { return owner.sendMessageToSlave (m); } - void pingFailed() override { connectionLost(); } - - void messageReceived (const MemoryBlock& m) override - { - pingReceived(); - - if (m.getSize() != specialMessageSize || ! isPingMessage (m)) - owner.handleMessageFromSlave (m); - } - - ChildProcessMaster& owner; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Connection) -}; - -//============================================================================== -ChildProcessMaster::ChildProcessMaster() {} - -ChildProcessMaster::~ChildProcessMaster() -{ - if (connection != nullptr) - { - sendMessageToSlave (MemoryBlock (killMessage, specialMessageSize)); - connection->disconnect(); - connection = nullptr; - } -} - -void ChildProcessMaster::handleConnectionLost() {} - -bool ChildProcessMaster::sendMessageToSlave (const MemoryBlock& mb) -{ - if (connection != nullptr) - return connection->sendMessage (mb); - - jassertfalse; // this can only be used when the connection is active! - return false; -} - -bool ChildProcessMaster::launchSlaveProcess (const File& executable, const String& commandLineUniqueID, int timeoutMs, int streamFlags) -{ - connection = nullptr; - jassert (childProcess.kill()); - - const String pipeName ("p" + String::toHexString (Random().nextInt64())); - - StringArray args; - args.add (executable.getFullPathName()); - args.add (getCommandLinePrefix (commandLineUniqueID) + pipeName); - - if (childProcess.start (args, streamFlags)) - { - connection = new Connection (*this, pipeName, timeoutMs <= 0 ? defaultTimeoutMs : timeoutMs); - - if (connection->isConnected()) - { - sendMessageToSlave (MemoryBlock (startMessage, specialMessageSize)); - return true; - } - - connection = nullptr; - } - - return false; -} - -//============================================================================== -struct ChildProcessSlave::Connection : public InterprocessConnection, - private ChildProcessPingThread -{ - Connection (ChildProcessSlave& p, const String& pipeName, int timeout) - : InterprocessConnection (false, magicMastSlaveConnectionHeader), - ChildProcessPingThread (timeout), - owner (p) - { - connectToPipe (pipeName, timeoutMs); - startThread (4); - } - - ~Connection() - { - stopThread (10000); - } - -private: - ChildProcessSlave& owner; - - void connectionMade() override {} - void connectionLost() override { owner.handleConnectionLost(); } - - bool sendPingMessage (const MemoryBlock& m) override { return owner.sendMessageToMaster (m); } - void pingFailed() override { connectionLost(); } - - void messageReceived (const MemoryBlock& m) override - { - pingReceived(); - - if (m.getSize() == specialMessageSize) - { - if (isPingMessage (m)) - return; - - if (memcmp (m.getData(), killMessage, specialMessageSize) == 0) - { - triggerConnectionLostMessage(); - return; - } - - if (memcmp (m.getData(), startMessage, specialMessageSize) == 0) - { - owner.handleConnectionMade(); - return; - } - } - - owner.handleMessageFromMaster (m); - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Connection) -}; - -//============================================================================== -ChildProcessSlave::ChildProcessSlave() {} -ChildProcessSlave::~ChildProcessSlave() {} - -void ChildProcessSlave::handleConnectionMade() {} -void ChildProcessSlave::handleConnectionLost() {} - -bool ChildProcessSlave::sendMessageToMaster (const MemoryBlock& mb) -{ - if (connection != nullptr) - return connection->sendMessage (mb); - - jassertfalse; // this can only be used when the connection is active! - return false; -} - -bool ChildProcessSlave::initialiseFromCommandLine (const String& commandLine, - const String& commandLineUniqueID, - int timeoutMs) -{ - String prefix (getCommandLinePrefix (commandLineUniqueID)); - - if (commandLine.trim().startsWith (prefix)) - { - String pipeName (commandLine.fromFirstOccurrenceOf (prefix, false, false) - .upToFirstOccurrenceOf (" ", false, false).trim()); - - if (pipeName.isNotEmpty()) - { - connection = new Connection (*this, pipeName, timeoutMs <= 0 ? defaultTimeoutMs : timeoutMs); - - if (! connection->isConnected()) - connection = nullptr; - } - } - - return connection != nullptr; -} - -} // namespace juce diff --git a/source/modules/juce_events/interprocess/juce_ConnectedChildProcess.h b/source/modules/juce_events/interprocess/juce_ConnectedChildProcess.h deleted file mode 100644 index 8f6cc8cc1..000000000 --- a/source/modules/juce_events/interprocess/juce_ConnectedChildProcess.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Acts as the slave end of a master/slave pair of connected processes. - - The ChildProcessSlave and ChildProcessMaster classes make it easy for an app - to spawn a child process, and to manage a 2-way messaging connection to control it. - - To use the system, you need to create subclasses of both ChildProcessSlave and - ChildProcessMaster. To instantiate the ChildProcessSlave object, you must - add some code to your main() or JUCEApplication::initialise() function that - calls the initialiseFromCommandLine() method to check the app's command-line - parameters to see whether it's being launched as a child process. If this returns - true then the slave process can be allowed to run, and its handleMessageFromMaster() - method will be called whenever a message arrives. - - The juce demo app has a good example of this class in action. - - @see ChildProcessMaster, InterprocessConnection, ChildProcess -*/ -class JUCE_API ChildProcessSlave -{ -public: - /** Creates a non-connected slave process. - Use initialiseFromCommandLine to connect to a master process. - */ - ChildProcessSlave(); - - /** Destructor. */ - virtual ~ChildProcessSlave(); - - /** This checks some command-line parameters to see whether they were generated by - ChildProcessMaster::launchSlaveProcess(), and if so, connects to that master process. - - In an exe that can be used as a child process, you should add some code to your - main() or JUCEApplication::initialise() that calls this method. - - The commandLineUniqueID should be a short alphanumeric identifier (no spaces!) - that matches the string passed to ChildProcessMaster::launchSlaveProcess(). - - The timeoutMs parameter lets you specify how long the child process is allowed - to run without receiving a ping from the master before the master is considered to - have died, and handleConnectionLost() will be called. Passing <= 0 for this timeout - makes it use a default value. - - Returns true if the command-line matches and the connection is made successfully. - */ - bool initialiseFromCommandLine (const String& commandLine, - const String& commandLineUniqueID, - int timeoutMs = 0); - - //============================================================================== - /** This will be called to deliver messages from the master process. - The call will probably be made on a background thread, so be careful with your - thread-safety! You may want to respond by sending back a message with - sendMessageToMaster() - */ - virtual void handleMessageFromMaster (const MemoryBlock&) = 0; - - /** This will be called when the master process finishes connecting to this slave. - The call will probably be made on a background thread, so be careful with your thread-safety! - */ - virtual void handleConnectionMade(); - - /** This will be called when the connection to the master process is lost. - The call may be made from any thread (including the message thread). - Typically, if your process only exists to act as a slave, you should probably exit - when this happens. - */ - virtual void handleConnectionLost(); - - /** Tries to send a message to the master process. - This returns true if the message was sent, but doesn't check that it actually gets - delivered at the other end. If successful, the data will emerge in a call to your - ChildProcessMaster::handleMessageFromSlave(). - */ - bool sendMessageToMaster (const MemoryBlock&); - -private: - struct Connection; - friend struct Connection; - friend struct ContainerDeletePolicy; - ScopedPointer connection; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildProcessSlave) -}; - -//============================================================================== -/** - Acts as the master in a master/slave pair of connected processes. - - The ChildProcessSlave and ChildProcessMaster classes make it easy for an app - to spawn a child process, and to manage a 2-way messaging connection to control it. - - To use the system, you need to create subclasses of both ChildProcessSlave and - ChildProcessMaster. When you want your master process to launch the slave, you - just call launchSlaveProcess(), and it'll attempt to launch the executable that - you specify (which may be the same exe), and assuming it has been set-up to - correctly parse the command-line parameters (see ChildProcessSlave) then a - two-way connection will be created. - - The juce demo app has a good example of this class in action. - - @see ChildProcessSlave, InterprocessConnection, ChildProcess -*/ -class JUCE_API ChildProcessMaster -{ -public: - /** Creates an uninitialised master process object. - Use launchSlaveProcess to launch and connect to a child process. - */ - ChildProcessMaster(); - - /** Destructor. */ - virtual ~ChildProcessMaster(); - - /** Attempts to launch and connect to a slave process. - This will start the given executable, passing it a special command-line - parameter based around the commandLineUniqueID string, which must be a - short alphanumeric string (no spaces!) that identifies your app. The exe - that gets launched must respond by calling ChildProcessSlave::initialiseFromCommandLine() - in its startup code, and must use a matching ID to commandLineUniqueID. - - The timeoutMs parameter lets you specify how long the child process is allowed - to go without sending a ping before it is considered to have died and - handleConnectionLost() will be called. Passing <= 0 for this timeout makes - it use a default value. - - If this all works, the method returns true, and you can begin sending and - receiving messages with the slave process. - */ - bool launchSlaveProcess (const File& executableToLaunch, - const String& commandLineUniqueID, - int timeoutMs = 0, - int streamFlags = ChildProcess::wantStdOut | ChildProcess::wantStdErr); - - /** This will be called to deliver a message from the slave process. - The call will probably be made on a background thread, so be careful with your thread-safety! - */ - virtual void handleMessageFromSlave (const MemoryBlock&) = 0; - - /** This will be called when the slave process dies or is somehow disconnected. - The call will probably be made on a background thread, so be careful with your thread-safety! - */ - virtual void handleConnectionLost(); - - /** Attempts to send a message to the slave process. - This returns true if the message was dispatched, but doesn't check that it actually - gets delivered at the other end. If successful, the data will emerge in a call to - your ChildProcessSlave::handleMessageFromMaster(). - */ - bool sendMessageToSlave (const MemoryBlock&); - -private: - ChildProcess childProcess; - - struct Connection; - friend struct Connection; - friend struct ContainerDeletePolicy; - ScopedPointer connection; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildProcessMaster) -}; - -} // namespace juce diff --git a/source/modules/juce_events/interprocess/juce_InterprocessConnection.cpp b/source/modules/juce_events/interprocess/juce_InterprocessConnection.cpp deleted file mode 100644 index 8764d061c..000000000 --- a/source/modules/juce_events/interprocess/juce_InterprocessConnection.cpp +++ /dev/null @@ -1,362 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -struct InterprocessConnection::ConnectionThread : public Thread -{ - ConnectionThread (InterprocessConnection& c) : Thread ("JUCE IPC"), owner (c) {} - void run() override { owner.runThread(); } - - InterprocessConnection& owner; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ConnectionThread) -}; - -//============================================================================== -InterprocessConnection::InterprocessConnection (bool callbacksOnMessageThread, uint32 magicMessageHeaderNumber) - : useMessageThread (callbacksOnMessageThread), - magicMessageHeader (magicMessageHeaderNumber) -{ - thread = new ConnectionThread (*this); -} - -InterprocessConnection::~InterprocessConnection() -{ - callbackConnectionState = false; - disconnect(); - masterReference.clear(); - thread = nullptr; -} - -//============================================================================== -bool InterprocessConnection::connectToSocket (const String& hostName, - const int portNumber, - const int timeOutMillisecs) -{ - disconnect(); - - const ScopedLock sl (pipeAndSocketLock); - socket = new StreamingSocket(); - - if (socket->connect (hostName, portNumber, timeOutMillisecs)) - { - connectionMadeInt(); - thread->startThread(); - return true; - } - - socket = nullptr; - return false; -} - -bool InterprocessConnection::connectToPipe (const String& pipeName, const int timeoutMs) -{ - disconnect(); - - ScopedPointer newPipe (new NamedPipe()); - - if (newPipe->openExisting (pipeName)) - { - const ScopedLock sl (pipeAndSocketLock); - pipeReceiveMessageTimeout = timeoutMs; - initialiseWithPipe (newPipe.release()); - return true; - } - - return false; -} - -bool InterprocessConnection::createPipe (const String& pipeName, const int timeoutMs, bool mustNotExist) -{ - disconnect(); - - ScopedPointer newPipe (new NamedPipe()); - - if (newPipe->createNewPipe (pipeName, mustNotExist)) - { - const ScopedLock sl (pipeAndSocketLock); - pipeReceiveMessageTimeout = timeoutMs; - initialiseWithPipe (newPipe.release()); - return true; - } - - return false; -} - -void InterprocessConnection::disconnect() -{ - thread->signalThreadShouldExit(); - - { - const ScopedLock sl (pipeAndSocketLock); - if (socket != nullptr) socket->close(); - if (pipe != nullptr) pipe->close(); - } - - thread->stopThread (4000); - deletePipeAndSocket(); - connectionLostInt(); -} - -void InterprocessConnection::deletePipeAndSocket() -{ - const ScopedLock sl (pipeAndSocketLock); - socket = nullptr; - pipe = nullptr; -} - -bool InterprocessConnection::isConnected() const -{ - const ScopedLock sl (pipeAndSocketLock); - - return ((socket != nullptr && socket->isConnected()) - || (pipe != nullptr && pipe->isOpen())) - && thread->isThreadRunning(); -} - -String InterprocessConnection::getConnectedHostName() const -{ - { - const ScopedLock sl (pipeAndSocketLock); - - if (pipe == nullptr && socket == nullptr) - return {}; - - if (socket != nullptr && ! socket->isLocal()) - return socket->getHostName(); - } - - return IPAddress::local().toString(); -} - -//============================================================================== -bool InterprocessConnection::sendMessage (const MemoryBlock& message) -{ - uint32 messageHeader[2] = { ByteOrder::swapIfBigEndian (magicMessageHeader), - ByteOrder::swapIfBigEndian ((uint32) message.getSize()) }; - - MemoryBlock messageData (sizeof (messageHeader) + message.getSize()); - messageData.copyFrom (messageHeader, 0, sizeof (messageHeader)); - messageData.copyFrom (message.getData(), sizeof (messageHeader), message.getSize()); - - return writeData (messageData.getData(), (int) messageData.getSize()) == (int) messageData.getSize(); -} - -int InterprocessConnection::writeData (void* data, int dataSize) -{ - const ScopedLock sl (pipeAndSocketLock); - - if (socket != nullptr) - return socket->write (data, dataSize); - - if (pipe != nullptr) - return pipe->write (data, dataSize, pipeReceiveMessageTimeout); - - return 0; -} - -//============================================================================== -void InterprocessConnection::initialiseWithSocket (StreamingSocket* newSocket) -{ - jassert (socket == nullptr && pipe == nullptr); - socket = newSocket; - connectionMadeInt(); - thread->startThread(); -} - -void InterprocessConnection::initialiseWithPipe (NamedPipe* newPipe) -{ - jassert (socket == nullptr && pipe == nullptr); - pipe = newPipe; - connectionMadeInt(); - thread->startThread(); -} - -//============================================================================== -struct ConnectionStateMessage : public MessageManager::MessageBase -{ - ConnectionStateMessage (InterprocessConnection* ipc, bool connected) noexcept - : owner (ipc), connectionMade (connected) - {} - - void messageCallback() override - { - if (auto* ipc = owner.get()) - { - if (connectionMade) - ipc->connectionMade(); - else - ipc->connectionLost(); - } - } - - WeakReference owner; - bool connectionMade; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ConnectionStateMessage) -}; - -void InterprocessConnection::connectionMadeInt() -{ - if (! callbackConnectionState) - { - callbackConnectionState = true; - - if (useMessageThread) - (new ConnectionStateMessage (this, true))->post(); - else - connectionMade(); - } -} - -void InterprocessConnection::connectionLostInt() -{ - if (callbackConnectionState) - { - callbackConnectionState = false; - - if (useMessageThread) - (new ConnectionStateMessage (this, false))->post(); - else - connectionLost(); - } -} - -struct DataDeliveryMessage : public Message -{ - DataDeliveryMessage (InterprocessConnection* ipc, const MemoryBlock& d) - : owner (ipc), data (d) - {} - - void messageCallback() override - { - if (auto* ipc = owner.get()) - ipc->messageReceived (data); - } - - WeakReference owner; - MemoryBlock data; -}; - -void InterprocessConnection::deliverDataInt (const MemoryBlock& data) -{ - jassert (callbackConnectionState); - - if (useMessageThread) - (new DataDeliveryMessage (this, data))->post(); - else - messageReceived (data); -} - -//============================================================================== -bool InterprocessConnection::readNextMessageInt() -{ - uint32 messageHeader[2]; - const int bytes = socket != nullptr ? socket->read (messageHeader, sizeof (messageHeader), true) - : pipe ->read (messageHeader, sizeof (messageHeader), -1); - - if (bytes == sizeof (messageHeader) - && ByteOrder::swapIfBigEndian (messageHeader[0]) == magicMessageHeader) - { - int bytesInMessage = (int) ByteOrder::swapIfBigEndian (messageHeader[1]); - - if (bytesInMessage > 0) - { - MemoryBlock messageData ((size_t) bytesInMessage, true); - int bytesRead = 0; - - while (bytesInMessage > 0) - { - if (thread->threadShouldExit()) - return false; - - const int numThisTime = jmin (bytesInMessage, 65536); - void* const data = addBytesToPointer (messageData.getData(), bytesRead); - - const int bytesIn = socket != nullptr ? socket->read (data, numThisTime, true) - : pipe ->read (data, numThisTime, -1); - - if (bytesIn <= 0) - break; - - bytesRead += bytesIn; - bytesInMessage -= bytesIn; - } - - if (bytesRead >= 0) - deliverDataInt (messageData); - } - } - else if (bytes < 0) - { - if (socket != nullptr) - deletePipeAndSocket(); - - connectionLostInt(); - return false; - } - - return true; -} - -void InterprocessConnection::runThread() -{ - while (! thread->threadShouldExit()) - { - if (socket != nullptr) - { - auto ready = socket->waitUntilReady (true, 0); - - if (ready < 0) - { - deletePipeAndSocket(); - connectionLostInt(); - break; - } - - if (ready == 0) - { - thread->wait (1); - continue; - } - } - else if (pipe != nullptr) - { - if (! pipe->isOpen()) - { - deletePipeAndSocket(); - connectionLostInt(); - break; - } - } - else - { - break; - } - - if (thread->threadShouldExit() || ! readNextMessageInt()) - break; - } -} - -} // namespace juce diff --git a/source/modules/juce_events/interprocess/juce_InterprocessConnection.h b/source/modules/juce_events/interprocess/juce_InterprocessConnection.h deleted file mode 100644 index 7a5a1b72d..000000000 --- a/source/modules/juce_events/interprocess/juce_InterprocessConnection.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -class InterprocessConnectionServer; -class MemoryBlock; - - -//============================================================================== -/** - Manages a simple two-way messaging connection to another process, using either - a socket or a named pipe as the transport medium. - - To connect to a waiting socket or an open pipe, use the connectToSocket() or - connectToPipe() methods. If this succeeds, messages can be sent to the other end, - and incoming messages will result in a callback via the messageReceived() - method. - - To open a pipe and wait for another client to connect to it, use the createPipe() - method. - - To act as a socket server and create connections for one or more client, see the - InterprocessConnectionServer class. - - @see InterprocessConnectionServer, Socket, NamedPipe -*/ -class JUCE_API InterprocessConnection -{ -public: - //============================================================================== - /** Creates a connection. - - Connections are created manually, connecting them with the connectToSocket() - or connectToPipe() methods, or they are created automatically by a InterprocessConnectionServer - when a client wants to connect. - - @param callbacksOnMessageThread if true, callbacks to the connectionMade(), - connectionLost() and messageReceived() methods will - always be made using the message thread; if false, - these will be called immediately on the connection's - own thread. - @param magicMessageHeaderNumber a magic number to use in the header to check the - validity of the data blocks being sent and received. This - can be any number, but the sender and receiver must obviously - use matching values or they won't recognise each other. - */ - InterprocessConnection (bool callbacksOnMessageThread = true, - uint32 magicMessageHeaderNumber = 0xf2b49e2c); - - /** Destructor. */ - virtual ~InterprocessConnection(); - - //============================================================================== - /** Tries to connect this object to a socket. - - For this to work, the machine on the other end needs to have a InterprocessConnectionServer - object waiting to receive client connections on this port number. - - @param hostName the host computer, either a network address or name - @param portNumber the socket port number to try to connect to - @param timeOutMillisecs how long to keep trying before giving up - @returns true if the connection is established successfully - @see Socket - */ - bool connectToSocket (const String& hostName, - int portNumber, - int timeOutMillisecs); - - /** Tries to connect the object to an existing named pipe. - - For this to work, another process on the same computer must already have opened - an InterprocessConnection object and used createPipe() to create a pipe for this - to connect to. - - @param pipeName the name to use for the pipe - this should be unique to your app - @param pipeReceiveMessageTimeoutMs a timeout length to be used when reading or writing - to the pipe, or -1 for an infinite timeout. - @returns true if it connects successfully. - @see createPipe, NamedPipe - */ - bool connectToPipe (const String& pipeName, int pipeReceiveMessageTimeoutMs); - - /** Tries to create a new pipe for other processes to connect to. - - This creates a pipe with the given name, so that other processes can use - connectToPipe() to connect to the other end. - - @param pipeName the name to use for the pipe - this should be unique to your app - @param pipeReceiveMessageTimeoutMs a timeout length to be used when reading or writing - to the pipe, or -1 for an infinite timeout - @param mustNotExist if set to true, the method will fail if the pipe already exists - @returns true if the pipe was created, or false if it fails (e.g. if another process is - already using using the pipe) - */ - bool createPipe (const String& pipeName, int pipeReceiveMessageTimeoutMs, bool mustNotExist = false); - - /** Disconnects and closes any currently-open sockets or pipes. */ - void disconnect(); - - /** True if a socket or pipe is currently active. */ - bool isConnected() const; - - /** Returns the socket that this connection is using (or nullptr if it uses a pipe). */ - StreamingSocket* getSocket() const noexcept { return socket; } - - /** Returns the pipe that this connection is using (or nullptr if it uses a socket). */ - NamedPipe* getPipe() const noexcept { return pipe; } - - /** Returns the name of the machine at the other end of this connection. - This may return an empty string if the name is unknown. - */ - String getConnectedHostName() const; - - //============================================================================== - /** Tries to send a message to the other end of this connection. - - This will fail if it's not connected, or if there's some kind of write error. If - it succeeds, the connection object at the other end will receive the message by - a callback to its messageReceived() method. - - @see messageReceived - */ - bool sendMessage (const MemoryBlock& message); - - //============================================================================== - /** Called when the connection is first connected. - - If the connection was created with the callbacksOnMessageThread flag set, then - this will be called on the message thread; otherwise it will be called on a server - thread. - */ - virtual void connectionMade() = 0; - - /** Called when the connection is broken. - - If the connection was created with the callbacksOnMessageThread flag set, then - this will be called on the message thread; otherwise it will be called on a server - thread. - */ - virtual void connectionLost() = 0; - - /** Called when a message arrives. - - When the object at the other end of this connection sends us a message with sendMessage(), - this callback is used to deliver it to us. - - If the connection was created with the callbacksOnMessageThread flag set, then - this will be called on the message thread; otherwise it will be called on a server - thread. - - @see sendMessage - */ - virtual void messageReceived (const MemoryBlock& message) = 0; - - -private: - //============================================================================== - CriticalSection pipeAndSocketLock; - ScopedPointer socket; - ScopedPointer pipe; - bool callbackConnectionState = false; - const bool useMessageThread; - const uint32 magicMessageHeader; - int pipeReceiveMessageTimeout = -1; - - friend class InterprocessConnectionServer; - void initialiseWithSocket (StreamingSocket*); - void initialiseWithPipe (NamedPipe*); - void deletePipeAndSocket(); - void connectionMadeInt(); - void connectionLostInt(); - void deliverDataInt (const MemoryBlock&); - bool readNextMessageInt(); - - struct ConnectionThread; - friend struct ConnectionThread; - friend struct ContainerDeletePolicy; - ScopedPointer thread; - void runThread(); - int writeData (void*, int); - - JUCE_DECLARE_WEAK_REFERENCEABLE (InterprocessConnection) - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InterprocessConnection) -}; - -} // namespace juce diff --git a/source/modules/juce_events/interprocess/juce_InterprocessConnectionServer.cpp b/source/modules/juce_events/interprocess/juce_InterprocessConnectionServer.cpp deleted file mode 100644 index 6c9022bd4..000000000 --- a/source/modules/juce_events/interprocess/juce_InterprocessConnectionServer.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -InterprocessConnectionServer::InterprocessConnectionServer() - : Thread ("Juce IPC server") -{ -} - -InterprocessConnectionServer::~InterprocessConnectionServer() -{ - stop(); -} - -//============================================================================== -bool InterprocessConnectionServer::beginWaitingForSocket (const int portNumber, const String& bindAddress) -{ - stop(); - - socket = new StreamingSocket(); - - if (socket->createListener (portNumber, bindAddress)) - { - startThread(); - return true; - } - - socket = nullptr; - return false; -} - -void InterprocessConnectionServer::stop() -{ - signalThreadShouldExit(); - - if (socket != nullptr) - socket->close(); - - stopThread (4000); - socket = nullptr; -} - -int InterprocessConnectionServer::getBoundPort() const noexcept -{ - return (socket == nullptr) ? -1 : socket->getBoundPort(); -} - -void InterprocessConnectionServer::run() -{ - while ((! threadShouldExit()) && socket != nullptr) - { - ScopedPointer clientSocket (socket->waitForNextConnection()); - - if (clientSocket != nullptr) - if (InterprocessConnection* newConnection = createConnectionObject()) - newConnection->initialiseWithSocket (clientSocket.release()); - } -} - -} // namespace juce diff --git a/source/modules/juce_events/interprocess/juce_InterprocessConnectionServer.h b/source/modules/juce_events/interprocess/juce_InterprocessConnectionServer.h deleted file mode 100644 index 552dd1c18..000000000 --- a/source/modules/juce_events/interprocess/juce_InterprocessConnectionServer.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - An object that waits for client sockets to connect to a port on this host, and - creates InterprocessConnection objects for each one. - - To use this, create a class derived from it which implements the createConnectionObject() - method, so that it creates suitable connection objects for each client that tries - to connect. - - @see InterprocessConnection -*/ -class JUCE_API InterprocessConnectionServer : private Thread -{ -public: - //============================================================================== - /** Creates an uninitialised server object. - */ - InterprocessConnectionServer(); - - /** Destructor. */ - ~InterprocessConnectionServer(); - - //============================================================================== - /** Starts an internal thread which listens on the given port number. - - While this is running, in another process tries to connect with the - InterprocessConnection::connectToSocket() method, this object will call - createConnectionObject() to create a connection to that client. - - Use stop() to stop the thread running. - - @param portNumber The port on which the server will receive - connections - @param bindAddress The address on which the server will listen - for connections. An empty string indicates - that it should listen on all addresses - assigned to this machine. - - @see createConnectionObject, stop - */ - bool beginWaitingForSocket (int portNumber, const String& bindAddress = String()); - - /** Terminates the listener thread, if it's active. - - @see beginWaitingForSocket - */ - void stop(); - - /** Returns the local port number to which this server is currently bound. - - This is useful if you need to know to which port the OS has actually bound your - socket when calling beginWaitingForSocket with a port number of zero. - - Returns -1 if the function fails. - */ - int getBoundPort() const noexcept; - -protected: - /** Creates a suitable connection object for a client process that wants to - connect to this one. - - This will be called by the listener thread when a client process tries - to connect, and must return a new InterprocessConnection object that will - then run as this end of the connection. - - @see InterprocessConnection - */ - virtual InterprocessConnection* createConnectionObject() = 0; - -private: - //============================================================================== - ScopedPointer socket; - - void run() override; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InterprocessConnectionServer) -}; - -} // namespace juce diff --git a/source/modules/juce_events/juce_events.cpp b/source/modules/juce_events/juce_events.cpp deleted file mode 100644 index bee0e3dff..000000000 --- a/source/modules/juce_events/juce_events.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -#ifdef JUCE_EVENTS_H_INCLUDED - /* When you add this cpp file to your project, you mustn't include it in a file where you've - already included any other headers - just put it inside a file on its own, possibly with your config - flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix - header files that the compiler may be using. - */ - #error "Incorrect use of JUCE cpp file" -#endif - -#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1 -#define JUCE_CORE_INCLUDE_JNI_HELPERS 1 -#define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1 -#define JUCE_CORE_INCLUDE_COM_SMART_PTR 1 -#define JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW 1 - -#if JUCE_USE_WINRT_MIDI - #define JUCE_EVENTS_INCLUDE_WINRT_WRAPPER 1 -#endif - -#include "juce_events.h" - -//============================================================================== -#if JUCE_MAC - #import - #import - #import - #import - #import - -#elif JUCE_LINUX - #include -#endif - -//============================================================================== -#include "messages/juce_ApplicationBase.cpp" -#include "messages/juce_DeletedAtShutdown.cpp" -#include "messages/juce_MessageListener.cpp" -#include "messages/juce_MessageManager.cpp" -#include "broadcasters/juce_ActionBroadcaster.cpp" -#include "broadcasters/juce_AsyncUpdater.cpp" -#include "broadcasters/juce_ChangeBroadcaster.cpp" -#include "timers/juce_MultiTimer.cpp" -#include "timers/juce_Timer.cpp" -#include "interprocess/juce_InterprocessConnection.cpp" -#include "interprocess/juce_InterprocessConnectionServer.cpp" -#include "interprocess/juce_ConnectedChildProcess.cpp" - -//============================================================================== -#if JUCE_MAC || JUCE_IOS - - #include "native/juce_osx_MessageQueue.h" - - #if JUCE_CLANG - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wundeclared-selector" - #endif - - #if JUCE_MAC - #include "native/juce_mac_MessageManager.mm" - #else - #include "native/juce_ios_MessageManager.mm" - #endif - - #if JUCE_CLANG - #pragma clang diagnostic pop - #endif - -#elif JUCE_WINDOWS - #include "native/juce_win32_Messaging.cpp" - #if JUCE_EVENTS_INCLUDE_WINRT_WRAPPER - #include "native/juce_win32_WinRTWrapper.cpp" - #endif - -#elif JUCE_LINUX - #include "native/juce_linux_Messaging.cpp" - -#elif JUCE_ANDROID - #include "native/juce_android_Messaging.cpp" - -#endif diff --git a/source/modules/juce_events/juce_events.h b/source/modules/juce_events/juce_events.h deleted file mode 100644 index d0340e1fd..000000000 --- a/source/modules/juce_events/juce_events.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -/******************************************************************************* - The block below describes the properties of this module, and is read by - the Projucer to automatically generate project code that uses it. - For details about the syntax and how to create or use a module, see the - JUCE Module Format.txt file. - - - BEGIN_JUCE_MODULE_DECLARATION - - ID: juce_events - vendor: juce - version: 5.1.2 - name: JUCE message and event handling classes - description: Classes for running an application's main event loop and sending/receiving messages, timers, etc. - website: http://www.juce.com/juce - license: ISC - - dependencies: juce_core - - END_JUCE_MODULE_DECLARATION - -*******************************************************************************/ - - -#pragma once -#define JUCE_EVENTS_H_INCLUDED - -#include - -//============================================================================== -/** Config: JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK - Will execute your application's suspend method on an iOS background task, giving - you extra time to save your applications state. -*/ -#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK - #define JUCE_EXECUTE_APP_SUSPEND_ON_BACKGROUND_TASK 0 -#endif - -#if JUCE_EVENTS_INCLUDE_WINRT_WRAPPER && JUCE_WINDOWS - #include -#endif - -#include "messages/juce_MessageManager.h" -#include "messages/juce_Message.h" -#include "messages/juce_MessageListener.h" -#include "messages/juce_CallbackMessage.h" -#include "messages/juce_DeletedAtShutdown.h" -#include "messages/juce_NotificationType.h" -#include "messages/juce_ApplicationBase.h" -#include "messages/juce_Initialisation.h" -#include "messages/juce_MountedVolumeListChangeDetector.h" -#include "broadcasters/juce_ActionBroadcaster.h" -#include "broadcasters/juce_ActionListener.h" -#include "broadcasters/juce_AsyncUpdater.h" -#include "broadcasters/juce_ChangeListener.h" -#include "broadcasters/juce_ChangeBroadcaster.h" -#include "timers/juce_Timer.h" -#include "timers/juce_MultiTimer.h" -#include "interprocess/juce_InterprocessConnection.h" -#include "interprocess/juce_InterprocessConnectionServer.h" -#include "interprocess/juce_ConnectedChildProcess.h" - -#if JUCE_LINUX - #include "native/juce_linux_EventLoop.h" -#endif - -#if JUCE_WINDOWS - #if JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW - #include "native/juce_win32_HiddenMessageWindow.h" - #endif - #if JUCE_EVENTS_INCLUDE_WINRT_WRAPPER - #include "native/juce_win32_WinRTWrapper.h" - #endif -#endif diff --git a/source/modules/juce_events/messages/juce_ApplicationBase.cpp b/source/modules/juce_events/messages/juce_ApplicationBase.cpp deleted file mode 100644 index cbd549f8b..000000000 --- a/source/modules/juce_events/messages/juce_ApplicationBase.cpp +++ /dev/null @@ -1,333 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -JUCEApplicationBase::CreateInstanceFunction JUCEApplicationBase::createInstance = 0; -JUCEApplicationBase* JUCEApplicationBase::appInstance = nullptr; - -#if JUCE_IOS -void* JUCEApplicationBase::iOSCustomDelegate = nullptr; -#endif - -JUCEApplicationBase::JUCEApplicationBase() - : appReturnValue (0), - stillInitialising (true) -{ - jassert (isStandaloneApp() && appInstance == nullptr); - appInstance = this; -} - -JUCEApplicationBase::~JUCEApplicationBase() -{ - jassert (appInstance == this); - appInstance = nullptr; -} - -void JUCEApplicationBase::setApplicationReturnValue (const int newReturnValue) noexcept -{ - appReturnValue = newReturnValue; -} - -// This is called on the Mac and iOS where the OS doesn't allow the stack to unwind on shutdown.. -void JUCEApplicationBase::appWillTerminateByForce() -{ - JUCE_AUTORELEASEPOOL - { - { - const ScopedPointer app (appInstance); - - if (app != nullptr) - app->shutdownApp(); - } - - DeletedAtShutdown::deleteAll(); - MessageManager::deleteInstance(); - } -} - -void JUCEApplicationBase::quit() -{ - MessageManager::getInstance()->stopDispatchLoop(); -} - -void JUCEApplicationBase::sendUnhandledException (const std::exception* const e, - const char* const sourceFile, - const int lineNumber) -{ - if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance()) - { - // If you hit this assertion then the __FILE__ macro is providing a - // relative path instead of an absolute path. On Windows this will be - // a path relative to the build directory rather than the currently - // running application. To fix this you must compile with the /FC flag. - jassert (File::isAbsolutePath (sourceFile)); - - app->unhandledException (e, sourceFile, lineNumber); - } -} - -//============================================================================== -#if ! (JUCE_IOS || JUCE_ANDROID) - #define JUCE_HANDLE_MULTIPLE_INSTANCES 1 -#endif - -#if JUCE_HANDLE_MULTIPLE_INSTANCES -struct JUCEApplicationBase::MultipleInstanceHandler : public ActionListener -{ -public: - MultipleInstanceHandler (const String& appName) - : appLock ("juceAppLock_" + appName) - { - } - - bool sendCommandLineToPreexistingInstance() - { - if (appLock.enter (0)) - return false; - - JUCEApplicationBase* const app = JUCEApplicationBase::getInstance(); - jassert (app != nullptr); - - MessageManager::broadcastMessage (app->getApplicationName() - + "/" + app->getCommandLineParameters()); - return true; - } - - void actionListenerCallback (const String& message) override - { - if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance()) - { - const String appName (app->getApplicationName()); - - if (message.startsWith (appName + "/")) - app->anotherInstanceStarted (message.substring (appName.length() + 1)); - } - } - -private: - InterProcessLock appLock; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultipleInstanceHandler) -}; - -bool JUCEApplicationBase::sendCommandLineToPreexistingInstance() -{ - jassert (multipleInstanceHandler == nullptr); // this must only be called once! - - multipleInstanceHandler = new MultipleInstanceHandler (getApplicationName()); - return multipleInstanceHandler->sendCommandLineToPreexistingInstance(); -} - -#else -struct JUCEApplicationBase::MultipleInstanceHandler {}; -#endif - -//============================================================================== -#if JUCE_ANDROID - -StringArray JUCEApplicationBase::getCommandLineParameterArray() { return {}; } -String JUCEApplicationBase::getCommandLineParameters() { return {}; } - -#else - -#if JUCE_WINDOWS && ! defined (_CONSOLE) - -String JUCE_CALLTYPE JUCEApplicationBase::getCommandLineParameters() -{ - return CharacterFunctions::findEndOfToken (CharPointer_UTF16 (GetCommandLineW()), - CharPointer_UTF16 (L" "), - CharPointer_UTF16 (L"\"")).findEndOfWhitespace(); -} - -StringArray JUCE_CALLTYPE JUCEApplicationBase::getCommandLineParameterArray() -{ - StringArray s; - - int argc = 0; - if (LPWSTR* const argv = CommandLineToArgvW (GetCommandLineW(), &argc)) - { - s = StringArray (argv + 1, argc - 1); - LocalFree (argv); - } - - return s; -} - -#else - -#if JUCE_IOS - extern int juce_iOSMain (int argc, const char* argv[], void* classPtr); -#endif - -#if JUCE_MAC - extern void initialiseNSApplication(); -#endif - -#if JUCE_LINUX && JUCE_MODULE_AVAILABLE_juce_gui_extra && (! defined(JUCE_WEB_BROWSER) || JUCE_WEB_BROWSER) - extern int juce_gtkWebkitMain (int argc, const char* argv[]); -#endif - -#if JUCE_WINDOWS - const char* const* juce_argv = nullptr; - int juce_argc = 0; -#else - extern const char* const* juce_argv; // declared in juce_core - extern int juce_argc; -#endif - -String JUCEApplicationBase::getCommandLineParameters() -{ - String argString; - - for (int i = 1; i < juce_argc; ++i) - { - String arg (juce_argv[i]); - - if (arg.containsChar (' ') && ! arg.isQuotedString()) - arg = arg.quoted ('"'); - - argString << arg << ' '; - } - - return argString.trim(); -} - -StringArray JUCEApplicationBase::getCommandLineParameterArray() -{ - return StringArray (juce_argv + 1, juce_argc - 1); -} - -int JUCEApplicationBase::main (int argc, const char* argv[]) -{ - JUCE_AUTORELEASEPOOL - { - juce_argc = argc; - juce_argv = argv; - - #if JUCE_MAC - initialiseNSApplication(); - #endif - - #if JUCE_LINUX && JUCE_MODULE_AVAILABLE_juce_gui_extra && (! defined(JUCE_WEB_BROWSER) || JUCE_WEB_BROWSER) - if (argc >= 2 && String (argv[1]) == "--juce-gtkwebkitfork-child") - return juce_gtkWebkitMain (argc, argv); - #endif - - #if JUCE_IOS - return juce_iOSMain (argc, argv, iOSCustomDelegate); - #else - - return JUCEApplicationBase::main(); - #endif - } -} - -#endif - -//============================================================================== -int JUCEApplicationBase::main() -{ - ScopedJuceInitialiser_GUI libraryInitialiser; - jassert (createInstance != nullptr); - - const ScopedPointer app (createInstance()); - jassert (app != nullptr); - - if (! app->initialiseApp()) - return app->shutdownApp(); - - JUCE_TRY - { - // loop until a quit message is received.. - MessageManager::getInstance()->runDispatchLoop(); - } - JUCE_CATCH_EXCEPTION - - return app->shutdownApp(); -} - -#endif - -//============================================================================== -bool JUCEApplicationBase::initialiseApp() -{ - #if JUCE_HANDLE_MULTIPLE_INSTANCES - if ((! moreThanOneInstanceAllowed()) && sendCommandLineToPreexistingInstance()) - { - DBG ("Another instance is running - quitting..."); - return false; - } - #endif - - #if JUCE_WINDOWS && JUCE_STANDALONE_APPLICATION && (! defined (_CONSOLE)) && (! JUCE_MINGW) - if (AttachConsole (ATTACH_PARENT_PROCESS) != 0) - { - // if we've launched a GUI app from cmd.exe or PowerShell, we need this to enable printf etc. - // However, only reassign stdout, stderr, stdin if they have not been already opened by - // a redirect or similar. - FILE* ignore; - - if (_fileno(stdout) < 0) freopen_s (&ignore, "CONOUT$", "w", stdout); - if (_fileno(stderr) < 0) freopen_s (&ignore, "CONOUT$", "w", stderr); - if (_fileno(stdin) < 0) freopen_s (&ignore, "CONIN$", "r", stdin); - } - #endif - - // let the app do its setting-up.. - initialise (getCommandLineParameters()); - - stillInitialising = false; - - if (MessageManager::getInstance()->hasStopMessageBeenSent()) - return false; - - #if JUCE_HANDLE_MULTIPLE_INSTANCES - if (multipleInstanceHandler != nullptr) - MessageManager::getInstance()->registerBroadcastListener (multipleInstanceHandler); - #endif - - return true; -} - -int JUCEApplicationBase::shutdownApp() -{ - jassert (JUCEApplicationBase::getInstance() == this); - - #if JUCE_HANDLE_MULTIPLE_INSTANCES - if (multipleInstanceHandler != nullptr) - MessageManager::getInstance()->deregisterBroadcastListener (multipleInstanceHandler); - #endif - - JUCE_TRY - { - // give the app a chance to clean up.. - shutdown(); - } - JUCE_CATCH_EXCEPTION - - multipleInstanceHandler = nullptr; - return getApplicationReturnValue(); -} - -} // namespace juce diff --git a/source/modules/juce_events/messages/juce_ApplicationBase.h b/source/modules/juce_events/messages/juce_ApplicationBase.h deleted file mode 100644 index 88950fd7c..000000000 --- a/source/modules/juce_events/messages/juce_ApplicationBase.h +++ /dev/null @@ -1,312 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Abstract base class for application classes. - - Note that in the juce_gui_basics module, there's a utility class JUCEApplication - which derives from JUCEApplicationBase, and takes care of a few chores. Most - of the time you'll want to derive your class from JUCEApplication rather than - using JUCEApplicationBase directly, but if you're not using the juce_gui_basics - module then you might need to go straight to this base class. - - Any application that wants to run an event loop must declare a subclass of - JUCEApplicationBase, and implement its various pure virtual methods. - - It then needs to use the START_JUCE_APPLICATION macro somewhere in a CPP file - to declare an instance of this class and generate suitable platform-specific - boilerplate code to launch the app. - - e.g. @code - class MyJUCEApp : public JUCEApplication - { - public: - MyJUCEApp() {} - ~MyJUCEApp() {} - - void initialise (const String& commandLine) override - { - myMainWindow = new MyApplicationWindow(); - myMainWindow->setBounds (100, 100, 400, 500); - myMainWindow->setVisible (true); - } - - void shutdown() override - { - myMainWindow = nullptr; - } - - const String getApplicationName() override - { - return "Super JUCE-o-matic"; - } - - const String getApplicationVersion() override - { - return "1.0"; - } - - private: - ScopedPointer myMainWindow; - }; - - // this generates boilerplate code to launch our app class: - START_JUCE_APPLICATION (MyJUCEApp) - @endcode - - @see JUCEApplication, START_JUCE_APPLICATION -*/ -class JUCE_API JUCEApplicationBase -{ -protected: - //============================================================================== - JUCEApplicationBase(); - -public: - /** Destructor. */ - virtual ~JUCEApplicationBase(); - - //============================================================================== - /** Returns the global instance of the application object that's running. */ - static JUCEApplicationBase* getInstance() noexcept { return appInstance; } - - //============================================================================== - /** Returns the application's name. */ - virtual const String getApplicationName() = 0; - - /** Returns the application's version number. */ - virtual const String getApplicationVersion() = 0; - - /** Checks whether multiple instances of the app are allowed. - - If you application class returns true for this, more than one instance is - permitted to run (except on the Mac where this isn't possible). - - If it's false, the second instance won't start, but it you will still get a - callback to anotherInstanceStarted() to tell you about this - which - gives you a chance to react to what the user was trying to do. - */ - virtual bool moreThanOneInstanceAllowed() = 0; - - /** Called when the application starts. - - This will be called once to let the application do whatever initialisation - it needs, create its windows, etc. - - After the method returns, the normal event-dispatch loop will be run, - until the quit() method is called, at which point the shutdown() - method will be called to let the application clear up anything it needs - to delete. - - If during the initialise() method, the application decides not to start-up - after all, it can just call the quit() method and the event loop won't be run. - - @param commandLineParameters the line passed in does not include the name of - the executable, just the parameter list. To get the - parameters as an array, you can call - JUCEApplication::getCommandLineParameters() - @see shutdown, quit - */ - virtual void initialise (const String& commandLineParameters) = 0; - - /* Called to allow the application to clear up before exiting. - - After JUCEApplication::quit() has been called, the event-dispatch loop will - terminate, and this method will get called to allow the app to sort itself - out. - - Be careful that nothing happens in this method that might rely on messages - being sent, or any kind of window activity, because the message loop is no - longer running at this point. - - @see DeletedAtShutdown - */ - virtual void shutdown() = 0; - - /** Indicates that the user has tried to start up another instance of the app. - - This will get called even if moreThanOneInstanceAllowed() is false. - */ - virtual void anotherInstanceStarted (const String& commandLine) = 0; - - /** Called when the operating system is trying to close the application. - - The default implementation of this method is to call quit(), but it may - be overloaded to ignore the request or do some other special behaviour - instead. For example, you might want to offer the user the chance to save - their changes before quitting, and give them the chance to cancel. - - If you want to send a quit signal to your app, this is the correct method - to call, because it means that requests that come from the system get handled - in the same way as those from your own application code. So e.g. you'd - call this method from a "quit" item on a menu bar. - */ - virtual void systemRequestedQuit() = 0; - - /** This method is called when the application is being put into background mode - by the operating system. - */ - virtual void suspended() = 0; - - /** This method is called when the application is being woken from background mode - by the operating system. - */ - virtual void resumed() = 0; - - /** If any unhandled exceptions make it through to the message dispatch loop, this - callback will be triggered, in case you want to log them or do some other - type of error-handling. - - If the type of exception is derived from the std::exception class, the pointer - passed-in will be valid. If the exception is of unknown type, this pointer - will be null. - */ - virtual void unhandledException (const std::exception*, - const String& sourceFilename, - int lineNumber) = 0; - - //============================================================================== - /** Override this method to be informed when the back button is pressed on a device. - - This is currently only implemented on Android devices. - */ - virtual void backButtonPressed() { } - - //============================================================================== - /** Signals that the main message loop should stop and the application should terminate. - - This isn't synchronous, it just posts a quit message to the main queue, and - when this message arrives, the message loop will stop, the shutdown() method - will be called, and the app will exit. - - Note that this will cause an unconditional quit to happen, so if you need an - extra level before this, e.g. to give the user the chance to save their work - and maybe cancel the quit, you'll need to handle this in the systemRequestedQuit() - method - see that method's help for more info. - - @see MessageManager - */ - static void quit(); - - //============================================================================== - /** Returns the application's command line parameters as a set of strings. - @see getCommandLineParameters - */ - static StringArray JUCE_CALLTYPE getCommandLineParameterArray(); - - /** Returns the application's command line parameters as a single string. - @see getCommandLineParameterArray - */ - static String JUCE_CALLTYPE getCommandLineParameters(); - - //============================================================================== - /** Sets the value that should be returned as the application's exit code when the - app quits. - - This is the value that's returned by the main() function. Normally you'd leave this - as 0 unless you want to indicate an error code. - - @see getApplicationReturnValue - */ - void setApplicationReturnValue (int newReturnValue) noexcept; - - /** Returns the value that has been set as the application's exit code. - @see setApplicationReturnValue - */ - int getApplicationReturnValue() const noexcept { return appReturnValue; } - - //============================================================================== - /** Returns true if this executable is running as an app (as opposed to being a plugin - or other kind of shared library. */ - static bool isStandaloneApp() noexcept { return createInstance != nullptr; } - - /** Returns true if the application hasn't yet completed its initialise() method - and entered the main event loop. - - This is handy for things like splash screens to know when the app's up-and-running - properly. - */ - bool isInitialising() const noexcept { return stillInitialising; } - - - //============================================================================== - #ifndef DOXYGEN - // The following methods are for internal use only... - static int main(); - static int main (int argc, const char* argv[]); - - static void appWillTerminateByForce(); - typedef JUCEApplicationBase* (*CreateInstanceFunction)(); - static CreateInstanceFunction createInstance; - - #if JUCE_IOS - static void* iOSCustomDelegate; - #endif - - virtual bool initialiseApp(); - int shutdownApp(); - static void JUCE_CALLTYPE sendUnhandledException (const std::exception*, const char* sourceFile, int lineNumber); - bool sendCommandLineToPreexistingInstance(); - #endif - -private: - //============================================================================== - static JUCEApplicationBase* appInstance; - int appReturnValue; - bool stillInitialising; - - struct MultipleInstanceHandler; - friend struct MultipleInstanceHandler; - friend struct ContainerDeletePolicy; - ScopedPointer multipleInstanceHandler; - - JUCE_DECLARE_NON_COPYABLE (JUCEApplicationBase) -}; - - -//============================================================================== -#if JUCE_CATCH_UNHANDLED_EXCEPTIONS || defined (DOXYGEN) - - /** The JUCE_TRY/JUCE_CATCH_EXCEPTION wrappers can be used to pass any uncaught exceptions to - the JUCEApplicationBase::sendUnhandledException() method. - This functionality can be enabled with the JUCE_CATCH_UNHANDLED_EXCEPTIONS macro. - */ - #define JUCE_TRY try - - /** The JUCE_TRY/JUCE_CATCH_EXCEPTION wrappers can be used to pass any uncaught exceptions to - the JUCEApplicationBase::sendUnhandledException() method. - This functionality can be enabled with the JUCE_CATCH_UNHANDLED_EXCEPTIONS macro. - */ - #define JUCE_CATCH_EXCEPTION \ - catch (const std::exception& e) { juce::JUCEApplicationBase::sendUnhandledException (&e, __FILE__, __LINE__); } \ - catch (...) { juce::JUCEApplicationBase::sendUnhandledException (nullptr, __FILE__, __LINE__); } - -#else - #define JUCE_TRY - #define JUCE_CATCH_EXCEPTION -#endif - -} // namespace juce diff --git a/source/modules/juce_events/messages/juce_CallbackMessage.h b/source/modules/juce_events/messages/juce_CallbackMessage.h deleted file mode 100644 index 303c1b438..000000000 --- a/source/modules/juce_events/messages/juce_CallbackMessage.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A message that invokes a callback method when it gets delivered. - - You can use this class to fire off actions that you want to be performed later - on the message thread. - - To use it, create a subclass of CallbackMessage which implements the messageCallback() - method, then call post() to dispatch it. The event thread will then invoke your - messageCallback() method later on, and will automatically delete the message object - afterwards. - - Always create a new instance of a CallbackMessage on the heap, as it will be - deleted automatically after the message has been delivered. - - Note that this class was essential back in the days before C++11, but in modern - times you may prefer to use MessageManager::callAsync() with a lambda. - - @see MessageManager::callAsync, MessageListener, ActionListener, ChangeListener -*/ -class JUCE_API CallbackMessage : public MessageManager::MessageBase -{ -public: - //============================================================================== - CallbackMessage() noexcept {} - - /** Destructor. */ - ~CallbackMessage() {} - - //============================================================================== - /** Called when the message is delivered. - - You should implement this method and make it do whatever action you want - to perform. - - Note that like all other messages, this object will be deleted immediately - after this method has been invoked. - */ - virtual void messageCallback() = 0; - -private: - // Avoid the leak-detector because for plugins, the host can unload our DLL with undelivered - // messages still in the system event queue. These aren't harmful, but can cause annoying assertions. - JUCE_DECLARE_NON_COPYABLE (CallbackMessage) -}; - -} // namespace juce diff --git a/source/modules/juce_events/messages/juce_DeletedAtShutdown.cpp b/source/modules/juce_events/messages/juce_DeletedAtShutdown.cpp deleted file mode 100644 index feede821f..000000000 --- a/source/modules/juce_events/messages/juce_DeletedAtShutdown.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -static SpinLock deletedAtShutdownLock; // use a spin lock because it can be statically initialised - -static Array& getDeletedAtShutdownObjects() -{ - static Array objects; - return objects; -} - -DeletedAtShutdown::DeletedAtShutdown() -{ - const SpinLock::ScopedLockType sl (deletedAtShutdownLock); - getDeletedAtShutdownObjects().add (this); -} - -DeletedAtShutdown::~DeletedAtShutdown() -{ - const SpinLock::ScopedLockType sl (deletedAtShutdownLock); - getDeletedAtShutdownObjects().removeFirstMatchingValue (this); -} - -#if JUCE_MSVC - // Disable unreachable code warning, in case the compiler manages to figure out that - // you have no classes of DeletedAtShutdown that could throw an exception in their destructor. - #pragma warning (push) - #pragma warning (disable: 4702) -#endif - -void DeletedAtShutdown::deleteAll() -{ - // make a local copy of the array, so it can't get into a loop if something - // creates another DeletedAtShutdown object during its destructor. - Array localCopy; - - { - const SpinLock::ScopedLockType sl (deletedAtShutdownLock); - localCopy = getDeletedAtShutdownObjects(); - } - - for (int i = localCopy.size(); --i >= 0;) - { - JUCE_TRY - { - auto* deletee = localCopy.getUnchecked(i); - - // double-check that it's not already been deleted during another object's destructor. - { - const SpinLock::ScopedLockType sl (deletedAtShutdownLock); - - if (! getDeletedAtShutdownObjects().contains (deletee)) - deletee = nullptr; - } - - delete deletee; - } - JUCE_CATCH_EXCEPTION - } - - // if this fails, then it's likely that some new DeletedAtShutdown objects were - // created while executing the destructors of the other ones. - jassert (getDeletedAtShutdownObjects().isEmpty()); - - getDeletedAtShutdownObjects().clear(); // just to make sure the array doesn't have any memory still allocated -} - -#if JUCE_MSVC - #pragma warning (pop) -#endif - -} // namespace juce diff --git a/source/modules/juce_events/messages/juce_DeletedAtShutdown.h b/source/modules/juce_events/messages/juce_DeletedAtShutdown.h deleted file mode 100644 index 9b28a49ed..000000000 --- a/source/modules/juce_events/messages/juce_DeletedAtShutdown.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Classes derived from this will be automatically deleted when the application exits. - - After JUCEApplicationBase::shutdown() has been called, any objects derived from - DeletedAtShutdown which are still in existence will be deleted in the reverse - order to that in which they were created. - - So if you've got a singleton and don't want to have to explicitly delete it, just - inherit from this and it'll be taken care of. -*/ -class JUCE_API DeletedAtShutdown -{ -protected: - /** Creates a DeletedAtShutdown object. */ - DeletedAtShutdown(); - - /** Destructor. - - It's ok to delete these objects explicitly - it's only the ones left - dangling at the end that will be deleted automatically. - */ - virtual ~DeletedAtShutdown(); - - -public: - /** Deletes all extant objects. - - This shouldn't be used by applications, as it's called automatically - in the shutdown code of the JUCEApplicationBase class. - */ - static void deleteAll(); - -private: - JUCE_DECLARE_NON_COPYABLE (DeletedAtShutdown) -}; - -} // namespace juce diff --git a/source/modules/juce_events/messages/juce_Initialisation.h b/source/modules/juce_events/messages/juce_Initialisation.h deleted file mode 100644 index db2988a70..000000000 --- a/source/modules/juce_events/messages/juce_Initialisation.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** Initialises Juce's GUI classes. - - If you're embedding Juce into an application that uses its own event-loop rather - than using the START_JUCE_APPLICATION macro, call this function before making any - Juce calls, to make sure things are initialised correctly. - - Note that if you're creating a Juce DLL for Windows, you may also need to call the - Process::setCurrentModuleInstanceHandle() method. - - @see shutdownJuce_GUI() -*/ -JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI(); - -/** Clears up any static data being used by Juce's GUI classes. - - If you're embedding Juce into an application that uses its own event-loop rather - than using the START_JUCE_APPLICATION macro, call this function in your shutdown - code to clean up any juce objects that might be lying around. - - @see initialiseJuce_GUI() -*/ -JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI(); - - -//============================================================================== -/** A utility object that helps you initialise and shutdown Juce correctly - using an RAII pattern. - - When the first instance of this class is created, it calls initialiseJuce_GUI(), - and when the last instance is deleted, it calls shutdownJuce_GUI(), so that you - can easily be sure that as long as at least one instance of the class exists, the - library will be initialised. - - This class is particularly handy to use at the beginning of a console app's - main() function, because it'll take care of shutting down whenever you return - from the main() call. - - Be careful with your threading though - to be safe, you should always make sure - that these objects are created and deleted on the message thread. -*/ -class JUCE_API ScopedJuceInitialiser_GUI -{ -public: - /** The constructor simply calls initialiseJuce_GUI(). */ - ScopedJuceInitialiser_GUI(); - - /** The destructor simply calls shutdownJuce_GUI(). */ - ~ScopedJuceInitialiser_GUI(); -}; - - -//============================================================================== -/** - To start a JUCE app, use this macro: START_JUCE_APPLICATION (AppSubClass) where - AppSubClass is the name of a class derived from JUCEApplication or JUCEApplicationBase. - - See the JUCEApplication and JUCEApplicationBase class documentation for more details. -*/ -#ifdef DOXYGEN - #define START_JUCE_APPLICATION(AppClass) -#else - #if JUCE_WINDOWS && ! defined (_CONSOLE) - #define JUCE_MAIN_FUNCTION int __stdcall WinMain (struct HINSTANCE__*, struct HINSTANCE__*, char*, int) - #define JUCE_MAIN_FUNCTION_ARGS - #else - #define JUCE_MAIN_FUNCTION int main (int argc, char* argv[]) - #define JUCE_MAIN_FUNCTION_ARGS argc, (const char**) argv - #endif - - #if JUCE_IOS - - #define JUCE_CREATE_APPLICATION_DEFINE(AppClass) \ - juce::JUCEApplicationBase* juce_CreateApplication() { return new AppClass(); } \ - void* juce_GetIOSCustomDelegateClass() { return nullptr; } - - #define JUCE_CREATE_APPLICATION_DEFINE_CUSTOM_DELEGATE(AppClass, DelegateClass) \ - juce::JUCEApplicationBase* juce_CreateApplication() { return new AppClass(); } \ - void* juce_GetIOSCustomDelegateClass() { return [DelegateClass class]; } - - #define JUCE_MAIN_FUNCTION_DEFINITION \ - extern "C" JUCE_MAIN_FUNCTION \ - { \ - juce::JUCEApplicationBase::createInstance = &juce_CreateApplication; \ - juce::JUCEApplicationBase::iOSCustomDelegate = juce_GetIOSCustomDelegateClass(); \ - return juce::JUCEApplicationBase::main (JUCE_MAIN_FUNCTION_ARGS); \ - } - - #elif JUCE_ANDROID - - #define JUCE_CREATE_APPLICATION_DEFINE(AppClass) \ - juce::JUCEApplicationBase* juce_CreateApplication() { return new AppClass(); } - - #define JUCE_MAIN_FUNCTION_DEFINITION - - #else - - #define JUCE_CREATE_APPLICATION_DEFINE(AppClass) \ - juce::JUCEApplicationBase* juce_CreateApplication() { return new AppClass(); } - - #define JUCE_MAIN_FUNCTION_DEFINITION \ - extern "C" JUCE_MAIN_FUNCTION \ - { \ - juce::JUCEApplicationBase::createInstance = &juce_CreateApplication; \ - return juce::JUCEApplicationBase::main (JUCE_MAIN_FUNCTION_ARGS); \ - } - - #endif - - #if JucePlugin_Build_Standalone - #if JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP - #define START_JUCE_APPLICATION(AppClass) JUCE_CREATE_APPLICATION_DEFINE(AppClass) - #if JUCE_IOS - #define START_JUCE_APPLICATION_WITH_CUSTOM_DELEGATE(AppClass, DelegateClass) JUCE_CREATE_APPLICATION_DEFINE_CUSTOM_DELEGATE(AppClass, DelegateClass) - #endif - #else - #define START_JUCE_APPLICATION(AppClass) static_assert(false, "You are trying to use START_JUCE_APPLICATION in an audio plug-in. Define JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP=1 if you want to use a custom standalone target app."); - #if JUCE_IOS - #define START_JUCE_APPLICATION_WITH_CUSTOM_DELEGATE(AppClass, DelegateClass) static_assert(false, "You are trying to use START_JUCE_APPLICATION in an audio plug-in. Define JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP=1 if you want to use a custom standalone target app."); - #endif - #endif - #else - - #define START_JUCE_APPLICATION(AppClass) \ - JUCE_CREATE_APPLICATION_DEFINE(AppClass) \ - JUCE_MAIN_FUNCTION_DEFINITION - - #if JUCE_IOS - /** - You can instruct JUCE to use a custom iOS app delegate class instaed of JUCE's default - app delegate. For JUCE to work you must pass all messages to JUCE's internal app delegate. - Below is an example of minimal forwarding custom delegate. Note that you are at your own - risk if you decide to use your own delegate an subtle, hard to debug bugs may occur. - - @interface MyCustomDelegate : NSObject { NSObject* juceDelegate; } @end - @implementation MyCustomDelegate - -(id) init - { - self = [super init]; - juceDelegate = reinterpret_cast*> ([[NSClassFromString (@"JuceAppStartupDelegate") alloc] init]); - - return self; - } - - -(void)dealloc - { - [juceDelegate release]; - [super dealloc]; - } - - - (void)forwardInvocation:(NSInvocation *)anInvocation - { - if (juceDelegate != nullptr && [juceDelegate respondsToSelector:[anInvocation selector]]) - [anInvocation invokeWithTarget:juceDelegate]; - else - [super forwardInvocation:anInvocation]; - } - - -(BOOL)respondsToSelector:(SEL)aSelector - { - if (juceDelegate != nullptr && [juceDelegate respondsToSelector:aSelector]) - return YES; - - return [super respondsToSelector:aSelector]; - } - @end - */ - #define START_JUCE_APPLICATION_WITH_CUSTOM_DELEGATE(AppClass, DelegateClass) \ - JUCE_CREATE_APPLICATION_DEFINE_CUSTOM_DELEGATE(AppClass, DelegateClass) \ - JUCE_MAIN_FUNCTION_DEFINITION - #endif - #endif -#endif - -} // namespace juce diff --git a/source/modules/juce_events/messages/juce_Message.h b/source/modules/juce_events/messages/juce_Message.h deleted file mode 100644 index c0abb238c..000000000 --- a/source/modules/juce_events/messages/juce_Message.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -class MessageListener; - - -//============================================================================== -/** The base class for objects that can be sent to a MessageListener. - - If you want to send a message that carries some kind of custom data, just - create a subclass of Message with some appropriate member variables to hold - your data. - - Always create a new instance of a Message object on the heap, as it will be - deleted automatically after the message has been delivered. - - @see MessageListener, MessageManager, ActionListener, ChangeListener -*/ -class JUCE_API Message : public MessageManager::MessageBase -{ -public: - //============================================================================== - /** Creates an uninitialised message. */ - Message() noexcept; - ~Message(); - - typedef ReferenceCountedObjectPtr Ptr; - - //============================================================================== -private: - friend class MessageListener; - WeakReference recipient; - void messageCallback() override; - - // Avoid the leak-detector because for plugins, the host can unload our DLL with undelivered - // messages still in the system event queue. These aren't harmful, but can cause annoying assertions. - JUCE_DECLARE_NON_COPYABLE (Message) -}; - -} // namespace juce diff --git a/source/modules/juce_events/messages/juce_MessageListener.cpp b/source/modules/juce_events/messages/juce_MessageListener.cpp deleted file mode 100644 index e1e8dcf63..000000000 --- a/source/modules/juce_events/messages/juce_MessageListener.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -Message::Message() noexcept {} -Message::~Message() {} - -void Message::messageCallback() -{ - if (MessageListener* const r = recipient) - r->handleMessage (*this); -} - -MessageListener::MessageListener() noexcept -{ - // Are you trying to create a messagelistener before or after juce has been intialised?? - jassert (MessageManager::getInstanceWithoutCreating() != nullptr); -} - -MessageListener::~MessageListener() -{ - masterReference.clear(); -} - -void MessageListener::postMessage (Message* const message) const -{ - message->recipient = const_cast (this); - message->post(); -} - -} // namespace juce diff --git a/source/modules/juce_events/messages/juce_MessageListener.h b/source/modules/juce_events/messages/juce_MessageListener.h deleted file mode 100644 index 8c8fe9bd5..000000000 --- a/source/modules/juce_events/messages/juce_MessageListener.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - MessageListener subclasses can post and receive Message objects. - - @see Message, MessageManager, ActionListener, ChangeListener -*/ -class JUCE_API MessageListener -{ -public: - //============================================================================== - MessageListener() noexcept; - - /** Destructor. */ - virtual ~MessageListener(); - - //============================================================================== - /** This is the callback method that receives incoming messages. - - This is called by the MessageManager from its dispatch loop. - - @see postMessage - */ - virtual void handleMessage (const Message& message) = 0; - - //============================================================================== - /** Sends a message to the message queue, for asynchronous delivery to this listener - later on. - - This method can be called safely by any thread. - - @param message the message object to send - this will be deleted - automatically by the message queue, so make sure it's - allocated on the heap, not the stack! - @see handleMessage - */ - void postMessage (Message* message) const; - -private: - WeakReference::Master masterReference; - friend class WeakReference; -}; - -} // namespace juce diff --git a/source/modules/juce_events/messages/juce_MessageManager.cpp b/source/modules/juce_events/messages/juce_MessageManager.cpp deleted file mode 100644 index 563852e54..000000000 --- a/source/modules/juce_events/messages/juce_MessageManager.cpp +++ /dev/null @@ -1,387 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -MessageManager::MessageManager() noexcept - : messageThreadId (Thread::getCurrentThreadId()) -{ - if (JUCEApplicationBase::isStandaloneApp()) - Thread::setCurrentThreadName ("Juce Message Thread"); -} - -MessageManager::~MessageManager() noexcept -{ - broadcaster = nullptr; - - doPlatformSpecificShutdown(); - - jassert (instance == this); - instance = nullptr; // do this last in case this instance is still needed by doPlatformSpecificShutdown() -} - -MessageManager* MessageManager::instance = nullptr; - -MessageManager* MessageManager::getInstance() -{ - if (instance == nullptr) - { - instance = new MessageManager(); - doPlatformSpecificInitialisation(); - } - - return instance; -} - -MessageManager* MessageManager::getInstanceWithoutCreating() noexcept -{ - return instance; -} - -void MessageManager::deleteInstance() -{ - deleteAndZero (instance); -} - -//============================================================================== -bool MessageManager::MessageBase::post() -{ - auto* mm = MessageManager::instance; - - if (mm == nullptr || mm->quitMessagePosted || ! postMessageToSystemQueue (this)) - { - Ptr deleter (this); // (this will delete messages that were just created with a 0 ref count) - return false; - } - - return true; -} - -//============================================================================== -#if JUCE_MODAL_LOOPS_PERMITTED && ! (JUCE_MAC || JUCE_IOS) -bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) -{ - jassert (isThisTheMessageThread()); // must only be called by the message thread - - const int64 endTime = Time::currentTimeMillis() + millisecondsToRunFor; - - while (! quitMessageReceived) - { - JUCE_TRY - { - if (! dispatchNextMessageOnSystemQueue (millisecondsToRunFor >= 0)) - Thread::sleep (1); - } - JUCE_CATCH_EXCEPTION - - if (millisecondsToRunFor >= 0 && Time::currentTimeMillis() >= endTime) - break; - } - - return ! quitMessageReceived; -} -#endif - -#if ! (JUCE_MAC || JUCE_IOS || JUCE_ANDROID) -class MessageManager::QuitMessage : public MessageManager::MessageBase -{ -public: - QuitMessage() {} - - void messageCallback() override - { - if (auto* mm = MessageManager::instance) - mm->quitMessageReceived = true; - } - - JUCE_DECLARE_NON_COPYABLE (QuitMessage) -}; - -void MessageManager::runDispatchLoop() -{ - jassert (isThisTheMessageThread()); // must only be called by the message thread - - while (! quitMessageReceived) - { - JUCE_TRY - { - if (! dispatchNextMessageOnSystemQueue (false)) - Thread::sleep (1); - } - JUCE_CATCH_EXCEPTION - } -} - -void MessageManager::stopDispatchLoop() -{ - (new QuitMessage())->post(); - quitMessagePosted = true; -} - -#endif - -//============================================================================== -class AsyncFunctionCallback : public MessageManager::MessageBase -{ -public: - AsyncFunctionCallback (MessageCallbackFunction* const f, void* const param) - : func (f), parameter (param) - {} - - void messageCallback() override - { - result = (*func) (parameter); - finished.signal(); - } - - WaitableEvent finished; - void* volatile result = nullptr; - -private: - MessageCallbackFunction* const func; - void* const parameter; - - JUCE_DECLARE_NON_COPYABLE (AsyncFunctionCallback) -}; - -void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* const func, void* const parameter) -{ - if (isThisTheMessageThread()) - return func (parameter); - - // If this thread has the message manager locked, then this will deadlock! - jassert (! currentThreadHasLockedMessageManager()); - - const ReferenceCountedObjectPtr message (new AsyncFunctionCallback (func, parameter)); - - if (message->post()) - { - message->finished.wait(); - return message->result; - } - - jassertfalse; // the OS message queue failed to send the message! - return nullptr; -} - -//============================================================================== -void MessageManager::deliverBroadcastMessage (const String& value) -{ - if (broadcaster != nullptr) - broadcaster->sendActionMessage (value); -} - -void MessageManager::registerBroadcastListener (ActionListener* const listener) -{ - if (broadcaster == nullptr) - broadcaster = new ActionBroadcaster(); - - broadcaster->addActionListener (listener); -} - -void MessageManager::deregisterBroadcastListener (ActionListener* const listener) -{ - if (broadcaster != nullptr) - broadcaster->removeActionListener (listener); -} - -//============================================================================== -bool MessageManager::isThisTheMessageThread() const noexcept -{ - return Thread::getCurrentThreadId() == messageThreadId; -} - -void MessageManager::setCurrentThreadAsMessageThread() -{ - const Thread::ThreadID thisThread = Thread::getCurrentThreadId(); - - if (messageThreadId != thisThread) - { - messageThreadId = thisThread; - - // This is needed on windows to make sure the message window is created by this thread - doPlatformSpecificShutdown(); - doPlatformSpecificInitialisation(); - } -} - -bool MessageManager::currentThreadHasLockedMessageManager() const noexcept -{ - const Thread::ThreadID thisThread = Thread::getCurrentThreadId(); - return thisThread == messageThreadId || thisThread == threadWithLock; -} - -//============================================================================== -//============================================================================== -/* The only safe way to lock the message thread while another thread does - some work is by posting a special message, whose purpose is to tie up the event - loop until the other thread has finished its business. - - Any other approach can get horribly deadlocked if the OS uses its own hidden locks which - get locked before making an event callback, because if the same OS lock gets indirectly - accessed from another thread inside a MM lock, you're screwed. (this is exactly what happens - in Cocoa). -*/ -class MessageManagerLock::BlockingMessage : public MessageManager::MessageBase -{ -public: - BlockingMessage() noexcept {} - - void messageCallback() override - { - lockedEvent.signal(); - releaseEvent.wait(); - } - - WaitableEvent lockedEvent, releaseEvent; - - JUCE_DECLARE_NON_COPYABLE (BlockingMessage) -}; - -//============================================================================== -MessageManagerLock::MessageManagerLock (Thread* const threadToCheck) - : blockingMessage(), checker (threadToCheck, nullptr), - locked (attemptLock (threadToCheck != nullptr ? &checker : nullptr)) -{ -} - -MessageManagerLock::MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSignal) - : blockingMessage(), checker (nullptr, jobToCheckForExitSignal), - locked (attemptLock (jobToCheckForExitSignal != nullptr ? &checker : nullptr)) -{ -} - -MessageManagerLock::MessageManagerLock (BailOutChecker& bailOutChecker) - : blockingMessage(), checker (nullptr, nullptr), - locked (attemptLock (&bailOutChecker)) -{ -} - -bool MessageManagerLock::attemptLock (BailOutChecker* bailOutChecker) -{ - auto* mm = MessageManager::instance; - - if (mm == nullptr) - return false; - - if (mm->currentThreadHasLockedMessageManager()) - return true; - - if (bailOutChecker == nullptr) - { - mm->lockingLock.enter(); - } - else - { - while (! mm->lockingLock.tryEnter()) - { - if (bailOutChecker->shouldAbortAcquiringLock()) - return false; - - Thread::yield(); - } - } - - blockingMessage = new BlockingMessage(); - - if (! blockingMessage->post()) - { - blockingMessage = nullptr; - return false; - } - - while (! blockingMessage->lockedEvent.wait (20)) - { - if (bailOutChecker != nullptr && bailOutChecker->shouldAbortAcquiringLock()) - { - blockingMessage->releaseEvent.signal(); - blockingMessage = nullptr; - mm->lockingLock.exit(); - return false; - } - } - - jassert (mm->threadWithLock == 0); - - mm->threadWithLock = Thread::getCurrentThreadId(); - return true; -} - -MessageManagerLock::~MessageManagerLock() noexcept -{ - if (blockingMessage != nullptr) - { - auto* mm = MessageManager::instance; - - jassert (mm == nullptr || mm->currentThreadHasLockedMessageManager()); - - blockingMessage->releaseEvent.signal(); - blockingMessage = nullptr; - - if (mm != nullptr) - { - mm->threadWithLock = 0; - mm->lockingLock.exit(); - } - } -} - -//============================================================================== -MessageManagerLock::ThreadChecker::ThreadChecker (Thread* const threadToUse, - ThreadPoolJob* const threadJobToUse) - : threadToCheck (threadToUse), job (threadJobToUse) -{ -} - -bool MessageManagerLock::ThreadChecker::shouldAbortAcquiringLock() -{ - return (threadToCheck != nullptr && threadToCheck->threadShouldExit()) - || (job != nullptr && job->shouldExit()); -} - -//============================================================================== -JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI(); -JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI() -{ - JUCE_AUTORELEASEPOOL - { - MessageManager::getInstance(); - } -} - -JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI(); -JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI() -{ - JUCE_AUTORELEASEPOOL - { - DeletedAtShutdown::deleteAll(); - MessageManager::deleteInstance(); - } -} - -static int numScopedInitInstances = 0; - -ScopedJuceInitialiser_GUI::ScopedJuceInitialiser_GUI() { if (numScopedInitInstances++ == 0) initialiseJuce_GUI(); } -ScopedJuceInitialiser_GUI::~ScopedJuceInitialiser_GUI() { if (--numScopedInitInstances == 0) shutdownJuce_GUI(); } - -} // namespace juce diff --git a/source/modules/juce_events/messages/juce_MessageManager.h b/source/modules/juce_events/messages/juce_MessageManager.h deleted file mode 100644 index 688d53039..000000000 --- a/source/modules/juce_events/messages/juce_MessageManager.h +++ /dev/null @@ -1,381 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -class MessageManagerLock; -class ThreadPoolJob; -class ActionListener; -class ActionBroadcaster; - -//============================================================================== -#if JUCE_MODULE_AVAILABLE_juce_opengl -class OpenGLContext; -#endif - -//============================================================================== -/** See MessageManager::callFunctionOnMessageThread() for use of this function type. */ -typedef void* (MessageCallbackFunction) (void* userData); - - -//============================================================================== -/** - This class is in charge of the application's event-dispatch loop. - - @see Message, CallbackMessage, MessageManagerLock, JUCEApplication, JUCEApplicationBase -*/ -class JUCE_API MessageManager -{ -public: - //============================================================================== - /** Returns the global instance of the MessageManager. */ - static MessageManager* getInstance(); - - /** Returns the global instance of the MessageManager, or nullptr if it doesn't exist. */ - static MessageManager* getInstanceWithoutCreating() noexcept; - - /** Deletes the global MessageManager instance. - Does nothing if no instance had been created. - */ - static void deleteInstance(); - - //============================================================================== - /** Runs the event dispatch loop until a stop message is posted. - - This method is only intended to be run by the application's startup routine, - as it blocks, and will only return after the stopDispatchLoop() method has been used. - - @see stopDispatchLoop - */ - void runDispatchLoop(); - - /** Sends a signal that the dispatch loop should terminate. - - After this is called, the runDispatchLoop() or runDispatchLoopUntil() methods - will be interrupted and will return. - - @see runDispatchLoop - */ - void stopDispatchLoop(); - - /** Returns true if the stopDispatchLoop() method has been called. - */ - bool hasStopMessageBeenSent() const noexcept { return quitMessagePosted; } - - #if JUCE_MODAL_LOOPS_PERMITTED || DOXYGEN - /** Synchronously dispatches messages until a given time has elapsed. - - Returns false if a quit message has been posted by a call to stopDispatchLoop(), - otherwise returns true. - */ - bool runDispatchLoopUntil (int millisecondsToRunFor); - #endif - - //============================================================================== - /** Asynchronously invokes a function or C++11 lambda on the message thread. */ - template - static void callAsync (FunctionType functionToCall) - { - new AsyncCallInvoker (functionToCall); - } - - /** Calls a function using the message-thread. - - This can be used by any thread to cause this function to be called-back - by the message thread. If it's the message-thread that's calling this method, - then the function will just be called; if another thread is calling, a message - will be posted to the queue, and this method will block until that message - is delivered, the function is called, and the result is returned. - - Be careful not to cause any deadlocks with this! It's easy to do - e.g. if the caller - thread has a critical section locked, which an unrelated message callback then tries to lock - before the message thread gets round to processing this callback. - - @param callback the function to call - its signature must be @code - void* myCallbackFunction (void*) @endcode - @param userData a user-defined pointer that will be passed to the function that gets called - @returns the value that the callback function returns. - @see MessageManagerLock - */ - void* callFunctionOnMessageThread (MessageCallbackFunction* callback, void* userData); - - /** Returns true if the caller-thread is the message thread. */ - bool isThisTheMessageThread() const noexcept; - - /** Called to tell the manager that the current thread is the one that's running the dispatch loop. - - (Best to ignore this method unless you really know what you're doing..) - @see getCurrentMessageThread - */ - void setCurrentThreadAsMessageThread(); - - /** Returns the ID of the current message thread, as set by setCurrentThreadAsMessageThread(). - - (Best to ignore this method unless you really know what you're doing..) - @see setCurrentThreadAsMessageThread - */ - Thread::ThreadID getCurrentMessageThread() const noexcept { return messageThreadId; } - - /** Returns true if the caller thread has currently got the message manager locked. - - see the MessageManagerLock class for more info about this. - - This will be true if the caller is the message thread, because that automatically - gains a lock while a message is being dispatched. - */ - bool currentThreadHasLockedMessageManager() const noexcept; - - //============================================================================== - /** Sends a message to all other JUCE applications that are running. - - @param messageText the string that will be passed to the actionListenerCallback() - method of the broadcast listeners in the other app. - @see registerBroadcastListener, ActionListener - */ - static void broadcastMessage (const String& messageText); - - /** Registers a listener to get told about broadcast messages. - - The actionListenerCallback() callback's string parameter - is the message passed into broadcastMessage(). - - @see broadcastMessage - */ - void registerBroadcastListener (ActionListener* listener); - - /** Deregisters a broadcast listener. */ - void deregisterBroadcastListener (ActionListener* listener); - - //============================================================================== - /** Internal class used as the base class for all message objects. - You shouldn't need to use this directly - see the CallbackMessage or Message - classes instead. - */ - class JUCE_API MessageBase : public ReferenceCountedObject - { - public: - MessageBase() noexcept {} - virtual ~MessageBase() {} - - virtual void messageCallback() = 0; - bool post(); - - typedef ReferenceCountedObjectPtr Ptr; - - JUCE_DECLARE_NON_COPYABLE (MessageBase) - }; - - //============================================================================== - #ifndef DOXYGEN - // Internal methods - do not use! - void deliverBroadcastMessage (const String&); - ~MessageManager() noexcept; - static bool dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages); - #endif - -private: - //============================================================================== - MessageManager() noexcept; - - static MessageManager* instance; - - friend class MessageBase; - class QuitMessage; - friend class QuitMessage; - friend class MessageManagerLock; - - ScopedPointer broadcaster; - bool quitMessagePosted = false, quitMessageReceived = false; - Thread::ThreadID messageThreadId; - Thread::ThreadID volatile threadWithLock = {}; - CriticalSection lockingLock; - - static bool postMessageToSystemQueue (MessageBase*); - static void* exitModalLoopCallback (void*); - static void doPlatformSpecificInitialisation(); - static void doPlatformSpecificShutdown(); - - template - struct AsyncCallInvoker : public MessageBase - { - AsyncCallInvoker (FunctionType f) : callback (f) { post(); } - void messageCallback() override { callback(); } - FunctionType callback; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AsyncCallInvoker) - }; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MessageManager) -}; - - -//============================================================================== -/** Used to make sure that the calling thread has exclusive access to the message loop. - - Because it's not thread-safe to call any of the Component or other UI classes - from threads other than the message thread, one of these objects can be used to - lock the message loop and allow this to be done. The message thread will be - suspended for the lifetime of the MessageManagerLock object, so create one on - the stack like this: @code - void MyThread::run() - { - someData = 1234; - - const MessageManagerLock mmLock; - // the event loop will now be locked so it's safe to make a few calls.. - - myComponent->setBounds (newBounds); - myComponent->repaint(); - - // ..the event loop will now be unlocked as the MessageManagerLock goes out of scope - } - @endcode - - Obviously be careful not to create one of these and leave it lying around, or - your app will grind to a halt! - - MessageManagerLocks are re-entrant, so can be safely nested if the current thread - already has the lock. - - Another caveat is that using this in conjunction with other CriticalSections - can create lots of interesting ways of producing a deadlock! In particular, if - your message thread calls stopThread() for a thread that uses these locks, - you'll get an (occasional) deadlock.. - - @see MessageManager, MessageManager::currentThreadHasLockedMessageManager -*/ -class JUCE_API MessageManagerLock -{ -public: - //============================================================================== - /** Tries to acquire a lock on the message manager. - - The constructor attempts to gain a lock on the message loop, and the lock will be - kept for the lifetime of this object. - - Optionally, you can pass a thread object here, and while waiting to obtain the lock, - this method will keep checking whether the thread has been given the - Thread::signalThreadShouldExit() signal. If this happens, then it will return - without gaining the lock. If you pass a thread, you must check whether the lock was - successful by calling lockWasGained(). If this is false, your thread is being told to - die, so you should take evasive action. - - If you pass nullptr for the thread object, it will wait indefinitely for the lock - be - careful when doing this, because it's very easy to deadlock if your message thread - attempts to call stopThread() on a thread just as that thread attempts to get the - message lock. - - If the calling thread already has the lock, nothing will be done, so it's safe and - quick to use these locks recursively. - - E.g. - @code - void run() - { - ... - - while (! threadShouldExit()) - { - MessageManagerLock mml (Thread::getCurrentThread()); - - if (! mml.lockWasGained()) - return; // another thread is trying to kill us! - - ..do some locked stuff here.. - } - - ..and now the MM is now unlocked.. - } - @endcode - - */ - MessageManagerLock (Thread* threadToCheckForExitSignal = nullptr); - - //============================================================================== - /** This has the same behaviour as the other constructor, but takes a ThreadPoolJob - instead of a thread. - - See the MessageManagerLock (Thread*) constructor for details on how this works. - */ - MessageManagerLock (ThreadPoolJob* jobToCheckForExitSignal); - - //============================================================================== - struct BailOutChecker - { - virtual ~BailOutChecker() {} - - /** Return true if acquiring the lock should be aborted. */ - virtual bool shouldAbortAcquiringLock() = 0; - }; - - /** This is an abstraction of the other constructors. You can pass this constructor - a functor which is periodically checked if attempting the lock should be aborted. - - See the MessageManagerLock (Thread*) constructor for details on how this works. - */ - MessageManagerLock (BailOutChecker&); - - - //============================================================================== - /** Releases the current thread's lock on the message manager. - - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! - */ - ~MessageManagerLock() noexcept; - - //============================================================================== - /** Returns true if the lock was successfully acquired. - (See the constructor that takes a Thread for more info). - */ - bool lockWasGained() const noexcept { return locked; } - -private: - class BlockingMessage; - friend class ReferenceCountedObjectPtr; - ReferenceCountedObjectPtr blockingMessage; - - struct ThreadChecker : BailOutChecker - { - ThreadChecker (Thread* const, ThreadPoolJob* const); - - // Required to supress VS2013 compiler warnings - ThreadChecker& operator= (const ThreadChecker&) = delete; - - bool shouldAbortAcquiringLock() override; - - Thread* const threadToCheck; - ThreadPoolJob* const job; - }; - - //============================================================================== - ThreadChecker checker; - bool locked; - - //============================================================================== - bool attemptLock (BailOutChecker*); - - JUCE_DECLARE_NON_COPYABLE (MessageManagerLock) -}; - -} // namespace juce diff --git a/source/modules/juce_events/messages/juce_MountedVolumeListChangeDetector.h b/source/modules/juce_events/messages/juce_MountedVolumeListChangeDetector.h deleted file mode 100644 index ccc00b11b..000000000 --- a/source/modules/juce_events/messages/juce_MountedVolumeListChangeDetector.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -#if JUCE_MAC || JUCE_WINDOWS || defined (DOXYGEN) - -//============================================================================== -/** - An instance of this class will provide callbacks when drives are - mounted or unmounted on the system. - - Just inherit from this class and implement the pure virtual method - to get the callbacks, there's no need to do anything else. - - @see File::findFileSystemRoots() -*/ -class JUCE_API MountedVolumeListChangeDetector -{ -public: - MountedVolumeListChangeDetector(); - virtual ~MountedVolumeListChangeDetector(); - - /** This method is called when a volume is mounted or unmounted. */ - virtual void mountedVolumeListChanged() = 0; - -private: - JUCE_PUBLIC_IN_DLL_BUILD (struct Pimpl) - friend struct ContainerDeletePolicy; - ScopedPointer pimpl; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MountedVolumeListChangeDetector) -}; - -#endif - -} // namespace juce diff --git a/source/modules/juce_events/messages/juce_NotificationType.h b/source/modules/juce_events/messages/juce_NotificationType.h deleted file mode 100644 index 168ac5c68..000000000 --- a/source/modules/juce_events/messages/juce_NotificationType.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - These enums are used in various classes to indicate whether a notification - event should be sent out. -*/ -enum NotificationType -{ - dontSendNotification = 0, /**< No notification message should be sent. */ - sendNotification = 1, /**< Requests a notification message, either synchronous or not. */ - sendNotificationSync, /**< Requests a synchronous notification. */ - sendNotificationAsync, /**< Requests an asynchronous notification. */ -}; - -} // namespace juce diff --git a/source/modules/juce_events/native/juce_android_Messaging.cpp b/source/modules/juce_events/native/juce_android_Messaging.cpp deleted file mode 100644 index 9cb4dfbfc..000000000 --- a/source/modules/juce_events/native/juce_android_Messaging.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ - METHOD (constructor, "", "()V") \ - METHOD (post, "post", "(Ljava/lang/Runnable;)Z") \ - -DECLARE_JNI_CLASS (JNIHandler, "android/os/Handler"); -#undef JNI_CLASS_MEMBERS - - -//============================================================================== -namespace Android -{ - class Runnable : public juce::AndroidInterfaceImplementer - { - public: - virtual void run() = 0; - - private: - jobject invoke (jobject proxy, jobject method, jobjectArray args) override - { - auto* env = getEnv(); - auto methodName = juce::juceString ((jstring) env->CallObjectMethod (method, Method.getName)); - - if (methodName == "run") - { - run(); - return nullptr; - } - - // invoke base class - return AndroidInterfaceImplementer::invoke (proxy, method, args); - } - }; - - struct Handler - { - juce_DeclareSingleton (Handler, false) - - Handler() : nativeHandler (getEnv()->NewObject (JNIHandler, JNIHandler.constructor)) {} - - bool post (Runnable* runnable) - { - return (getEnv()->CallBooleanMethod (nativeHandler.get(), JNIHandler.post, - CreateJavaInterface (runnable, "java/lang/Runnable").get()) != 0); - } - - GlobalRef nativeHandler; - }; - - juce_ImplementSingleton (Handler); -} - -//============================================================================== -void MessageManager::doPlatformSpecificInitialisation() { Android::Handler::getInstance(); } -void MessageManager::doPlatformSpecificShutdown() {} - -//============================================================================== -bool MessageManager::dispatchNextMessageOnSystemQueue (const bool) -{ - Logger::outputDebugString ("*** Modal loops are not possible in Android!! Exiting..."); - exit (1); - - return true; -} - -//============================================================================== -struct AndroidMessageCallback : public Android::Runnable -{ - AndroidMessageCallback (const MessageManager::MessageBase::Ptr& messageToDeliver) - : message (messageToDeliver) - {} - - AndroidMessageCallback (MessageManager::MessageBase::Ptr && messageToDeliver) - : message (static_cast (messageToDeliver)) - {} - - void run() override - { - JUCE_TRY - { - message->messageCallback(); - - // delete the message already here as Java will only run the - // destructor of this runnable the next time the garbage - // collector kicks in. - message = nullptr; - } - JUCE_CATCH_EXCEPTION - } - - MessageManager::MessageBase::Ptr message; -}; - -bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message) -{ - return Android::Handler::getInstance()->post (new AndroidMessageCallback (message)); -} -//============================================================================== -void MessageManager::broadcastMessage (const String&) -{ -} - -void MessageManager::runDispatchLoop() -{ -} - -void MessageManager::stopDispatchLoop() -{ - struct QuitCallback : public CallbackMessage - { - QuitCallback() {} - - void messageCallback() override - { - android.activity.callVoidMethod (JuceAppActivity.finish); - } - }; - - (new QuitCallback())->post(); - quitMessagePosted = true; -} - -} // namespace juce diff --git a/source/modules/juce_events/native/juce_ios_MessageManager.mm b/source/modules/juce_events/native/juce_ios_MessageManager.mm deleted file mode 100644 index 47aed5f49..000000000 --- a/source/modules/juce_events/native/juce_ios_MessageManager.mm +++ /dev/null @@ -1,103 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -void MessageManager::runDispatchLoop() -{ - jassert (isThisTheMessageThread()); // must only be called by the message thread - - while (! quitMessagePosted) - { - JUCE_AUTORELEASEPOOL - { - [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode - beforeDate: [NSDate dateWithTimeIntervalSinceNow: 0.001]]; - } - } -} - -void MessageManager::stopDispatchLoop() -{ - if (! SystemStats::isRunningInAppExtensionSandbox()) - [[[UIApplication sharedApplication] delegate] applicationWillTerminate: [UIApplication sharedApplication]]; - - exit (0); // iOS apps get no mercy.. -} - -#if JUCE_MODAL_LOOPS_PERMITTED -bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) -{ - JUCE_AUTORELEASEPOOL - { - jassert (isThisTheMessageThread()); // must only be called by the message thread - - uint32 startTime = Time::getMillisecondCounter(); - NSDate* endDate = [NSDate dateWithTimeIntervalSinceNow: millisecondsToRunFor * 0.001]; - - while (! quitMessagePosted) - { - JUCE_AUTORELEASEPOOL - { - [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode - beforeDate: endDate]; - - if (millisecondsToRunFor >= 0 - && Time::getMillisecondCounter() >= startTime + (uint32) millisecondsToRunFor) - break; - } - } - - return ! quitMessagePosted; - } -} -#endif - -//============================================================================== -static ScopedPointer messageQueue; - -void MessageManager::doPlatformSpecificInitialisation() -{ - if (messageQueue == nullptr) - messageQueue = new MessageQueue(); -} - -void MessageManager::doPlatformSpecificShutdown() -{ - messageQueue = nullptr; -} - -bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message) -{ - if (messageQueue != nullptr) - messageQueue->post (message); - - return true; -} - -void MessageManager::broadcastMessage (const String&) -{ - // N/A on current iOS -} - -} // namespace juce diff --git a/source/modules/juce_events/native/juce_linux_EventLoop.h b/source/modules/juce_events/native/juce_linux_EventLoop.h deleted file mode 100644 index ce99bd7ff..000000000 --- a/source/modules/juce_events/native/juce_linux_EventLoop.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -namespace LinuxEventLoop -{ - struct CallbackFunctionBase - { - virtual ~CallbackFunctionBase() {} - virtual bool operator()(int fd) = 0; - bool active = true; - }; - - template - struct CallbackFunction : public CallbackFunctionBase - { - FdCallbackFunction callback; - - CallbackFunction (FdCallbackFunction c) : callback (c) {} - - bool operator() (int fd) override { return callback (fd); } - }; - - template - void setWindowSystemFd (int fd, FdCallbackFunction readCallback) - { - setWindowSystemFdInternal (fd, new CallbackFunction (readCallback)); - } - void removeWindowSystemFd() noexcept; - - void setWindowSystemFdInternal (int fd, CallbackFunctionBase* readCallback) noexcept; -} - -} // namespace juce diff --git a/source/modules/juce_events/native/juce_linux_Messaging.cpp b/source/modules/juce_events/native/juce_linux_Messaging.cpp deleted file mode 100644 index 35cf97aef..000000000 --- a/source/modules/juce_events/native/juce_linux_Messaging.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -#include - -enum FdType -{ - INTERNAL_QUEUE_FD, - WINDOW_SYSTEM_FD, - FD_COUNT, -}; - -namespace juce -{ - -//============================================================================== -class InternalMessageQueue -{ -public: - InternalMessageQueue() - { - auto ret = ::socketpair (AF_LOCAL, SOCK_STREAM, 0, fd); - ignoreUnused (ret); jassert (ret == 0); - - auto internalQueueCb = [this] (int _fd) - { - if (const MessageManager::MessageBase::Ptr msg = this->popNextMessage (_fd)) - { - JUCE_TRY - { - msg->messageCallback(); - return true; - } - JUCE_CATCH_EXCEPTION - } - return false; - }; - - pfds[INTERNAL_QUEUE_FD].fd = getReadHandle(); - pfds[INTERNAL_QUEUE_FD].events = POLLIN; - readCallback[INTERNAL_QUEUE_FD] = new LinuxEventLoop::CallbackFunction (internalQueueCb); - } - - ~InternalMessageQueue() - { - close (getReadHandle()); - close (getWriteHandle()); - - clearSingletonInstance(); - } - - //============================================================================== - void postMessage (MessageManager::MessageBase* const msg) noexcept - { - ScopedLock sl (lock); - queue.add (msg); - - const int maxBytesInSocketQueue = 128; - - if (bytesInSocket < maxBytesInSocketQueue) - { - bytesInSocket++; - - ScopedUnlock ul (lock); - const unsigned char x = 0xff; - ssize_t bytesWritten = write (getWriteHandle(), &x, 1); - ignoreUnused (bytesWritten); - } - } - - void setWindowSystemFd (int _fd, LinuxEventLoop::CallbackFunctionBase* _readCallback) - { - jassert (fdCount == 1); - - ScopedLock sl (lock); - - fdCount = 2; - pfds[WINDOW_SYSTEM_FD].fd = _fd; - pfds[WINDOW_SYSTEM_FD].events = POLLIN; - readCallback[WINDOW_SYSTEM_FD] = _readCallback; - readCallback[WINDOW_SYSTEM_FD]->active = true; - } - - void removeWindowSystemFd() - { - jassert (fdCount == FD_COUNT); - - ScopedLock sl (lock); - - fdCount = 1; - readCallback[WINDOW_SYSTEM_FD]->active = false; - } - - bool dispatchNextEvent() noexcept - { - for (int counter = 0; counter < fdCount; counter++) - { - const int i = loopCount++; - loopCount %= fdCount; - - if (readCallback[i] != nullptr && readCallback[i]->active) - if ((*readCallback[i]) (pfds[i].fd)) - return true; - } - - return false; - } - - bool sleepUntilEvent (const int timeoutMs) - { - const int pnum = poll (pfds, static_cast (fdCount), timeoutMs); - return (pnum > 0); - } - - //============================================================================== - juce_DeclareSingleton_SingleThreaded_Minimal (InternalMessageQueue) - -private: - CriticalSection lock; - ReferenceCountedArray queue; - int fd[2]; - pollfd pfds[FD_COUNT]; - ScopedPointer readCallback[FD_COUNT]; - int fdCount = 1; - int loopCount = 0; - int bytesInSocket = 0; - - int getWriteHandle() const noexcept { return fd[0]; } - int getReadHandle() const noexcept { return fd[1]; } - - MessageManager::MessageBase::Ptr popNextMessage (int _fd) noexcept - { - const ScopedLock sl (lock); - - if (bytesInSocket > 0) - { - --bytesInSocket; - - const ScopedUnlock ul (lock); - unsigned char x; - ssize_t numBytes = read (_fd, &x, 1); - ignoreUnused (numBytes); - } - - return queue.removeAndReturn (0); - } -}; - -juce_ImplementSingleton_SingleThreaded (InternalMessageQueue) - - -//============================================================================== -namespace LinuxErrorHandling -{ - static bool keyboardBreakOccurred = false; - - //============================================================================== - void keyboardBreakSignalHandler (int sig) - { - if (sig == SIGINT) - keyboardBreakOccurred = true; - } - - void installKeyboardBreakHandler() - { - struct sigaction saction; - sigset_t maskSet; - sigemptyset (&maskSet); - saction.sa_handler = keyboardBreakSignalHandler; - saction.sa_mask = maskSet; - saction.sa_flags = 0; - sigaction (SIGINT, &saction, 0); - } -} - -//============================================================================== -void MessageManager::doPlatformSpecificInitialisation() -{ - if (JUCEApplicationBase::isStandaloneApp()) - LinuxErrorHandling::installKeyboardBreakHandler(); - - // Create the internal message queue - auto* queue = InternalMessageQueue::getInstance(); - ignoreUnused (queue); -} - -void MessageManager::doPlatformSpecificShutdown() -{ - InternalMessageQueue::deleteInstance(); -} - -bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message) -{ - if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) - { - queue->postMessage (message); - return true; - } - - return false; -} - -void MessageManager::broadcastMessage (const String&) -{ - // TODO -} - -// this function expects that it will NEVER be called simultaneously for two concurrent threads -bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages) -{ - for (;;) - { - if (LinuxErrorHandling::keyboardBreakOccurred) - JUCEApplicationBase::getInstance()->quit(); - - if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) - { - if (queue->dispatchNextEvent()) - break; - - if (returnIfNoPendingMessages) - return false; - - // wait for 2000ms for next events if necessary - queue->sleepUntilEvent (2000); - } - } - - return true; -} - -//============================================================================== -void LinuxEventLoop::setWindowSystemFdInternal (int fd, LinuxEventLoop::CallbackFunctionBase* readCallback) noexcept -{ - if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) - queue->setWindowSystemFd (fd, readCallback); -} - -void LinuxEventLoop::removeWindowSystemFd() noexcept -{ - if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) - queue->removeWindowSystemFd(); -} - - -} // namespace juce diff --git a/source/modules/juce_events/native/juce_mac_MessageManager.mm b/source/modules/juce_events/native/juce_mac_MessageManager.mm deleted file mode 100644 index 27456e63a..000000000 --- a/source/modules/juce_events/native/juce_mac_MessageManager.mm +++ /dev/null @@ -1,430 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -typedef void (*AppFocusChangeCallback)(); -AppFocusChangeCallback appFocusChangeCallback = nullptr; - -typedef bool (*CheckEventBlockedByModalComps) (NSEvent*); -CheckEventBlockedByModalComps isEventBlockedByModalComps = nullptr; - -typedef void (*MenuTrackingChangedCallback)(bool); -MenuTrackingChangedCallback menuTrackingChangedCallback = nullptr; - -//============================================================================== -struct AppDelegate -{ -public: - AppDelegate() - { - static AppDelegateClass cls; - delegate = [cls.createInstance() init]; - - NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; - - [center addObserver: delegate selector: @selector (mainMenuTrackingBegan:) - name: NSMenuDidBeginTrackingNotification object: nil]; - [center addObserver: delegate selector: @selector (mainMenuTrackingEnded:) - name: NSMenuDidEndTrackingNotification object: nil]; - - if (JUCEApplicationBase::isStandaloneApp()) - { - [NSApp setDelegate: delegate]; - - [[NSDistributedNotificationCenter defaultCenter] addObserver: delegate - selector: @selector (broadcastMessageCallback:) - name: getBroadcastEventName() - object: nil - suspensionBehavior: NSNotificationSuspensionBehaviorDeliverImmediately]; - } - else - { - [center addObserver: delegate selector: @selector (applicationDidResignActive:) - name: NSApplicationDidResignActiveNotification object: NSApp]; - - [center addObserver: delegate selector: @selector (applicationDidBecomeActive:) - name: NSApplicationDidBecomeActiveNotification object: NSApp]; - - [center addObserver: delegate selector: @selector (applicationWillUnhide:) - name: NSApplicationWillUnhideNotification object: NSApp]; - } - } - - ~AppDelegate() - { - [[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: delegate]; - [[NSNotificationCenter defaultCenter] removeObserver: delegate]; - - if (JUCEApplicationBase::isStandaloneApp()) - { - [NSApp setDelegate: nil]; - - [[NSDistributedNotificationCenter defaultCenter] removeObserver: delegate - name: getBroadcastEventName() - object: nil]; - } - - [delegate release]; - } - - static NSString* getBroadcastEventName() - { - return juceStringToNS ("juce_" + String::toHexString (File::getSpecialLocation (File::currentExecutableFile).hashCode64())); - } - - MessageQueue messageQueue; - id delegate; - -private: - //============================================================================== - struct AppDelegateClass : public ObjCClass - { - AppDelegateClass() : ObjCClass ("JUCEAppDelegate_") - { - addMethod (@selector (applicationWillFinishLaunching:), applicationWillFinishLaunching, "v@:@@"); - addMethod (@selector (getUrl:withReplyEvent:), getUrl_withReplyEvent, "v@:@@"); - addMethod (@selector (applicationShouldTerminate:), applicationShouldTerminate, "I@:@"); - addMethod (@selector (applicationWillTerminate:), applicationWillTerminate, "v@:@"); - addMethod (@selector (application:openFile:), application_openFile, "c@:@@"); - addMethod (@selector (application:openFiles:), application_openFiles, "v@:@@"); - addMethod (@selector (applicationDidBecomeActive:), applicationDidBecomeActive, "v@:@"); - addMethod (@selector (applicationDidResignActive:), applicationDidResignActive, "v@:@"); - addMethod (@selector (applicationWillUnhide:), applicationWillUnhide, "v@:@"); - addMethod (@selector (broadcastMessageCallback:), broadcastMessageCallback, "v@:@"); - addMethod (@selector (mainMenuTrackingBegan:), mainMenuTrackingBegan, "v@:@"); - addMethod (@selector (mainMenuTrackingEnded:), mainMenuTrackingEnded, "v@:@"); - addMethod (@selector (dummyMethod), dummyMethod, "v@:"); - - registerClass(); - } - - private: - static void applicationWillFinishLaunching (id self, SEL, NSApplication*, NSNotification*) - { - [[NSAppleEventManager sharedAppleEventManager] setEventHandler: self - andSelector: @selector (getUrl:withReplyEvent:) - forEventClass: kInternetEventClass - andEventID: kAEGetURL]; - } - - static NSApplicationTerminateReply applicationShouldTerminate (id /*self*/, SEL, NSApplication*) - { - if (auto* app = JUCEApplicationBase::getInstance()) - { - app->systemRequestedQuit(); - - if (! MessageManager::getInstance()->hasStopMessageBeenSent()) - return NSTerminateCancel; - } - - return NSTerminateNow; - } - - static void applicationWillTerminate (id /*self*/, SEL, NSNotification*) - { - JUCEApplicationBase::appWillTerminateByForce(); - } - - static BOOL application_openFile (id /*self*/, SEL, NSApplication*, NSString* filename) - { - if (auto* app = JUCEApplicationBase::getInstance()) - { - app->anotherInstanceStarted (quotedIfContainsSpaces (filename)); - return YES; - } - - return NO; - } - - static void application_openFiles (id /*self*/, SEL, NSApplication*, NSArray* filenames) - { - if (auto* app = JUCEApplicationBase::getInstance()) - { - StringArray files; - - for (NSString* f in filenames) - files.add (quotedIfContainsSpaces (f)); - - if (files.size() > 0) - app->anotherInstanceStarted (files.joinIntoString (" ")); - } - } - - static void applicationDidBecomeActive (id /*self*/, SEL, NSNotification*) { focusChanged(); } - static void applicationDidResignActive (id /*self*/, SEL, NSNotification*) { focusChanged(); } - static void applicationWillUnhide (id /*self*/, SEL, NSNotification*) { focusChanged(); } - - static void broadcastMessageCallback (id /*self*/, SEL, NSNotification* n) - { - NSDictionary* dict = (NSDictionary*) [n userInfo]; - const String messageString (nsStringToJuce ((NSString*) [dict valueForKey: nsStringLiteral ("message")])); - MessageManager::getInstance()->deliverBroadcastMessage (messageString); - } - - static void mainMenuTrackingBegan (id /*self*/, SEL, NSNotification*) - { - if (menuTrackingChangedCallback != nullptr) - (*menuTrackingChangedCallback) (true); - } - - static void mainMenuTrackingEnded (id /*self*/, SEL, NSNotification*) - { - if (menuTrackingChangedCallback != nullptr) - (*menuTrackingChangedCallback) (false); - } - - static void dummyMethod (id /*self*/, SEL) {} // (used as a way of running a dummy thread) - - static void focusChanged() - { - if (appFocusChangeCallback != nullptr) - (*appFocusChangeCallback)(); - } - - static void getUrl_withReplyEvent (id /*self*/, SEL, NSAppleEventDescriptor* event, NSAppleEventDescriptor*) - { - if (auto* app = JUCEApplicationBase::getInstance()) - app->anotherInstanceStarted (quotedIfContainsSpaces ([[event paramDescriptorForKeyword: keyDirectObject] stringValue])); - } - - static String quotedIfContainsSpaces (NSString* file) - { - String s (nsStringToJuce (file)); - if (s.containsChar (' ')) - s = s.quoted ('"'); - - return s; - } - }; -}; - -//============================================================================== -void MessageManager::runDispatchLoop() -{ - if (! quitMessagePosted) // check that the quit message wasn't already posted.. - { - JUCE_AUTORELEASEPOOL - { - // must only be called by the message thread! - jassert (isThisTheMessageThread()); - - #if JUCE_PROJUCER_LIVE_BUILD - runDispatchLoopUntil (std::numeric_limits::max()); - #else - #if JUCE_CATCH_UNHANDLED_EXCEPTIONS - @try - { - [NSApp run]; - } - @catch (NSException* e) - { - // An AppKit exception will kill the app, but at least this provides a chance to log it., - std::runtime_error ex (std::string ("NSException: ") + [[e name] UTF8String] + ", Reason:" + [[e reason] UTF8String]); - JUCEApplicationBase::sendUnhandledException (&ex, __FILE__, __LINE__); - } - @finally - { - } - #else - [NSApp run]; - #endif - #endif - } - } -} - -static void shutdownNSApp() -{ - [NSApp stop: nil]; - [NSEvent startPeriodicEventsAfterDelay: 0 withPeriod: 0.1]; -} - -void MessageManager::stopDispatchLoop() -{ - #if JUCE_PROJUCER_LIVE_BUILD - quitMessagePosted = true; - #else - - if (isThisTheMessageThread()) - { - quitMessagePosted = true; - shutdownNSApp(); - } - else - { - struct QuitCallback : public CallbackMessage - { - QuitCallback() {} - void messageCallback() override { MessageManager::getInstance()->stopDispatchLoop(); } - }; - - (new QuitCallback())->post(); - } - #endif -} - -#if JUCE_MODAL_LOOPS_PERMITTED -bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) -{ - jassert (millisecondsToRunFor >= 0); - jassert (isThisTheMessageThread()); // must only be called by the message thread - - uint32 endTime = Time::getMillisecondCounter() + (uint32) millisecondsToRunFor; - - while (! quitMessagePosted) - { - JUCE_AUTORELEASEPOOL - { - CFRunLoopRunInMode (kCFRunLoopDefaultMode, 0.001, true); - - NSEvent* e = [NSApp nextEventMatchingMask: NSEventMaskAny - untilDate: [NSDate dateWithTimeIntervalSinceNow: 0.001] - inMode: NSDefaultRunLoopMode - dequeue: YES]; - - if (e != nil && (isEventBlockedByModalComps == nullptr || ! (*isEventBlockedByModalComps) (e))) - [NSApp sendEvent: e]; - - if (Time::getMillisecondCounter() >= endTime) - break; - } - } - - return ! quitMessagePosted; -} -#endif - -//============================================================================== -void initialiseNSApplication(); -void initialiseNSApplication() -{ - JUCE_AUTORELEASEPOOL - { - [NSApplication sharedApplication]; - } -} - -static AppDelegate* appDelegate = nullptr; - -void MessageManager::doPlatformSpecificInitialisation() -{ - if (appDelegate == nil) - appDelegate = new AppDelegate(); -} - -void MessageManager::doPlatformSpecificShutdown() -{ - delete appDelegate; - appDelegate = nullptr; -} - -bool MessageManager::postMessageToSystemQueue (MessageBase* message) -{ - jassert (appDelegate != nil); - appDelegate->messageQueue.post (message); - return true; -} - -void MessageManager::broadcastMessage (const String& message) -{ - NSDictionary* info = [NSDictionary dictionaryWithObject: juceStringToNS (message) - forKey: nsStringLiteral ("message")]; - - [[NSDistributedNotificationCenter defaultCenter] postNotificationName: AppDelegate::getBroadcastEventName() - object: nil - userInfo: info]; -} - -// Special function used by some plugin classes to re-post carbon events -void __attribute__ ((visibility("default"))) repostCurrentNSEvent(); -void __attribute__ ((visibility("default"))) repostCurrentNSEvent() -{ - struct EventReposter : public CallbackMessage - { - EventReposter() : e ([[NSApp currentEvent] retain]) {} - ~EventReposter() { [e release]; } - - void messageCallback() override - { - [NSApp postEvent: e atStart: YES]; - } - - NSEvent* e; - }; - - (new EventReposter())->post(); -} - - -//============================================================================== -#if JUCE_MAC -struct MountedVolumeListChangeDetector::Pimpl -{ - Pimpl (MountedVolumeListChangeDetector& d) : owner (d) - { - static ObserverClass cls; - delegate = [cls.createInstance() init]; - ObserverClass::setOwner (delegate, this); - - NSNotificationCenter* nc = [[NSWorkspace sharedWorkspace] notificationCenter]; - - [nc addObserver: delegate selector: @selector (changed:) name: NSWorkspaceDidMountNotification object: nil]; - [nc addObserver: delegate selector: @selector (changed:) name: NSWorkspaceDidUnmountNotification object: nil]; - } - - ~Pimpl() - { - [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver: delegate]; - [delegate release]; - } - -private: - MountedVolumeListChangeDetector& owner; - id delegate; - - struct ObserverClass : public ObjCClass - { - ObserverClass() : ObjCClass ("JUCEDriveObserver_") - { - addIvar ("owner"); - addMethod (@selector (changed:), changed, "v@:@"); - addProtocol (@protocol (NSTextInput)); - registerClass(); - } - - static Pimpl* getOwner (id self) { return getIvar (self, "owner"); } - static void setOwner (id self, Pimpl* owner) { object_setInstanceVariable (self, "owner", owner); } - - static void changed (id self, SEL, NSNotification*) - { - getOwner (self)->owner.mountedVolumeListChanged(); - } - }; -}; - -MountedVolumeListChangeDetector::MountedVolumeListChangeDetector() { pimpl = new Pimpl (*this); } -MountedVolumeListChangeDetector::~MountedVolumeListChangeDetector() {} -#endif - -} // namespace juce diff --git a/source/modules/juce_events/native/juce_osx_MessageQueue.h b/source/modules/juce_events/native/juce_osx_MessageQueue.h deleted file mode 100644 index 32f24fde7..000000000 --- a/source/modules/juce_events/native/juce_osx_MessageQueue.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/* An internal message pump class used in OSX and iOS. */ -class MessageQueue -{ -public: - MessageQueue() - { - #if JUCE_IOS - runLoop = CFRunLoopGetCurrent(); - #else - runLoop = CFRunLoopGetMain(); - #endif - - CFRunLoopSourceContext sourceContext; - zerostruct (sourceContext); // (can't use "= { 0 }" on this object because it's typedef'ed as a C struct) - sourceContext.info = this; - sourceContext.perform = runLoopSourceCallback; - runLoopSource = CFRunLoopSourceCreate (kCFAllocatorDefault, 1, &sourceContext); - CFRunLoopAddSource (runLoop, runLoopSource, kCFRunLoopCommonModes); - } - - ~MessageQueue() noexcept - { - CFRunLoopRemoveSource (runLoop, runLoopSource, kCFRunLoopCommonModes); - CFRunLoopSourceInvalidate (runLoopSource); - CFRelease (runLoopSource); - } - - void post (MessageManager::MessageBase* const message) - { - messages.add (message); - wakeUp(); - } - -private: - ReferenceCountedArray messages; - CFRunLoopRef runLoop; - CFRunLoopSourceRef runLoopSource; - - void wakeUp() noexcept - { - CFRunLoopSourceSignal (runLoopSource); - CFRunLoopWakeUp (runLoop); - } - - bool deliverNextMessage() - { - const MessageManager::MessageBase::Ptr nextMessage (messages.removeAndReturn (0)); - - if (nextMessage == nullptr) - return false; - - JUCE_AUTORELEASEPOOL - { - JUCE_TRY - { - nextMessage->messageCallback(); - } - JUCE_CATCH_EXCEPTION - } - - return true; - } - - void runLoopCallback() noexcept - { - for (int i = 4; --i >= 0;) - if (! deliverNextMessage()) - return; - - wakeUp(); - } - - static void runLoopSourceCallback (void* info) noexcept - { - static_cast (info)->runLoopCallback(); - } -}; - -} // namespace juce diff --git a/source/modules/juce_events/native/juce_win32_HiddenMessageWindow.h b/source/modules/juce_events/native/juce_win32_HiddenMessageWindow.h deleted file mode 100644 index 9135d99bd..000000000 --- a/source/modules/juce_events/native/juce_win32_HiddenMessageWindow.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -class HiddenMessageWindow -{ -public: - HiddenMessageWindow (const TCHAR* const messageWindowName, WNDPROC wndProc) - { - String className ("JUCE_"); - className << String::toHexString (Time::getHighResolutionTicks()); - - HMODULE moduleHandle = (HMODULE) Process::getCurrentModuleInstanceHandle(); - - WNDCLASSEX wc = { 0 }; - wc.cbSize = sizeof (wc); - wc.lpfnWndProc = wndProc; - wc.cbWndExtra = 4; - wc.hInstance = moduleHandle; - wc.lpszClassName = className.toWideCharPointer(); - - atom = RegisterClassEx (&wc); - jassert (atom != 0); - - hwnd = CreateWindow (getClassNameFromAtom(), messageWindowName, - 0, 0, 0, 0, 0, 0, 0, moduleHandle, 0); - jassert (hwnd != 0); - } - - ~HiddenMessageWindow() - { - DestroyWindow (hwnd); - UnregisterClass (getClassNameFromAtom(), 0); - } - - inline HWND getHWND() const noexcept { return hwnd; } - -private: - ATOM atom; - HWND hwnd; - - LPCTSTR getClassNameFromAtom() noexcept { return (LPCTSTR) (pointer_sized_uint) atom; } -}; - -//============================================================================== -class JuceWindowIdentifier -{ -public: - static bool isJUCEWindow (HWND hwnd) noexcept - { - return GetWindowLongPtr (hwnd, GWLP_USERDATA) == getImprobableWindowNumber(); - } - - static void setAsJUCEWindow (HWND hwnd, bool isJuceWindow) noexcept - { - SetWindowLongPtr (hwnd, GWLP_USERDATA, isJuceWindow ? getImprobableWindowNumber() : 0); - } - -private: - static LONG_PTR getImprobableWindowNumber() noexcept - { - static auto number = (LONG_PTR) Random().nextInt64(); - return number; - } -}; - -//============================================================================== -class DeviceChangeDetector : private Timer -{ -public: - DeviceChangeDetector (const wchar_t* const name) - : messageWindow (name, (WNDPROC) deviceChangeEventCallback) - { - SetWindowLongPtr (messageWindow.getHWND(), GWLP_USERDATA, (LONG_PTR) this); - } - - virtual ~DeviceChangeDetector() {} - - virtual void systemDeviceChanged() = 0; - - void triggerAsyncDeviceChangeCallback() - { - // We'll pause before sending a message, because on device removal, the OS hasn't always updated - // its device lists correctly at this point. This also helps avoid repeated callbacks. - startTimer (500); - } - -private: - HiddenMessageWindow messageWindow; - - static LRESULT CALLBACK deviceChangeEventCallback (HWND h, const UINT message, - const WPARAM wParam, const LPARAM lParam) - { - if (message == WM_DEVICECHANGE - && (wParam == 0x8000 /*DBT_DEVICEARRIVAL*/ - || wParam == 0x8004 /*DBT_DEVICEREMOVECOMPLETE*/ - || wParam == 0x0007 /*DBT_DEVNODES_CHANGED*/)) - { - ((DeviceChangeDetector*) GetWindowLongPtr (h, GWLP_USERDATA)) - ->triggerAsyncDeviceChangeCallback(); - } - - return DefWindowProc (h, message, wParam, lParam); - } - - void timerCallback() override - { - stopTimer(); - systemDeviceChanged(); - } -}; - -} // namespace juce diff --git a/source/modules/juce_events/native/juce_win32_Messaging.cpp b/source/modules/juce_events/native/juce_win32_Messaging.cpp deleted file mode 100644 index 38b636aae..000000000 --- a/source/modules/juce_events/native/juce_win32_Messaging.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -extern HWND juce_messageWindowHandle; - -typedef bool (*CheckEventBlockedByModalComps) (const MSG&); -CheckEventBlockedByModalComps isEventBlockedByModalComps = nullptr; - -//============================================================================== -namespace WindowsMessageHelpers -{ - const unsigned int customMessageID = WM_USER + 123; - const unsigned int broadcastMessageMagicNumber = 0xc403; - - const TCHAR messageWindowName[] = _T("JUCEWindow"); - ScopedPointer messageWindow; - - void dispatchMessageFromLParam (LPARAM lParam) - { - if (MessageManager::MessageBase* message = reinterpret_cast (lParam)) - { - JUCE_TRY - { - message->messageCallback(); - } - JUCE_CATCH_EXCEPTION - - message->decReferenceCount(); - } - } - - BOOL CALLBACK broadcastEnumWindowProc (HWND hwnd, LPARAM lParam) - { - if (hwnd != juce_messageWindowHandle) - { - TCHAR windowName[64] = { 0 }; // no need to read longer strings than this - GetWindowText (hwnd, windowName, 63); - - if (String (windowName) == messageWindowName) - reinterpret_cast*> (lParam)->add (hwnd); - } - - return TRUE; - } - - void handleBroadcastMessage (const COPYDATASTRUCT* const data) - { - if (data != nullptr && data->dwData == broadcastMessageMagicNumber) - { - struct BroadcastMessage : public CallbackMessage - { - BroadcastMessage (CharPointer_UTF32 text, size_t length) : message (text, length) {} - void messageCallback() override { MessageManager::getInstance()->deliverBroadcastMessage (message); } - - String message; - }; - - (new BroadcastMessage (CharPointer_UTF32 ((const CharPointer_UTF32::CharType*) data->lpData), - data->cbData / sizeof (CharPointer_UTF32::CharType))) - ->post(); - } - } - - //============================================================================== - LRESULT CALLBACK messageWndProc (HWND h, const UINT message, const WPARAM wParam, const LPARAM lParam) noexcept - { - if (h == juce_messageWindowHandle) - { - if (message == customMessageID) - { - // (These are trapped early in our dispatch loop, but must also be checked - // here in case some 3rd-party code is running the dispatch loop). - dispatchMessageFromLParam (lParam); - return 0; - } - - if (message == WM_COPYDATA) - { - handleBroadcastMessage (reinterpret_cast (lParam)); - return 0; - } - } - - return DefWindowProc (h, message, wParam, lParam); - } -} - -#if JUCE_MODULE_AVAILABLE_juce_gui_extra && ! JUCE_MINGW -LRESULT juce_offerEventToActiveXControl (::MSG&); -#endif - -//============================================================================== -bool MessageManager::dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages) -{ - using namespace WindowsMessageHelpers; - MSG m; - - if (returnIfNoPendingMessages && ! PeekMessage (&m, (HWND) 0, 0, 0, PM_NOREMOVE)) - return false; - - if (GetMessage (&m, (HWND) 0, 0, 0) >= 0) - { - #if JUCE_MODULE_AVAILABLE_juce_gui_extra && ! JUCE_MINGW - if (juce_offerEventToActiveXControl (m) != S_FALSE) - return true; - #endif - - if (m.message == customMessageID && m.hwnd == juce_messageWindowHandle) - { - dispatchMessageFromLParam (m.lParam); - } - else if (m.message == WM_QUIT) - { - if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance()) - app->systemRequestedQuit(); - } - else if (isEventBlockedByModalComps == nullptr || ! isEventBlockedByModalComps (m)) - { - if ((m.message == WM_LBUTTONDOWN || m.message == WM_RBUTTONDOWN) - && ! JuceWindowIdentifier::isJUCEWindow (m.hwnd)) - { - // if it's someone else's window being clicked on, and the focus is - // currently on a juce window, pass the kb focus over.. - HWND currentFocus = GetFocus(); - - if (currentFocus == 0 || JuceWindowIdentifier::isJUCEWindow (currentFocus)) - SetFocus (m.hwnd); - } - - TranslateMessage (&m); - DispatchMessage (&m); - } - } - - return true; -} - -bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message) -{ - message->incReferenceCount(); - return PostMessage (juce_messageWindowHandle, WindowsMessageHelpers::customMessageID, 0, (LPARAM) message) != 0; -} - -void MessageManager::broadcastMessage (const String& value) -{ - const String localCopy (value); - - Array windows; - EnumWindows (&WindowsMessageHelpers::broadcastEnumWindowProc, (LPARAM) &windows); - - for (int i = windows.size(); --i >= 0;) - { - COPYDATASTRUCT data; - data.dwData = WindowsMessageHelpers::broadcastMessageMagicNumber; - data.cbData = (localCopy.length() + 1) * sizeof (CharPointer_UTF32::CharType); - data.lpData = (void*) localCopy.toUTF32().getAddress(); - - DWORD_PTR result; - SendMessageTimeout (windows.getUnchecked (i), WM_COPYDATA, - (WPARAM) juce_messageWindowHandle, - (LPARAM) &data, - SMTO_BLOCK | SMTO_ABORTIFHUNG, 8000, &result); - } -} - -//============================================================================== -void MessageManager::doPlatformSpecificInitialisation() -{ - OleInitialize (0); - - using namespace WindowsMessageHelpers; - messageWindow = new HiddenMessageWindow (messageWindowName, (WNDPROC) messageWndProc); - juce_messageWindowHandle = messageWindow->getHWND(); -} - -void MessageManager::doPlatformSpecificShutdown() -{ - WindowsMessageHelpers::messageWindow = nullptr; - - OleUninitialize(); -} - -//============================================================================== -struct MountedVolumeListChangeDetector::Pimpl : private DeviceChangeDetector -{ - Pimpl (MountedVolumeListChangeDetector& d) : DeviceChangeDetector (L"MountedVolumeList"), owner (d) - { - File::findFileSystemRoots (lastVolumeList); - } - - void systemDeviceChanged() override - { - Array newList; - File::findFileSystemRoots (newList); - - if (lastVolumeList != newList) - { - lastVolumeList = newList; - owner.mountedVolumeListChanged(); - } - } - - MountedVolumeListChangeDetector& owner; - Array lastVolumeList; -}; - -MountedVolumeListChangeDetector::MountedVolumeListChangeDetector() { pimpl = new Pimpl (*this); } -MountedVolumeListChangeDetector::~MountedVolumeListChangeDetector() {} - -} // namespace juce diff --git a/source/modules/juce_events/native/juce_win32_WinRTWrapper.cpp b/source/modules/juce_events/native/juce_win32_WinRTWrapper.cpp deleted file mode 100644 index e8d848da4..000000000 --- a/source/modules/juce_events/native/juce_win32_WinRTWrapper.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - juce_ImplementSingleton (WinRTWrapper) -} diff --git a/source/modules/juce_events/native/juce_win32_WinRTWrapper.h b/source/modules/juce_events/native/juce_win32_WinRTWrapper.h deleted file mode 100644 index 4a48e0428..000000000 --- a/source/modules/juce_events/native/juce_win32_WinRTWrapper.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -class WinRTWrapper : public DeletedAtShutdown -{ -public: - juce_DeclareSingleton (WinRTWrapper, true) - - class ScopedHString - { - public: - ScopedHString (String str) - { - if (WinRTWrapper::getInstance()->isInitialised()) - WinRTWrapper::getInstance()->createHString (str.toWideCharPointer(), - static_cast (str.length()), - &hstr); - } - - ~ScopedHString() - { - if (WinRTWrapper::getInstance()->isInitialised() && hstr != nullptr) - WinRTWrapper::getInstance()->deleteHString (hstr); - } - - HSTRING get() const noexcept - { - return hstr; - } - - private: - HSTRING hstr = nullptr; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ScopedHString) - }; - - ~WinRTWrapper() - { - if (winRTHandle != nullptr) - ::FreeLibrary (winRTHandle); - } - - String hStringToString (HSTRING hstr) - { - if (isInitialised()) - if (const wchar_t* str = getHStringRawBuffer (hstr, nullptr)) - return String (str); - - return {}; - } - - bool isInitialised() const noexcept - { - return initialised; - } - - template - ComSmartPtr getWRLFactory (const wchar_t* runtimeClassID) - { - ComSmartPtr comPtr; - - if (isInitialised()) - { - ScopedHString classID (runtimeClassID); - if (classID.get() != nullptr) - roGetActivationFactory (classID.get(), __uuidof (ComClass), (void**) comPtr.resetAndGetPointerAddress()); - } - - return comPtr; - } - -private: - WinRTWrapper() - { - winRTHandle = ::LoadLibraryA ("api-ms-win-core-winrt-l1-1-0"); - if (winRTHandle == nullptr) - return; - - roInitialize = (RoInitializeFuncPtr) ::GetProcAddress (winRTHandle, "RoInitialize"); - createHString = (WindowsCreateStringFuncPtr) ::GetProcAddress (winRTHandle, "WindowsCreateString"); - deleteHString = (WindowsDeleteStringFuncPtr) ::GetProcAddress (winRTHandle, "WindowsDeleteString"); - getHStringRawBuffer = (WindowsGetStringRawBufferFuncPtr) ::GetProcAddress (winRTHandle, "WindowsGetStringRawBuffer"); - roGetActivationFactory = (RoGetActivationFactoryFuncPtr) ::GetProcAddress (winRTHandle, "RoGetActivationFactory"); - - if (roInitialize == nullptr || createHString == nullptr || deleteHString == nullptr - || getHStringRawBuffer == nullptr || roGetActivationFactory == nullptr) - return; - - HRESULT status = roInitialize (1); - initialised = ! (status != S_OK && status != S_FALSE && status != 0x80010106L); - } - - HMODULE winRTHandle = nullptr; - bool initialised = false; - - typedef HRESULT (WINAPI* RoInitializeFuncPtr) (int); - typedef HRESULT (WINAPI* WindowsCreateStringFuncPtr) (LPCWSTR, UINT32, HSTRING*); - typedef HRESULT (WINAPI* WindowsDeleteStringFuncPtr) (HSTRING); - typedef PCWSTR (WINAPI* WindowsGetStringRawBufferFuncPtr) (HSTRING, UINT32*); - typedef HRESULT (WINAPI* RoGetActivationFactoryFuncPtr) (HSTRING, REFIID, void**); - - RoInitializeFuncPtr roInitialize = nullptr; - WindowsCreateStringFuncPtr createHString = nullptr; - WindowsDeleteStringFuncPtr deleteHString = nullptr; - WindowsGetStringRawBufferFuncPtr getHStringRawBuffer = nullptr; - RoGetActivationFactoryFuncPtr roGetActivationFactory = nullptr; -}; - -} // namespace juce diff --git a/source/modules/juce_events/timers/juce_MultiTimer.cpp b/source/modules/juce_events/timers/juce_MultiTimer.cpp deleted file mode 100644 index 3f73eb3d7..000000000 --- a/source/modules/juce_events/timers/juce_MultiTimer.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -struct MultiTimerCallback : public Timer -{ - MultiTimerCallback (const int tid, MultiTimer& mt) noexcept - : owner (mt), timerID (tid) - { - } - - void timerCallback() override - { - owner.timerCallback (timerID); - } - - MultiTimer& owner; - const int timerID; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultiTimerCallback) -}; - -//============================================================================== -MultiTimer::MultiTimer() noexcept {} -MultiTimer::MultiTimer (const MultiTimer&) noexcept {} - -MultiTimer::~MultiTimer() -{ - const SpinLock::ScopedLockType sl (timerListLock); - timers.clear(); -} - -//============================================================================== -Timer* MultiTimer::getCallback (int timerID) const noexcept -{ - for (int i = timers.size(); --i >= 0;) - { - MultiTimerCallback* const t = static_cast (timers.getUnchecked(i)); - - if (t->timerID == timerID) - return t; - } - - return nullptr; -} - -void MultiTimer::startTimer (const int timerID, const int intervalInMilliseconds) noexcept -{ - const SpinLock::ScopedLockType sl (timerListLock); - - Timer* timer = getCallback (timerID); - - if (timer == nullptr) - timers.add (timer = new MultiTimerCallback (timerID, *this)); - - timer->startTimer (intervalInMilliseconds); -} - -void MultiTimer::stopTimer (const int timerID) noexcept -{ - const SpinLock::ScopedLockType sl (timerListLock); - - if (Timer* const t = getCallback (timerID)) - t->stopTimer(); -} - -bool MultiTimer::isTimerRunning (const int timerID) const noexcept -{ - const SpinLock::ScopedLockType sl (timerListLock); - - if (Timer* const t = getCallback (timerID)) - return t->isTimerRunning(); - - return false; -} - -int MultiTimer::getTimerInterval (const int timerID) const noexcept -{ - const SpinLock::ScopedLockType sl (timerListLock); - - if (Timer* const t = getCallback (timerID)) - return t->getTimerInterval(); - - return 0; -} - -} // namespace juce diff --git a/source/modules/juce_events/timers/juce_MultiTimer.h b/source/modules/juce_events/timers/juce_MultiTimer.h deleted file mode 100644 index 8921b6844..000000000 --- a/source/modules/juce_events/timers/juce_MultiTimer.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A type of timer class that can run multiple timers with different frequencies, - all of which share a single callback. - - This class is very similar to the Timer class, but allows you run multiple - separate timers, where each one has a unique ID number. The methods in this - class are exactly equivalent to those in Timer, but with the addition of - this ID number. - - To use it, you need to create a subclass of MultiTimer, implementing the - timerCallback() method. Then you can start timers with startTimer(), and - each time the callback is triggered, it passes in the ID of the timer that - caused it. - - @see Timer -*/ -class JUCE_API MultiTimer -{ -protected: - //============================================================================== - /** Creates a MultiTimer. - - When created, no timers are running, so use startTimer() to start things off. - */ - MultiTimer() noexcept; - - /** Creates a copy of another timer. - - Note that this timer will not contain any running timers, even if the one you're - copying from was running. - */ - MultiTimer (const MultiTimer&) noexcept; - -public: - //============================================================================== - /** Destructor. */ - virtual ~MultiTimer(); - - //============================================================================== - /** The user-defined callback routine that actually gets called by each of the - timers that are running. - - It's perfectly ok to call startTimer() or stopTimer() from within this - callback to change the subsequent intervals. - */ - virtual void timerCallback (int timerID) = 0; - - //============================================================================== - /** Starts a timer and sets the length of interval required. - - If the timer is already started, this will reset it, so the - time between calling this method and the next timer callback - will not be less than the interval length passed in. - - @param timerID a unique Id number that identifies the timer to - start. This is the id that will be passed back - to the timerCallback() method when this timer is - triggered - @param intervalInMilliseconds the interval to use (any values less than 1 will be - rounded up to 1) - */ - void startTimer (int timerID, int intervalInMilliseconds) noexcept; - - /** Stops a timer. - - If a timer has been started with the given ID number, it will be cancelled. - No more callbacks will be made for the specified timer after this method returns. - - If this is called from a different thread, any callbacks that may - be currently executing may be allowed to finish before the method - returns. - */ - void stopTimer (int timerID) noexcept; - - //============================================================================== - /** Checks whether a timer has been started for a specified ID. - @returns true if a timer with the given ID is running. - */ - bool isTimerRunning (int timerID) const noexcept; - - /** Returns the interval for a specified timer ID. - @returns the timer's interval in milliseconds if it's running, or 0 if no - timer was running for the ID number specified. - */ - int getTimerInterval (int timerID) const noexcept; - - - //============================================================================== -private: - SpinLock timerListLock; - OwnedArray timers; - - Timer* getCallback (int) const noexcept; - MultiTimer& operator= (const MultiTimer&); -}; - -} // namespace juce diff --git a/source/modules/juce_events/timers/juce_Timer.cpp b/source/modules/juce_events/timers/juce_Timer.cpp deleted file mode 100644 index ae6e48fb5..000000000 --- a/source/modules/juce_events/timers/juce_Timer.cpp +++ /dev/null @@ -1,371 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -class Timer::TimerThread : private Thread, - private DeletedAtShutdown, - private AsyncUpdater -{ -public: - typedef CriticalSection LockType; // (mysteriously, using a SpinLock here causes problems on some XP machines..) - - TimerThread() - : Thread ("Juce Timer"), - firstTimer (nullptr) - { - triggerAsyncUpdate(); - } - - ~TimerThread() noexcept - { - signalThreadShouldExit(); - callbackArrived.signal(); - stopThread (4000); - - jassert (instance == this || instance == nullptr); - if (instance == this) - instance = nullptr; - } - - void run() override - { - uint32 lastTime = Time::getMillisecondCounter(); - MessageManager::MessageBase::Ptr messageToSend (new CallTimersMessage()); - - while (! threadShouldExit()) - { - const uint32 now = Time::getMillisecondCounter(); - - const int elapsed = (int) (now >= lastTime ? (now - lastTime) - : (std::numeric_limits::max() - (lastTime - now))); - lastTime = now; - - const int timeUntilFirstTimer = getTimeUntilFirstTimer (elapsed); - - if (timeUntilFirstTimer <= 0) - { - if (callbackArrived.wait (0)) - { - // already a message in flight - do nothing.. - } - else - { - messageToSend->post(); - - if (! callbackArrived.wait (300)) - { - // Sometimes our message can get discarded by the OS (e.g. when running as an RTAS - // when the app has a modal loop), so this is how long to wait before assuming the - // message has been lost and trying again. - messageToSend->post(); - } - - continue; - } - } - - // don't wait for too long because running this loop also helps keep the - // Time::getApproximateMillisecondTimer value stay up-to-date - wait (jlimit (1, 100, timeUntilFirstTimer)); - } - } - - void callTimers() - { - // avoid getting stuck in a loop if a timer callback repeatedly takes too long - const uint32 timeout = Time::getMillisecondCounter() + 100; - - const LockType::ScopedLockType sl (lock); - - while (firstTimer != nullptr && firstTimer->timerCountdownMs <= 0) - { - Timer* const t = firstTimer; - t->timerCountdownMs = t->timerPeriodMs; - - removeTimer (t); - addTimer (t); - - const LockType::ScopedUnlockType ul (lock); - - JUCE_TRY - { - t->timerCallback(); - } - JUCE_CATCH_EXCEPTION - - if (Time::getMillisecondCounter() > timeout) - break; - } - - callbackArrived.signal(); - } - - void callTimersSynchronously() - { - if (! isThreadRunning()) - { - // (This is relied on by some plugins in cases where the MM has - // had to restart and the async callback never started) - cancelPendingUpdate(); - triggerAsyncUpdate(); - } - - callTimers(); - } - - static inline void add (Timer* const tim) noexcept - { - if (instance == nullptr) - instance = new TimerThread(); - - instance->addTimer (tim); - } - - static inline void remove (Timer* const tim) noexcept - { - if (instance != nullptr) - instance->removeTimer (tim); - } - - static inline void resetCounter (Timer* const tim, const int newCounter) noexcept - { - if (instance != nullptr) - { - tim->timerCountdownMs = newCounter; - tim->timerPeriodMs = newCounter; - - if ((tim->nextTimer != nullptr && tim->nextTimer->timerCountdownMs < tim->timerCountdownMs) - || (tim->previousTimer != nullptr && tim->previousTimer->timerCountdownMs > tim->timerCountdownMs)) - { - instance->removeTimer (tim); - instance->addTimer (tim); - } - } - } - - static TimerThread* instance; - static LockType lock; - -private: - Timer* volatile firstTimer; - WaitableEvent callbackArrived; - - struct CallTimersMessage : public MessageManager::MessageBase - { - CallTimersMessage() {} - - void messageCallback() override - { - if (instance != nullptr) - instance->callTimers(); - } - }; - - //============================================================================== - void addTimer (Timer* const t) noexcept - { - #if JUCE_DEBUG - // trying to add a timer that's already here - shouldn't get to this point, - // so if you get this assertion, let me know! - jassert (! timerExists (t)); - #endif - - Timer* i = firstTimer; - - if (i == nullptr || i->timerCountdownMs > t->timerCountdownMs) - { - t->nextTimer = firstTimer; - firstTimer = t; - } - else - { - while (i->nextTimer != nullptr && i->nextTimer->timerCountdownMs <= t->timerCountdownMs) - i = i->nextTimer; - - jassert (i != nullptr); - - t->nextTimer = i->nextTimer; - t->previousTimer = i; - i->nextTimer = t; - } - - if (t->nextTimer != nullptr) - t->nextTimer->previousTimer = t; - - jassert ((t->nextTimer == nullptr || t->nextTimer->timerCountdownMs >= t->timerCountdownMs) - && (t->previousTimer == nullptr || t->previousTimer->timerCountdownMs <= t->timerCountdownMs)); - - notify(); - } - - void removeTimer (Timer* const t) noexcept - { - #if JUCE_DEBUG - // trying to remove a timer that's not here - shouldn't get to this point, - // so if you get this assertion, let me know! - jassert (timerExists (t)); - #endif - - if (t->previousTimer != nullptr) - { - jassert (firstTimer != t); - t->previousTimer->nextTimer = t->nextTimer; - } - else - { - jassert (firstTimer == t); - firstTimer = t->nextTimer; - } - - if (t->nextTimer != nullptr) - t->nextTimer->previousTimer = t->previousTimer; - - t->nextTimer = nullptr; - t->previousTimer = nullptr; - } - - int getTimeUntilFirstTimer (const int numMillisecsElapsed) const - { - const LockType::ScopedLockType sl (lock); - - for (Timer* t = firstTimer; t != nullptr; t = t->nextTimer) - t->timerCountdownMs -= numMillisecsElapsed; - - return firstTimer != nullptr ? firstTimer->timerCountdownMs : 1000; - } - - void handleAsyncUpdate() override - { - startThread (7); - } - - #if JUCE_DEBUG - bool timerExists (Timer* const t) const noexcept - { - for (Timer* tt = firstTimer; tt != nullptr; tt = tt->nextTimer) - if (tt == t) - return true; - - return false; - } - #endif - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TimerThread) -}; - -Timer::TimerThread* Timer::TimerThread::instance = nullptr; -Timer::TimerThread::LockType Timer::TimerThread::lock; - -//============================================================================== -Timer::Timer() noexcept - : timerCountdownMs (0), - timerPeriodMs (0), - previousTimer (nullptr), - nextTimer (nullptr) -{ -} - -Timer::Timer (const Timer&) noexcept - : timerCountdownMs (0), - timerPeriodMs (0), - previousTimer (nullptr), - nextTimer (nullptr) -{ -} - -Timer::~Timer() -{ - stopTimer(); -} - -void Timer::startTimer (const int interval) noexcept -{ - // If you're calling this before (or after) the MessageManager is - // running, then you're not going to get any timer callbacks! - jassert (MessageManager::getInstanceWithoutCreating() != nullptr); - - const TimerThread::LockType::ScopedLockType sl (TimerThread::lock); - - if (timerPeriodMs == 0) - { - timerCountdownMs = interval; - timerPeriodMs = jmax (1, interval); - TimerThread::add (this); - } - else - { - TimerThread::resetCounter (this, interval); - } -} - -void Timer::startTimerHz (int timerFrequencyHz) noexcept -{ - if (timerFrequencyHz > 0) - startTimer (1000 / timerFrequencyHz); - else - stopTimer(); -} - -void Timer::stopTimer() noexcept -{ - const TimerThread::LockType::ScopedLockType sl (TimerThread::lock); - - if (timerPeriodMs > 0) - { - TimerThread::remove (this); - timerPeriodMs = 0; - } -} - -void JUCE_CALLTYPE Timer::callPendingTimersSynchronously() -{ - if (TimerThread::instance != nullptr) - TimerThread::instance->callTimersSynchronously(); -} - -struct LambdaInvoker : private Timer -{ - LambdaInvoker (int milliseconds, std::function f) : function (f) - { - startTimer (milliseconds); - } - - void timerCallback() override - { - auto f = function; - delete this; - f(); - } - - std::function function; - - JUCE_DECLARE_NON_COPYABLE (LambdaInvoker) -}; - -void JUCE_CALLTYPE Timer::callAfterDelay (int milliseconds, std::function f) -{ - new LambdaInvoker (milliseconds, f); -} - -} // namespace juce diff --git a/source/modules/juce_events/timers/juce_Timer.h b/source/modules/juce_events/timers/juce_Timer.h deleted file mode 100644 index 06bd0bc10..000000000 --- a/source/modules/juce_events/timers/juce_Timer.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Makes repeated callbacks to a virtual method at a specified time interval. - - A Timer's timerCallback() method will be repeatedly called at a given - interval. When you create a Timer object, it will do nothing until the - startTimer() method is called, which will cause the message thread to - start making callbacks at the specified interval, until stopTimer() is called - or the object is deleted. - - The time interval isn't guaranteed to be precise to any more than maybe - 10-20ms, and the intervals may end up being much longer than requested if the - system is busy. Because the callbacks are made by the main message thread, - anything that blocks the message queue for a period of time will also prevent - any timers from running until it can carry on. - - If you need to have a single callback that is shared by multiple timers with - different frequencies, then the MultiTimer class allows you to do that - its - structure is very similar to the Timer class, but contains multiple timers - internally, each one identified by an ID number. - - @see HighResolutionTimer, MultiTimer -*/ -class JUCE_API Timer -{ -protected: - //============================================================================== - /** Creates a Timer. - When created, the timer is stopped, so use startTimer() to get it going. - */ - Timer() noexcept; - - /** Creates a copy of another timer. - - Note that this timer won't be started, even if the one you're copying - is running. - */ - Timer (const Timer&) noexcept; - -public: - //============================================================================== - /** Destructor. */ - virtual ~Timer(); - - //============================================================================== - /** The user-defined callback routine that actually gets called periodically. - - It's perfectly ok to call startTimer() or stopTimer() from within this - callback to change the subsequent intervals. - */ - virtual void timerCallback() = 0; - - //============================================================================== - /** Starts the timer and sets the length of interval required. - - If the timer is already started, this will reset it, so the - time between calling this method and the next timer callback - will not be less than the interval length passed in. - - @param intervalInMilliseconds the interval to use (any value less - than 1 will be rounded up to 1) - */ - void startTimer (int intervalInMilliseconds) noexcept; - - /** Starts the timer with an interval specified in Hertz. - This is effectively the same as calling startTimer (1000 / timerFrequencyHz). - */ - void startTimerHz (int timerFrequencyHz) noexcept; - - /** Stops the timer. - - No more timer callbacks will be triggered after this method returns. - - Note that if you call this from a background thread while the message-thread - is already in the middle of your callback, then this method will cancel any - future timer callbacks, but it will return without waiting for the current one - to finish. The current callback will continue, possibly still running some of - your timer code after this method has returned. - */ - void stopTimer() noexcept; - - //============================================================================== - /** Returns true if the timer is currently running. */ - bool isTimerRunning() const noexcept { return timerPeriodMs > 0; } - - /** Returns the timer's interval. - @returns the timer's interval in milliseconds if it's running, or 0 if it's not. - */ - int getTimerInterval() const noexcept { return timerPeriodMs; } - - //============================================================================== - /** Invokes a lambda after a given number of milliseconds. */ - static void JUCE_CALLTYPE callAfterDelay (int milliseconds, std::function functionToCall); - - //============================================================================== - /** For internal use only: invokes any timers that need callbacks. - Don't call this unless you really know what you're doing! - */ - static void JUCE_CALLTYPE callPendingTimersSynchronously(); - -private: - class TimerThread; - friend class TimerThread; - int timerCountdownMs, timerPeriodMs; // NB: these member variable names are a little verbose - Timer* previousTimer, *nextTimer; // to reduce risk of name-clashes with user subclasses - - Timer& operator= (const Timer&) JUCE_DELETED_FUNCTION; -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/Makefile b/source/modules/juce_graphics/Makefile deleted file mode 100644 index 64f273573..000000000 --- a/source/modules/juce_graphics/Makefile +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/make -f -# Makefile for juce_graphics # -# -------------------------- # -# Created by falkTX -# - -CWD=../.. -MODULENAME=juce_graphics -include ../Makefile.mk - -# ---------------------------------------------------------------------------------------------------------------------------- - -BUILD_CXX_FLAGS += $(JUCE_GRAPHICS_FLAGS) -I.. - -ifeq ($(WIN32),true) -BUILD_CXX_FLAGS += -Wno-missing-field-initializers -Wno-strict-overflow -endif - -# ---------------------------------------------------------------------------------------------------------------------------- - -ifeq ($(MACOS),true) -OBJS = $(OBJDIR)/$(MODULENAME).mm.o -OBJS_posix32 = $(OBJDIR)/$(MODULENAME).mm.posix32.o -OBJS_posix64 = $(OBJDIR)/$(MODULENAME).mm.posix64.o -else -OBJS = $(OBJDIR)/$(MODULENAME).cpp.o -OBJS_posix32 = $(OBJDIR)/$(MODULENAME).cpp.posix32.o -OBJS_posix64 = $(OBJDIR)/$(MODULENAME).cpp.posix64.o -endif -OBJS_win32 = $(OBJDIR)/$(MODULENAME).cpp.win32.o -OBJS_win64 = $(OBJDIR)/$(MODULENAME).cpp.win64.o - -# ---------------------------------------------------------------------------------------------------------------------------- - -all: $(MODULEDIR)/$(MODULENAME).a -posix32: $(MODULEDIR)/$(MODULENAME).posix32.a -posix64: $(MODULEDIR)/$(MODULENAME).posix64.a -win32: $(MODULEDIR)/$(MODULENAME).win32.a -win64: $(MODULEDIR)/$(MODULENAME).win64.a - -# ---------------------------------------------------------------------------------------------------------------------------- - -clean: - rm -f $(OBJDIR)/*.o $(MODULEDIR)/$(MODULENAME)*.a - -debug: - $(MAKE) DEBUG=true - -# ---------------------------------------------------------------------------------------------------------------------------- - -$(MODULEDIR)/$(MODULENAME).a: $(OBJS) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).posix32.a: $(OBJS_posix32) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).posix32.a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).posix64.a: $(OBJS_posix64) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).posix64.a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).win32.a: $(OBJS_win32) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).win32.a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).win64.a: $(OBJS_win64) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).win64.a" - @rm -f $@ - @$(AR) crs $@ $^ - -# ---------------------------------------------------------------------------------------------------------------------------- - -$(OBJDIR)/$(MODULENAME).cpp.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $<" - @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ - -$(OBJDIR)/$(MODULENAME).cpp.%32.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (32bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -c -o $@ - -$(OBJDIR)/$(MODULENAME).cpp.%64.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (64bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -c -o $@ - -# ---------------------------------------------------------------------------------------------------------------------------- - -$(OBJDIR)/$(MODULENAME).mm.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $<" - @$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ - -$(OBJDIR)/$(MODULENAME).mm.%32.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (32bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -ObjC++ -c -o $@ - -$(OBJDIR)/$(MODULENAME).mm.%64.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (64bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -ObjC++ -c -o $@ - -# ---------------------------------------------------------------------------------------------------------------------------- - --include $(OBJS:%.o=%.d) --include $(OBJS_posix32:%.o=%.d) --include $(OBJS_posix64:%.o=%.d) --include $(OBJS_win32:%.o=%.d) --include $(OBJS_win64:%.o=%.d) - -# ---------------------------------------------------------------------------------------------------------------------------- diff --git a/source/modules/juce_graphics/colour/juce_Colour.cpp b/source/modules/juce_graphics/colour/juce_Colour.cpp deleted file mode 100644 index a4a863046..000000000 --- a/source/modules/juce_graphics/colour/juce_Colour.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -namespace ColourHelpers -{ - static uint8 floatToUInt8 (const float n) noexcept - { - return n <= 0.0f ? 0 : (n >= 1.0f ? 255 : static_cast (n * 255.996f)); - } - - //============================================================================== - struct HSB - { - HSB (Colour col) noexcept - { - const int r = col.getRed(); - const int g = col.getGreen(); - const int b = col.getBlue(); - - const int hi = jmax (r, g, b); - const int lo = jmin (r, g, b); - - if (hi != 0) - { - saturation = (hi - lo) / (float) hi; - - if (saturation > 0) - { - const float invDiff = 1.0f / (hi - lo); - - const float red = (hi - r) * invDiff; - const float green = (hi - g) * invDiff; - const float blue = (hi - b) * invDiff; - - if (r == hi) - hue = blue - green; - else if (g == hi) - hue = 2.0f + red - blue; - else - hue = 4.0f + green - red; - - hue *= 1.0f / 6.0f; - - if (hue < 0) - ++hue; - } - else - { - hue = 0; - } - } - else - { - saturation = hue = 0; - } - - brightness = hi / 255.0f; - } - - Colour toColour (Colour original) const noexcept - { - return Colour (hue, saturation, brightness, original.getAlpha()); - } - - static PixelARGB toRGB (float h, float s, float v, const uint8 alpha) noexcept - { - v = jlimit (0.0f, 255.0f, v * 255.0f); - const uint8 intV = (uint8) roundToInt (v); - - if (s <= 0) - return PixelARGB (alpha, intV, intV, intV); - - s = jmin (1.0f, s); - h = (h - std::floor (h)) * 6.0f + 0.00001f; // need a small adjustment to compensate for rounding errors - const float f = h - std::floor (h); - const uint8 x = (uint8) roundToInt (v * (1.0f - s)); - - if (h < 1.0f) return PixelARGB (alpha, intV, (uint8) roundToInt (v * (1.0f - (s * (1.0f - f)))), x); - if (h < 2.0f) return PixelARGB (alpha, (uint8) roundToInt (v * (1.0f - s * f)), intV, x); - if (h < 3.0f) return PixelARGB (alpha, x, intV, (uint8) roundToInt (v * (1.0f - (s * (1.0f - f))))); - if (h < 4.0f) return PixelARGB (alpha, x, (uint8) roundToInt (v * (1.0f - s * f)), intV); - if (h < 5.0f) return PixelARGB (alpha, (uint8) roundToInt (v * (1.0f - (s * (1.0f - f)))), x, intV); - return PixelARGB (alpha, intV, x, (uint8) roundToInt (v * (1.0f - s * f))); - } - - float hue, saturation, brightness; - }; - - //============================================================================== - struct YIQ - { - YIQ (Colour c) noexcept - { - const float r = c.getFloatRed(); - const float g = c.getFloatGreen(); - const float b = c.getFloatBlue(); - - y = 0.2999f * r + 0.5870f * g + 0.1140f * b; - i = 0.5957f * r - 0.2744f * g - 0.3212f * b; - q = 0.2114f * r - 0.5225f * g - 0.3113f * b; - alpha = c.getFloatAlpha(); - } - - Colour toColour() const noexcept - { - return Colour::fromFloatRGBA (y + 0.9563f * i + 0.6210f * q, - y - 0.2721f * i - 0.6474f * q, - y - 1.1070f * i + 1.7046f * q, - alpha); - } - - float y, i, q, alpha; - }; -} - -//============================================================================== -Colour::Colour() noexcept - : argb (0, 0, 0, 0) -{ -} - -Colour::Colour (const Colour& other) noexcept - : argb (other.argb) -{ -} - -Colour& Colour::operator= (const Colour& other) noexcept -{ - argb = other.argb; - return *this; -} - -bool Colour::operator== (const Colour& other) const noexcept { return argb.getNativeARGB() == other.argb.getNativeARGB(); } -bool Colour::operator!= (const Colour& other) const noexcept { return argb.getNativeARGB() != other.argb.getNativeARGB(); } - -//============================================================================== -Colour::Colour (const uint32 col) noexcept - : argb ((col >> 24) & 0xff, (col >> 16) & 0xff, (col >> 8) & 0xff, col & 0xff) -{ -} - -Colour::Colour (const uint8 red, const uint8 green, const uint8 blue) noexcept -{ - argb.setARGB (0xff, red, green, blue); -} - -Colour Colour::fromRGB (const uint8 red, const uint8 green, const uint8 blue) noexcept -{ - return Colour (red, green, blue); -} - -Colour::Colour (const uint8 red, const uint8 green, const uint8 blue, const uint8 alpha) noexcept -{ - argb.setARGB (alpha, red, green, blue); -} - -Colour Colour::fromRGBA (const uint8 red, const uint8 green, const uint8 blue, const uint8 alpha) noexcept -{ - return Colour (red, green, blue, alpha); -} - -Colour::Colour (const uint8 red, const uint8 green, const uint8 blue, const float alpha) noexcept -{ - argb.setARGB (ColourHelpers::floatToUInt8 (alpha), red, green, blue); -} - -Colour Colour::fromFloatRGBA (const float red, const float green, const float blue, const float alpha) noexcept -{ - return Colour (ColourHelpers::floatToUInt8 (red), - ColourHelpers::floatToUInt8 (green), - ColourHelpers::floatToUInt8 (blue), alpha); -} - -Colour::Colour (const float hue, const float saturation, const float brightness, const float alpha) noexcept - : argb (ColourHelpers::HSB::toRGB (hue, saturation, brightness, ColourHelpers::floatToUInt8 (alpha))) -{ -} - -Colour Colour::fromHSV (const float hue, const float saturation, const float brightness, const float alpha) noexcept -{ - return Colour (hue, saturation, brightness, alpha); -} - -Colour::Colour (const float hue, const float saturation, const float brightness, const uint8 alpha) noexcept - : argb (ColourHelpers::HSB::toRGB (hue, saturation, brightness, alpha)) -{ -} - -Colour::Colour (PixelARGB argb_) noexcept - : argb (argb_) -{ -} - -Colour::Colour (PixelRGB rgb) noexcept - : argb (Colour (rgb.getInARGBMaskOrder()).argb) -{ -} - -Colour::Colour (PixelAlpha alpha) noexcept - : argb (Colour (alpha.getInARGBMaskOrder()).argb) -{ -} - -Colour::~Colour() noexcept -{ -} - - -//============================================================================== -const PixelARGB Colour::getPixelARGB() const noexcept -{ - PixelARGB p (argb); - p.premultiply(); - return p; -} - -uint32 Colour::getARGB() const noexcept -{ - return argb.getInARGBMaskOrder(); -} - -//============================================================================== -bool Colour::isTransparent() const noexcept -{ - return getAlpha() == 0; -} - -bool Colour::isOpaque() const noexcept -{ - return getAlpha() == 0xff; -} - -Colour Colour::withAlpha (const uint8 newAlpha) const noexcept -{ - PixelARGB newCol (argb); - newCol.setAlpha (newAlpha); - return Colour (newCol); -} - -Colour Colour::withAlpha (const float newAlpha) const noexcept -{ - jassert (newAlpha >= 0 && newAlpha <= 1.0f); - - PixelARGB newCol (argb); - newCol.setAlpha (ColourHelpers::floatToUInt8 (newAlpha)); - return Colour (newCol); -} - -Colour Colour::withMultipliedAlpha (const float alphaMultiplier) const noexcept -{ - jassert (alphaMultiplier >= 0); - - PixelARGB newCol (argb); - newCol.setAlpha ((uint8) jmin (0xff, roundToInt (alphaMultiplier * newCol.getAlpha()))); - return Colour (newCol); -} - -//============================================================================== -Colour Colour::overlaidWith (Colour src) const noexcept -{ - const int destAlpha = getAlpha(); - - if (destAlpha <= 0) - return src; - - const int invA = 0xff - (int) src.getAlpha(); - const int resA = 0xff - (((0xff - destAlpha) * invA) >> 8); - - if (resA <= 0) - return *this; - - const int da = (invA * destAlpha) / resA; - - return Colour ((uint8) (src.getRed() + ((((int) getRed() - src.getRed()) * da) >> 8)), - (uint8) (src.getGreen() + ((((int) getGreen() - src.getGreen()) * da) >> 8)), - (uint8) (src.getBlue() + ((((int) getBlue() - src.getBlue()) * da) >> 8)), - (uint8) resA); -} - -Colour Colour::interpolatedWith (Colour other, float proportionOfOther) const noexcept -{ - if (proportionOfOther <= 0) - return *this; - - if (proportionOfOther >= 1.0f) - return other; - - PixelARGB c1 (getPixelARGB()); - const PixelARGB c2 (other.getPixelARGB()); - c1.tween (c2, (uint32) roundToInt (proportionOfOther * 255.0f)); - c1.unpremultiply(); - - return Colour (c1); -} - -//============================================================================== -float Colour::getFloatRed() const noexcept { return getRed() / 255.0f; } -float Colour::getFloatGreen() const noexcept { return getGreen() / 255.0f; } -float Colour::getFloatBlue() const noexcept { return getBlue() / 255.0f; } -float Colour::getFloatAlpha() const noexcept { return getAlpha() / 255.0f; } - -//============================================================================== -void Colour::getHSB (float& h, float& s, float& v) const noexcept -{ - const ColourHelpers::HSB hsb (*this); - h = hsb.hue; - s = hsb.saturation; - v = hsb.brightness; -} - -float Colour::getHue() const noexcept { return ColourHelpers::HSB (*this).hue; } -float Colour::getSaturation() const noexcept { return ColourHelpers::HSB (*this).saturation; } -float Colour::getBrightness() const noexcept { return ColourHelpers::HSB (*this).brightness; } - -Colour Colour::withHue (float h) const noexcept { ColourHelpers::HSB hsb (*this); hsb.hue = h; return hsb.toColour (*this); } -Colour Colour::withSaturation (float s) const noexcept { ColourHelpers::HSB hsb (*this); hsb.saturation = s; return hsb.toColour (*this); } -Colour Colour::withBrightness (float v) const noexcept { ColourHelpers::HSB hsb (*this); hsb.brightness = v; return hsb.toColour (*this); } - -float Colour::getPerceivedBrightness() const noexcept -{ - return std::sqrt (0.241f * square (getFloatRed()) - + 0.691f * square (getFloatGreen()) - + 0.068f * square (getFloatBlue())); -} - -//============================================================================== -Colour Colour::withRotatedHue (const float amountToRotate) const noexcept -{ - ColourHelpers::HSB hsb (*this); - hsb.hue += amountToRotate; - return hsb.toColour (*this); -} - -Colour Colour::withMultipliedSaturation (const float amount) const noexcept -{ - ColourHelpers::HSB hsb (*this); - hsb.saturation = jmin (1.0f, hsb.saturation * amount); - return hsb.toColour (*this); -} - -Colour Colour::withMultipliedBrightness (const float amount) const noexcept -{ - ColourHelpers::HSB hsb (*this); - hsb.brightness = jmin (1.0f, hsb.brightness * amount); - return hsb.toColour (*this); -} - -//============================================================================== -Colour Colour::brighter (float amount) const noexcept -{ - amount = 1.0f / (1.0f + amount); - - return Colour ((uint8) (255 - (amount * (255 - getRed()))), - (uint8) (255 - (amount * (255 - getGreen()))), - (uint8) (255 - (amount * (255 - getBlue()))), - getAlpha()); -} - -Colour Colour::darker (float amount) const noexcept -{ - amount = 1.0f / (1.0f + amount); - - return Colour ((uint8) (amount * getRed()), - (uint8) (amount * getGreen()), - (uint8) (amount * getBlue()), - getAlpha()); -} - -//============================================================================== -Colour Colour::greyLevel (const float brightness) noexcept -{ - const uint8 level = ColourHelpers::floatToUInt8 (brightness); - return Colour (level, level, level); -} - -//============================================================================== -Colour Colour::contrasting (const float amount) const noexcept -{ - return overlaidWith ((getPerceivedBrightness() >= 0.5f - ? Colours::black - : Colours::white).withAlpha (amount)); -} - -Colour Colour::contrasting (Colour target, float minContrast) const noexcept -{ - const ColourHelpers::YIQ bg (*this); - ColourHelpers::YIQ fg (target); - - if (std::abs (bg.y - fg.y) >= minContrast) - return target; - - const float y1 = jmax (0.0f, bg.y - minContrast); - const float y2 = jmin (1.0f, bg.y + minContrast); - fg.y = (std::abs (y1 - bg.y) > std::abs (y2 - bg.y)) ? y1 : y2; - - return fg.toColour(); -} - -Colour Colour::contrasting (Colour colour1, - Colour colour2) noexcept -{ - const float b1 = colour1.getPerceivedBrightness(); - const float b2 = colour2.getPerceivedBrightness(); - float best = 0.0f; - float bestDist = 0.0f; - - for (float i = 0.0f; i < 1.0f; i += 0.02f) - { - const float d1 = std::abs (i - b1); - const float d2 = std::abs (i - b2); - const float dist = jmin (d1, d2, 1.0f - d1, 1.0f - d2); - - if (dist > bestDist) - { - best = i; - bestDist = dist; - } - } - - return colour1.overlaidWith (colour2.withMultipliedAlpha (0.5f)) - .withBrightness (best); -} - -//============================================================================== -String Colour::toString() const -{ - return String::toHexString ((int) argb.getInARGBMaskOrder()); -} - -Colour Colour::fromString (StringRef encodedColourString) -{ - return Colour ((uint32) CharacterFunctions::HexParser::parse (encodedColourString.text)); -} - -String Colour::toDisplayString (const bool includeAlphaValue) const -{ - return String::toHexString ((int) (argb.getInARGBMaskOrder() & (includeAlphaValue ? 0xffffffff : 0xffffff))) - .paddedLeft ('0', includeAlphaValue ? 8 : 6) - .toUpperCase(); -} - -} // namespace juce diff --git a/source/modules/juce_graphics/colour/juce_Colour.h b/source/modules/juce_graphics/colour/juce_Colour.h deleted file mode 100644 index c5b0c6ec3..000000000 --- a/source/modules/juce_graphics/colour/juce_Colour.h +++ /dev/null @@ -1,367 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Represents a colour, also including a transparency value. - - The colour is stored internally as unsigned 8-bit red, green, blue and alpha values. -*/ -class JUCE_API Colour -{ -public: - //============================================================================== - /** Creates a transparent black colour. */ - Colour() noexcept; - - /** Creates a copy of another Colour object. */ - Colour (const Colour& other) noexcept; - - /** Creates a colour from a 32-bit ARGB value. - - The format of this number is: - ((alpha << 24) | (red << 16) | (green << 8) | blue). - - All components in the range 0x00 to 0xff. - An alpha of 0x00 is completely transparent, alpha of 0xff is opaque. - - @see getPixelARGB - */ - explicit Colour (uint32 argb) noexcept; - - /** Creates an opaque colour using 8-bit red, green and blue values */ - Colour (uint8 red, - uint8 green, - uint8 blue) noexcept; - - /** Creates an opaque colour using 8-bit red, green and blue values */ - static Colour fromRGB (uint8 red, - uint8 green, - uint8 blue) noexcept; - - /** Creates a colour using 8-bit red, green, blue and alpha values. */ - Colour (uint8 red, - uint8 green, - uint8 blue, - uint8 alpha) noexcept; - - /** Creates a colour using 8-bit red, green, blue and alpha values. */ - static Colour fromRGBA (uint8 red, - uint8 green, - uint8 blue, - uint8 alpha) noexcept; - - /** Creates a colour from 8-bit red, green, and blue values, and a floating-point alpha. - - Alpha of 0.0 is transparent, alpha of 1.0f is opaque. - Values outside the valid range will be clipped. - */ - Colour (uint8 red, - uint8 green, - uint8 blue, - float alpha) noexcept; - - /** Creates a colour using floating point red, green, blue and alpha values. - Numbers outside the range 0..1 will be clipped. - */ - static Colour fromFloatRGBA (float red, - float green, - float blue, - float alpha) noexcept; - - /** Creates a colour using floating point hue, saturation and brightness values, and an 8-bit alpha. - - The floating point values must be between 0.0 and 1.0. - An alpha of 0x00 is completely transparent, alpha of 0xff is opaque. - Values outside the valid range will be clipped. - */ - Colour (float hue, - float saturation, - float brightness, - uint8 alpha) noexcept; - - /** Creates a colour using floating point hue, saturation, brightness and alpha values. - - All values must be between 0.0 and 1.0. - Numbers outside the valid range will be clipped. - */ - Colour (float hue, - float saturation, - float brightness, - float alpha) noexcept; - - /** Creates a colour using a PixelARGB object. This function assumes that the argb pixel is - not premultiplied. - */ - Colour (PixelARGB argb) noexcept; - - /** Creates a colour using a PixelRGB object. - */ - Colour (PixelRGB rgb) noexcept; - - /** Creates a colour using a PixelAlpha object. - */ - Colour (PixelAlpha alpha) noexcept; - - /** Creates a colour using floating point hue, saturation and brightness values, and an 8-bit alpha. - - The floating point values must be between 0.0 and 1.0. - An alpha of 0x00 is completely transparent, alpha of 0xff is opaque. - Values outside the valid range will be clipped. - */ - static Colour fromHSV (float hue, - float saturation, - float brightness, - float alpha) noexcept; - - /** Destructor. */ - ~Colour() noexcept; - - /** Copies another Colour object. */ - Colour& operator= (const Colour& other) noexcept; - - /** Compares two colours. */ - bool operator== (const Colour& other) const noexcept; - /** Compares two colours. */ - bool operator!= (const Colour& other) const noexcept; - - //============================================================================== - /** Returns the red component of this colour. - @returns a value between 0x00 and 0xff. - */ - uint8 getRed() const noexcept { return argb.getRed(); } - - /** Returns the green component of this colour. - @returns a value between 0x00 and 0xff. - */ - uint8 getGreen() const noexcept { return argb.getGreen(); } - - /** Returns the blue component of this colour. - @returns a value between 0x00 and 0xff. - */ - uint8 getBlue() const noexcept { return argb.getBlue(); } - - /** Returns the red component of this colour as a floating point value. - @returns a value between 0.0 and 1.0 - */ - float getFloatRed() const noexcept; - - /** Returns the green component of this colour as a floating point value. - @returns a value between 0.0 and 1.0 - */ - float getFloatGreen() const noexcept; - - /** Returns the blue component of this colour as a floating point value. - @returns a value between 0.0 and 1.0 - */ - float getFloatBlue() const noexcept; - - /** Returns a premultiplied ARGB pixel object that represents this colour. - */ - const PixelARGB getPixelARGB() const noexcept; - - /** Returns a 32-bit integer that represents this colour. - - The format of this number is: - ((alpha << 24) | (red << 16) | (green << 16) | blue). - */ - uint32 getARGB() const noexcept; - - //============================================================================== - /** Returns the colour's alpha (opacity). - - Alpha of 0x00 is completely transparent, 0xff is completely opaque. - */ - uint8 getAlpha() const noexcept { return argb.getAlpha(); } - - /** Returns the colour's alpha (opacity) as a floating point value. - - Alpha of 0.0 is completely transparent, 1.0 is completely opaque. - */ - float getFloatAlpha() const noexcept; - - /** Returns true if this colour is completely opaque. - - Equivalent to (getAlpha() == 0xff). - */ - bool isOpaque() const noexcept; - - /** Returns true if this colour is completely transparent. - - Equivalent to (getAlpha() == 0x00). - */ - bool isTransparent() const noexcept; - - /** Returns a colour that's the same colour as this one, but with a new alpha value. */ - Colour withAlpha (uint8 newAlpha) const noexcept; - - /** Returns a colour that's the same colour as this one, but with a new alpha value. */ - Colour withAlpha (float newAlpha) const noexcept; - - /** Returns a colour that's the same colour as this one, but with a modified alpha value. - The new colour's alpha will be this object's alpha multiplied by the value passed-in. - */ - Colour withMultipliedAlpha (float alphaMultiplier) const noexcept; - - //============================================================================== - /** Returns a colour that is the result of alpha-compositing a new colour over this one. - If the foreground colour is semi-transparent, it is blended onto this colour accordingly. - */ - Colour overlaidWith (Colour foregroundColour) const noexcept; - - /** Returns a colour that lies somewhere between this one and another. - If amountOfOther is zero, the result is 100% this colour, if amountOfOther - is 1.0, the result is 100% of the other colour. - */ - Colour interpolatedWith (Colour other, float proportionOfOther) const noexcept; - - //============================================================================== - /** Returns the colour's hue component. - The value returned is in the range 0.0 to 1.0 - */ - float getHue() const noexcept; - - /** Returns the colour's saturation component. - The value returned is in the range 0.0 to 1.0 - */ - float getSaturation() const noexcept; - - /** Returns the colour's brightness component. - The value returned is in the range 0.0 to 1.0 - */ - float getBrightness() const noexcept; - - /** Returns a skewed brightness value, adjusted to better reflect the way the human - eye responds to different colour channels. This makes it better than getBrightness() - for comparing differences in brightness. - */ - float getPerceivedBrightness() const noexcept; - - /** Returns the colour's hue, saturation and brightness components all at once. - The values returned are in the range 0.0 to 1.0 - */ - void getHSB (float& hue, - float& saturation, - float& brightness) const noexcept; - - //============================================================================== - /** Returns a copy of this colour with a different hue. */ - Colour withHue (float newHue) const noexcept; - - /** Returns a copy of this colour with a different saturation. */ - Colour withSaturation (float newSaturation) const noexcept; - - /** Returns a copy of this colour with a different brightness. - @see brighter, darker, withMultipliedBrightness - */ - Colour withBrightness (float newBrightness) const noexcept; - - /** Returns a copy of this colour with it hue rotated. - The new colour's hue is ((this->getHue() + amountToRotate) % 1.0) - @see brighter, darker, withMultipliedBrightness - */ - Colour withRotatedHue (float amountToRotate) const noexcept; - - /** Returns a copy of this colour with its saturation multiplied by the given value. - The new colour's saturation is (this->getSaturation() * multiplier) - (the result is clipped to legal limits). - */ - Colour withMultipliedSaturation (float multiplier) const noexcept; - - /** Returns a copy of this colour with its brightness multiplied by the given value. - The new colour's brightness is (this->getBrightness() * multiplier) - (the result is clipped to legal limits). - */ - Colour withMultipliedBrightness (float amount) const noexcept; - - //============================================================================== - /** Returns a brighter version of this colour. - @param amountBrighter how much brighter to make it - a value from 0 to 1.0 where 0 is - unchanged, and higher values make it brighter - @see withMultipliedBrightness - */ - Colour brighter (float amountBrighter = 0.4f) const noexcept; - - /** Returns a darker version of this colour. - @param amountDarker how much darker to make it - a value from 0 to 1.0 where 0 is - unchanged, and higher values make it darker - @see withMultipliedBrightness - */ - Colour darker (float amountDarker = 0.4f) const noexcept; - - //============================================================================== - /** Returns a colour that will be clearly visible against this colour. - - The amount parameter indicates how contrasting the new colour should - be, so e.g. Colours::black.contrasting (0.1f) will return a colour - that's just a little bit lighter; Colours::black.contrasting (1.0f) will - return white; Colours::white.contrasting (1.0f) will return black, etc. - */ - Colour contrasting (float amount = 1.0f) const noexcept; - - /** Returns a colour that is as close as possible to a target colour whilst - still being in contrast to this one. - - The colour that is returned will be the targetColour, but with its luminosity - nudged up or down so that it differs from the luminosity of this colour - by at least the amount specified by minLuminosityDiff. - */ - Colour contrasting (Colour targetColour, float minLuminosityDiff) const noexcept; - - /** Returns a colour that contrasts against two colours. - Looks for a colour that contrasts with both of the colours passed-in. - Handy for things like choosing a highlight colour in text editors, etc. - */ - static Colour contrasting (Colour colour1, - Colour colour2) noexcept; - - //============================================================================== - /** Returns an opaque shade of grey. - @param brightness the level of grey to return - 0 is black, 1.0 is white - */ - static Colour greyLevel (float brightness) noexcept; - - //============================================================================== - /** Returns a stringified version of this colour. - The string can be turned back into a colour using the fromString() method. - */ - String toString() const; - - /** Reads the colour from a string that was created with toString(). */ - static Colour fromString (StringRef encodedColourString); - - /** Returns the colour as a hex string in the form RRGGBB or AARRGGBB. */ - String toDisplayString (bool includeAlphaValue) const; - -private: - //============================================================================== - PixelARGB argb; -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/colour/juce_ColourGradient.cpp b/source/modules/juce_graphics/colour/juce_ColourGradient.cpp deleted file mode 100644 index c025468e8..000000000 --- a/source/modules/juce_graphics/colour/juce_ColourGradient.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -ColourGradient::ColourGradient() noexcept -{ - #if JUCE_DEBUG - point1.setX (987654.0f); - #define JUCE_COLOURGRADIENT_CHECK_COORDS_INITIALISED jassert (point1.x != 987654.0f); - #else - #define JUCE_COLOURGRADIENT_CHECK_COORDS_INITIALISED - #endif -} - -ColourGradient::ColourGradient (Colour colour1, const float x1, const float y1, - Colour colour2, const float x2, const float y2, - const bool radial) - : point1 (x1, y1), - point2 (x2, y2), - isRadial (radial) -{ - colours.add (ColourPoint (0.0, colour1)); - colours.add (ColourPoint (1.0, colour2)); -} - -ColourGradient::ColourGradient (Colour colour1, Point p1, - Colour colour2, Point p2, - const bool radial) - : point1 (p1), - point2 (p2), - isRadial (radial) -{ - colours.add (ColourPoint (0.0, colour1)); - colours.add (ColourPoint (1.0, colour2)); -} - -ColourGradient::~ColourGradient() -{ -} - -bool ColourGradient::operator== (const ColourGradient& other) const noexcept -{ - return point1 == other.point1 && point2 == other.point2 - && isRadial == other.isRadial - && colours == other.colours; -} - -bool ColourGradient::operator!= (const ColourGradient& other) const noexcept -{ - return ! operator== (other); -} - -//============================================================================== -void ColourGradient::clearColours() -{ - colours.clear(); -} - -int ColourGradient::addColour (const double proportionAlongGradient, Colour colour) -{ - // must be within the two end-points - jassert (proportionAlongGradient >= 0 && proportionAlongGradient <= 1.0); - - if (proportionAlongGradient <= 0) - { - colours.set (0, ColourPoint (0.0, colour)); - return 0; - } - - const double pos = jmin (1.0, proportionAlongGradient); - - int i; - for (i = 0; i < colours.size(); ++i) - if (colours.getReference(i).position > pos) - break; - - colours.insert (i, ColourPoint (pos, colour)); - return i; -} - -void ColourGradient::removeColour (int index) -{ - jassert (index > 0 && index < colours.size() - 1); - colours.remove (index); -} - -void ColourGradient::multiplyOpacity (const float multiplier) noexcept -{ - for (int i = 0; i < colours.size(); ++i) - { - Colour& c = colours.getReference(i).colour; - c = c.withMultipliedAlpha (multiplier); - } -} - -//============================================================================== -int ColourGradient::getNumColours() const noexcept -{ - return colours.size(); -} - -double ColourGradient::getColourPosition (const int index) const noexcept -{ - if (isPositiveAndBelow (index, colours.size())) - return colours.getReference (index).position; - - return 0; - } - -Colour ColourGradient::getColour (const int index) const noexcept -{ - if (isPositiveAndBelow (index, colours.size())) - return colours.getReference (index).colour; - - return Colour(); -} - -void ColourGradient::setColour (int index, Colour newColour) noexcept -{ - if (isPositiveAndBelow (index, colours.size())) - colours.getReference (index).colour = newColour; -} - -Colour ColourGradient::getColourAtPosition (const double position) const noexcept -{ - jassert (colours.getReference(0).position == 0.0); // the first colour specified has to go at position 0 - - if (position <= 0 || colours.size() <= 1) - return colours.getReference(0).colour; - - int i = colours.size() - 1; - while (position < colours.getReference(i).position) - --i; - - auto& p1 = colours.getReference (i); - - if (i >= colours.size() - 1) - return p1.colour; - - auto& p2 = colours.getReference (i + 1); - - return p1.colour.interpolatedWith (p2.colour, (float) ((position - p1.position) / (p2.position - p1.position))); -} - -//============================================================================== -void ColourGradient::createLookupTable (PixelARGB* const lookupTable, const int numEntries) const noexcept -{ - JUCE_COLOURGRADIENT_CHECK_COORDS_INITIALISED // Trying to use this object without setting its coordinates? - jassert (colours.size() >= 2); - jassert (numEntries > 0); - jassert (colours.getReference(0).position == 0.0); // The first colour specified has to go at position 0 - - PixelARGB pix1 (colours.getReference (0).colour.getPixelARGB()); - int index = 0; - - for (int j = 1; j < colours.size(); ++j) - { - const ColourPoint& p = colours.getReference (j); - const int numToDo = roundToInt (p.position * (numEntries - 1)) - index; - const PixelARGB pix2 (p.colour.getPixelARGB()); - - for (int i = 0; i < numToDo; ++i) - { - jassert (index >= 0 && index < numEntries); - - lookupTable[index] = pix1; - lookupTable[index].tween (pix2, (uint32) ((i << 8) / numToDo)); - ++index; - } - - pix1 = pix2; - } - - while (index < numEntries) - lookupTable [index++] = pix1; -} - -int ColourGradient::createLookupTable (const AffineTransform& transform, HeapBlock& lookupTable) const -{ - JUCE_COLOURGRADIENT_CHECK_COORDS_INITIALISED // Trying to use this object without setting its coordinates? - jassert (colours.size() >= 2); - - const int numEntries = jlimit (1, jmax (1, (colours.size() - 1) << 8), - 3 * (int) point1.transformedBy (transform) - .getDistanceFrom (point2.transformedBy (transform))); - lookupTable.malloc ((size_t) numEntries); - createLookupTable (lookupTable, numEntries); - return numEntries; -} - -bool ColourGradient::isOpaque() const noexcept -{ - for (int i = 0; i < colours.size(); ++i) - if (! colours.getReference(i).colour.isOpaque()) - return false; - - return true; -} - -bool ColourGradient::isInvisible() const noexcept -{ - for (int i = 0; i < colours.size(); ++i) - if (! colours.getReference(i).colour.isTransparent()) - return false; - - return true; -} - -bool ColourGradient::ColourPoint::operator== (const ColourPoint& other) const noexcept -{ - return position == other.position && colour == other.colour; -} - -bool ColourGradient::ColourPoint::operator!= (const ColourPoint& other) const noexcept -{ - return position != other.position || colour != other.colour; -} - -} // namespace juce diff --git a/source/modules/juce_graphics/colour/juce_ColourGradient.h b/source/modules/juce_graphics/colour/juce_ColourGradient.h deleted file mode 100644 index 8f5ff7b22..000000000 --- a/source/modules/juce_graphics/colour/juce_ColourGradient.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Describes the layout and colours that should be used to paint a colour gradient. - - @see Graphics::setGradientFill -*/ -class JUCE_API ColourGradient -{ -public: - //============================================================================== - /** Creates a gradient object. - - (x1, y1) is the location to draw with colour1. Likewise (x2, y2) is where - colour2 should be. In between them there's a gradient. - - If isRadial is true, the colours form a circular gradient with (x1, y1) at - its centre. - - The alpha transparencies of the colours are used, so note that - if you blend from transparent to a solid colour, the RGB of the transparent - colour will become visible in parts of the gradient. e.g. blending - from Colour::transparentBlack to Colours::white will produce a - muddy grey colour midway, but Colour::transparentWhite to Colours::white - will be white all the way across. - - @see ColourGradient - */ - ColourGradient (Colour colour1, float x1, float y1, - Colour colour2, float x2, float y2, - bool isRadial); - - /** Creates a gradient object. - - point1 is the location to draw with colour1. Likewise point2 is where - colour2 should be. In between them there's a gradient. - - If isRadial is true, the colours form a circular gradient with point1 at - its centre. - - The alpha transparencies of the colours are used, so note that - if you blend from transparent to a solid colour, the RGB of the transparent - colour will become visible in parts of the gradient. e.g. blending - from Colour::transparentBlack to Colours::white will produce a - muddy grey colour midway, but Colour::transparentWhite to Colours::white - will be white all the way across. - - @see ColourGradient - */ - ColourGradient (Colour colour1, Point point1, - Colour colour2, Point point2, - bool isRadial); - - /** Creates an uninitialised gradient. - - If you use this constructor instead of the other one, be sure to set all the - object's public member variables before using it! - */ - ColourGradient() noexcept; - - /** Destructor */ - ~ColourGradient(); - - //============================================================================== - /** Removes any colours that have been added. - - This will also remove any start and end colours, so the gradient won't work. You'll - need to add more colours with addColour(). - */ - void clearColours(); - - /** Adds a colour at a point along the length of the gradient. - - This allows the gradient to go through a spectrum of colours, instead of just a - start and end colour. - - @param proportionAlongGradient a value between 0 and 1.0, which is the proportion - of the distance along the line between the two points - at which the colour should occur. - @param colour the colour that should be used at this point - @returns the index at which the new point was added - */ - int addColour (double proportionAlongGradient, - Colour colour); - - /** Removes one of the colours from the gradient. */ - void removeColour (int index); - - /** Multiplies the alpha value of all the colours by the given scale factor */ - void multiplyOpacity (float multiplier) noexcept; - - //============================================================================== - /** Returns the number of colour-stops that have been added. */ - int getNumColours() const noexcept; - - /** Returns the position along the length of the gradient of the colour with this index. - - The index is from 0 to getNumColours() - 1. The return value will be between 0.0 and 1.0 - */ - double getColourPosition (int index) const noexcept; - - /** Returns the colour that was added with a given index. - The index is from 0 to getNumColours() - 1. - */ - Colour getColour (int index) const noexcept; - - /** Changes the colour at a given index. - The index is from 0 to getNumColours() - 1. - */ - void setColour (int index, Colour newColour) noexcept; - - /** Returns the an interpolated colour at any position along the gradient. - @param position the position along the gradient, between 0 and 1 - */ - Colour getColourAtPosition (double position) const noexcept; - - //============================================================================== - /** Creates a set of interpolated premultiplied ARGB values. - This will resize the HeapBlock, fill it with the colours, and will return the number of - colours that it added. - When calling this, the ColourGradient must have at least 2 colour stops specified. - */ - int createLookupTable (const AffineTransform& transform, HeapBlock& resultLookupTable) const; - - /** Creates a set of interpolated premultiplied ARGB values. - This will fill an array of a user-specified size with the gradient, interpolating to fit. - The numEntries argument specifies the size of the array, and this size must be greater than zero. - When calling this, the ColourGradient must have at least 2 colour stops specified. - */ - void createLookupTable (PixelARGB* resultLookupTable, int numEntries) const noexcept; - - /** Returns true if all colours are opaque. */ - bool isOpaque() const noexcept; - - /** Returns true if all colours are completely transparent. */ - bool isInvisible() const noexcept; - - //============================================================================== - Point point1, point2; - - /** If true, the gradient should be filled circularly, centred around - point1, with point2 defining a point on the circumference. - - If false, the gradient is linear between the two points. - */ - bool isRadial; - - bool operator== (const ColourGradient&) const noexcept; - bool operator!= (const ColourGradient&) const noexcept; - - -private: - //============================================================================== - struct ColourPoint - { - ColourPoint() noexcept {} - - ColourPoint (const double pos, Colour col) noexcept - : position (pos), colour (col) - {} - - bool operator== (const ColourPoint&) const noexcept; - bool operator!= (const ColourPoint&) const noexcept; - - double position; - Colour colour; - }; - - Array colours; - - JUCE_LEAK_DETECTOR (ColourGradient) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/colour/juce_Colours.cpp b/source/modules/juce_graphics/colour/juce_Colours.cpp deleted file mode 100644 index 2b0629120..000000000 --- a/source/modules/juce_graphics/colour/juce_Colours.cpp +++ /dev/null @@ -1,335 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -const Colour Colours::transparentBlack (0); -const Colour Colours::transparentWhite (0x00ffffff); - -const Colour Colours::aliceblue (0xfff0f8ff); -const Colour Colours::antiquewhite (0xfffaebd7); -const Colour Colours::aqua (0xff00ffff); -const Colour Colours::aquamarine (0xff7fffd4); -const Colour Colours::azure (0xfff0ffff); -const Colour Colours::beige (0xfff5f5dc); -const Colour Colours::bisque (0xffffe4c4); -const Colour Colours::black (0xff000000); -const Colour Colours::blanchedalmond (0xffffebcd); -const Colour Colours::blue (0xff0000ff); -const Colour Colours::blueviolet (0xff8a2be2); -const Colour Colours::brown (0xffa52a2a); -const Colour Colours::burlywood (0xffdeb887); -const Colour Colours::cadetblue (0xff5f9ea0); -const Colour Colours::chartreuse (0xff7fff00); -const Colour Colours::chocolate (0xffd2691e); -const Colour Colours::coral (0xffff7f50); -const Colour Colours::cornflowerblue (0xff6495ed); -const Colour Colours::cornsilk (0xfffff8dc); -const Colour Colours::crimson (0xffdc143c); -const Colour Colours::cyan (0xff00ffff); -const Colour Colours::darkblue (0xff00008b); -const Colour Colours::darkcyan (0xff008b8b); -const Colour Colours::darkgoldenrod (0xffb8860b); -const Colour Colours::darkgrey (0xff555555); -const Colour Colours::darkgreen (0xff006400); -const Colour Colours::darkkhaki (0xffbdb76b); -const Colour Colours::darkmagenta (0xff8b008b); -const Colour Colours::darkolivegreen (0xff556b2f); -const Colour Colours::darkorange (0xffff8c00); -const Colour Colours::darkorchid (0xff9932cc); -const Colour Colours::darkred (0xff8b0000); -const Colour Colours::darksalmon (0xffe9967a); -const Colour Colours::darkseagreen (0xff8fbc8f); -const Colour Colours::darkslateblue (0xff483d8b); -const Colour Colours::darkslategrey (0xff2f4f4f); -const Colour Colours::darkturquoise (0xff00ced1); -const Colour Colours::darkviolet (0xff9400d3); -const Colour Colours::deeppink (0xffff1493); -const Colour Colours::deepskyblue (0xff00bfff); -const Colour Colours::dimgrey (0xff696969); -const Colour Colours::dodgerblue (0xff1e90ff); -const Colour Colours::firebrick (0xffb22222); -const Colour Colours::floralwhite (0xfffffaf0); -const Colour Colours::forestgreen (0xff228b22); -const Colour Colours::fuchsia (0xffff00ff); -const Colour Colours::gainsboro (0xffdcdcdc); -const Colour Colours::ghostwhite (0xfff8f8ff); -const Colour Colours::gold (0xffffd700); -const Colour Colours::goldenrod (0xffdaa520); -const Colour Colours::grey (0xff808080); -const Colour Colours::green (0xff008000); -const Colour Colours::greenyellow (0xffadff2f); -const Colour Colours::honeydew (0xfff0fff0); -const Colour Colours::hotpink (0xffff69b4); -const Colour Colours::indianred (0xffcd5c5c); -const Colour Colours::indigo (0xff4b0082); -const Colour Colours::ivory (0xfffffff0); -const Colour Colours::khaki (0xfff0e68c); -const Colour Colours::lavender (0xffe6e6fa); -const Colour Colours::lavenderblush (0xfffff0f5); -const Colour Colours::lawngreen (0xff7cfc00); -const Colour Colours::lemonchiffon (0xfffffacd); -const Colour Colours::lightblue (0xffadd8e6); -const Colour Colours::lightcoral (0xfff08080); -const Colour Colours::lightcyan (0xffe0ffff); -const Colour Colours::lightgoldenrodyellow (0xfffafad2); -const Colour Colours::lightgreen (0xff90ee90); -const Colour Colours::lightgrey (0xffd3d3d3); -const Colour Colours::lightpink (0xffffb6c1); -const Colour Colours::lightsalmon (0xffffa07a); -const Colour Colours::lightseagreen (0xff20b2aa); -const Colour Colours::lightskyblue (0xff87cefa); -const Colour Colours::lightslategrey (0xff778899); -const Colour Colours::lightsteelblue (0xffb0c4de); -const Colour Colours::lightyellow (0xffffffe0); -const Colour Colours::lime (0xff00ff00); -const Colour Colours::limegreen (0xff32cd32); -const Colour Colours::linen (0xfffaf0e6); -const Colour Colours::magenta (0xffff00ff); -const Colour Colours::maroon (0xff800000); -const Colour Colours::mediumaquamarine (0xff66cdaa); -const Colour Colours::mediumblue (0xff0000cd); -const Colour Colours::mediumorchid (0xffba55d3); -const Colour Colours::mediumpurple (0xff9370db); -const Colour Colours::mediumseagreen (0xff3cb371); -const Colour Colours::mediumslateblue (0xff7b68ee); -const Colour Colours::mediumspringgreen (0xff00fa9a); -const Colour Colours::mediumturquoise (0xff48d1cc); -const Colour Colours::mediumvioletred (0xffc71585); -const Colour Colours::midnightblue (0xff191970); -const Colour Colours::mintcream (0xfff5fffa); -const Colour Colours::mistyrose (0xffffe4e1); -const Colour Colours::moccasin (0xffffe4b5); -const Colour Colours::navajowhite (0xffffdead); -const Colour Colours::navy (0xff000080); -const Colour Colours::oldlace (0xfffdf5e6); -const Colour Colours::olive (0xff808000); -const Colour Colours::olivedrab (0xff6b8e23); -const Colour Colours::orange (0xffffa500); -const Colour Colours::orangered (0xffff4500); -const Colour Colours::orchid (0xffda70d6); -const Colour Colours::palegoldenrod (0xffeee8aa); -const Colour Colours::palegreen (0xff98fb98); -const Colour Colours::paleturquoise (0xffafeeee); -const Colour Colours::palevioletred (0xffdb7093); -const Colour Colours::papayawhip (0xffffefd5); -const Colour Colours::peachpuff (0xffffdab9); -const Colour Colours::peru (0xffcd853f); -const Colour Colours::pink (0xffffc0cb); -const Colour Colours::plum (0xffdda0dd); -const Colour Colours::powderblue (0xffb0e0e6); -const Colour Colours::purple (0xff800080); -const Colour Colours::rebeccapurple (0xff663399); -const Colour Colours::red (0xffff0000); -const Colour Colours::rosybrown (0xffbc8f8f); -const Colour Colours::royalblue (0xff4169e1); -const Colour Colours::saddlebrown (0xff8b4513); -const Colour Colours::salmon (0xfffa8072); -const Colour Colours::sandybrown (0xfff4a460); -const Colour Colours::seagreen (0xff2e8b57); -const Colour Colours::seashell (0xfffff5ee); -const Colour Colours::sienna (0xffa0522d); -const Colour Colours::silver (0xffc0c0c0); -const Colour Colours::skyblue (0xff87ceeb); -const Colour Colours::slateblue (0xff6a5acd); -const Colour Colours::slategrey (0xff708090); -const Colour Colours::snow (0xfffffafa); -const Colour Colours::springgreen (0xff00ff7f); -const Colour Colours::steelblue (0xff4682b4); -const Colour Colours::tan (0xffd2b48c); -const Colour Colours::teal (0xff008080); -const Colour Colours::thistle (0xffd8bfd8); -const Colour Colours::tomato (0xffff6347); -const Colour Colours::turquoise (0xff40e0d0); -const Colour Colours::violet (0xffee82ee); -const Colour Colours::wheat (0xfff5deb3); -const Colour Colours::white (0xffffffff); -const Colour Colours::whitesmoke (0xfff5f5f5); -const Colour Colours::yellow (0xffffff00); -const Colour Colours::yellowgreen (0xff9acd32); - -//============================================================================== -Colour Colours::findColourForName (const String& colourName, - Colour defaultColour) -{ - static const uint32 presets[] = - { - // (first value is the string's hashcode, second is ARGB) - - 0x05978fff, 0xff000000, /* black */ - 0x06bdcc29, 0xffffffff, /* white */ - 0x002e305a, 0xff0000ff, /* blue */ - 0x00308adf, 0xff808080, /* grey */ - 0x05e0cf03, 0xff008000, /* green */ - 0x0001b891, 0xffff0000, /* red */ - 0xd43c6474, 0xffffff00, /* yellow */ - 0x620886da, 0xfff0f8ff, /* aliceblue */ - 0x20a2676a, 0xfffaebd7, /* antiquewhite */ - 0x002dcebc, 0xff00ffff, /* aqua */ - 0x46bb5f7e, 0xff7fffd4, /* aquamarine */ - 0x0590228f, 0xfff0ffff, /* azure */ - 0x05947fe4, 0xfff5f5dc, /* beige */ - 0xad388e35, 0xffffe4c4, /* bisque */ - 0x00674f7e, 0xffffebcd, /* blanchedalmond */ - 0x39129959, 0xff8a2be2, /* blueviolet */ - 0x059a8136, 0xffa52a2a, /* brown */ - 0x89cea8f9, 0xffdeb887, /* burlywood */ - 0x0fa260cf, 0xff5f9ea0, /* cadetblue */ - 0x6b748956, 0xff7fff00, /* chartreuse */ - 0x2903623c, 0xffd2691e, /* chocolate */ - 0x05a74431, 0xffff7f50, /* coral */ - 0x618d42dd, 0xff6495ed, /* cornflowerblue */ - 0xe4b479fd, 0xfffff8dc, /* cornsilk */ - 0x3d8c4edf, 0xffdc143c, /* crimson */ - 0x002ed323, 0xff00ffff, /* cyan */ - 0x67cc74d0, 0xff00008b, /* darkblue */ - 0x67cd1799, 0xff008b8b, /* darkcyan */ - 0x31bbd168, 0xffb8860b, /* darkgoldenrod */ - 0x67cecf55, 0xff555555, /* darkgrey */ - 0x920b194d, 0xff006400, /* darkgreen */ - 0x923edd4c, 0xffbdb76b, /* darkkhaki */ - 0x5c293873, 0xff8b008b, /* darkmagenta */ - 0x6b6671fe, 0xff556b2f, /* darkolivegreen */ - 0xbcfd2524, 0xffff8c00, /* darkorange */ - 0xbcfdf799, 0xff9932cc, /* darkorchid */ - 0x55ee0d5b, 0xff8b0000, /* darkred */ - 0xc2e5f564, 0xffe9967a, /* darksalmon */ - 0x61be858a, 0xff8fbc8f, /* darkseagreen */ - 0xc2b0f2bd, 0xff483d8b, /* darkslateblue */ - 0xc2b34d42, 0xff2f4f4f, /* darkslategrey */ - 0x7cf2b06b, 0xff00ced1, /* darkturquoise */ - 0xc8769375, 0xff9400d3, /* darkviolet */ - 0x25832862, 0xffff1493, /* deeppink */ - 0xfcad568f, 0xff00bfff, /* deepskyblue */ - 0x634c8b67, 0xff696969, /* dimgrey */ - 0x45c1ce55, 0xff1e90ff, /* dodgerblue */ - 0xef19e3cb, 0xffb22222, /* firebrick */ - 0xb852b195, 0xfffffaf0, /* floralwhite */ - 0xd086fd06, 0xff228b22, /* forestgreen */ - 0xe106b6d7, 0xffff00ff, /* fuchsia */ - 0x7880d61e, 0xffdcdcdc, /* gainsboro */ - 0x2018a2fa, 0xfff8f8ff, /* ghostwhite */ - 0x00308060, 0xffffd700, /* gold */ - 0xb3b3bc1e, 0xffdaa520, /* goldenrod */ - 0xbab8a537, 0xffadff2f, /* greenyellow */ - 0xe4cacafb, 0xfff0fff0, /* honeydew */ - 0x41892743, 0xffff69b4, /* hotpink */ - 0xd5796f1a, 0xffcd5c5c, /* indianred */ - 0xb969fed2, 0xff4b0082, /* indigo */ - 0x05fef6a9, 0xfffffff0, /* ivory */ - 0x06149302, 0xfff0e68c, /* khaki */ - 0xad5a05c7, 0xffe6e6fa, /* lavender */ - 0x7c4d5b99, 0xfffff0f5, /* lavenderblush */ - 0x41cc4377, 0xff7cfc00, /* lawngreen */ - 0x195756f0, 0xfffffacd, /* lemonchiffon */ - 0x28e4ea70, 0xffadd8e6, /* lightblue */ - 0xf3c7ccdb, 0xfff08080, /* lightcoral */ - 0x28e58d39, 0xffe0ffff, /* lightcyan */ - 0x21234e3c, 0xfffafad2, /* lightgoldenrodyellow */ - 0xf40157ad, 0xff90ee90, /* lightgreen */ - 0x28e744f5, 0xffd3d3d3, /* lightgrey */ - 0x28eb3b8c, 0xffffb6c1, /* lightpink */ - 0x9fb78304, 0xffffa07a, /* lightsalmon */ - 0x50632b2a, 0xff20b2aa, /* lightseagreen */ - 0x68fb7b25, 0xff87cefa, /* lightskyblue */ - 0xa8a35ba2, 0xff778899, /* lightslategrey */ - 0xa20d484f, 0xffb0c4de, /* lightsteelblue */ - 0xaa2cf10a, 0xffffffe0, /* lightyellow */ - 0x0032afd5, 0xff00ff00, /* lime */ - 0x607bbc4e, 0xff32cd32, /* limegreen */ - 0x06234efa, 0xfffaf0e6, /* linen */ - 0x316858a9, 0xffff00ff, /* magenta */ - 0xbf8ca470, 0xff800000, /* maroon */ - 0xbd58e0b3, 0xff66cdaa, /* mediumaquamarine */ - 0x967dfd4f, 0xff0000cd, /* mediumblue */ - 0x056f5c58, 0xffba55d3, /* mediumorchid */ - 0x07556b71, 0xff9370db, /* mediumpurple */ - 0x5369b689, 0xff3cb371, /* mediumseagreen */ - 0x066be19e, 0xff7b68ee, /* mediumslateblue */ - 0x3256b281, 0xff00fa9a, /* mediumspringgreen */ - 0xc0ad9f4c, 0xff48d1cc, /* mediumturquoise */ - 0x628e63dd, 0xffc71585, /* mediumvioletred */ - 0x168eb32a, 0xff191970, /* midnightblue */ - 0x4306b960, 0xfff5fffa, /* mintcream */ - 0x4cbc0e6b, 0xffffe4e1, /* mistyrose */ - 0xd9447d59, 0xffffe4b5, /* moccasin */ - 0xe97218a6, 0xffffdead, /* navajowhite */ - 0x00337bb6, 0xff000080, /* navy */ - 0xadd2d33e, 0xfffdf5e6, /* oldlace */ - 0x064ee1db, 0xff808000, /* olive */ - 0x9e33a98a, 0xff6b8e23, /* olivedrab */ - 0xc3de262e, 0xffffa500, /* orange */ - 0x58bebba3, 0xffff4500, /* orangered */ - 0xc3def8a3, 0xffda70d6, /* orchid */ - 0x28cb4834, 0xffeee8aa, /* palegoldenrod */ - 0x3d9dd619, 0xff98fb98, /* palegreen */ - 0x74022737, 0xffafeeee, /* paleturquoise */ - 0x15e2ebc8, 0xffdb7093, /* palevioletred */ - 0x5fd898e2, 0xffffefd5, /* papayawhip */ - 0x93e1b776, 0xffffdab9, /* peachpuff */ - 0x003472f8, 0xffcd853f, /* peru */ - 0x00348176, 0xffffc0cb, /* pink */ - 0x00348d94, 0xffdda0dd, /* plum */ - 0xd036be93, 0xffb0e0e6, /* powderblue */ - 0xc5c507bc, 0xff800080, /* purple */ - 0xf381f607, 0xff663399, /* rebeccapurple */ - 0xa89d65b3, 0xffbc8f8f, /* rosybrown */ - 0xbd9413e1, 0xff4169e1, /* royalblue */ - 0xf456044f, 0xff8b4513, /* saddlebrown */ - 0xc9c6f66e, 0xfffa8072, /* salmon */ - 0x0bb131e1, 0xfff4a460, /* sandybrown */ - 0x34636c14, 0xff2e8b57, /* seagreen */ - 0x3507fb41, 0xfffff5ee, /* seashell */ - 0xca348772, 0xffa0522d, /* sienna */ - 0xca37d30d, 0xffc0c0c0, /* silver */ - 0x80da74fb, 0xff87ceeb, /* skyblue */ - 0x44a8dd73, 0xff6a5acd, /* slateblue */ - 0x44ab37f8, 0xff708090, /* slategrey */ - 0x0035f183, 0xfffffafa, /* snow */ - 0xd5440d16, 0xff00ff7f, /* springgreen */ - 0x3e1524a5, 0xff4682b4, /* steelblue */ - 0x0001bfa1, 0xffd2b48c, /* tan */ - 0x0036425c, 0xff008080, /* teal */ - 0xafc8858f, 0xffd8bfd8, /* thistle */ - 0xcc41600a, 0xffff6347, /* tomato */ - 0xfeea9b21, 0xff40e0d0, /* turquoise */ - 0xcf57947f, 0xffee82ee, /* violet */ - 0x06bdbae7, 0xfff5deb3, /* wheat */ - 0x10802ee6, 0xfff5f5f5, /* whitesmoke */ - 0xe1b5130f, 0xff9acd32 /* yellowgreen */ - }; - - const uint32 hash = (uint32) colourName.trim().toLowerCase().hashCode(); - - for (int i = 0; i < numElementsInArray (presets); i += 2) - if (presets [i] == hash) - return Colour (presets [i + 1]); - - return defaultColour; -} - -} // namespace juce diff --git a/source/modules/juce_graphics/colour/juce_Colours.h b/source/modules/juce_graphics/colour/juce_Colours.h deleted file mode 100644 index cef12a3e6..000000000 --- a/source/modules/juce_graphics/colour/juce_Colours.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Contains a set of predefined named colours (mostly standard HTML colours) - - @see Colour, Colours::greyLevel -*/ -class Colours -{ -public: - static JUCE_API const Colour - - //============================================================================== - transparentBlack, /**< ARGB = 0x00000000 */ - transparentWhite, /**< ARGB = 0x00ffffff */ - - //============================================================================== - black, /**< ARGB = 0xff000000 */ - white, /**< ARGB = 0xffffffff */ - blue, /**< ARGB = 0xff0000ff */ - grey, /**< ARGB = 0xff808080 */ - green, /**< ARGB = 0xff008000 */ - red, /**< ARGB = 0xffff0000 */ - yellow, /**< ARGB = 0xffffff00 */ - - //============================================================================== - aliceblue, antiquewhite, aqua, aquamarine, - azure, beige, bisque, blanchedalmond, - blueviolet, brown, burlywood, cadetblue, - chartreuse, chocolate, coral, cornflowerblue, - cornsilk, crimson, cyan, darkblue, - darkcyan, darkgoldenrod, darkgrey, darkgreen, - darkkhaki, darkmagenta, darkolivegreen, darkorange, - darkorchid, darkred, darksalmon, darkseagreen, - darkslateblue, darkslategrey, darkturquoise, darkviolet, - deeppink, deepskyblue, dimgrey, dodgerblue, - firebrick, floralwhite, forestgreen, fuchsia, - gainsboro, ghostwhite, gold, goldenrod, - greenyellow, honeydew, hotpink, indianred, - indigo, ivory, khaki, lavender, - lavenderblush, lawngreen, lemonchiffon, lightblue, - lightcoral, lightcyan, lightgoldenrodyellow, lightgreen, - lightgrey, lightpink, lightsalmon, lightseagreen, - lightskyblue, lightslategrey, lightsteelblue, lightyellow, - lime, limegreen, linen, magenta, - maroon, mediumaquamarine, mediumblue, mediumorchid, - mediumpurple, mediumseagreen, mediumslateblue, mediumspringgreen, - mediumturquoise, mediumvioletred, midnightblue, mintcream, - mistyrose, moccasin, navajowhite, navy, - oldlace, olive, olivedrab, orange, - orangered, orchid, palegoldenrod, palegreen, - paleturquoise, palevioletred, papayawhip, peachpuff, - peru, pink, plum, powderblue, - purple, rebeccapurple, rosybrown, royalblue, - saddlebrown, salmon, sandybrown, seagreen, - seashell, sienna, silver, skyblue, - slateblue, slategrey, snow, springgreen, - steelblue, tan, teal, thistle, - tomato, turquoise, violet, wheat, - whitesmoke, yellowgreen; - - /** Attempts to look up a string in the list of known colour names, and return - the appropriate colour. - - A non-case-sensitive search is made of the list of predefined colours, and - if a match is found, that colour is returned. If no match is found, the - colour passed in as the defaultColour parameter is returned. - */ - static JUCE_API Colour findColourForName (const String& colourName, - Colour defaultColour); - -private: - //============================================================================== - // this isn't a class you should ever instantiate - it's just here for the - // static values in it. - Colours(); - - JUCE_DECLARE_NON_COPYABLE (Colours) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/colour/juce_FillType.cpp b/source/modules/juce_graphics/colour/juce_FillType.cpp deleted file mode 100644 index e0a0c191d..000000000 --- a/source/modules/juce_graphics/colour/juce_FillType.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -FillType::FillType() noexcept - : colour (0xff000000) -{ -} - -FillType::FillType (Colour c) noexcept - : colour (c) -{ -} - -FillType::FillType (const ColourGradient& gradient_) - : colour (0xff000000), gradient (new ColourGradient (gradient_)) -{ -} - -FillType::FillType (const Image& image_, const AffineTransform& transform_) noexcept - : colour (0xff000000), image (image_), transform (transform_) -{ -} - -FillType::FillType (const FillType& other) - : colour (other.colour), - gradient (other.gradient.createCopy()), - image (other.image), - transform (other.transform) -{ -} - -FillType& FillType::operator= (const FillType& other) -{ - if (this != &other) - { - colour = other.colour; - gradient = other.gradient.createCopy(); - image = other.image; - transform = other.transform; - } - - return *this; -} - -FillType::FillType (FillType&& other) noexcept - : colour (other.colour), - gradient (other.gradient.release()), - image (static_cast (other.image)), - transform (other.transform) -{ -} - -FillType& FillType::operator= (FillType&& other) noexcept -{ - jassert (this != &other); // hopefully the compiler should make this situation impossible! - - colour = other.colour; - gradient = other.gradient.release(); - image = static_cast (other.image); - transform = other.transform; - return *this; -} - -FillType::~FillType() noexcept -{ -} - -bool FillType::operator== (const FillType& other) const -{ - return colour == other.colour && image == other.image - && transform == other.transform - && (gradient == other.gradient - || (gradient != nullptr && other.gradient != nullptr && *gradient == *other.gradient)); -} - -bool FillType::operator!= (const FillType& other) const -{ - return ! operator== (other); -} - -void FillType::setColour (Colour newColour) noexcept -{ - gradient = nullptr; - image = Image(); - colour = newColour; -} - -void FillType::setGradient (const ColourGradient& newGradient) -{ - if (gradient != nullptr) - { - *gradient = newGradient; - } - else - { - image = Image(); - gradient = new ColourGradient (newGradient); - colour = Colours::black; - } -} - -void FillType::setTiledImage (const Image& image_, const AffineTransform& transform_) noexcept -{ - gradient = nullptr; - image = image_; - transform = transform_; - colour = Colours::black; -} - -void FillType::setOpacity (const float newOpacity) noexcept -{ - colour = colour.withAlpha (newOpacity); -} - -bool FillType::isInvisible() const noexcept -{ - return colour.isTransparent() || (gradient != nullptr && gradient->isInvisible()); -} - -FillType FillType::transformed (const AffineTransform& t) const -{ - FillType f (*this); - f.transform = f.transform.followedBy (t); - return f; -} - -} // namespace juce diff --git a/source/modules/juce_graphics/colour/juce_FillType.h b/source/modules/juce_graphics/colour/juce_FillType.h deleted file mode 100644 index be3e518a6..000000000 --- a/source/modules/juce_graphics/colour/juce_FillType.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Represents a colour or fill pattern to use for rendering paths. - - This is used by the Graphics and DrawablePath classes as a way to encapsulate - a brush type. It can either be a solid colour, a gradient, or a tiled image. - - @see Graphics::setFillType, DrawablePath::setFill -*/ -class JUCE_API FillType -{ -public: - //============================================================================== - /** Creates a default fill type, of solid black. */ - FillType() noexcept; - - /** Creates a fill type of a solid colour. - @see setColour - */ - FillType (Colour colour) noexcept; - - /** Creates a gradient fill type. - @see setGradient - */ - FillType (const ColourGradient& gradient); - - /** Creates a tiled image fill type. The transform allows you to set the scaling, offset - and rotation of the pattern. - @see setTiledImage - */ - FillType (const Image& image, const AffineTransform& transform) noexcept; - - /** Creates a copy of another FillType. */ - FillType (const FillType&); - - /** Makes a copy of another FillType. */ - FillType& operator= (const FillType&); - - /** Move constructor */ - FillType (FillType&&) noexcept; - - /** Move assignment operator */ - FillType& operator= (FillType&&) noexcept; - - /** Destructor. */ - ~FillType() noexcept; - - //============================================================================== - /** Returns true if this is a solid colour fill, and not a gradient or image. */ - bool isColour() const noexcept { return gradient == nullptr && image.isNull(); } - - /** Returns true if this is a gradient fill. */ - bool isGradient() const noexcept { return gradient != nullptr; } - - /** Returns true if this is a tiled image pattern fill. */ - bool isTiledImage() const noexcept { return image.isValid(); } - - /** Turns this object into a solid colour fill. - If the object was an image or gradient, those fields will no longer be valid. */ - void setColour (Colour newColour) noexcept; - - /** Turns this object into a gradient fill. */ - void setGradient (const ColourGradient& newGradient); - - /** Turns this object into a tiled image fill type. The transform allows you to set - the scaling, offset and rotation of the pattern. - */ - void setTiledImage (const Image& image, const AffineTransform& transform) noexcept; - - /** Changes the opacity that should be used. - If the fill is a solid colour, this just changes the opacity of that colour. For - gradients and image tiles, it changes the opacity that will be used for them. - */ - void setOpacity (float newOpacity) noexcept; - - /** Returns the current opacity to be applied to the colour, gradient, or image. - @see setOpacity - */ - float getOpacity() const noexcept { return colour.getFloatAlpha(); } - - /** Returns true if this fill type is completely transparent. */ - bool isInvisible() const noexcept; - - /** Returns a copy of this fill, adding the specified transform applied to the - existing transform. - */ - FillType transformed (const AffineTransform& transform) const; - - //============================================================================== - /** The solid colour being used. - - If the fill type is not a solid colour, the alpha channel of this colour indicates - the opacity that should be used for the fill, and the RGB channels are ignored. - */ - Colour colour; - - /** Returns the gradient that should be used for filling. - This will be zero if the object is some other type of fill. - If a gradient is active, the overall opacity with which it should be applied - is indicated by the alpha channel of the colour variable. - */ - ScopedPointer gradient; - - /** The image that should be used for tiling. - If an image fill is active, the overall opacity with which it should be applied - is indicated by the alpha channel of the colour variable. - */ - Image image; - - /** The transform that should be applied to the image or gradient that's being drawn. */ - AffineTransform transform; - - //============================================================================== - bool operator== (const FillType&) const; - bool operator!= (const FillType&) const; - -private: - JUCE_LEAK_DETECTOR (FillType) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/colour/juce_PixelFormats.h b/source/modules/juce_graphics/colour/juce_PixelFormats.h deleted file mode 100644 index cb0867cfd..000000000 --- a/source/modules/juce_graphics/colour/juce_PixelFormats.h +++ /dev/null @@ -1,757 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -#if JUCE_MSVC - #pragma pack (push, 1) -#endif - -class PixelRGB; -class PixelAlpha; - -inline uint32 maskPixelComponents (uint32 x) noexcept -{ - return (x >> 8) & 0x00ff00ff; -} - -inline uint32 clampPixelComponents (uint32 x) noexcept -{ - return (x | (0x01000100 - maskPixelComponents (x))) & 0x00ff00ff; -} - -//============================================================================== -/** - Represents a 32-bit INTERNAL pixel with premultiplied alpha, and can perform compositing - operations with it. - - This is used internally by the imaging classes. - - @see PixelRGB -*/ -class JUCE_API PixelARGB -{ -public: - /** Creates a pixel without defining its colour. */ - PixelARGB() noexcept {} - ~PixelARGB() noexcept {} - - PixelARGB (const uint8 a, const uint8 r, const uint8 g, const uint8 b) noexcept - { - components.b = b; - components.g = g; - components.r = r; - components.a = a; - } - - //============================================================================== - /** Returns a uint32 which represents the pixel in a platform dependent format. */ - forcedinline uint32 getNativeARGB() const noexcept { return internal; } - - /** Returns a uint32 which will be in argb order as if constructed with the following mask operation - ((alpha << 24) | (red << 16) | (green << 8) | blue). */ - forcedinline uint32 getInARGBMaskOrder() const noexcept - { - #if JUCE_ANDROID - return (uint32) ((components.a << 24) | (components.r << 16) | (components.g << 8) | (components.b << 0)); - #else - return getNativeARGB(); - #endif - } - - /** Returns a uint32 which when written to memory, will be in the order a, r, g, b. In other words, - if the return-value is read as a uint8 array then the elements will be in the order of a, r, g, b*/ - inline uint32 getInARGBMemoryOrder() const noexcept - { - #if JUCE_BIG_ENDIAN - return getInARGBMaskOrder(); - #else - return (uint32) ((components.b << 24) | (components.g << 16) | (components.r << 8) | components.a); - #endif - } - - /** Return channels with an even index and insert zero bytes between them. This is useful for blending - operations. The exact channels which are returned is platform dependent. */ - forcedinline uint32 getEvenBytes() const noexcept { return 0x00ff00ff & internal; } - - /** Return channels with an odd index and insert zero bytes between them. This is useful for blending - operations. The exact channels which are returned is platform dependent. */ - forcedinline uint32 getOddBytes() const noexcept { return 0x00ff00ff & (internal >> 8); } - - //============================================================================== - forcedinline uint8 getAlpha() const noexcept { return components.a; } - forcedinline uint8 getRed() const noexcept { return components.r; } - forcedinline uint8 getGreen() const noexcept { return components.g; } - forcedinline uint8 getBlue() const noexcept { return components.b; } - - #if JUCE_GCC - // NB these are here as a workaround because GCC refuses to bind to packed values. - forcedinline uint8& getAlpha() noexcept { return comps [indexA]; } - forcedinline uint8& getRed() noexcept { return comps [indexR]; } - forcedinline uint8& getGreen() noexcept { return comps [indexG]; } - forcedinline uint8& getBlue() noexcept { return comps [indexB]; } - #else - forcedinline uint8& getAlpha() noexcept { return components.a; } - forcedinline uint8& getRed() noexcept { return components.r; } - forcedinline uint8& getGreen() noexcept { return components.g; } - forcedinline uint8& getBlue() noexcept { return components.b; } - #endif - - //============================================================================== - /** Copies another pixel colour over this one. - - This doesn't blend it - this colour is simply replaced by the other one. - */ - template - forcedinline void set (const Pixel& src) noexcept - { - internal = src.getNativeARGB(); - } - - //============================================================================== - /** Sets the pixel's colour from individual components. */ - void setARGB (const uint8 a, const uint8 r, const uint8 g, const uint8 b) noexcept - { - components.b = b; - components.g = g; - components.r = r; - components.a = a; - } - - //============================================================================== - /** Blends another pixel onto this one. - - This takes into account the opacity of the pixel being overlaid, and blends - it accordingly. - */ - template - forcedinline void blend (const Pixel& src) noexcept - { - uint32 rb = src.getEvenBytes(); - uint32 ag = src.getOddBytes(); - - const uint32 alpha = 0x100 - (ag >> 16); - - rb += maskPixelComponents (getEvenBytes() * alpha); - ag += maskPixelComponents (getOddBytes() * alpha); - - internal = clampPixelComponents (rb) | (clampPixelComponents (ag) << 8); - } - - /** Blends another pixel onto this one. - - This takes into account the opacity of the pixel being overlaid, and blends - it accordingly. - */ - forcedinline void blend (const PixelRGB src) noexcept; - - - /** Blends another pixel onto this one, applying an extra multiplier to its opacity. - - The opacity of the pixel being overlaid is scaled by the extraAlpha factor before - being used, so this can blend semi-transparently from a PixelRGB argument. - */ - template - forcedinline void blend (const Pixel& src, uint32 extraAlpha) noexcept - { - uint32 rb = maskPixelComponents (extraAlpha * src.getEvenBytes()); - uint32 ag = maskPixelComponents (extraAlpha * src.getOddBytes()); - - const uint32 alpha = 0x100 - (ag >> 16); - - rb += maskPixelComponents (getEvenBytes() * alpha); - ag += maskPixelComponents (getOddBytes() * alpha); - - internal = clampPixelComponents (rb) | (clampPixelComponents (ag) << 8); - } - - /** Blends another pixel with this one, creating a colour that is somewhere - between the two, as specified by the amount. - */ - template - forcedinline void tween (const Pixel& src, const uint32 amount) noexcept - { - uint32 dEvenBytes = getEvenBytes(); - dEvenBytes += (((src.getEvenBytes() - dEvenBytes) * amount) >> 8); - dEvenBytes &= 0x00ff00ff; - - uint32 dOddBytes = getOddBytes(); - dOddBytes += (((src.getOddBytes() - dOddBytes) * amount) >> 8); - dOddBytes &= 0x00ff00ff; - dOddBytes <<= 8; - - dOddBytes |= dEvenBytes; - internal = dOddBytes; - } - - //============================================================================== - /** Replaces the colour's alpha value with another one. */ - forcedinline void setAlpha (const uint8 newAlpha) noexcept - { - components.a = newAlpha; - } - - /** Multiplies the colour's alpha value with another one. */ - forcedinline void multiplyAlpha (int multiplier) noexcept - { - // increment alpha by 1, so that if multiplier == 255 (full alpha), - // this function will not change the values. - ++multiplier; - - internal = ((((uint32) multiplier) * getOddBytes()) & 0xff00ff00) - | (((((uint32) multiplier) * getEvenBytes()) >> 8) & 0x00ff00ff); - } - - forcedinline void multiplyAlpha (const float multiplier) noexcept - { - multiplyAlpha ((int) (multiplier * 255.0f)); - } - - - inline PixelARGB getUnpremultiplied() const noexcept { PixelARGB p (internal); p.unpremultiply(); return p; } - - /** Premultiplies the pixel's RGB values by its alpha. */ - forcedinline void premultiply() noexcept - { - const uint32 alpha = components.a; - - if (alpha < 0xff) - { - if (alpha == 0) - { - components.b = 0; - components.g = 0; - components.r = 0; - } - else - { - components.b = (uint8) ((components.b * alpha + 0x7f) >> 8); - components.g = (uint8) ((components.g * alpha + 0x7f) >> 8); - components.r = (uint8) ((components.r * alpha + 0x7f) >> 8); - } - } - } - - /** Unpremultiplies the pixel's RGB values. */ - forcedinline void unpremultiply() noexcept - { - const uint32 alpha = components.a; - - if (alpha < 0xff) - { - if (alpha == 0) - { - components.b = 0; - components.g = 0; - components.r = 0; - } - else - { - components.b = (uint8) jmin ((uint32) 0xffu, (components.b * 0xffu) / alpha); - components.g = (uint8) jmin ((uint32) 0xffu, (components.g * 0xffu) / alpha); - components.r = (uint8) jmin ((uint32) 0xffu, (components.r * 0xffu) / alpha); - } - } - } - - forcedinline void desaturate() noexcept - { - if (components.a < 0xff && components.a > 0) - { - const int newUnpremultipliedLevel = (0xff * ((int) components.r + (int) components.g + (int) components.b) / (3 * components.a)); - - components.r = components.g = components.b - = (uint8) ((newUnpremultipliedLevel * components.a + 0x7f) >> 8); - } - else - { - components.r = components.g = components.b - = (uint8) (((int) components.r + (int) components.g + (int) components.b) / 3); - } - } - - //============================================================================== - /** The indexes of the different components in the byte layout of this type of colour. */ - #if JUCE_ANDROID - #if JUCE_BIG_ENDIAN - enum { indexA = 0, indexR = 3, indexG = 2, indexB = 1 }; - #else - enum { indexA = 3, indexR = 0, indexG = 1, indexB = 2 }; - #endif - #else - #if JUCE_BIG_ENDIAN - enum { indexA = 0, indexR = 1, indexG = 2, indexB = 3 }; - #else - enum { indexA = 3, indexR = 2, indexG = 1, indexB = 0 }; - #endif - #endif - -private: - //============================================================================== - PixelARGB (const uint32 internalValue) noexcept - : internal (internalValue) - { - } - - //============================================================================== - struct Components - { - #if JUCE_ANDROID - #if JUCE_BIG_ENDIAN - uint8 a, b, g, r; - #else - uint8 r, g, b, a; - #endif - #else - #if JUCE_BIG_ENDIAN - uint8 a, r, g, b; - #else - uint8 b, g, r, a; - #endif - #endif - } JUCE_PACKED; - - union - { - uint32 internal; - Components components; - #if JUCE_GCC - uint8 comps[4]; // helper struct needed because gcc does not allow references to packed union members - #endif - }; -} -#ifndef DOXYGEN - JUCE_PACKED -#endif -; - - -//============================================================================== -/** - Represents a 24-bit RGB pixel, and can perform compositing operations on it. - - This is used internally by the imaging classes. - - @see PixelARGB -*/ -class JUCE_API PixelRGB -{ -public: - /** Creates a pixel without defining its colour. */ - PixelRGB() noexcept {} - ~PixelRGB() noexcept {} - - //============================================================================== - /** Returns a uint32 which represents the pixel in a platform dependent format which is compatible - with the native format of a PixelARGB. - - @see PixelARGB::getNativeARGB */ - forcedinline uint32 getNativeARGB() const noexcept - { - #if JUCE_ANDROID - return (uint32) ((0xff << 24) | r | (g << 8) | (b << 16)); - #else - return (uint32) ((0xff << 24) | b | (g << 8) | (r << 16)); - #endif - } - - /** Returns a uint32 which will be in argb order as if constructed with the following mask operation - ((alpha << 24) | (red << 16) | (green << 8) | blue). */ - forcedinline uint32 getInARGBMaskOrder() const noexcept - { - #if JUCE_ANDROID - return (uint32) ((0xff << 24) | (r << 16) | (g << 8) | (b << 0)); - #else - return getNativeARGB(); - #endif - } - - /** Returns a uint32 which when written to memory, will be in the order a, r, g, b. In other words, - if the return-value is read as a uint8 array then the elements will be in the order of a, r, g, b*/ - inline uint32 getInARGBMemoryOrder() const noexcept - { - #if JUCE_BIG_ENDIAN - return getInARGBMaskOrder(); - #else - return (uint32) ((b << 24) | (g << 16) | (r << 8) | 0xff); - #endif - } - - /** Return channels with an even index and insert zero bytes between them. This is useful for blending - operations. The exact channels which are returned is platform dependent but compatible with the - return value of getEvenBytes of the PixelARGB class. - - @see PixelARGB::getEvenBytes */ - forcedinline uint32 getEvenBytes() const noexcept - { - #if JUCE_ANDROID - return (uint32) (r | (b << 16)); - #else - return (uint32) (b | (r << 16)); - #endif - } - - /** Return channels with an odd index and insert zero bytes between them. This is useful for blending - operations. The exact channels which are returned is platform dependent but compatible with the - return value of getOddBytes of the PixelARGB class. - - @see PixelARGB::getOddBytes */ - forcedinline uint32 getOddBytes() const noexcept { return (uint32)0xff0000 | g; } - - //============================================================================== - forcedinline uint8 getAlpha() const noexcept { return 0xff; } - forcedinline uint8 getRed() const noexcept { return r; } - forcedinline uint8 getGreen() const noexcept { return g; } - forcedinline uint8 getBlue() const noexcept { return b; } - - forcedinline uint8& getRed() noexcept { return r; } - forcedinline uint8& getGreen() noexcept { return g; } - forcedinline uint8& getBlue() noexcept { return b; } - - //============================================================================== - /** Copies another pixel colour over this one. - - This doesn't blend it - this colour is simply replaced by the other one. - Because PixelRGB has no alpha channel, any alpha value in the source pixel - is thrown away. - */ - template - forcedinline void set (const Pixel& src) noexcept - { - b = src.getBlue(); - g = src.getGreen(); - r = src.getRed(); - } - - /** Sets the pixel's colour from individual components. */ - void setARGB (const uint8, const uint8 red, const uint8 green, const uint8 blue) noexcept - { - r = red; - g = green; - b = blue; - } - - //============================================================================== - /** Blends another pixel onto this one. - - This takes into account the opacity of the pixel being overlaid, and blends - it accordingly. - */ - template - forcedinline void blend (const Pixel& src) noexcept - { - const uint32 alpha = (uint32) (0x100 - src.getAlpha()); - - // getEvenBytes returns 0x00rr00bb on non-android - uint32 rb = clampPixelComponents (src.getEvenBytes() + maskPixelComponents (getEvenBytes() * alpha)); - // getOddBytes returns 0x00aa00gg on non-android - uint32 ag = clampPixelComponents (src.getOddBytes() + ((g * alpha) >> 8)); - - g = (uint8) (ag & 0xff); - - #if JUCE_ANDROID - b = (uint8) (rb >> 16); - r = (uint8) (rb & 0xff); - #else - r = (uint8) (rb >> 16); - b = (uint8) (rb & 0xff); - #endif - } - - forcedinline void blend (const PixelRGB src) noexcept - { - set (src); - } - - /** Blends another pixel onto this one, applying an extra multiplier to its opacity. - - The opacity of the pixel being overlaid is scaled by the extraAlpha factor before - being used, so this can blend semi-transparently from a PixelRGB argument. - */ - template - forcedinline void blend (const Pixel& src, uint32 extraAlpha) noexcept - { - uint32 ag = maskPixelComponents (extraAlpha * src.getOddBytes()); - uint32 rb = maskPixelComponents (extraAlpha * src.getEvenBytes()); - - const uint32 alpha = 0x100 - (ag >> 16); - - ag = clampPixelComponents (ag + (g * alpha >> 8)); - rb = clampPixelComponents (rb + maskPixelComponents (getEvenBytes() * alpha)); - - g = (uint8) (ag & 0xff); - - #if JUCE_ANDROID - b = (uint8) (rb >> 16); - r = (uint8) (rb & 0xff); - #else - r = (uint8) (rb >> 16); - b = (uint8) (rb & 0xff); - #endif - } - - /** Blends another pixel with this one, creating a colour that is somewhere - between the two, as specified by the amount. - */ - template - forcedinline void tween (const Pixel& src, const uint32 amount) noexcept - { - uint32 dEvenBytes = getEvenBytes(); - dEvenBytes += (((src.getEvenBytes() - dEvenBytes) * amount) >> 8); - - uint32 dOddBytes = getOddBytes(); - dOddBytes += (((src.getOddBytes() - dOddBytes) * amount) >> 8); - - g = (uint8) (dOddBytes & 0xff); // dOddBytes = 0x00aa00gg - - #if JUCE_ANDROID - r = (uint8) (dEvenBytes & 0xff); // dEvenBytes = 0x00bb00rr - b = (uint8) (dEvenBytes >> 16); - #else - b = (uint8) (dEvenBytes & 0xff); // dEvenBytes = 0x00rr00bb - r = (uint8) (dEvenBytes >> 16); - #endif - } - - //============================================================================== - /** This method is included for compatibility with the PixelARGB class. */ - forcedinline void setAlpha (const uint8) noexcept {} - - /** Multiplies the colour's alpha value with another one. */ - forcedinline void multiplyAlpha (int) noexcept {} - - /** Multiplies the colour's alpha value with another one. */ - forcedinline void multiplyAlpha (float) noexcept {} - - /** Premultiplies the pixel's RGB values by its alpha. */ - forcedinline void premultiply() noexcept {} - - /** Unpremultiplies the pixel's RGB values. */ - forcedinline void unpremultiply() noexcept {} - - forcedinline void desaturate() noexcept - { - r = g = b = (uint8) (((int) r + (int) g + (int) b) / 3); - } - - //============================================================================== - /** The indexes of the different components in the byte layout of this type of colour. */ - #if JUCE_MAC - enum { indexR = 0, indexG = 1, indexB = 2 }; - #else - enum { indexR = 2, indexG = 1, indexB = 0 }; - #endif - -private: - //============================================================================== - PixelRGB (const uint32 internal) noexcept - { - #if JUCE_ANDROID - b = (uint8) (internal >> 16); - g = (uint8) (internal >> 8); - r = (uint8) (internal); - #else - r = (uint8) (internal >> 16); - g = (uint8) (internal >> 8); - b = (uint8) (internal); - #endif - } - - //============================================================================== - #if JUCE_MAC - uint8 r, g, b; - #else - uint8 b, g, r; - #endif - -} -#ifndef DOXYGEN - JUCE_PACKED -#endif -; - -forcedinline void PixelARGB::blend (const PixelRGB src) noexcept -{ - set (src); -} - -//============================================================================== -/** - Represents an 8-bit single-channel pixel, and can perform compositing operations on it. - - This is used internally by the imaging classes. - - @see PixelARGB, PixelRGB -*/ -class JUCE_API PixelAlpha -{ -public: - /** Creates a pixel without defining its colour. */ - PixelAlpha() noexcept {} - ~PixelAlpha() noexcept {} - - //============================================================================== - /** Returns a uint32 which represents the pixel in a platform dependent format which is compatible - with the native format of a PixelARGB. - - @see PixelARGB::getNativeARGB */ - forcedinline uint32 getNativeARGB() const noexcept { return (uint32) ((a << 24) | (a << 16) | (a << 8) | a); } - - /** Returns a uint32 which will be in argb order as if constructed with the following mask operation - ((alpha << 24) | (red << 16) | (green << 8) | blue). */ - forcedinline uint32 getInARGBMaskOrder() const noexcept { return getNativeARGB(); } - - /** Returns a uint32 which when written to memory, will be in the order a, r, g, b. In other words, - if the return-value is read as a uint8 array then the elements will be in the order of a, r, g, b*/ - inline uint32 getInARGBMemoryOrder() const noexcept { return getNativeARGB(); } - - /** Return channels with an even index and insert zero bytes between them. This is useful for blending - operations. The exact channels which are returned is platform dependent but compatible with the - return value of getEvenBytes of the PixelARGB class. - - @see PixelARGB::getEvenBytes */ - forcedinline uint32 getEvenBytes() const noexcept { return (uint32) ((a << 16) | a); } - - /** Return channels with an odd index and insert zero bytes between them. This is useful for blending - operations. The exact channels which are returned is platform dependent but compatible with the - return value of getOddBytes of the PixelARGB class. - - @see PixelARGB::getOddBytes */ - forcedinline uint32 getOddBytes() const noexcept { return (uint32) ((a << 16) | a); } - - //============================================================================== - forcedinline uint8 getAlpha() const noexcept { return a; } - forcedinline uint8& getAlpha() noexcept { return a; } - - forcedinline uint8 getRed() const noexcept { return 0; } - forcedinline uint8 getGreen() const noexcept { return 0; } - forcedinline uint8 getBlue() const noexcept { return 0; } - - //============================================================================== - /** Copies another pixel colour over this one. - - This doesn't blend it - this colour is simply replaced by the other one. - */ - template - forcedinline void set (const Pixel& src) noexcept - { - a = src.getAlpha(); - } - - /** Sets the pixel's colour from individual components. */ - forcedinline void setARGB (const uint8 a_, const uint8 /*r*/, const uint8 /*g*/, const uint8 /*b*/) noexcept - { - a = a_; - } - - //============================================================================== - /** Blends another pixel onto this one. - - This takes into account the opacity of the pixel being overlaid, and blends - it accordingly. - */ - template - forcedinline void blend (const Pixel& src) noexcept - { - const int srcA = src.getAlpha(); - a = (uint8) ((a * (0x100 - srcA) >> 8) + srcA); - } - - /** Blends another pixel onto this one, applying an extra multiplier to its opacity. - - The opacity of the pixel being overlaid is scaled by the extraAlpha factor before - being used, so this can blend semi-transparently from a PixelRGB argument. - */ - template - forcedinline void blend (const Pixel& src, uint32 extraAlpha) noexcept - { - ++extraAlpha; - const int srcAlpha = (int) ((extraAlpha * src.getAlpha()) >> 8); - a = (uint8) ((a * (0x100 - srcAlpha) >> 8) + srcAlpha); - } - - /** Blends another pixel with this one, creating a colour that is somewhere - between the two, as specified by the amount. - */ - template - forcedinline void tween (const Pixel& src, const uint32 amount) noexcept - { - a += ((src.getAlpha() - a) * amount) >> 8; - } - - //============================================================================== - /** Replaces the colour's alpha value with another one. */ - forcedinline void setAlpha (const uint8 newAlpha) noexcept - { - a = newAlpha; - } - - /** Multiplies the colour's alpha value with another one. */ - forcedinline void multiplyAlpha (int multiplier) noexcept - { - ++multiplier; - a = (uint8) ((a * multiplier) >> 8); - } - - forcedinline void multiplyAlpha (const float multiplier) noexcept - { - a = (uint8) (a * multiplier); - } - - /** Premultiplies the pixel's RGB values by its alpha. */ - forcedinline void premultiply() noexcept {} - - /** Unpremultiplies the pixel's RGB values. */ - forcedinline void unpremultiply() noexcept {} - - forcedinline void desaturate() noexcept {} - - //============================================================================== - /** The indexes of the different components in the byte layout of this type of colour. */ - enum { indexA = 0 }; - -private: - //============================================================================== - PixelAlpha (const uint32 internal) noexcept - { - a = (uint8) (internal >> 24); - } - - //============================================================================== - uint8 a; -} -#ifndef DOXYGEN - JUCE_PACKED -#endif -; - -#if JUCE_MSVC - #pragma pack (pop) -#endif - -} // namespace juce diff --git a/source/modules/juce_graphics/contexts/juce_GraphicsContext.cpp b/source/modules/juce_graphics/contexts/juce_GraphicsContext.cpp deleted file mode 100644 index c8df50d4b..000000000 --- a/source/modules/juce_graphics/contexts/juce_GraphicsContext.cpp +++ /dev/null @@ -1,699 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -namespace -{ - template - Rectangle coordsToRectangle (Type x, Type y, Type w, Type h) noexcept - { - #if JUCE_DEBUG - const int maxVal = 0x3fffffff; - - jassert ((int) x >= -maxVal && (int) x <= maxVal - && (int) y >= -maxVal && (int) y <= maxVal - && (int) w >= 0 && (int) w <= maxVal - && (int) h >= 0 && (int) h <= maxVal); - #endif - - return { x, y, w, h }; - } -} - -//============================================================================== -LowLevelGraphicsContext::LowLevelGraphicsContext() {} -LowLevelGraphicsContext::~LowLevelGraphicsContext() {} - -//============================================================================== -Graphics::Graphics (const Image& imageToDrawOnto) - : context (*imageToDrawOnto.createLowLevelContext()), - contextToDelete (&context) -{ - jassert (imageToDrawOnto.isValid()); // Can't draw into a null image! -} - -Graphics::Graphics (LowLevelGraphicsContext& internalContext) noexcept - : context (internalContext) -{ -} - -Graphics::~Graphics() -{ -} - -//============================================================================== -void Graphics::resetToDefaultState() -{ - saveStateIfPending(); - context.setFill (FillType()); - context.setFont (Font()); - context.setInterpolationQuality (Graphics::mediumResamplingQuality); -} - -bool Graphics::isVectorDevice() const -{ - return context.isVectorDevice(); -} - -bool Graphics::reduceClipRegion (Rectangle area) -{ - saveStateIfPending(); - return context.clipToRectangle (area); -} - -bool Graphics::reduceClipRegion (int x, int y, int w, int h) -{ - return reduceClipRegion (coordsToRectangle (x, y, w, h)); -} - -bool Graphics::reduceClipRegion (const RectangleList& clipRegion) -{ - saveStateIfPending(); - return context.clipToRectangleList (clipRegion); -} - -bool Graphics::reduceClipRegion (const Path& path, const AffineTransform& transform) -{ - saveStateIfPending(); - context.clipToPath (path, transform); - return ! context.isClipEmpty(); -} - -bool Graphics::reduceClipRegion (const Image& image, const AffineTransform& transform) -{ - saveStateIfPending(); - context.clipToImageAlpha (image, transform); - return ! context.isClipEmpty(); -} - -void Graphics::excludeClipRegion (Rectangle rectangleToExclude) -{ - saveStateIfPending(); - context.excludeClipRectangle (rectangleToExclude); -} - -bool Graphics::isClipEmpty() const -{ - return context.isClipEmpty(); -} - -Rectangle Graphics::getClipBounds() const -{ - return context.getClipBounds(); -} - -void Graphics::saveState() -{ - saveStateIfPending(); - saveStatePending = true; -} - -void Graphics::restoreState() -{ - if (saveStatePending) - saveStatePending = false; - else - context.restoreState(); -} - -void Graphics::saveStateIfPending() -{ - if (saveStatePending) - { - saveStatePending = false; - context.saveState(); - } -} - -void Graphics::setOrigin (Point newOrigin) -{ - saveStateIfPending(); - context.setOrigin (newOrigin); -} - -void Graphics::setOrigin (int x, int y) -{ - setOrigin ({ x, y }); -} - -void Graphics::addTransform (const AffineTransform& transform) -{ - saveStateIfPending(); - context.addTransform (transform); -} - -bool Graphics::clipRegionIntersects (Rectangle area) const -{ - return context.clipRegionIntersects (area); -} - -void Graphics::beginTransparencyLayer (float layerOpacity) -{ - saveStateIfPending(); - context.beginTransparencyLayer (layerOpacity); -} - -void Graphics::endTransparencyLayer() -{ - context.endTransparencyLayer(); -} - -//============================================================================== -void Graphics::setColour (Colour newColour) -{ - saveStateIfPending(); - context.setFill (newColour); -} - -void Graphics::setOpacity (const float newOpacity) -{ - saveStateIfPending(); - context.setOpacity (newOpacity); -} - -void Graphics::setGradientFill (const ColourGradient& gradient) -{ - setFillType (gradient); -} - -void Graphics::setTiledImageFill (const Image& imageToUse, const int anchorX, const int anchorY, const float opacity) -{ - saveStateIfPending(); - context.setFill (FillType (imageToUse, AffineTransform::translation ((float) anchorX, (float) anchorY))); - context.setOpacity (opacity); -} - -void Graphics::setFillType (const FillType& newFill) -{ - saveStateIfPending(); - context.setFill (newFill); -} - -//============================================================================== -void Graphics::setFont (const Font& newFont) -{ - saveStateIfPending(); - context.setFont (newFont); -} - -void Graphics::setFont (const float newFontHeight) -{ - setFont (context.getFont().withHeight (newFontHeight)); -} - -Font Graphics::getCurrentFont() const -{ - return context.getFont(); -} - -//============================================================================== -void Graphics::drawSingleLineText (const String& text, const int startX, const int baselineY, - Justification justification) const -{ - if (text.isNotEmpty()) - { - // Don't pass any vertical placement flags to this method - they'll be ignored. - jassert (justification.getOnlyVerticalFlags() == 0); - - auto flags = justification.getOnlyHorizontalFlags(); - - if (flags == Justification::right && startX < context.getClipBounds().getX()) - return; - - if (flags == Justification::left && startX > context.getClipBounds().getRight()) - return; - - GlyphArrangement arr; - arr.addLineOfText (context.getFont(), text, (float) startX, (float) baselineY); - - if (flags != Justification::left) - { - auto w = arr.getBoundingBox (0, -1, true).getWidth(); - - if ((flags & (Justification::horizontallyCentred | Justification::horizontallyJustified)) != 0) - w /= 2.0f; - - arr.draw (*this, AffineTransform::translation (-w, 0)); - } - else - { - arr.draw (*this); - } - } -} - -void Graphics::drawMultiLineText (const String& text, const int startX, - const int baselineY, const int maximumLineWidth) const -{ - if (text.isNotEmpty() - && startX < context.getClipBounds().getRight()) - { - GlyphArrangement arr; - arr.addJustifiedText (context.getFont(), text, - (float) startX, (float) baselineY, (float) maximumLineWidth, - Justification::left); - arr.draw (*this); - } -} - -void Graphics::drawText (const String& text, Rectangle area, - Justification justificationType, bool useEllipsesIfTooBig) const -{ - if (text.isNotEmpty() && context.clipRegionIntersects (area.getSmallestIntegerContainer())) - { - GlyphArrangement arr; - arr.addCurtailedLineOfText (context.getFont(), text, 0.0f, 0.0f, - area.getWidth(), useEllipsesIfTooBig); - - arr.justifyGlyphs (0, arr.getNumGlyphs(), - area.getX(), area.getY(), area.getWidth(), area.getHeight(), - justificationType); - arr.draw (*this); - } -} - -void Graphics::drawText (const String& text, Rectangle area, - Justification justificationType, bool useEllipsesIfTooBig) const -{ - drawText (text, area.toFloat(), justificationType, useEllipsesIfTooBig); -} - -void Graphics::drawText (const String& text, int x, int y, int width, int height, - Justification justificationType, const bool useEllipsesIfTooBig) const -{ - drawText (text, coordsToRectangle (x, y, width, height), justificationType, useEllipsesIfTooBig); -} - -void Graphics::drawFittedText (const String& text, Rectangle area, - Justification justification, - const int maximumNumberOfLines, - const float minimumHorizontalScale) const -{ - if (text.isNotEmpty() && (! area.isEmpty()) && context.clipRegionIntersects (area)) - { - GlyphArrangement arr; - arr.addFittedText (context.getFont(), text, - (float) area.getX(), (float) area.getY(), - (float) area.getWidth(), (float) area.getHeight(), - justification, - maximumNumberOfLines, - minimumHorizontalScale); - - arr.draw (*this); - } -} - -void Graphics::drawFittedText (const String& text, int x, int y, int width, int height, - Justification justification, - const int maximumNumberOfLines, - const float minimumHorizontalScale) const -{ - drawFittedText (text, coordsToRectangle (x, y, width, height), - justification, maximumNumberOfLines, minimumHorizontalScale); -} - -//============================================================================== -void Graphics::fillRect (Rectangle r) const -{ - context.fillRect (r, false); -} - -void Graphics::fillRect (Rectangle r) const -{ - context.fillRect (r); -} - -void Graphics::fillRect (int x, int y, int width, int height) const -{ - context.fillRect (coordsToRectangle (x, y, width, height), false); -} - -void Graphics::fillRect (float x, float y, float width, float height) const -{ - fillRect (coordsToRectangle (x, y, width, height)); -} - -void Graphics::fillRectList (const RectangleList& rectangles) const -{ - context.fillRectList (rectangles); -} - -void Graphics::fillRectList (const RectangleList& rects) const -{ - for (auto& r : rects) - context.fillRect (r, false); -} - -void Graphics::fillAll() const -{ - fillRect (context.getClipBounds()); -} - -void Graphics::fillAll (Colour colourToUse) const -{ - if (! colourToUse.isTransparent()) - { - auto clip = context.getClipBounds(); - - context.saveState(); - context.setFill (colourToUse); - context.fillRect (clip, false); - context.restoreState(); - } -} - - -//============================================================================== -void Graphics::fillPath (const Path& path) const -{ - if (! (context.isClipEmpty() || path.isEmpty())) - context.fillPath (path, AffineTransform()); -} - -void Graphics::fillPath (const Path& path, const AffineTransform& transform) const -{ - if (! (context.isClipEmpty() || path.isEmpty())) - context.fillPath (path, transform); -} - -void Graphics::strokePath (const Path& path, - const PathStrokeType& strokeType, - const AffineTransform& transform) const -{ - Path stroke; - strokeType.createStrokedPath (stroke, path, transform, context.getPhysicalPixelScaleFactor()); - fillPath (stroke); -} - -//============================================================================== -void Graphics::drawRect (float x, float y, float width, float height, float lineThickness) const -{ - drawRect (coordsToRectangle (x, y, width, height), lineThickness); -} - -void Graphics::drawRect (int x, int y, int width, int height, int lineThickness) const -{ - drawRect (coordsToRectangle (x, y, width, height), lineThickness); -} - -void Graphics::drawRect (Rectangle r, int lineThickness) const -{ - drawRect (r.toFloat(), (float) lineThickness); -} - -void Graphics::drawRect (Rectangle r, const float lineThickness) const -{ - jassert (r.getWidth() >= 0.0f && r.getHeight() >= 0.0f); - - RectangleList rects; - rects.addWithoutMerging (r.removeFromTop (lineThickness)); - rects.addWithoutMerging (r.removeFromBottom (lineThickness)); - rects.addWithoutMerging (r.removeFromLeft (lineThickness)); - rects.addWithoutMerging (r.removeFromRight (lineThickness)); - context.fillRectList (rects); -} - -//============================================================================== -void Graphics::fillEllipse (Rectangle area) const -{ - Path p; - p.addEllipse (area); - fillPath (p); -} - -void Graphics::fillEllipse (float x, float y, float w, float h) const -{ - fillEllipse (coordsToRectangle (x, y, w, h)); -} - -void Graphics::drawEllipse (float x, float y, float width, float height, float lineThickness) const -{ - drawEllipse (coordsToRectangle (x, y, width, height), lineThickness); -} - -void Graphics::drawEllipse (Rectangle area, float lineThickness) const -{ - Path p; - - if (area.getWidth() == area.getHeight()) - { - // For a circle, we can avoid having to generate a stroke - p.addEllipse (area.expanded (lineThickness * 0.5f)); - p.addEllipse (area.reduced (lineThickness * 0.5f)); - p.setUsingNonZeroWinding (false); - fillPath (p); - } - else - { - p.addEllipse (area); - strokePath (p, PathStrokeType (lineThickness)); - } -} - -void Graphics::fillRoundedRectangle (float x, float y, float width, float height, float cornerSize) const -{ - fillRoundedRectangle (coordsToRectangle (x, y, width, height), cornerSize); -} - -void Graphics::fillRoundedRectangle (Rectangle r, const float cornerSize) const -{ - Path p; - p.addRoundedRectangle (r, cornerSize); - fillPath (p); -} - -void Graphics::drawRoundedRectangle (float x, float y, float width, float height, - float cornerSize, float lineThickness) const -{ - drawRoundedRectangle (coordsToRectangle (x, y, width, height), cornerSize, lineThickness); -} - -void Graphics::drawRoundedRectangle (Rectangle r, float cornerSize, float lineThickness) const -{ - Path p; - p.addRoundedRectangle (r, cornerSize); - strokePath (p, PathStrokeType (lineThickness)); -} - -void Graphics::drawArrow (Line line, float lineThickness, float arrowheadWidth, float arrowheadLength) const -{ - Path p; - p.addArrow (line, lineThickness, arrowheadWidth, arrowheadLength); - fillPath (p); -} - -void Graphics::fillCheckerBoard (Rectangle area, - const int checkWidth, const int checkHeight, - Colour colour1, Colour colour2) const -{ - jassert (checkWidth > 0 && checkHeight > 0); // can't be zero or less! - - if (checkWidth > 0 && checkHeight > 0) - { - context.saveState(); - - if (colour1 == colour2) - { - context.setFill (colour1); - context.fillRect (area, false); - } - else - { - auto clipped = context.getClipBounds().getIntersection (area); - - if (! clipped.isEmpty()) - { - context.clipToRectangle (clipped); - - const int checkNumX = (clipped.getX() - area.getX()) / checkWidth; - const int checkNumY = (clipped.getY() - area.getY()) / checkHeight; - const int startX = area.getX() + checkNumX * checkWidth; - const int startY = area.getY() + checkNumY * checkHeight; - const int right = clipped.getRight(); - const int bottom = clipped.getBottom(); - - for (int i = 0; i < 2; ++i) - { - context.setFill (i == ((checkNumX ^ checkNumY) & 1) ? colour1 : colour2); - - int cy = i; - for (int y = startY; y < bottom; y += checkHeight) - for (int x = startX + (cy++ & 1) * checkWidth; x < right; x += checkWidth * 2) - context.fillRect (Rectangle (x, y, checkWidth, checkHeight), false); - } - } - } - - context.restoreState(); - } -} - -//============================================================================== -void Graphics::drawVerticalLine (const int x, float top, float bottom) const -{ - if (top < bottom) - context.fillRect (Rectangle ((float) x, top, 1.0f, bottom - top)); -} - -void Graphics::drawHorizontalLine (const int y, float left, float right) const -{ - if (left < right) - context.fillRect (Rectangle (left, (float) y, right - left, 1.0f)); -} - -void Graphics::drawLine (Line line) const -{ - context.drawLine (line); -} - -void Graphics::drawLine (float x1, float y1, float x2, float y2) const -{ - context.drawLine (Line (x1, y1, x2, y2)); -} - -void Graphics::drawLine (float x1, float y1, float x2, float y2, float lineThickness) const -{ - drawLine (Line (x1, y1, x2, y2), lineThickness); -} - -void Graphics::drawLine (Line line, const float lineThickness) const -{ - Path p; - p.addLineSegment (line, lineThickness); - fillPath (p); -} - -void Graphics::drawDashedLine (Line line, const float* dashLengths, - int numDashLengths, float lineThickness, int n) const -{ - jassert (n >= 0 && n < numDashLengths); // your start index must be valid! - - const Point delta ((line.getEnd() - line.getStart()).toDouble()); - const double totalLen = delta.getDistanceFromOrigin(); - - if (totalLen >= 0.1) - { - const double onePixAlpha = 1.0 / totalLen; - - for (double alpha = 0.0; alpha < 1.0;) - { - jassert (dashLengths[n] > 0); // can't have zero-length dashes! - - const double lastAlpha = alpha; - alpha += dashLengths [n] * onePixAlpha; - n = (n + 1) % numDashLengths; - - if ((n & 1) != 0) - { - const Line segment (line.getStart() + (delta * lastAlpha).toFloat(), - line.getStart() + (delta * jmin (1.0, alpha)).toFloat()); - - if (lineThickness != 1.0f) - drawLine (segment, lineThickness); - else - context.drawLine (segment); - } - } - } -} - -//============================================================================== -void Graphics::setImageResamplingQuality (const Graphics::ResamplingQuality newQuality) -{ - saveStateIfPending(); - context.setInterpolationQuality (newQuality); -} - -//============================================================================== -void Graphics::drawImageAt (const Image& imageToDraw, int x, int y, bool fillAlphaChannel) const -{ - drawImageTransformed (imageToDraw, - AffineTransform::translation ((float) x, (float) y), - fillAlphaChannel); -} - -void Graphics::drawImage (const Image& imageToDraw, Rectangle targetArea, - RectanglePlacement placementWithinTarget, bool fillAlphaChannelWithCurrentBrush) const -{ - if (imageToDraw.isValid()) - drawImageTransformed (imageToDraw, - placementWithinTarget.getTransformToFit (imageToDraw.getBounds().toFloat(), targetArea), - fillAlphaChannelWithCurrentBrush); -} - -void Graphics::drawImageWithin (const Image& imageToDraw, int dx, int dy, int dw, int dh, - RectanglePlacement placementWithinTarget, bool fillAlphaChannelWithCurrentBrush) const -{ - drawImage (imageToDraw, coordsToRectangle (dx, dy, dw, dh).toFloat(), - placementWithinTarget, fillAlphaChannelWithCurrentBrush); -} - -void Graphics::drawImage (const Image& imageToDraw, - int dx, int dy, int dw, int dh, - int sx, int sy, int sw, int sh, - const bool fillAlphaChannelWithCurrentBrush) const -{ - if (imageToDraw.isValid() && context.clipRegionIntersects (coordsToRectangle (dx, dy, dw, dh))) - drawImageTransformed (imageToDraw.getClippedImage (coordsToRectangle (sx, sy, sw, sh)), - AffineTransform::scale (dw / (float) sw, dh / (float) sh) - .translated ((float) dx, (float) dy), - fillAlphaChannelWithCurrentBrush); -} - -void Graphics::drawImageTransformed (const Image& imageToDraw, - const AffineTransform& transform, - const bool fillAlphaChannelWithCurrentBrush) const -{ - if (imageToDraw.isValid() && ! context.isClipEmpty()) - { - if (fillAlphaChannelWithCurrentBrush) - { - context.saveState(); - context.clipToImageAlpha (imageToDraw, transform); - fillAll(); - context.restoreState(); - } - else - { - context.drawImage (imageToDraw, transform); - } - } -} - -//============================================================================== -Graphics::ScopedSaveState::ScopedSaveState (Graphics& g) : context (g) -{ - context.saveState(); -} - -Graphics::ScopedSaveState::~ScopedSaveState() -{ - context.restoreState(); -} - -} // namespace juce diff --git a/source/modules/juce_graphics/contexts/juce_GraphicsContext.h b/source/modules/juce_graphics/contexts/juce_GraphicsContext.h deleted file mode 100644 index 8351003c0..000000000 --- a/source/modules/juce_graphics/contexts/juce_GraphicsContext.h +++ /dev/null @@ -1,746 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A graphics context, used for drawing a component or image. - - When a Component needs painting, a Graphics context is passed to its - Component::paint() method, and this you then call methods within this - object to actually draw the component's content. - - A Graphics can also be created from an image, to allow drawing directly onto - that image. - - @see Component::paint -*/ -class JUCE_API Graphics -{ -public: - //============================================================================== - /** Creates a Graphics object to draw directly onto the given image. - - The graphics object that is created will be set up to draw onto the image, - with the context's clipping area being the entire size of the image, and its - origin being the image's origin. To draw into a subsection of an image, use the - reduceClipRegion() and setOrigin() methods. - - Obviously you shouldn't delete the image before this context is deleted. - */ - explicit Graphics (const Image& imageToDrawOnto); - - /** Destructor. */ - ~Graphics(); - - //============================================================================== - /** Changes the current drawing colour. - - This sets the colour that will now be used for drawing operations - it also - sets the opacity to that of the colour passed-in. - - If a brush is being used when this method is called, the brush will be deselected, - and any subsequent drawing will be done with a solid colour brush instead. - - @see setOpacity - */ - void setColour (Colour newColour); - - /** Changes the opacity to use with the current colour. - - If a solid colour is being used for drawing, this changes its opacity - to this new value (i.e. it doesn't multiply the colour's opacity by this amount). - - If a gradient is being used, this will have no effect on it. - - A value of 0.0 is completely transparent, 1.0 is completely opaque. - */ - void setOpacity (float newOpacity); - - /** Sets the context to use a gradient for its fill pattern. - */ - void setGradientFill (const ColourGradient& gradient); - - /** Sets the context to use a tiled image pattern for filling. - Make sure that you don't delete this image while it's still being used by - this context! - */ - void setTiledImageFill (const Image& imageToUse, - int anchorX, int anchorY, - float opacity); - - /** Changes the current fill settings. - @see setColour, setGradientFill, setTiledImageFill - */ - void setFillType (const FillType& newFill); - - //============================================================================== - /** Changes the font to use for subsequent text-drawing functions. - @see drawSingleLineText, drawMultiLineText, drawText, drawFittedText - */ - void setFont (const Font& newFont); - - /** Changes the size of the currently-selected font. - This is a convenient shortcut that changes the context's current font to a - different size. The typeface won't be changed. - @see Font - */ - void setFont (float newFontHeight); - - /** Returns the currently selected font. */ - Font getCurrentFont() const; - - /** Draws a one-line text string. - - This will use the current colour (or brush) to fill the text. The font is the last - one specified by setFont(). - - @param text the string to draw - @param startX the position to draw the left-hand edge of the text - @param baselineY the position of the text's baseline - @param justification the horizontal flags indicate which end of the text string is - anchored at the specified point. - @see drawMultiLineText, drawText, drawFittedText, GlyphArrangement::addLineOfText - */ - void drawSingleLineText (const String& text, - int startX, int baselineY, - Justification justification = Justification::left) const; - - /** Draws text across multiple lines. - - This will break the text onto a new line where there's a new-line or - carriage-return character, or at a word-boundary when the text becomes wider - than the size specified by the maximumLineWidth parameter. - - @see setFont, drawSingleLineText, drawFittedText, GlyphArrangement::addJustifiedText - */ - void drawMultiLineText (const String& text, - int startX, int baselineY, - int maximumLineWidth) const; - - /** Draws a line of text within a specified rectangle. - - The text will be positioned within the rectangle based on the justification - flags passed-in. If the string is too long to fit inside the rectangle, it will - either be truncated or will have ellipsis added to its end (if the useEllipsesIfTooBig - flag is true). - - @see drawSingleLineText, drawFittedText, drawMultiLineText, GlyphArrangement::addJustifiedText - */ - void drawText (const String& text, - int x, int y, int width, int height, - Justification justificationType, - bool useEllipsesIfTooBig = true) const; - - /** Draws a line of text within a specified rectangle. - - The text will be positioned within the rectangle based on the justification - flags passed-in. If the string is too long to fit inside the rectangle, it will - either be truncated or will have ellipsis added to its end (if the useEllipsesIfTooBig - flag is true). - - @see drawSingleLineText, drawFittedText, drawMultiLineText, GlyphArrangement::addJustifiedText - */ - void drawText (const String& text, - Rectangle area, - Justification justificationType, - bool useEllipsesIfTooBig = true) const; - - /** Draws a line of text within a specified rectangle. - - The text will be positioned within the rectangle based on the justification - flags passed-in. If the string is too long to fit inside the rectangle, it will - either be truncated or will have ellipsis added to its end (if the useEllipsesIfTooBig - flag is true). - - @see drawSingleLineText, drawFittedText, drawMultiLineText, GlyphArrangement::addJustifiedText - */ - void drawText (const String& text, - Rectangle area, - Justification justificationType, - bool useEllipsesIfTooBig = true) const; - - /** Tries to draw a text string inside a given space. - - This does its best to make the given text readable within the specified rectangle, - so it useful for labelling things. - - If the text is too big, it'll be squashed horizontally or broken over multiple lines - if the maximumLinesToUse value allows this. If the text just won't fit into the space, - it'll cram as much as possible in there, and put some ellipsis at the end to show that - it's been truncated. - - A Justification parameter lets you specify how the text is laid out within the rectangle, - both horizontally and vertically. - - The minimumHorizontalScale parameter specifies how much the text can be squashed horizontally - to try to squeeze it into the space. If you don't want any horizontal scaling to occur, you - can set this value to 1.0f. Pass 0 if you want it to use a default value. - - @see GlyphArrangement::addFittedText - */ - void drawFittedText (const String& text, - int x, int y, int width, int height, - Justification justificationFlags, - int maximumNumberOfLines, - float minimumHorizontalScale = 0.0f) const; - - /** Tries to draw a text string inside a given space. - - This does its best to make the given text readable within the specified rectangle, - so it useful for labelling things. - - If the text is too big, it'll be squashed horizontally or broken over multiple lines - if the maximumLinesToUse value allows this. If the text just won't fit into the space, - it'll cram as much as possible in there, and put some ellipsis at the end to show that - it's been truncated. - - A Justification parameter lets you specify how the text is laid out within the rectangle, - both horizontally and vertically. - - The minimumHorizontalScale parameter specifies how much the text can be squashed horizontally - to try to squeeze it into the space. If you don't want any horizontal scaling to occur, you - can set this value to 1.0f. Pass 0 if you want it to use a default value. - - @see GlyphArrangement::addFittedText - */ - void drawFittedText (const String& text, - Rectangle area, - Justification justificationFlags, - int maximumNumberOfLines, - float minimumHorizontalScale = 0.0f) const; - - //============================================================================== - /** Fills the context's entire clip region with the current colour or brush. - - (See also the fillAll (Colour) method which is a quick way of filling - it with a given colour). - */ - void fillAll() const; - - /** Fills the context's entire clip region with a given colour. - - This leaves the context's current colour and brush unchanged, it just - uses the specified colour temporarily. - */ - void fillAll (Colour colourToUse) const; - - //============================================================================== - /** Fills a rectangle with the current colour or brush. - @see drawRect, fillRoundedRectangle - */ - void fillRect (Rectangle rectangle) const; - - /** Fills a rectangle with the current colour or brush. - @see drawRect, fillRoundedRectangle - */ - void fillRect (Rectangle rectangle) const; - - /** Fills a rectangle with the current colour or brush. - @see drawRect, fillRoundedRectangle - */ - void fillRect (int x, int y, int width, int height) const; - - /** Fills a rectangle with the current colour or brush. - @see drawRect, fillRoundedRectangle - */ - void fillRect (float x, float y, float width, float height) const; - - /** Fills a set of rectangles using the current colour or brush. - If you have a lot of rectangles to draw, it may be more efficient - to create a RectangleList and use this method than to call fillRect() - multiple times. - */ - void fillRectList (const RectangleList& rectangles) const; - - /** Fills a set of rectangles using the current colour or brush. - If you have a lot of rectangles to draw, it may be more efficient - to create a RectangleList and use this method than to call fillRect() - multiple times. - */ - void fillRectList (const RectangleList& rectangles) const; - - /** Uses the current colour or brush to fill a rectangle with rounded corners. - @see drawRoundedRectangle, Path::addRoundedRectangle - */ - void fillRoundedRectangle (float x, float y, float width, float height, - float cornerSize) const; - - /** Uses the current colour or brush to fill a rectangle with rounded corners. - @see drawRoundedRectangle, Path::addRoundedRectangle - */ - void fillRoundedRectangle (Rectangle rectangle, - float cornerSize) const; - - /** Fills a rectangle with a checkerboard pattern, alternating between two colours. */ - void fillCheckerBoard (Rectangle area, - int checkWidth, int checkHeight, - Colour colour1, Colour colour2) const; - - /** Draws a rectangular outline, using the current colour or brush. - The lines are drawn inside the given rectangle, and greater line thicknesses extend inwards. - @see fillRect - */ - void drawRect (int x, int y, int width, int height, int lineThickness = 1) const; - - /** Draws a rectangular outline, using the current colour or brush. - The lines are drawn inside the given rectangle, and greater line thicknesses extend inwards. - @see fillRect - */ - void drawRect (float x, float y, float width, float height, float lineThickness = 1.0f) const; - - /** Draws a rectangular outline, using the current colour or brush. - The lines are drawn inside the given rectangle, and greater line thicknesses extend inwards. - @see fillRect - */ - void drawRect (Rectangle rectangle, int lineThickness = 1) const; - - /** Draws a rectangular outline, using the current colour or brush. - The lines are drawn inside the given rectangle, and greater line thicknesses extend inwards. - @see fillRect - */ - void drawRect (Rectangle rectangle, float lineThickness = 1.0f) const; - - /** Uses the current colour or brush to draw the outline of a rectangle with rounded corners. - @see fillRoundedRectangle, Path::addRoundedRectangle - */ - void drawRoundedRectangle (float x, float y, float width, float height, - float cornerSize, float lineThickness) const; - - /** Uses the current colour or brush to draw the outline of a rectangle with rounded corners. - @see fillRoundedRectangle, Path::addRoundedRectangle - */ - void drawRoundedRectangle (Rectangle rectangle, - float cornerSize, float lineThickness) const; - - //============================================================================== - /** Fills an ellipse with the current colour or brush. - The ellipse is drawn to fit inside the given rectangle. - @see drawEllipse, Path::addEllipse - */ - void fillEllipse (float x, float y, float width, float height) const; - - /** Fills an ellipse with the current colour or brush. - The ellipse is drawn to fit inside the given rectangle. - @see drawEllipse, Path::addEllipse - */ - void fillEllipse (Rectangle area) const; - - /** Draws an elliptical stroke using the current colour or brush. - @see fillEllipse, Path::addEllipse - */ - void drawEllipse (float x, float y, float width, float height, - float lineThickness) const; - - /** Draws an elliptical stroke using the current colour or brush. - @see fillEllipse, Path::addEllipse - */ - void drawEllipse (Rectangle area, float lineThickness) const; - - //============================================================================== - /** Draws a line between two points. - The line is 1 pixel wide and drawn with the current colour or brush. - TIP: If you're trying to draw horizontal or vertical lines, don't use this - - it's better to use fillRect() instead unless you really need an angled line. - */ - void drawLine (float startX, float startY, float endX, float endY) const; - - /** Draws a line between two points with a given thickness. - TIP: If you're trying to draw horizontal or vertical lines, don't use this - - it's better to use fillRect() instead unless you really need an angled line. - @see Path::addLineSegment - */ - void drawLine (float startX, float startY, float endX, float endY, float lineThickness) const; - - /** Draws a line between two points. - The line is 1 pixel wide and drawn with the current colour or brush. - TIP: If you're trying to draw horizontal or vertical lines, don't use this - - it's better to use fillRect() instead unless you really need an angled line. - */ - void drawLine (Line line) const; - - /** Draws a line between two points with a given thickness. - @see Path::addLineSegment - TIP: If you're trying to draw horizontal or vertical lines, don't use this - - it's better to use fillRect() instead unless you really need an angled line. - */ - void drawLine (Line line, float lineThickness) const; - - /** Draws a dashed line using a custom set of dash-lengths. - - @param line the line to draw - @param dashLengths a series of lengths to specify the on/off lengths - e.g. - { 4, 5, 6, 7 } will draw a line of 4 pixels, skip 5 pixels, - draw 6 pixels, skip 7 pixels, and then repeat. - @param numDashLengths the number of elements in the array (this must be an even number). - @param lineThickness the thickness of the line to draw - @param dashIndexToStartFrom the index in the dash-length array to use for the first segment - @see PathStrokeType::createDashedStroke - */ - void drawDashedLine (Line line, - const float* dashLengths, int numDashLengths, - float lineThickness = 1.0f, - int dashIndexToStartFrom = 0) const; - - /** Draws a vertical line of pixels at a given x position. - - The x position is an integer, but the top and bottom of the line can be sub-pixel - positions, and these will be anti-aliased if necessary. - - The bottom parameter must be greater than or equal to the top parameter. - */ - void drawVerticalLine (int x, float top, float bottom) const; - - /** Draws a horizontal line of pixels at a given y position. - - The y position is an integer, but the left and right ends of the line can be sub-pixel - positions, and these will be anti-aliased if necessary. - - The right parameter must be greater than or equal to the left parameter. - */ - void drawHorizontalLine (int y, float left, float right) const; - - //============================================================================== - /** Fills a path using the currently selected colour or brush. */ - void fillPath (const Path& path) const; - - /** Fills a path using the currently selected colour or brush, and adds a transform. */ - void fillPath (const Path& path, const AffineTransform& transform) const; - - /** Draws a path's outline using the currently selected colour or brush. */ - void strokePath (const Path& path, - const PathStrokeType& strokeType, - const AffineTransform& transform = {}) const; - - /** Draws a line with an arrowhead at its end. - - @param line the line to draw - @param lineThickness the thickness of the line - @param arrowheadWidth the width of the arrow head (perpendicular to the line) - @param arrowheadLength the length of the arrow head (along the length of the line) - */ - void drawArrow (Line line, - float lineThickness, - float arrowheadWidth, - float arrowheadLength) const; - - - //============================================================================== - /** Types of rendering quality that can be specified when drawing images. - - @see Graphics::setImageResamplingQuality - */ - enum ResamplingQuality - { - lowResamplingQuality = 0, /**< Just uses a nearest-neighbour algorithm for resampling. */ - mediumResamplingQuality = 1, /**< Uses bilinear interpolation for upsampling and area-averaging for downsampling. */ - highResamplingQuality = 2, /**< Uses bicubic interpolation for upsampling and area-averaging for downsampling. */ - }; - - /** Changes the quality that will be used when resampling images. - By default a Graphics object will be set to mediumRenderingQuality. - @see Graphics::drawImage, Graphics::drawImageTransformed, Graphics::drawImageWithin - */ - void setImageResamplingQuality (const ResamplingQuality newQuality); - - /** Draws an image. - - This will draw the whole of an image, positioning its top-left corner at the - given coordinates, and keeping its size the same. This is the simplest image - drawing method - the others give more control over the scaling and clipping - of the images. - - Images are composited using the context's current opacity, so if you - don't want it to be drawn semi-transparently, be sure to call setOpacity (1.0f) - (or setColour() with an opaque colour) before drawing images. - */ - void drawImageAt (const Image& imageToDraw, int topLeftX, int topLeftY, - bool fillAlphaChannelWithCurrentBrush = false) const; - - /** Draws part of an image, rescaling it to fit in a given target region. - - The specified area of the source image is rescaled and drawn to fill the - specifed destination rectangle. - - Images are composited using the context's current opacity, so if you - don't want it to be drawn semi-transparently, be sure to call setOpacity (1.0f) - (or setColour() with an opaque colour) before drawing images. - - @param imageToDraw the image to overlay - @param destX the left of the destination rectangle - @param destY the top of the destination rectangle - @param destWidth the width of the destination rectangle - @param destHeight the height of the destination rectangle - @param sourceX the left of the rectangle to copy from the source image - @param sourceY the top of the rectangle to copy from the source image - @param sourceWidth the width of the rectangle to copy from the source image - @param sourceHeight the height of the rectangle to copy from the source image - @param fillAlphaChannelWithCurrentBrush if true, then instead of drawing the source image's pixels, - the source image's alpha channel is used as a mask with - which to fill the destination using the current colour - or brush. (If the source is has no alpha channel, then - it will just fill the target with a solid rectangle) - @see setImageResamplingQuality, drawImageAt, drawImageWithin, fillAlphaMap - */ - void drawImage (const Image& imageToDraw, - int destX, int destY, int destWidth, int destHeight, - int sourceX, int sourceY, int sourceWidth, int sourceHeight, - bool fillAlphaChannelWithCurrentBrush = false) const; - - /** Draws an image, having applied an affine transform to it. - - This lets you throw the image around in some wacky ways, rotate it, shear, - scale it, etc. - - Images are composited using the context's current opacity, so if you - don't want it to be drawn semi-transparently, be sure to call setOpacity (1.0f) - (or setColour() with an opaque colour) before drawing images. - - If fillAlphaChannelWithCurrentBrush is set to true, then the image's RGB channels - are ignored and it is filled with the current brush, masked by its alpha channel. - - If you want to render only a subsection of an image, use Image::getClippedImage() to - create the section that you need. - - @see setImageResamplingQuality, drawImage - */ - void drawImageTransformed (const Image& imageToDraw, - const AffineTransform& transform, - bool fillAlphaChannelWithCurrentBrush = false) const; - - /** Draws an image to fit within a designated rectangle. - - @param imageToDraw the source image to draw - @param targetArea the target rectangle to fit it into - @param placementWithinTarget this specifies how the image should be positioned - within the target rectangle - see the RectanglePlacement - class for more details about this. - @param fillAlphaChannelWithCurrentBrush if true, then instead of drawing the image, just its - alpha channel will be used as a mask with which to - draw with the current brush or colour. This is - similar to fillAlphaMap(), and see also drawImage() - @see drawImage, drawImageTransformed, drawImageAt, RectanglePlacement - */ - void drawImage (const Image& imageToDraw, Rectangle targetArea, - RectanglePlacement placementWithinTarget = RectanglePlacement::stretchToFit, - bool fillAlphaChannelWithCurrentBrush = false) const; - - /** Draws an image to fit within a designated rectangle. - - If the image is too big or too small for the space, it will be rescaled - to fit as nicely as it can do without affecting its aspect ratio. It will - then be placed within the target rectangle according to the justification flags - specified. - - @param imageToDraw the source image to draw - @param destX top-left of the target rectangle to fit it into - @param destY top-left of the target rectangle to fit it into - @param destWidth size of the target rectangle to fit the image into - @param destHeight size of the target rectangle to fit the image into - @param placementWithinTarget this specifies how the image should be positioned - within the target rectangle - see the RectanglePlacement - class for more details about this. - @param fillAlphaChannelWithCurrentBrush if true, then instead of drawing the image, just its - alpha channel will be used as a mask with which to - draw with the current brush or colour. This is - similar to fillAlphaMap(), and see also drawImage() - @see setImageResamplingQuality, drawImage, drawImageTransformed, drawImageAt, RectanglePlacement - */ - void drawImageWithin (const Image& imageToDraw, - int destX, int destY, int destWidth, int destHeight, - RectanglePlacement placementWithinTarget, - bool fillAlphaChannelWithCurrentBrush = false) const; - - //============================================================================== - /** Returns the position of the bounding box for the current clipping region. - @see getClipRegion, clipRegionIntersects - */ - Rectangle getClipBounds() const; - - /** Checks whether a rectangle overlaps the context's clipping region. - - If this returns false, no part of the given area can be drawn onto, so this - method can be used to optimise a component's paint() method, by letting it - avoid drawing complex objects that aren't within the region being repainted. - */ - bool clipRegionIntersects (Rectangle area) const; - - /** Intersects the current clipping region with another region. - - @returns true if the resulting clipping region is non-zero in size - @see setOrigin, clipRegionIntersects - */ - bool reduceClipRegion (int x, int y, int width, int height); - - /** Intersects the current clipping region with another region. - - @returns true if the resulting clipping region is non-zero in size - @see setOrigin, clipRegionIntersects - */ - bool reduceClipRegion (Rectangle area); - - /** Intersects the current clipping region with a rectangle list region. - - @returns true if the resulting clipping region is non-zero in size - @see setOrigin, clipRegionIntersects - */ - bool reduceClipRegion (const RectangleList& clipRegion); - - /** Intersects the current clipping region with a path. - - @returns true if the resulting clipping region is non-zero in size - @see reduceClipRegion - */ - bool reduceClipRegion (const Path& path, const AffineTransform& transform = AffineTransform()); - - /** Intersects the current clipping region with an image's alpha-channel. - - The current clipping path is intersected with the area covered by this image's - alpha-channel, after the image has been transformed by the specified matrix. - - @param image the image whose alpha-channel should be used. If the image doesn't - have an alpha-channel, it is treated as entirely opaque. - @param transform a matrix to apply to the image - @returns true if the resulting clipping region is non-zero in size - @see reduceClipRegion - */ - bool reduceClipRegion (const Image& image, const AffineTransform& transform); - - /** Excludes a rectangle to stop it being drawn into. */ - void excludeClipRegion (Rectangle rectangleToExclude); - - /** Returns true if no drawing can be done because the clip region is zero. */ - bool isClipEmpty() const; - - //============================================================================== - /** Saves the current graphics state on an internal stack. - To restore the state, use restoreState(). - @see ScopedSaveState - */ - void saveState(); - - /** Restores a graphics state that was previously saved with saveState(). - @see ScopedSaveState - */ - void restoreState(); - - /** Uses RAII to save and restore the state of a graphics context. - On construction, this calls Graphics::saveState(), and on destruction it calls - Graphics::restoreState() on the Graphics object that you supply. - */ - class ScopedSaveState - { - public: - ScopedSaveState (Graphics&); - ~ScopedSaveState(); - - private: - Graphics& context; - JUCE_DECLARE_NON_COPYABLE (ScopedSaveState) - }; - - //============================================================================== - /** Begins rendering to an off-screen bitmap which will later be flattened onto the current - context with the given opacity. - - The context uses an internal stack of temporary image layers to do this. When you've - finished drawing to the layer, call endTransparencyLayer() to complete the operation and - composite the finished layer. Every call to beginTransparencyLayer() MUST be matched - by a corresponding call to endTransparencyLayer()! - - This call also saves the current state, and endTransparencyLayer() restores it. - */ - void beginTransparencyLayer (float layerOpacity); - - /** Completes a drawing operation to a temporary semi-transparent buffer. - See beginTransparencyLayer() for more details. - */ - void endTransparencyLayer(); - - /** Moves the position of the context's origin. - - This changes the position that the context considers to be (0, 0) to - the specified position. - - So if you call setOrigin with (100, 100), then the position that was previously - referred to as (100, 100) will subsequently be considered to be (0, 0). - - @see reduceClipRegion, addTransform - */ - void setOrigin (Point newOrigin); - - /** Moves the position of the context's origin. - - This changes the position that the context considers to be (0, 0) to - the specified position. - - So if you call setOrigin (100, 100), then the position that was previously - referred to as (100, 100) will subsequently be considered to be (0, 0). - - @see reduceClipRegion, addTransform - */ - void setOrigin (int newOriginX, int newOriginY); - - /** Adds a transformation which will be performed on all the graphics operations that - the context subsequently performs. - - After calling this, all the coordinates that are passed into the context will be - transformed by this matrix. - - @see setOrigin - */ - void addTransform (const AffineTransform& transform); - - /** Resets the current colour, brush, and font to default settings. */ - void resetToDefaultState(); - - /** Returns true if this context is drawing to a vector-based device, such as a printer. */ - bool isVectorDevice() const; - - //============================================================================== - /** Create a graphics that draws with a given low-level renderer. - This method is intended for use only by people who know what they're doing. - Note that the LowLevelGraphicsContext will NOT be deleted by this object. - */ - Graphics (LowLevelGraphicsContext&) noexcept; - - /** @internal */ - LowLevelGraphicsContext& getInternalContext() const noexcept { return context; } - -private: - //============================================================================== - LowLevelGraphicsContext& context; - ScopedPointer contextToDelete; - - bool saveStatePending = false; - void saveStateIfPending(); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Graphics) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/contexts/juce_LowLevelGraphicsContext.h b/source/modules/juce_graphics/contexts/juce_LowLevelGraphicsContext.h deleted file mode 100644 index a9828e305..000000000 --- a/source/modules/juce_graphics/contexts/juce_LowLevelGraphicsContext.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Interface class for graphics context objects, used internally by the Graphics class. - - Users are not supposed to create instances of this class directly - do your drawing - via the Graphics object instead. - - It's a base class for different types of graphics context, that may perform software-based - or OS-accelerated rendering. - - E.g. the LowLevelGraphicsSoftwareRenderer renders onto an image in memory, but other - subclasses could render directly to a windows HDC, a Quartz context, or an OpenGL - context. -*/ -class JUCE_API LowLevelGraphicsContext -{ -protected: - //============================================================================== - LowLevelGraphicsContext(); - -public: - virtual ~LowLevelGraphicsContext(); - - /** Returns true if this device is vector-based, e.g. a printer. */ - virtual bool isVectorDevice() const = 0; - - //============================================================================== - /** Moves the origin to a new position. - - The coordinates are relative to the current origin, and indicate the new position - of (0, 0). - */ - virtual void setOrigin (Point) = 0; - virtual void addTransform (const AffineTransform&) = 0; - virtual float getPhysicalPixelScaleFactor() = 0; - - virtual bool clipToRectangle (const Rectangle&) = 0; - virtual bool clipToRectangleList (const RectangleList&) = 0; - virtual void excludeClipRectangle (const Rectangle&) = 0; - virtual void clipToPath (const Path&, const AffineTransform&) = 0; - virtual void clipToImageAlpha (const Image&, const AffineTransform&) = 0; - - virtual bool clipRegionIntersects (const Rectangle&) = 0; - virtual Rectangle getClipBounds() const = 0; - virtual bool isClipEmpty() const = 0; - - virtual void saveState() = 0; - virtual void restoreState() = 0; - - virtual void beginTransparencyLayer (float opacity) = 0; - virtual void endTransparencyLayer() = 0; - - //============================================================================== - virtual void setFill (const FillType&) = 0; - virtual void setOpacity (float) = 0; - virtual void setInterpolationQuality (Graphics::ResamplingQuality) = 0; - - //============================================================================== - virtual void fillRect (const Rectangle&, bool replaceExistingContents) = 0; - virtual void fillRect (const Rectangle&) = 0; - virtual void fillRectList (const RectangleList&) = 0; - virtual void fillPath (const Path&, const AffineTransform&) = 0; - virtual void drawImage (const Image&, const AffineTransform&) = 0; - virtual void drawLine (const Line&) = 0; - - virtual void setFont (const Font&) = 0; - virtual const Font& getFont() = 0; - virtual void drawGlyph (int glyphNumber, const AffineTransform&) = 0; - virtual bool drawTextLayout (const AttributedString&, const Rectangle&) { return false; } -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp b/source/modules/juce_graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp deleted file mode 100644 index 868ccf735..000000000 --- a/source/modules/juce_graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp +++ /dev/null @@ -1,540 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -// this will throw an assertion if you try to draw something that's not -// possible in postscript -#define WARN_ABOUT_NON_POSTSCRIPT_OPERATIONS 0 - -//============================================================================== -#if JUCE_DEBUG && WARN_ABOUT_NON_POSTSCRIPT_OPERATIONS - #define notPossibleInPostscriptAssert jassertfalse -#else - #define notPossibleInPostscriptAssert -#endif - -//============================================================================== -LowLevelGraphicsPostScriptRenderer::LowLevelGraphicsPostScriptRenderer (OutputStream& resultingPostScript, - const String& documentTitle, - const int totalWidth_, - const int totalHeight_) - : out (resultingPostScript), - totalWidth (totalWidth_), - totalHeight (totalHeight_), - needToClip (true) -{ - stateStack.add (new SavedState()); - stateStack.getLast()->clip = Rectangle (totalWidth_, totalHeight_); - - const float scale = jmin ((520.0f / totalWidth_), (750.0f / totalHeight)); - - out << "%!PS-Adobe-3.0 EPSF-3.0" - "\n%%BoundingBox: 0 0 600 824" - "\n%%Pages: 0" - "\n%%Creator: ROLI Ltd. JUCE" - "\n%%Title: " << documentTitle << - "\n%%CreationDate: none" - "\n%%LanguageLevel: 2" - "\n%%EndComments" - "\n%%BeginProlog" - "\n%%BeginResource: JRes" - "\n/bd {bind def} bind def" - "\n/c {setrgbcolor} bd" - "\n/m {moveto} bd" - "\n/l {lineto} bd" - "\n/rl {rlineto} bd" - "\n/ct {curveto} bd" - "\n/cp {closepath} bd" - "\n/pr {3 index 3 index moveto 1 index 0 rlineto 0 1 index rlineto pop neg 0 rlineto pop pop closepath} bd" - "\n/doclip {initclip newpath} bd" - "\n/endclip {clip newpath} bd" - "\n%%EndResource" - "\n%%EndProlog" - "\n%%BeginSetup" - "\n%%EndSetup" - "\n%%Page: 1 1" - "\n%%BeginPageSetup" - "\n%%EndPageSetup\n\n" - << "40 800 translate\n" - << scale << ' ' << scale << " scale\n\n"; -} - -LowLevelGraphicsPostScriptRenderer::~LowLevelGraphicsPostScriptRenderer() -{ -} - -//============================================================================== -bool LowLevelGraphicsPostScriptRenderer::isVectorDevice() const -{ - return true; -} - -void LowLevelGraphicsPostScriptRenderer::setOrigin (Point o) -{ - if (! o.isOrigin()) - { - stateStack.getLast()->xOffset += o.x; - stateStack.getLast()->yOffset += o.y; - needToClip = true; - } -} - -void LowLevelGraphicsPostScriptRenderer::addTransform (const AffineTransform& /*transform*/) -{ - //xxx - jassertfalse; -} - -float LowLevelGraphicsPostScriptRenderer::getPhysicalPixelScaleFactor() { return 1.0f; } - -bool LowLevelGraphicsPostScriptRenderer::clipToRectangle (const Rectangle& r) -{ - needToClip = true; - return stateStack.getLast()->clip.clipTo (r.translated (stateStack.getLast()->xOffset, stateStack.getLast()->yOffset)); -} - -bool LowLevelGraphicsPostScriptRenderer::clipToRectangleList (const RectangleList& clipRegion) -{ - needToClip = true; - return stateStack.getLast()->clip.clipTo (clipRegion); -} - -void LowLevelGraphicsPostScriptRenderer::excludeClipRectangle (const Rectangle& r) -{ - needToClip = true; - stateStack.getLast()->clip.subtract (r.translated (stateStack.getLast()->xOffset, stateStack.getLast()->yOffset)); -} - -void LowLevelGraphicsPostScriptRenderer::clipToPath (const Path& path, const AffineTransform& transform) -{ - writeClip(); - - Path p (path); - p.applyTransform (transform.translated ((float) stateStack.getLast()->xOffset, (float) stateStack.getLast()->yOffset)); - writePath (p); - out << "clip\n"; -} - -void LowLevelGraphicsPostScriptRenderer::clipToImageAlpha (const Image& /*sourceImage*/, const AffineTransform& /*transform*/) -{ - needToClip = true; - jassertfalse; // xxx -} - -bool LowLevelGraphicsPostScriptRenderer::clipRegionIntersects (const Rectangle& r) -{ - return stateStack.getLast()->clip.intersectsRectangle (r.translated (stateStack.getLast()->xOffset, stateStack.getLast()->yOffset)); -} - -Rectangle LowLevelGraphicsPostScriptRenderer::getClipBounds() const -{ - return stateStack.getLast()->clip.getBounds().translated (-stateStack.getLast()->xOffset, - -stateStack.getLast()->yOffset); -} - -bool LowLevelGraphicsPostScriptRenderer::isClipEmpty() const -{ - return stateStack.getLast()->clip.isEmpty(); -} - -//============================================================================== -LowLevelGraphicsPostScriptRenderer::SavedState::SavedState() - : xOffset (0), - yOffset (0) -{ -} - -LowLevelGraphicsPostScriptRenderer::SavedState::~SavedState() -{ -} - -void LowLevelGraphicsPostScriptRenderer::saveState() -{ - stateStack.add (new SavedState (*stateStack.getLast())); -} - -void LowLevelGraphicsPostScriptRenderer::restoreState() -{ - jassert (stateStack.size() > 0); - - if (stateStack.size() > 0) - stateStack.removeLast(); -} - -void LowLevelGraphicsPostScriptRenderer::beginTransparencyLayer (float) -{ -} - -void LowLevelGraphicsPostScriptRenderer::endTransparencyLayer() -{ -} - -//============================================================================== -void LowLevelGraphicsPostScriptRenderer::writeClip() -{ - if (needToClip) - { - needToClip = false; - - out << "doclip "; - - int itemsOnLine = 0; - - for (auto& i : stateStack.getLast()->clip) - { - if (++itemsOnLine == 6) - { - itemsOnLine = 0; - out << '\n'; - } - - out << i.getX() << ' ' << -i.getY() << ' ' - << i.getWidth() << ' ' << -i.getHeight() << " pr "; - } - - out << "endclip\n"; - } -} - -void LowLevelGraphicsPostScriptRenderer::writeColour (Colour colour) -{ - Colour c (Colours::white.overlaidWith (colour)); - - if (lastColour != c) - { - lastColour = c; - - out << String (c.getFloatRed(), 3) << ' ' - << String (c.getFloatGreen(), 3) << ' ' - << String (c.getFloatBlue(), 3) << " c\n"; - } -} - -void LowLevelGraphicsPostScriptRenderer::writeXY (const float x, const float y) const -{ - out << String (x, 2) << ' ' - << String (-y, 2) << ' '; -} - -void LowLevelGraphicsPostScriptRenderer::writePath (const Path& path) const -{ - out << "newpath "; - - float lastX = 0.0f; - float lastY = 0.0f; - int itemsOnLine = 0; - - Path::Iterator i (path); - - while (i.next()) - { - if (++itemsOnLine == 4) - { - itemsOnLine = 0; - out << '\n'; - } - - switch (i.elementType) - { - case Path::Iterator::startNewSubPath: - writeXY (i.x1, i.y1); - lastX = i.x1; - lastY = i.y1; - out << "m "; - break; - - case Path::Iterator::lineTo: - writeXY (i.x1, i.y1); - lastX = i.x1; - lastY = i.y1; - out << "l "; - break; - - case Path::Iterator::quadraticTo: - { - const float cp1x = lastX + (i.x1 - lastX) * 2.0f / 3.0f; - const float cp1y = lastY + (i.y1 - lastY) * 2.0f / 3.0f; - const float cp2x = cp1x + (i.x2 - lastX) / 3.0f; - const float cp2y = cp1y + (i.y2 - lastY) / 3.0f; - - writeXY (cp1x, cp1y); - writeXY (cp2x, cp2y); - writeXY (i.x2, i.y2); - out << "ct "; - lastX = i.x2; - lastY = i.y2; - } - break; - - case Path::Iterator::cubicTo: - writeXY (i.x1, i.y1); - writeXY (i.x2, i.y2); - writeXY (i.x3, i.y3); - out << "ct "; - lastX = i.x3; - lastY = i.y3; - break; - - case Path::Iterator::closePath: - out << "cp "; - break; - - default: - jassertfalse; - break; - } - } - - out << '\n'; -} - -void LowLevelGraphicsPostScriptRenderer::writeTransform (const AffineTransform& trans) const -{ - out << "[ " - << trans.mat00 << ' ' - << trans.mat10 << ' ' - << trans.mat01 << ' ' - << trans.mat11 << ' ' - << trans.mat02 << ' ' - << trans.mat12 << " ] concat "; -} - -//============================================================================== -void LowLevelGraphicsPostScriptRenderer::setFill (const FillType& fillType) -{ - stateStack.getLast()->fillType = fillType; -} - -void LowLevelGraphicsPostScriptRenderer::setOpacity (float /*opacity*/) -{ -} - -void LowLevelGraphicsPostScriptRenderer::setInterpolationQuality (Graphics::ResamplingQuality /*quality*/) -{ -} - -//============================================================================== -void LowLevelGraphicsPostScriptRenderer::fillRect (const Rectangle& r, const bool /*replaceExistingContents*/) -{ - fillRect (r.toFloat()); -} - -void LowLevelGraphicsPostScriptRenderer::fillRect (const Rectangle& r) -{ - if (stateStack.getLast()->fillType.isColour()) - { - writeClip(); - writeColour (stateStack.getLast()->fillType.colour); - - Rectangle r2 (r.translated ((float) stateStack.getLast()->xOffset, - (float) stateStack.getLast()->yOffset)); - - out << r2.getX() << ' ' << -r2.getBottom() << ' ' << r2.getWidth() << ' ' << r2.getHeight() << " rectfill\n"; - } - else - { - Path p; - p.addRectangle (r); - fillPath (p, AffineTransform()); - } -} - -void LowLevelGraphicsPostScriptRenderer::fillRectList (const RectangleList& list) -{ - fillPath (list.toPath(), AffineTransform()); -} - -//============================================================================== -void LowLevelGraphicsPostScriptRenderer::fillPath (const Path& path, const AffineTransform& t) -{ - if (stateStack.getLast()->fillType.isColour()) - { - writeClip(); - - Path p (path); - p.applyTransform (t.translated ((float) stateStack.getLast()->xOffset, - (float) stateStack.getLast()->yOffset)); - writePath (p); - - writeColour (stateStack.getLast()->fillType.colour); - - out << "fill\n"; - } - else if (stateStack.getLast()->fillType.isGradient()) - { - // this doesn't work correctly yet - it could be improved to handle solid gradients, but - // postscript can't do semi-transparent ones. - notPossibleInPostscriptAssert; // you can disable this warning by setting the WARN_ABOUT_NON_POSTSCRIPT_OPERATIONS flag at the top of this file - - writeClip(); - out << "gsave "; - - { - Path p (path); - p.applyTransform (t.translated ((float) stateStack.getLast()->xOffset, (float) stateStack.getLast()->yOffset)); - writePath (p); - out << "clip\n"; - } - - const Rectangle bounds (stateStack.getLast()->clip.getBounds()); - - // ideally this would draw lots of lines or ellipses to approximate the gradient, but for the - // time-being, this just fills it with the average colour.. - writeColour (stateStack.getLast()->fillType.gradient->getColourAtPosition (0.5f)); - out << bounds.getX() << ' ' << -bounds.getBottom() << ' ' << bounds.getWidth() << ' ' << bounds.getHeight() << " rectfill\n"; - - out << "grestore\n"; - } -} - -//============================================================================== -void LowLevelGraphicsPostScriptRenderer::writeImage (const Image& im, - const int sx, const int sy, - const int maxW, const int maxH) const -{ - out << "{<\n"; - - const int w = jmin (maxW, im.getWidth()); - const int h = jmin (maxH, im.getHeight()); - - int charsOnLine = 0; - const Image::BitmapData srcData (im, 0, 0, w, h); - Colour pixel; - - for (int y = h; --y >= 0;) - { - for (int x = 0; x < w; ++x) - { - const uint8* pixelData = srcData.getPixelPointer (x, y); - - if (x >= sx && y >= sy) - { - if (im.isARGB()) - { - PixelARGB p (*(const PixelARGB*) pixelData); - p.unpremultiply(); - pixel = Colours::white.overlaidWith (Colour (p)); - } - else if (im.isRGB()) - { - pixel = Colour (*((const PixelRGB*) pixelData)); - } - else - { - pixel = Colour ((uint8) 0, (uint8) 0, (uint8) 0, *pixelData); - } - } - else - { - pixel = Colours::transparentWhite; - } - - const uint8 pixelValues[3] = { pixel.getRed(), pixel.getGreen(), pixel.getBlue() }; - - out << String::toHexString (pixelValues, 3, 0); - charsOnLine += 3; - - if (charsOnLine > 100) - { - out << '\n'; - charsOnLine = 0; - } - } - } - - out << "\n>}\n"; -} - -void LowLevelGraphicsPostScriptRenderer::drawImage (const Image& sourceImage, const AffineTransform& transform) -{ - const int w = sourceImage.getWidth(); - const int h = sourceImage.getHeight(); - - writeClip(); - - out << "gsave "; - writeTransform (transform.translated ((float) stateStack.getLast()->xOffset, (float) stateStack.getLast()->yOffset) - .scaled (1.0f, -1.0f)); - - RectangleList imageClip; - sourceImage.createSolidAreaMask (imageClip, 0.5f); - - out << "newpath "; - int itemsOnLine = 0; - - for (auto& i : imageClip) - { - if (++itemsOnLine == 6) - { - out << '\n'; - itemsOnLine = 0; - } - - out << i.getX() << ' ' << i.getY() << ' ' << i.getWidth() << ' ' << i.getHeight() << " pr "; - } - - out << " clip newpath\n"; - - out << w << ' ' << h << " scale\n"; - out << w << ' ' << h << " 8 [" << w << " 0 0 -" << h << ' ' << (int) 0 << ' ' << h << " ]\n"; - - writeImage (sourceImage, 0, 0, w, h); - - out << "false 3 colorimage grestore\n"; - needToClip = true; -} - - -//============================================================================== -void LowLevelGraphicsPostScriptRenderer::drawLine (const Line & line) -{ - Path p; - p.addLineSegment (line, 1.0f); - fillPath (p, AffineTransform()); -} - -//============================================================================== -void LowLevelGraphicsPostScriptRenderer::setFont (const Font& newFont) -{ - stateStack.getLast()->font = newFont; -} - -const Font& LowLevelGraphicsPostScriptRenderer::getFont() -{ - return stateStack.getLast()->font; -} - -void LowLevelGraphicsPostScriptRenderer::drawGlyph (int glyphNumber, const AffineTransform& transform) -{ - Path p; - Font& font = stateStack.getLast()->font; - font.getTypeface()->getOutlineForGlyph (glyphNumber, p); - fillPath (p, AffineTransform::scale (font.getHeight() * font.getHorizontalScale(), font.getHeight()).followedBy (transform)); -} - -} // namespace juce diff --git a/source/modules/juce_graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.h b/source/modules/juce_graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.h deleted file mode 100644 index 889702bca..000000000 --- a/source/modules/juce_graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - An implementation of LowLevelGraphicsContext that turns the drawing operations - into a PostScript document. - -*/ -class JUCE_API LowLevelGraphicsPostScriptRenderer : public LowLevelGraphicsContext -{ -public: - //============================================================================== - LowLevelGraphicsPostScriptRenderer (OutputStream& resultingPostScript, - const String& documentTitle, - int totalWidth, - int totalHeight); - - ~LowLevelGraphicsPostScriptRenderer(); - - //============================================================================== - bool isVectorDevice() const override; - void setOrigin (Point) override; - void addTransform (const AffineTransform&) override; - float getPhysicalPixelScaleFactor() override; - - bool clipToRectangle (const Rectangle&) override; - bool clipToRectangleList (const RectangleList&) override; - void excludeClipRectangle (const Rectangle&) override; - void clipToPath (const Path&, const AffineTransform&) override; - void clipToImageAlpha (const Image&, const AffineTransform&) override; - - void saveState() override; - void restoreState() override; - - void beginTransparencyLayer (float) override; - void endTransparencyLayer() override; - - bool clipRegionIntersects (const Rectangle&) override; - Rectangle getClipBounds() const override; - bool isClipEmpty() const override; - - //============================================================================== - void setFill (const FillType&) override; - void setOpacity (float) override; - void setInterpolationQuality (Graphics::ResamplingQuality) override; - - //============================================================================== - void fillRect (const Rectangle&, bool replaceExistingContents) override; - void fillRect (const Rectangle&) override; - void fillRectList (const RectangleList&) override; - void fillPath (const Path&, const AffineTransform&) override; - void drawImage (const Image&, const AffineTransform&) override; - void drawLine (const Line &) override; - - //============================================================================== - const Font& getFont() override; - void setFont (const Font&) override; - void drawGlyph (int glyphNumber, const AffineTransform&) override; - -protected: - //============================================================================== - OutputStream& out; - int totalWidth, totalHeight; - bool needToClip; - Colour lastColour; - - struct SavedState - { - SavedState(); - ~SavedState(); - - RectangleList clip; - int xOffset, yOffset; - FillType fillType; - Font font; - - private: - SavedState& operator= (const SavedState&); - }; - - OwnedArray stateStack; - - void writeClip(); - void writeColour (Colour colour); - void writePath (const Path&) const; - void writeXY (float x, float y) const; - void writeTransform (const AffineTransform&) const; - void writeImage (const Image&, int sx, int sy, int maxW, int maxH) const; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LowLevelGraphicsPostScriptRenderer) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp b/source/modules/juce_graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp deleted file mode 100644 index a32e90771..000000000 --- a/source/modules/juce_graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -LowLevelGraphicsSoftwareRenderer::LowLevelGraphicsSoftwareRenderer (const Image& image) - : RenderingHelpers::StackBasedLowLevelGraphicsContext - (new RenderingHelpers::SoftwareRendererSavedState (image, image.getBounds())) -{ -} - -LowLevelGraphicsSoftwareRenderer::LowLevelGraphicsSoftwareRenderer (const Image& image, Point origin, - const RectangleList& initialClip) - : RenderingHelpers::StackBasedLowLevelGraphicsContext - (new RenderingHelpers::SoftwareRendererSavedState (image, initialClip, origin)) -{ -} - -LowLevelGraphicsSoftwareRenderer::~LowLevelGraphicsSoftwareRenderer() {} - -} // namespace juce diff --git a/source/modules/juce_graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.h b/source/modules/juce_graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.h deleted file mode 100644 index 06ecca5e0..000000000 --- a/source/modules/juce_graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A lowest-common-denominator implementation of LowLevelGraphicsContext that does all - its rendering in memory. - - User code is not supposed to create instances of this class directly - do all your - rendering via the Graphics class instead. -*/ -class JUCE_API LowLevelGraphicsSoftwareRenderer : public RenderingHelpers::StackBasedLowLevelGraphicsContext -{ -public: - //============================================================================== - /** Creates a context to render into an image. */ - LowLevelGraphicsSoftwareRenderer (const Image& imageToRenderOnto); - - /** Creates a context to render into a clipped subsection of an image. */ - LowLevelGraphicsSoftwareRenderer (const Image& imageToRenderOnto, Point origin, - const RectangleList& initialClip); - - /** Destructor. */ - ~LowLevelGraphicsSoftwareRenderer(); - -private: - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LowLevelGraphicsSoftwareRenderer) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/effects/juce_DropShadowEffect.cpp b/source/modules/juce_graphics/effects/juce_DropShadowEffect.cpp deleted file mode 100644 index 6557c9dd8..000000000 --- a/source/modules/juce_graphics/effects/juce_DropShadowEffect.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -static inline void blurDataTriplets (uint8* d, int num, const int delta) noexcept -{ - uint32 last = d[0]; - d[0] = (uint8) ((d[0] + d[delta] + 1) / 3); - d += delta; - - num -= 2; - - do - { - const uint32 newLast = d[0]; - d[0] = (uint8) ((last + d[0] + d[delta] + 1) / 3); - d += delta; - last = newLast; - } - while (--num > 0); - - d[0] = (uint8) ((last + d[0] + 1) / 3); -} - -static void blurSingleChannelImage (uint8* const data, const int width, const int height, - const int lineStride, const int repetitions) noexcept -{ - jassert (width > 2 && height > 2); - - for (int y = 0; y < height; ++y) - for (int i = repetitions; --i >= 0;) - blurDataTriplets (data + lineStride * y, width, 1); - - for (int x = 0; x < width; ++x) - for (int i = repetitions; --i >= 0;) - blurDataTriplets (data + x, height, lineStride); -} - -static void blurSingleChannelImage (Image& image, int radius) -{ - const Image::BitmapData bm (image, Image::BitmapData::readWrite); - blurSingleChannelImage (bm.data, bm.width, bm.height, bm.lineStride, 2 * radius); -} - -//============================================================================== -DropShadow::DropShadow() noexcept - : colour (0x90000000), radius (4) -{ -} - -DropShadow::DropShadow (Colour shadowColour, const int r, Point o) noexcept - : colour (shadowColour), radius (r), offset (o) -{ - jassert (radius > 0); -} - -void DropShadow::drawForImage (Graphics& g, const Image& srcImage) const -{ - jassert (radius > 0); - - if (srcImage.isValid()) - { - Image shadowImage (srcImage.convertedToFormat (Image::SingleChannel)); - shadowImage.duplicateIfShared(); - - blurSingleChannelImage (shadowImage, radius); - - g.setColour (colour); - g.drawImageAt (shadowImage, offset.x, offset.y, true); - } -} - -void DropShadow::drawForPath (Graphics& g, const Path& path) const -{ - jassert (radius > 0); - - const Rectangle area ((path.getBounds().getSmallestIntegerContainer() + offset) - .expanded (radius + 1) - .getIntersection (g.getClipBounds().expanded (radius + 1))); - - if (area.getWidth() > 2 && area.getHeight() > 2) - { - Image renderedPath (Image::SingleChannel, area.getWidth(), area.getHeight(), true); - - { - Graphics g2 (renderedPath); - g2.setColour (Colours::white); - g2.fillPath (path, AffineTransform::translation ((float) (offset.x - area.getX()), - (float) (offset.y - area.getY()))); - } - - blurSingleChannelImage (renderedPath, radius); - - g.setColour (colour); - g.drawImageAt (renderedPath, area.getX(), area.getY(), true); - } -} - -static void drawShadowSection (Graphics& g, ColourGradient& cg, Rectangle area, - bool isCorner, float centreX, float centreY, float edgeX, float edgeY) -{ - cg.point1 = area.getRelativePoint (centreX, centreY); - cg.point2 = area.getRelativePoint (edgeX, edgeY); - cg.isRadial = isCorner; - - g.setGradientFill (cg); - g.fillRect (area); -} - -void DropShadow::drawForRectangle (Graphics& g, const Rectangle& targetArea) const -{ - ColourGradient cg (colour, 0, 0, colour.withAlpha (0.0f), 0, 0, false); - - for (float i = 0.05f; i < 1.0f; i += 0.1f) - cg.addColour (1.0 - i, colour.withMultipliedAlpha (i * i)); - - const float radiusInset = (radius + 1) / 2.0f; - const float expandedRadius = radius + radiusInset; - - const Rectangle area (targetArea.toFloat().reduced (radiusInset) + offset.toFloat()); - - Rectangle r (area.expanded (expandedRadius)); - Rectangle top (r.removeFromTop (expandedRadius)); - Rectangle bottom (r.removeFromBottom (expandedRadius)); - - drawShadowSection (g, cg, top.removeFromLeft (expandedRadius), true, 1.0f, 1.0f, 0, 1.0f); - drawShadowSection (g, cg, top.removeFromRight (expandedRadius), true, 0, 1.0f, 1.0f, 1.0f); - drawShadowSection (g, cg, top, false, 0, 1.0f, 0, 0); - - drawShadowSection (g, cg, bottom.removeFromLeft (expandedRadius), true, 1.0f, 0, 0, 0); - drawShadowSection (g, cg, bottom.removeFromRight (expandedRadius), true, 0, 0, 1.0f, 0); - drawShadowSection (g, cg, bottom, false, 0, 0, 0, 1.0f); - - drawShadowSection (g, cg, r.removeFromLeft (expandedRadius), false, 1.0f, 0, 0, 0); - drawShadowSection (g, cg, r.removeFromRight (expandedRadius), false, 0, 0, 1.0f, 0); - - g.setColour (colour); - g.fillRect (area); -} - -//============================================================================== -DropShadowEffect::DropShadowEffect() {} -DropShadowEffect::~DropShadowEffect() {} - -void DropShadowEffect::setShadowProperties (const DropShadow& newShadow) -{ - shadow = newShadow; -} - -void DropShadowEffect::applyEffect (Image& image, Graphics& g, float scaleFactor, float alpha) -{ - DropShadow s (shadow); - s.radius = roundToInt (s.radius * scaleFactor); - s.colour = s.colour.withMultipliedAlpha (alpha); - s.offset.x = roundToInt (s.offset.x * scaleFactor); - s.offset.y = roundToInt (s.offset.y * scaleFactor); - - s.drawForImage (g, image); - - g.setOpacity (alpha); - g.drawImageAt (image, 0, 0); -} - -} // namespace juce diff --git a/source/modules/juce_graphics/effects/juce_DropShadowEffect.h b/source/modules/juce_graphics/effects/juce_DropShadowEffect.h deleted file mode 100644 index 3de0f97a6..000000000 --- a/source/modules/juce_graphics/effects/juce_DropShadowEffect.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Defines a drop-shadow effect. -*/ -struct JUCE_API DropShadow -{ - /** Creates a default drop-shadow effect. */ - DropShadow() noexcept; - - /** Creates a drop-shadow object with the given parameters. */ - DropShadow (Colour shadowColour, int radius, Point offset) noexcept; - - /** Renders a drop-shadow based on the alpha-channel of the given image. */ - void drawForImage (Graphics& g, const Image& srcImage) const; - - /** Renders a drop-shadow based on the shape of a path. */ - void drawForPath (Graphics& g, const Path& path) const; - - /** Renders a drop-shadow for a rectangle. - Note that for speed, this approximates the shadow using gradients. - */ - void drawForRectangle (Graphics& g, const Rectangle& area) const; - - /** The colour with which to render the shadow. - In most cases you'll probably want to leave this as black with an alpha - value of around 0.5 - */ - Colour colour; - - /** The approximate spread of the shadow. */ - int radius; - - /** The offset of the shadow. */ - Point offset; -}; - -//============================================================================== -/** - An effect filter that adds a drop-shadow behind the image's content. - - (This will only work on images/components that aren't opaque, of course). - - When added to a component, this effect will draw a soft-edged - shadow based on what gets drawn inside it. The shadow will also - be applied to the component's children. - - For speed, this doesn't use a proper gaussian blur, but cheats by - using a simple bilinear filter. If you need a really high-quality - shadow, check out ImageConvolutionKernel::createGaussianBlur() - - @see Component::setComponentEffect -*/ -class JUCE_API DropShadowEffect : public ImageEffectFilter -{ -public: - //============================================================================== - /** Creates a default drop-shadow effect. - To customise the shadow's appearance, use the setShadowProperties() method. - */ - DropShadowEffect(); - - /** Destructor. */ - ~DropShadowEffect(); - - //============================================================================== - /** Sets up parameters affecting the shadow's appearance. */ - void setShadowProperties (const DropShadow& newShadow); - - //============================================================================== - /** @internal */ - void applyEffect (Image& sourceImage, Graphics& destContext, float scaleFactor, float alpha) override; - - -private: - //============================================================================== - DropShadow shadow; - - JUCE_LEAK_DETECTOR (DropShadowEffect) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/effects/juce_GlowEffect.cpp b/source/modules/juce_graphics/effects/juce_GlowEffect.cpp deleted file mode 100644 index 4e1ee32c5..000000000 --- a/source/modules/juce_graphics/effects/juce_GlowEffect.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -GlowEffect::GlowEffect() {} -GlowEffect::~GlowEffect() {} - -void GlowEffect::setGlowProperties (float newRadius, Colour newColour, Point pos) -{ - radius = newRadius; - colour = newColour; - offset = pos; -} - -void GlowEffect::applyEffect (Image& image, Graphics& g, float scaleFactor, float alpha) -{ - Image temp (image.getFormat(), image.getWidth(), image.getHeight(), true); - - ImageConvolutionKernel blurKernel (roundToInt (radius * scaleFactor * 2.0f)); - - blurKernel.createGaussianBlur (radius); - blurKernel.rescaleAllValues (radius); - - blurKernel.applyToImage (temp, image, image.getBounds()); - - g.setColour (colour.withMultipliedAlpha (alpha)); - g.drawImageAt (temp, offset.x, offset.y, true); - - g.setOpacity (alpha); - g.drawImageAt (image, offset.x, offset.y, false); -} - -} // namespace juce diff --git a/source/modules/juce_graphics/effects/juce_GlowEffect.h b/source/modules/juce_graphics/effects/juce_GlowEffect.h deleted file mode 100644 index 428ebad70..000000000 --- a/source/modules/juce_graphics/effects/juce_GlowEffect.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A component effect that adds a coloured blur around the component's contents. - - (This will only work on non-opaque components). - - @see Component::setComponentEffect, DropShadowEffect -*/ -class JUCE_API GlowEffect : public ImageEffectFilter -{ -public: - //============================================================================== - /** Creates a default 'glow' effect. - To customise its appearance, use the setGlowProperties() method. - */ - GlowEffect(); - - /** Destructor. */ - ~GlowEffect(); - - //============================================================================== - /** Sets the glow's radius and colour. - - The radius is how large the blur should be, and the colour is - used to render it (for a less intense glow, lower the colour's - opacity). - */ - void setGlowProperties (float newRadius, - Colour newColour, - Point offset = {}); - - - //============================================================================== - /** @internal */ - void applyEffect (Image&, Graphics&, float scaleFactor, float alpha) override; - -private: - //============================================================================== - float radius = 2.0f; - Colour colour { Colours::white }; - Point offset; - - JUCE_LEAK_DETECTOR (GlowEffect) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/effects/juce_ImageEffectFilter.h b/source/modules/juce_graphics/effects/juce_ImageEffectFilter.h deleted file mode 100644 index e06222d92..000000000 --- a/source/modules/juce_graphics/effects/juce_ImageEffectFilter.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A graphical effect filter that can be applied to components. - - An ImageEffectFilter can be applied to the image that a component - paints before it hits the screen. - - This is used for adding effects like shadows, blurs, etc. - - @see Component::setComponentEffect -*/ -class JUCE_API ImageEffectFilter -{ -public: - //============================================================================== - /** Overridden to render the effect. - - The implementation of this method must use the image that is passed in - as its source, and should render its output to the graphics context passed in. - - @param sourceImage the image that the source component has just rendered with - its paint() method. The image may or may not have an alpha - channel, depending on whether the component is opaque. - @param destContext the graphics context to use to draw the resultant image. - @param scaleFactor a scale factor that has been applied to the image - e.g. if - this is 2, then the image is actually scaled-up to twice the - original resolution - @param alpha the alpha with which to draw the resultant image to the - target context - */ - virtual void applyEffect (Image& sourceImage, - Graphics& destContext, - float scaleFactor, - float alpha) = 0; - - /** Destructor. */ - virtual ~ImageEffectFilter() {} - -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/fonts/juce_AttributedString.cpp b/source/modules/juce_graphics/fonts/juce_AttributedString.cpp deleted file mode 100644 index 000223d96..000000000 --- a/source/modules/juce_graphics/fonts/juce_AttributedString.cpp +++ /dev/null @@ -1,356 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -namespace -{ - int getLength (const Array& atts) noexcept - { - return atts.size() != 0 ? atts.getReference (atts.size() - 1).range.getEnd() : 0; - } - - void splitAttributeRanges (Array& atts, int position) - { - for (int i = atts.size(); --i >= 0;) - { - const AttributedString::Attribute& att = atts.getReference (i); - const int offset = position - att.range.getStart(); - - if (offset >= 0) - { - if (offset > 0 && position < att.range.getEnd()) - { - atts.insert (i + 1, att); - atts.getReference (i).range.setEnd (position); - atts.getReference (i + 1).range.setStart (position); - } - - break; - } - } - } - - Range splitAttributeRanges (Array& atts, Range newRange) - { - newRange = newRange.getIntersectionWith (Range (0, getLength (atts))); - - if (! newRange.isEmpty()) - { - splitAttributeRanges (atts, newRange.getStart()); - splitAttributeRanges (atts, newRange.getEnd()); - } - - return newRange; - } - - void mergeAdjacentRanges (Array& atts) - { - for (int i = atts.size() - 1; --i >= 0;) - { - AttributedString::Attribute& a1 = atts.getReference (i); - AttributedString::Attribute& a2 = atts.getReference (i + 1); - - if (a1.colour == a2.colour && a1.font == a2.font) - { - a1.range.setEnd (a2.range.getEnd()); - atts.remove (i + 1); - - if (i < atts.size() - 1) - ++i; - } - } - } - - void appendRange (Array& atts, - int length, const Font* f, const Colour* c) - { - if (atts.size() == 0) - { - atts.add (AttributedString::Attribute (Range (0, length), - f != nullptr ? *f : Font(), - c != nullptr ? *c : Colour (0xff000000))); - } - else - { - const int start = getLength (atts); - atts.add (AttributedString::Attribute (Range (start, start + length), - f != nullptr ? *f : atts.getReference (atts.size() - 1).font, - c != nullptr ? *c : atts.getReference (atts.size() - 1).colour)); - mergeAdjacentRanges (atts); - } - } - - void applyFontAndColour (Array& atts, - Range range, const Font* f, const Colour* c) - { - range = splitAttributeRanges (atts, range); - - for (int i = 0; i < atts.size(); ++i) - { - AttributedString::Attribute& att = atts.getReference (i); - - if (range.getStart() < att.range.getEnd()) - { - if (range.getEnd() <= att.range.getStart()) - break; - - if (c != nullptr) att.colour = *c; - if (f != nullptr) att.font = *f; - } - } - - mergeAdjacentRanges (atts); - } - - void truncate (Array& atts, int newLength) - { - splitAttributeRanges (atts, newLength); - - for (int i = atts.size(); --i >= 0;) - if (atts.getReference (i).range.getStart() >= newLength) - atts.remove (i); - } -} - -//============================================================================== -AttributedString::Attribute::Attribute() noexcept : colour (0xff000000) {} -AttributedString::Attribute::~Attribute() noexcept {} - -AttributedString::Attribute::Attribute (Attribute&& other) noexcept - : range (other.range), - font (static_cast (other.font)), - colour (other.colour) -{ -} - -AttributedString::Attribute& AttributedString::Attribute::operator= (Attribute&& other) noexcept -{ - range = other.range; - font = static_cast (other.font); - colour = other.colour; - return *this; -} - -AttributedString::Attribute::Attribute (const Attribute& other) noexcept - : range (other.range), - font (other.font), - colour (other.colour) -{ -} - -AttributedString::Attribute& AttributedString::Attribute::operator= (const Attribute& other) noexcept -{ - range = other.range; - font = other.font; - colour = other.colour; - return *this; -} - -AttributedString::Attribute::Attribute (Range r, const Font& f, Colour c) noexcept - : range (r), font (f), colour (c) -{ -} - -//============================================================================== -AttributedString::AttributedString() - : lineSpacing (0.0f), - justification (Justification::left), - wordWrap (AttributedString::byWord), - readingDirection (AttributedString::natural) -{ -} - -AttributedString::AttributedString (const String& newString) - : lineSpacing (0.0f), - justification (Justification::left), - wordWrap (AttributedString::byWord), - readingDirection (AttributedString::natural) -{ - setText (newString); -} - -AttributedString::AttributedString (const AttributedString& other) - : text (other.text), - lineSpacing (other.lineSpacing), - justification (other.justification), - wordWrap (other.wordWrap), - readingDirection (other.readingDirection), - attributes (other.attributes) -{ -} - -AttributedString& AttributedString::operator= (const AttributedString& other) -{ - if (this != &other) - { - text = other.text; - lineSpacing = other.lineSpacing; - justification = other.justification; - wordWrap = other.wordWrap; - readingDirection = other.readingDirection; - attributes = other.attributes; - } - - return *this; -} - -AttributedString::AttributedString (AttributedString&& other) noexcept - : text (static_cast (other.text)), - lineSpacing (other.lineSpacing), - justification (other.justification), - wordWrap (other.wordWrap), - readingDirection (other.readingDirection), - attributes (static_cast&&> (other.attributes)) -{ -} - -AttributedString& AttributedString::operator= (AttributedString&& other) noexcept -{ - text = static_cast (other.text); - lineSpacing = other.lineSpacing; - justification = other.justification; - wordWrap = other.wordWrap; - readingDirection = other.readingDirection; - attributes = static_cast&&> (other.attributes); - return *this; -} - -AttributedString::~AttributedString() noexcept {} - -void AttributedString::setText (const String& newText) -{ - const int newLength = newText.length(); - const int oldLength = getLength (attributes); - - if (newLength > oldLength) - appendRange (attributes, newLength - oldLength, nullptr, nullptr); - else if (newLength < oldLength) - truncate (attributes, newLength); - - text = newText; -} - -void AttributedString::append (const String& textToAppend) -{ - text += textToAppend; - appendRange (attributes, textToAppend.length(), nullptr, nullptr); -} - -void AttributedString::append (const String& textToAppend, const Font& font) -{ - text += textToAppend; - appendRange (attributes, textToAppend.length(), &font, nullptr); -} - -void AttributedString::append (const String& textToAppend, Colour colour) -{ - text += textToAppend; - appendRange (attributes, textToAppend.length(), nullptr, &colour); -} - -void AttributedString::append (const String& textToAppend, const Font& font, Colour colour) -{ - text += textToAppend; - appendRange (attributes, textToAppend.length(), &font, &colour); -} - -void AttributedString::append (const AttributedString& other) -{ - const int originalLength = getLength (attributes); - const int originalNumAtts = attributes.size(); - text += other.text; - attributes.addArray (other.attributes); - - for (int i = originalNumAtts; i < attributes.size(); ++i) - attributes.getReference (i).range += originalLength; - - mergeAdjacentRanges (attributes); -} - -void AttributedString::clear() -{ - text.clear(); - attributes.clear(); -} - -void AttributedString::setJustification (Justification newJustification) noexcept -{ - justification = newJustification; -} - -void AttributedString::setWordWrap (WordWrap newWordWrap) noexcept -{ - wordWrap = newWordWrap; -} - -void AttributedString::setReadingDirection (ReadingDirection newReadingDirection) noexcept -{ - readingDirection = newReadingDirection; -} - -void AttributedString::setLineSpacing (const float newLineSpacing) noexcept -{ - lineSpacing = newLineSpacing; -} - -void AttributedString::setColour (Range range, Colour colour) -{ - applyFontAndColour (attributes, range, nullptr, &colour); -} - -void AttributedString::setFont (Range range, const Font& font) -{ - applyFontAndColour (attributes, range, &font, nullptr); -} - -void AttributedString::setColour (Colour colour) -{ - setColour (Range (0, getLength (attributes)), colour); -} - -void AttributedString::setFont (const Font& font) -{ - setFont (Range (0, getLength (attributes)), font); -} - -void AttributedString::draw (Graphics& g, const Rectangle& area) const -{ - if (text.isNotEmpty() && g.clipRegionIntersects (area.getSmallestIntegerContainer())) - { - jassert (text.length() == getLength (attributes)); - - if (! g.getInternalContext().drawTextLayout (*this, area)) - { - TextLayout layout; - layout.createLayout (*this, area.getWidth()); - layout.draw (g, area); - } - } -} - -} // namespace juce diff --git a/source/modules/juce_graphics/fonts/juce_AttributedString.h b/source/modules/juce_graphics/fonts/juce_AttributedString.h deleted file mode 100644 index f0cac6a06..000000000 --- a/source/modules/juce_graphics/fonts/juce_AttributedString.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A text string with a set of colour/font settings that are associated with sub-ranges - of the text. - - An attributed string lets you create a string with varied fonts, colours, word-wrapping, - layout, etc., and draw it using AttributedString::draw(). - - @see TextLayout -*/ -class JUCE_API AttributedString -{ -public: - /** Creates an empty attributed string. */ - AttributedString(); - - /** Creates an attributed string with the given text. */ - explicit AttributedString (const String& text); - - AttributedString (const AttributedString&); - AttributedString& operator= (const AttributedString&); - AttributedString (AttributedString&&) noexcept; - AttributedString& operator= (AttributedString&&) noexcept; - - /** Destructor. */ - ~AttributedString() noexcept; - - //============================================================================== - /** Returns the complete text of this attributed string. */ - const String& getText() const noexcept { return text; } - - /** Replaces all the text. - This will change the text, but won't affect any of the colour or font attributes - that have been added. - */ - void setText (const String& newText); - - /** Appends some text (with a default font and colour). */ - void append (const String& textToAppend); - /** Appends some text, with a specified font, and the default colour (black). */ - void append (const String& textToAppend, const Font& font); - /** Appends some text, with a specified colour, and the default font. */ - void append (const String& textToAppend, Colour colour); - /** Appends some text, with a specified font and colour. */ - void append (const String& textToAppend, const Font& font, Colour colour); - - /** Appends another AttributedString to this one. - Note that this will only append the text, fonts, and colours - it won't copy any - other properties such as justification, line-spacing, etc from the other object. - */ - void append (const AttributedString& other); - - /** Resets the string, clearing all text and attributes. - Note that this won't affect global settings like the justification type, - word-wrap mode, etc. - */ - void clear(); - - //============================================================================== - /** Draws this string within the given area. - The layout of the string within the rectangle is controlled by the justification - value passed to setJustification(). - */ - void draw (Graphics& g, const Rectangle& area) const; - - //============================================================================== - /** Returns the justification that should be used for laying-out the text. - This may include both vertical and horizontal flags. - */ - Justification getJustification() const noexcept { return justification; } - - /** Sets the justification that should be used for laying-out the text. - This may include both vertical and horizontal flags. - */ - void setJustification (Justification newJustification) noexcept; - - //============================================================================== - /** Types of word-wrap behaviour. - @see getWordWrap, setWordWrap - */ - enum WordWrap - { - none, /**< No word-wrapping: lines extend indefinitely. */ - byWord, /**< Lines are wrapped on a word boundary. */ - byChar, /**< Lines are wrapped on a character boundary. */ - }; - - /** Returns the word-wrapping behaviour. */ - WordWrap getWordWrap() const noexcept { return wordWrap; } - - /** Sets the word-wrapping behaviour. */ - void setWordWrap (WordWrap newWordWrap) noexcept; - - //============================================================================== - /** Types of reading direction that can be used. - @see getReadingDirection, setReadingDirection - */ - enum ReadingDirection - { - natural, - leftToRight, - rightToLeft, - }; - - /** Returns the reading direction for the text. */ - ReadingDirection getReadingDirection() const noexcept { return readingDirection; } - - /** Sets the reading direction that should be used for the text. */ - void setReadingDirection (ReadingDirection newReadingDirection) noexcept; - - //============================================================================== - /** Returns the extra line-spacing distance. */ - float getLineSpacing() const noexcept { return lineSpacing; } - - /** Sets an extra line-spacing distance. */ - void setLineSpacing (float newLineSpacing) noexcept; - - //============================================================================== - /** An attribute that has been applied to a range of characters in an AttributedString. */ - class JUCE_API Attribute - { - public: - Attribute() noexcept; - ~Attribute() noexcept; - Attribute (const Attribute&) noexcept; - Attribute& operator= (const Attribute&) noexcept; - Attribute (Attribute&&) noexcept; - Attribute& operator= (Attribute&&) noexcept; - - /** Creates an attribute that specifies the font and colour for a range of characters. */ - Attribute (Range range, const Font& font, Colour colour) noexcept; - - /** The range of characters to which this attribute will be applied. */ - Range range; - - /** The font for this range of characters. */ - Font font; - - /** The colour for this range of characters. */ - Colour colour; - - private: - JUCE_LEAK_DETECTOR (Attribute) - }; - - /** Returns the number of attributes that have been added to this string. */ - int getNumAttributes() const noexcept { return attributes.size(); } - - /** Returns one of the string's attributes. - The index provided must be less than getNumAttributes(), and >= 0. - */ - const Attribute& getAttribute (int index) const noexcept { return attributes.getReference (index); } - - //============================================================================== - /** Adds a colour attribute for the specified range. */ - void setColour (Range range, Colour colour); - - /** Removes all existing colour attributes, and applies this colour to the whole string. */ - void setColour (Colour colour); - - /** Adds a font attribute for the specified range. */ - void setFont (Range range, const Font& font); - - /** Removes all existing font attributes, and applies this font to the whole string. */ - void setFont (const Font& font); - -private: - String text; - float lineSpacing; - Justification justification; - WordWrap wordWrap; - ReadingDirection readingDirection; - Array attributes; - - JUCE_LEAK_DETECTOR (AttributedString) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/fonts/juce_CustomTypeface.cpp b/source/modules/juce_graphics/fonts/juce_CustomTypeface.cpp deleted file mode 100644 index 5897a3753..000000000 --- a/source/modules/juce_graphics/fonts/juce_CustomTypeface.cpp +++ /dev/null @@ -1,413 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -class CustomTypeface::GlyphInfo -{ -public: - GlyphInfo (const juce_wchar c, const Path& p, const float w) noexcept - : character (c), path (p), width (w) - { - } - - struct KerningPair - { - juce_wchar character2; - float kerningAmount; - }; - - void addKerningPair (const juce_wchar subsequentCharacter, - const float extraKerningAmount) noexcept - { - KerningPair kp; - kp.character2 = subsequentCharacter; - kp.kerningAmount = extraKerningAmount; - kerningPairs.add (kp); - } - - float getHorizontalSpacing (const juce_wchar subsequentCharacter) const noexcept - { - if (subsequentCharacter != 0) - for (int i = kerningPairs.size(); --i >= 0;) - if (kerningPairs.getReference(i).character2 == subsequentCharacter) - return width + kerningPairs.getReference(i).kerningAmount; - - return width; - } - - const juce_wchar character; - const Path path; - float width; - Array kerningPairs; - -private: - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GlyphInfo) -}; - -//============================================================================== -namespace CustomTypefaceHelpers -{ - static juce_wchar readChar (InputStream& in) - { - uint32 n = (uint32) (uint16) in.readShort(); - - if (n >= 0xd800 && n <= 0xdfff) - { - const uint32 nextWord = (uint32) (uint16) in.readShort(); - jassert (nextWord >= 0xdc00); // illegal unicode character! - - n = 0x10000 + (((n - 0xd800) << 10) | (nextWord - 0xdc00)); - } - - return (juce_wchar) n; - } - - static void writeChar (OutputStream& out, juce_wchar charToWrite) - { - if (charToWrite >= 0x10000) - { - charToWrite -= 0x10000; - out.writeShort ((short) (uint16) (0xd800 + (charToWrite >> 10))); - out.writeShort ((short) (uint16) (0xdc00 + (charToWrite & 0x3ff))); - } - else - { - out.writeShort ((short) (uint16) charToWrite); - } - } -} - -//============================================================================== -CustomTypeface::CustomTypeface() - : Typeface (String(), String()) -{ - clear(); -} - -CustomTypeface::CustomTypeface (InputStream& serialisedTypefaceStream) - : Typeface (String(), String()) -{ - clear(); - - GZIPDecompressorInputStream gzin (serialisedTypefaceStream); - BufferedInputStream in (gzin, 32768); - - name = in.readString(); - - const bool isBold = in.readBool(); - const bool isItalic = in.readBool(); - style = FontStyleHelpers::getStyleName (isBold, isItalic); - - ascent = in.readFloat(); - defaultCharacter = CustomTypefaceHelpers::readChar (in); - - int numChars = in.readInt(); - - for (int i = 0; i < numChars; ++i) - { - const juce_wchar c = CustomTypefaceHelpers::readChar (in); - const float width = in.readFloat(); - - Path p; - p.loadPathFromStream (in); - addGlyph (c, p, width); - } - - const int numKerningPairs = in.readInt(); - - for (int i = 0; i < numKerningPairs; ++i) - { - const juce_wchar char1 = CustomTypefaceHelpers::readChar (in); - const juce_wchar char2 = CustomTypefaceHelpers::readChar (in); - - addKerningPair (char1, char2, in.readFloat()); - } -} - -CustomTypeface::~CustomTypeface() -{ -} - -//============================================================================== -void CustomTypeface::clear() -{ - defaultCharacter = 0; - ascent = 1.0f; - style = "Regular"; - zeromem (lookupTable, sizeof (lookupTable)); - glyphs.clear(); -} - -void CustomTypeface::setCharacteristics (const String& newName, const float newAscent, const bool isBold, - const bool isItalic, const juce_wchar newDefaultCharacter) noexcept -{ - name = newName; - defaultCharacter = newDefaultCharacter; - ascent = newAscent; - style = FontStyleHelpers::getStyleName (isBold, isItalic); -} - -void CustomTypeface::setCharacteristics (const String& newName, const String& newStyle, const float newAscent, - const juce_wchar newDefaultCharacter) noexcept -{ - name = newName; - style = newStyle; - defaultCharacter = newDefaultCharacter; - ascent = newAscent; -} - -void CustomTypeface::addGlyph (const juce_wchar character, const Path& path, const float width) noexcept -{ - // Check that you're not trying to add the same character twice.. - jassert (findGlyph (character, false) == nullptr); - - if (isPositiveAndBelow ((int) character, numElementsInArray (lookupTable))) - lookupTable [character] = (short) glyphs.size(); - - glyphs.add (new GlyphInfo (character, path, width)); -} - -void CustomTypeface::addKerningPair (const juce_wchar char1, const juce_wchar char2, const float extraAmount) noexcept -{ - if (extraAmount != 0.0f) - { - if (auto* g = findGlyph (char1, true)) - g->addKerningPair (char2, extraAmount); - else - jassertfalse; // can only add kerning pairs for characters that exist! - } -} - -CustomTypeface::GlyphInfo* CustomTypeface::findGlyph (const juce_wchar character, const bool loadIfNeeded) noexcept -{ - if (isPositiveAndBelow ((int) character, numElementsInArray (lookupTable)) && lookupTable [character] > 0) - return glyphs [(int) lookupTable [(int) character]]; - - for (int i = 0; i < glyphs.size(); ++i) - { - GlyphInfo* const g = glyphs.getUnchecked(i); - if (g->character == character) - return g; - } - - if (loadIfNeeded && loadGlyphIfPossible (character)) - return findGlyph (character, false); - - return nullptr; -} - -bool CustomTypeface::loadGlyphIfPossible (const juce_wchar /*characterNeeded*/) -{ - return false; -} - -void CustomTypeface::addGlyphsFromOtherTypeface (Typeface& typefaceToCopy, juce_wchar characterStartIndex, int numCharacters) noexcept -{ - setCharacteristics (name, style, typefaceToCopy.getAscent(), defaultCharacter); - - for (int i = 0; i < numCharacters; ++i) - { - const juce_wchar c = (juce_wchar) (characterStartIndex + static_cast (i)); - - Array glyphIndexes; - Array offsets; - typefaceToCopy.getGlyphPositions (String::charToString (c), glyphIndexes, offsets); - - const int glyphIndex = glyphIndexes.getFirst(); - - if (glyphIndex >= 0 && glyphIndexes.size() > 0) - { - const float glyphWidth = offsets[1]; - - Path p; - typefaceToCopy.getOutlineForGlyph (glyphIndex, p); - - addGlyph (c, p, glyphWidth); - - for (int j = glyphs.size() - 1; --j >= 0;) - { - const juce_wchar char2 = glyphs.getUnchecked (j)->character; - glyphIndexes.clearQuick(); - offsets.clearQuick(); - typefaceToCopy.getGlyphPositions (String::charToString (c) + String::charToString (char2), glyphIndexes, offsets); - - if (offsets.size() > 1) - addKerningPair (c, char2, offsets[1] - glyphWidth); - } - } - } -} - -bool CustomTypeface::writeToStream (OutputStream& outputStream) -{ - GZIPCompressorOutputStream out (&outputStream); - - out.writeString (name); - out.writeBool (FontStyleHelpers::isBold (style)); - out.writeBool (FontStyleHelpers::isItalic (style)); - out.writeFloat (ascent); - CustomTypefaceHelpers::writeChar (out, defaultCharacter); - out.writeInt (glyphs.size()); - - int numKerningPairs = 0; - - for (int i = 0; i < glyphs.size(); ++i) - { - const GlyphInfo* const g = glyphs.getUnchecked (i); - CustomTypefaceHelpers::writeChar (out, g->character); - out.writeFloat (g->width); - g->path.writePathToStream (out); - - numKerningPairs += g->kerningPairs.size(); - } - - out.writeInt (numKerningPairs); - - for (int i = 0; i < glyphs.size(); ++i) - { - const GlyphInfo* const g = glyphs.getUnchecked (i); - - for (int j = 0; j < g->kerningPairs.size(); ++j) - { - const GlyphInfo::KerningPair& p = g->kerningPairs.getReference (j); - CustomTypefaceHelpers::writeChar (out, g->character); - CustomTypefaceHelpers::writeChar (out, p.character2); - out.writeFloat (p.kerningAmount); - } - } - - return true; -} - -//============================================================================== -float CustomTypeface::getAscent() const { return ascent; } -float CustomTypeface::getDescent() const { return 1.0f - ascent; } -float CustomTypeface::getHeightToPointsFactor() const { return ascent; } - -float CustomTypeface::getStringWidth (const String& text) -{ - float x = 0; - - for (String::CharPointerType t (text.getCharPointer()); ! t.isEmpty();) - { - const juce_wchar c = t.getAndAdvance(); - - if (const GlyphInfo* const glyph = findGlyph (c, true)) - { - x += glyph->getHorizontalSpacing (*t); - } - else - { - const Typeface::Ptr fallbackTypeface (Typeface::getFallbackTypeface()); - - if (fallbackTypeface != nullptr && fallbackTypeface != this) - x += fallbackTypeface->getStringWidth (String::charToString (c)); - } - } - - return x; -} - -void CustomTypeface::getGlyphPositions (const String& text, Array & resultGlyphs, Array& xOffsets) -{ - xOffsets.add (0); - float x = 0; - - for (String::CharPointerType t (text.getCharPointer()); ! t.isEmpty();) - { - float width = 0.0f; - int glyphChar = 0; - - const juce_wchar c = t.getAndAdvance(); - - if (const GlyphInfo* const glyph = findGlyph (c, true)) - { - width = glyph->getHorizontalSpacing (*t); - glyphChar = (int) glyph->character; - } - else - { - const Typeface::Ptr fallbackTypeface (getFallbackTypeface()); - - if (fallbackTypeface != nullptr && fallbackTypeface != this) - { - Array subGlyphs; - Array subOffsets; - fallbackTypeface->getGlyphPositions (String::charToString (c), subGlyphs, subOffsets); - - if (subGlyphs.size() > 0) - { - glyphChar = subGlyphs.getFirst(); - width = subOffsets[1]; - } - } - } - - x += width; - resultGlyphs.add (glyphChar); - xOffsets.add (x); - } -} - -bool CustomTypeface::getOutlineForGlyph (int glyphNumber, Path& path) -{ - if (const GlyphInfo* const glyph = findGlyph ((juce_wchar) glyphNumber, true)) - { - path = glyph->path; - return true; - } - - const Typeface::Ptr fallbackTypeface (getFallbackTypeface()); - - if (fallbackTypeface != nullptr && fallbackTypeface != this) - return fallbackTypeface->getOutlineForGlyph (glyphNumber, path); - - return false; -} - -EdgeTable* CustomTypeface::getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight) -{ - if (const GlyphInfo* const glyph = findGlyph ((juce_wchar) glyphNumber, true)) - { - if (! glyph->path.isEmpty()) - return new EdgeTable (glyph->path.getBoundsTransformed (transform) - .getSmallestIntegerContainer().expanded (1, 0), - glyph->path, transform); - } - else - { - const Typeface::Ptr fallbackTypeface (getFallbackTypeface()); - - if (fallbackTypeface != nullptr && fallbackTypeface != this) - return fallbackTypeface->getEdgeTableForGlyph (glyphNumber, transform, fontHeight); - } - - return nullptr; -} - -} // namespace juce diff --git a/source/modules/juce_graphics/fonts/juce_CustomTypeface.h b/source/modules/juce_graphics/fonts/juce_CustomTypeface.h deleted file mode 100644 index 36dda6d5c..000000000 --- a/source/modules/juce_graphics/fonts/juce_CustomTypeface.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A typeface that can be populated with custom glyphs. - - You can create a CustomTypeface if you need one that contains your own glyphs, - or if you need to load a typeface from a Juce-formatted binary stream. - - If you want to create a copy of a native face, you can use addGlyphsFromOtherTypeface() - to copy glyphs into this face. - - NOTE! For most people this class is almost certainly NOT the right tool to use! - If what you want to do is to embed a font into your exe, then your best plan is - probably to embed your TTF/OTF font file into your binary using the Projucer, - and then call Typeface::createSystemTypefaceFor() to load it from memory. - - @see Typeface, Font -*/ -class JUCE_API CustomTypeface : public Typeface -{ -public: - //============================================================================== - /** Creates a new, empty typeface. */ - CustomTypeface(); - - /** Loads a typeface from a previously saved stream. - The stream must have been created by writeToStream(). - - NOTE! Since this class was written, support was added for loading real font files from - memory, so for most people, using Typeface::createSystemTypefaceFor() to load a real font - is more appropriate than using this class to store it in a proprietary format. - - @see writeToStream - */ - explicit CustomTypeface (InputStream& serialisedTypefaceStream); - - /** Destructor. */ - ~CustomTypeface(); - - //============================================================================== - /** Resets this typeface, deleting all its glyphs and settings. */ - void clear(); - - /** Sets the vital statistics for the typeface. - @param fontFamily the typeface's font family - @param ascent the ascent - this is normalised to a height of 1.0 and this is - the value that will be returned by Typeface::getAscent(). The - descent is assumed to be (1.0 - ascent) - @param isBold should be true if the typeface is bold - @param isItalic should be true if the typeface is italic - @param defaultCharacter the character to be used as a replacement if there's - no glyph available for the character that's being drawn - */ - void setCharacteristics (const String& fontFamily, float ascent, - bool isBold, bool isItalic, - juce_wchar defaultCharacter) noexcept; - - /** Sets the vital statistics for the typeface. - @param fontFamily the typeface's font family - @param fontStyle the typeface's font style - @param ascent the ascent - this is normalised to a height of 1.0 and this is - the value that will be returned by Typeface::getAscent(). The - descent is assumed to be (1.0 - ascent) - @param defaultCharacter the character to be used as a replacement if there's - no glyph available for the character that's being drawn - */ - void setCharacteristics (const String& fontFamily, const String& fontStyle, - float ascent, juce_wchar defaultCharacter) noexcept; - - /** Adds a glyph to the typeface. - - The path that is passed in is normalised so that the font height is 1.0, and its - origin is the anchor point of the character on its baseline. - - The width is the nominal width of the character, and any extra kerning values that - are specified will be added to this width. - */ - void addGlyph (juce_wchar character, const Path& path, float width) noexcept; - - /** Specifies an extra kerning amount to be used between a pair of characters. - The amount will be added to the nominal width of the first character when laying out a string. - */ - void addKerningPair (juce_wchar char1, juce_wchar char2, float extraAmount) noexcept; - - /** Adds a range of glyphs from another typeface. - This will attempt to pull in the paths and kerning information from another typeface and - add it to this one. - */ - void addGlyphsFromOtherTypeface (Typeface& typefaceToCopy, juce_wchar characterStartIndex, int numCharacters) noexcept; - - /** Saves this typeface as a Juce-formatted font file. - A CustomTypeface can be created to reload the data that is written - see the CustomTypeface - constructor. - - NOTE! Since this class was written, support was added for loading real font files from - memory, so for most people, using Typeface::createSystemTypefaceFor() to load a real font - is more appropriate than using this class to store it in a proprietary format. - */ - bool writeToStream (OutputStream& outputStream); - - //============================================================================== - // The following methods implement the basic Typeface behaviour. - float getAscent() const override; - float getDescent() const override; - float getHeightToPointsFactor() const override; - float getStringWidth (const String&) override; - void getGlyphPositions (const String&, Array & glyphs, Array& xOffsets) override; - bool getOutlineForGlyph (int glyphNumber, Path&) override; - EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform&, float fontHeight) override; - -protected: - //============================================================================== - juce_wchar defaultCharacter; - float ascent; - - //============================================================================== - /** If a subclass overrides this, it can load glyphs into the font on-demand. - When methods such as getGlyphPositions() or getOutlineForGlyph() are asked for a - particular character and there's no corresponding glyph, they'll call this - method so that a subclass can try to add that glyph, returning true if it - manages to do so. - */ - virtual bool loadGlyphIfPossible (juce_wchar characterNeeded); - -private: - //============================================================================== - class GlyphInfo; - friend struct ContainerDeletePolicy; - OwnedArray glyphs; - short lookupTable [128]; - - GlyphInfo* findGlyph (const juce_wchar character, bool loadIfNeeded) noexcept; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomTypeface) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/fonts/juce_Font.cpp b/source/modules/juce_graphics/fonts/juce_Font.cpp deleted file mode 100644 index 40e7f1bde..000000000 --- a/source/modules/juce_graphics/fonts/juce_Font.cpp +++ /dev/null @@ -1,722 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -namespace FontValues -{ - static float limitFontHeight (const float height) noexcept - { - return jlimit (0.1f, 10000.0f, height); - } - - const float defaultFontHeight = 14.0f; - float minimumHorizontalScale = 0.7f; - String fallbackFont; - String fallbackFontStyle; -} - -typedef Typeface::Ptr (*GetTypefaceForFont) (const Font&); -GetTypefaceForFont juce_getTypefaceForFont = nullptr; - -float Font::getDefaultMinimumHorizontalScaleFactor() noexcept { return FontValues::minimumHorizontalScale; } -void Font::setDefaultMinimumHorizontalScaleFactor (float newValue) noexcept { FontValues::minimumHorizontalScale = newValue; } - -//============================================================================== -class TypefaceCache : private DeletedAtShutdown -{ -public: - TypefaceCache() - { - setSize (10); - } - - ~TypefaceCache() - { - clearSingletonInstance(); - } - - juce_DeclareSingleton (TypefaceCache, false) - - void setSize (const int numToCache) - { - const ScopedWriteLock sl (lock); - - faces.clear(); - faces.insertMultiple (-1, CachedFace(), numToCache); - } - - void clear() - { - const ScopedWriteLock sl (lock); - - setSize (faces.size()); - defaultFace = nullptr; - } - - Typeface::Ptr findTypefaceFor (const Font& font) - { - const ScopedReadLock slr (lock); - - auto faceName = font.getTypefaceName(); - auto faceStyle = font.getTypefaceStyle(); - - jassert (faceName.isNotEmpty()); - - for (int i = faces.size(); --i >= 0;) - { - CachedFace& face = faces.getReference(i); - - if (face.typefaceName == faceName - && face.typefaceStyle == faceStyle - && face.typeface != nullptr - && face.typeface->isSuitableForFont (font)) - { - face.lastUsageCount = ++counter; - return face.typeface; - } - } - - const ScopedWriteLock slw (lock); - int replaceIndex = 0; - auto bestLastUsageCount = std::numeric_limits::max(); - - for (int i = faces.size(); --i >= 0;) - { - auto lu = faces.getReference(i).lastUsageCount; - - if (bestLastUsageCount > lu) - { - bestLastUsageCount = lu; - replaceIndex = i; - } - } - - auto& face = faces.getReference (replaceIndex); - face.typefaceName = faceName; - face.typefaceStyle = faceStyle; - face.lastUsageCount = ++counter; - - if (juce_getTypefaceForFont == nullptr) - face.typeface = Font::getDefaultTypefaceForFont (font); - else - face.typeface = juce_getTypefaceForFont (font); - - jassert (face.typeface != nullptr); // the look and feel must return a typeface! - - if (defaultFace == nullptr && font == Font()) - defaultFace = face.typeface; - - return face.typeface; - } - - Typeface::Ptr defaultFace; - -private: - struct CachedFace - { - CachedFace() noexcept : lastUsageCount (0) {} - - // Although it seems a bit wacky to store the name here, it's because it may be a - // placeholder rather than a real one, e.g. "" vs the actual typeface name. - // Since the typeface itself doesn't know that it may have this alias, the name under - // which it was fetched needs to be stored separately. - String typefaceName, typefaceStyle; - size_t lastUsageCount; - Typeface::Ptr typeface; - }; - - ReadWriteLock lock; - Array faces; - size_t counter = 0; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TypefaceCache) -}; - -juce_ImplementSingleton (TypefaceCache) - -void Typeface::setTypefaceCacheSize (int numFontsToCache) -{ - TypefaceCache::getInstance()->setSize (numFontsToCache); -} - -void (*clearOpenGLGlyphCache)() = nullptr; - -void Typeface::clearTypefaceCache() -{ - TypefaceCache::getInstance()->clear(); - - RenderingHelpers::SoftwareRendererSavedState::clearGlyphCache(); - - if (clearOpenGLGlyphCache != nullptr) - clearOpenGLGlyphCache(); -} - -//============================================================================== -class Font::SharedFontInternal : public ReferenceCountedObject -{ -public: - SharedFontInternal() noexcept - : typeface (TypefaceCache::getInstance()->defaultFace), - typefaceName (Font::getDefaultSansSerifFontName()), - typefaceStyle (Font::getDefaultStyle()), - height (FontValues::defaultFontHeight) - { - } - - SharedFontInternal (int styleFlags, float fontHeight) noexcept - : typefaceName (Font::getDefaultSansSerifFontName()), - typefaceStyle (FontStyleHelpers::getStyleName (styleFlags)), - height (fontHeight), - underline ((styleFlags & underlined) != 0) - { - if (styleFlags == plain) - typeface = TypefaceCache::getInstance()->defaultFace; - } - - SharedFontInternal (const String& name, int styleFlags, float fontHeight) noexcept - : typefaceName (name), - typefaceStyle (FontStyleHelpers::getStyleName (styleFlags)), - height (fontHeight), - underline ((styleFlags & underlined) != 0) - { - if (styleFlags == plain && typefaceName.isEmpty()) - typeface = TypefaceCache::getInstance()->defaultFace; - } - - SharedFontInternal (const String& name, const String& style, float fontHeight) noexcept - : typefaceName (name), typefaceStyle (style), height (fontHeight) - { - if (typefaceName.isEmpty()) - typefaceName = Font::getDefaultSansSerifFontName(); - } - - explicit SharedFontInternal (const Typeface::Ptr& face) noexcept - : typeface (face), - typefaceName (face->getName()), - typefaceStyle (face->getStyle()), - height (FontValues::defaultFontHeight) - { - jassert (typefaceName.isNotEmpty()); - } - - SharedFontInternal (const SharedFontInternal& other) noexcept - : ReferenceCountedObject(), - typeface (other.typeface), - typefaceName (other.typefaceName), - typefaceStyle (other.typefaceStyle), - height (other.height), - horizontalScale (other.horizontalScale), - kerning (other.kerning), - ascent (other.ascent), - underline (other.underline) - { - } - - bool operator== (const SharedFontInternal& other) const noexcept - { - return height == other.height - && underline == other.underline - && horizontalScale == other.horizontalScale - && kerning == other.kerning - && typefaceName == other.typefaceName - && typefaceStyle == other.typefaceStyle; - } - - Typeface::Ptr typeface; - String typefaceName, typefaceStyle; - float height, horizontalScale = 1.0f, kerning = 0, ascent = 0; - bool underline = false; -}; - -//============================================================================== -Font::Font() : font (new SharedFontInternal()) {} -Font::Font (const Typeface::Ptr& typeface) : font (new SharedFontInternal (typeface)) {} -Font::Font (const Font& other) noexcept : font (other.font) {} - -Font::Font (float fontHeight, int styleFlags) - : font (new SharedFontInternal (styleFlags, FontValues::limitFontHeight (fontHeight))) -{ -} - -Font::Font (const String& typefaceName, float fontHeight, int styleFlags) - : font (new SharedFontInternal (typefaceName, styleFlags, FontValues::limitFontHeight (fontHeight))) -{ -} - -Font::Font (const String& typefaceName, const String& typefaceStyle, float fontHeight) - : font (new SharedFontInternal (typefaceName, typefaceStyle, FontValues::limitFontHeight (fontHeight))) -{ -} - -Font& Font::operator= (const Font& other) noexcept -{ - font = other.font; - return *this; -} - -Font::Font (Font&& other) noexcept - : font (static_cast&&> (other.font)) -{ -} - -Font& Font::operator= (Font&& other) noexcept -{ - font = static_cast&&> (other.font); - return *this; -} - -Font::~Font() noexcept -{ -} - -bool Font::operator== (const Font& other) const noexcept -{ - return font == other.font - || *font == *other.font; -} - -bool Font::operator!= (const Font& other) const noexcept -{ - return ! operator== (other); -} - -void Font::dupeInternalIfShared() -{ - if (font->getReferenceCount() > 1) - font = new SharedFontInternal (*font); -} - -void Font::checkTypefaceSuitability() -{ - if (font->typeface != nullptr && ! font->typeface->isSuitableForFont (*this)) - font->typeface = nullptr; -} - -//============================================================================== -struct FontPlaceholderNames -{ - String sans { "" }, - serif { "" }, - mono { "" }, - regular { "" }; -}; - -const FontPlaceholderNames& getFontPlaceholderNames() -{ - static FontPlaceholderNames names; - return names; -} - -#if JUCE_MSVC -// This is a workaround for the lack of thread-safety in MSVC's handling of function-local -// statics - if multiple threads all try to create the first Font object at the same time, -// it can cause a race-condition in creating these placeholder strings. -struct FontNamePreloader { FontNamePreloader() { getFontPlaceholderNames(); } }; -static FontNamePreloader fnp; -#endif - -const String& Font::getDefaultSansSerifFontName() { return getFontPlaceholderNames().sans; } -const String& Font::getDefaultSerifFontName() { return getFontPlaceholderNames().serif; } -const String& Font::getDefaultMonospacedFontName() { return getFontPlaceholderNames().mono; } -const String& Font::getDefaultStyle() { return getFontPlaceholderNames().regular; } - -const String& Font::getTypefaceName() const noexcept { return font->typefaceName; } -const String& Font::getTypefaceStyle() const noexcept { return font->typefaceStyle; } - -void Font::setTypefaceName (const String& faceName) -{ - if (faceName != font->typefaceName) - { - jassert (faceName.isNotEmpty()); - - dupeInternalIfShared(); - font->typefaceName = faceName; - font->typeface = nullptr; - font->ascent = 0; - } -} - -void Font::setTypefaceStyle (const String& typefaceStyle) -{ - if (typefaceStyle != font->typefaceStyle) - { - dupeInternalIfShared(); - font->typefaceStyle = typefaceStyle; - font->typeface = nullptr; - font->ascent = 0; - } -} - -Font Font::withTypefaceStyle (const String& newStyle) const -{ - Font f (*this); - f.setTypefaceStyle (newStyle); - return f; -} - -StringArray Font::getAvailableStyles() const -{ - return findAllTypefaceStyles (getTypeface()->getName()); -} - -Typeface* Font::getTypeface() const -{ - if (font->typeface == nullptr) - { - font->typeface = TypefaceCache::getInstance()->findTypefaceFor (*this); - jassert (font->typeface != nullptr); - } - - return font->typeface; -} - -//============================================================================== -const String& Font::getFallbackFontName() -{ - return FontValues::fallbackFont; -} - -void Font::setFallbackFontName (const String& name) -{ - FontValues::fallbackFont = name; - - #if JUCE_MAC || JUCE_IOS - jassertfalse; // Note that use of a fallback font isn't currently implemented in OSX.. - #endif -} - -const String& Font::getFallbackFontStyle() -{ - return FontValues::fallbackFontStyle; -} - -void Font::setFallbackFontStyle (const String& style) -{ - FontValues::fallbackFontStyle = style; - - #if JUCE_MAC || JUCE_IOS - jassertfalse; // Note that use of a fallback font isn't currently implemented in OSX.. - #endif -} - -//============================================================================== -Font Font::withHeight (const float newHeight) const -{ - Font f (*this); - f.setHeight (newHeight); - return f; -} - -float Font::getHeightToPointsFactor() const -{ - return getTypeface()->getHeightToPointsFactor(); -} - -Font Font::withPointHeight (float heightInPoints) const -{ - Font f (*this); - f.setHeight (heightInPoints / getHeightToPointsFactor()); - return f; -} - -void Font::setHeight (float newHeight) -{ - newHeight = FontValues::limitFontHeight (newHeight); - - if (font->height != newHeight) - { - dupeInternalIfShared(); - font->height = newHeight; - checkTypefaceSuitability(); - } -} - -void Font::setHeightWithoutChangingWidth (float newHeight) -{ - newHeight = FontValues::limitFontHeight (newHeight); - - if (font->height != newHeight) - { - dupeInternalIfShared(); - font->horizontalScale *= (font->height / newHeight); - font->height = newHeight; - checkTypefaceSuitability(); - } -} - -int Font::getStyleFlags() const noexcept -{ - int styleFlags = font->underline ? underlined : plain; - - if (isBold()) styleFlags |= bold; - if (isItalic()) styleFlags |= italic; - - return styleFlags; -} - -Font Font::withStyle (const int newFlags) const -{ - Font f (*this); - f.setStyleFlags (newFlags); - return f; -} - -void Font::setStyleFlags (const int newFlags) -{ - if (getStyleFlags() != newFlags) - { - dupeInternalIfShared(); - font->typeface = nullptr; - font->typefaceStyle = FontStyleHelpers::getStyleName (newFlags); - font->underline = (newFlags & underlined) != 0; - font->ascent = 0; - } -} - -void Font::setSizeAndStyle (float newHeight, - const int newStyleFlags, - const float newHorizontalScale, - const float newKerningAmount) -{ - newHeight = FontValues::limitFontHeight (newHeight); - - if (font->height != newHeight - || font->horizontalScale != newHorizontalScale - || font->kerning != newKerningAmount) - { - dupeInternalIfShared(); - font->height = newHeight; - font->horizontalScale = newHorizontalScale; - font->kerning = newKerningAmount; - checkTypefaceSuitability(); - } - - setStyleFlags (newStyleFlags); -} - -void Font::setSizeAndStyle (float newHeight, - const String& newStyle, - const float newHorizontalScale, - const float newKerningAmount) -{ - newHeight = FontValues::limitFontHeight (newHeight); - - if (font->height != newHeight - || font->horizontalScale != newHorizontalScale - || font->kerning != newKerningAmount) - { - dupeInternalIfShared(); - font->height = newHeight; - font->horizontalScale = newHorizontalScale; - font->kerning = newKerningAmount; - checkTypefaceSuitability(); - } - - setTypefaceStyle (newStyle); -} - -Font Font::withHorizontalScale (const float newHorizontalScale) const -{ - Font f (*this); - f.setHorizontalScale (newHorizontalScale); - return f; -} - -void Font::setHorizontalScale (const float scaleFactor) -{ - dupeInternalIfShared(); - font->horizontalScale = scaleFactor; - checkTypefaceSuitability(); -} - -float Font::getHorizontalScale() const noexcept -{ - return font->horizontalScale; -} - -float Font::getExtraKerningFactor() const noexcept -{ - return font->kerning; -} - -Font Font::withExtraKerningFactor (const float extraKerning) const -{ - Font f (*this); - f.setExtraKerningFactor (extraKerning); - return f; -} - -void Font::setExtraKerningFactor (const float extraKerning) -{ - dupeInternalIfShared(); - font->kerning = extraKerning; - checkTypefaceSuitability(); -} - -Font Font::boldened() const { return withStyle (getStyleFlags() | bold); } -Font Font::italicised() const { return withStyle (getStyleFlags() | italic); } - -bool Font::isBold() const noexcept { return FontStyleHelpers::isBold (font->typefaceStyle); } -bool Font::isItalic() const noexcept { return FontStyleHelpers::isItalic (font->typefaceStyle); } -bool Font::isUnderlined() const noexcept { return font->underline; } - -void Font::setBold (const bool shouldBeBold) -{ - auto flags = getStyleFlags(); - setStyleFlags (shouldBeBold ? (flags | bold) - : (flags & ~bold)); -} - -void Font::setItalic (const bool shouldBeItalic) -{ - auto flags = getStyleFlags(); - setStyleFlags (shouldBeItalic ? (flags | italic) - : (flags & ~italic)); -} - -void Font::setUnderline (const bool shouldBeUnderlined) -{ - dupeInternalIfShared(); - font->underline = shouldBeUnderlined; - checkTypefaceSuitability(); -} - -float Font::getAscent() const -{ - if (font->ascent == 0.0f) - font->ascent = getTypeface()->getAscent(); - - return font->height * font->ascent; -} - -float Font::getHeight() const noexcept { return font->height; } -float Font::getDescent() const { return font->height - getAscent(); } - -float Font::getHeightInPoints() const { return getHeight() * getHeightToPointsFactor(); } -float Font::getAscentInPoints() const { return getAscent() * getHeightToPointsFactor(); } -float Font::getDescentInPoints() const { return getDescent() * getHeightToPointsFactor(); } - -int Font::getStringWidth (const String& text) const -{ - return (int) std::ceil (getStringWidthFloat (text)); -} - -float Font::getStringWidthFloat (const String& text) const -{ - // This call isn't thread-safe when there's a message thread running - jassert (MessageManager::getInstanceWithoutCreating() == nullptr - || MessageManager::getInstanceWithoutCreating()->currentThreadHasLockedMessageManager()); - - auto w = getTypeface()->getStringWidth (text); - - if (font->kerning != 0.0f) - w += font->kerning * text.length(); - - return w * font->height * font->horizontalScale; -} - -void Font::getGlyphPositions (const String& text, Array& glyphs, Array& xOffsets) const -{ - // This call isn't thread-safe when there's a message thread running - jassert (MessageManager::getInstanceWithoutCreating() == nullptr - || MessageManager::getInstanceWithoutCreating()->currentThreadHasLockedMessageManager()); - - getTypeface()->getGlyphPositions (text, glyphs, xOffsets); - - if (auto num = xOffsets.size()) - { - auto scale = font->height * font->horizontalScale; - auto* x = xOffsets.getRawDataPointer(); - - if (font->kerning != 0.0f) - { - for (int i = 0; i < num; ++i) - x[i] = (x[i] + i * font->kerning) * scale; - } - else - { - for (int i = 0; i < num; ++i) - x[i] *= scale; - } - } -} - -void Font::findFonts (Array& destArray) -{ - for (auto& name : findAllTypefaceNames()) - { - auto styles = findAllTypefaceStyles (name); - - String style ("Regular"); - - if (! styles.contains (style, true)) - style = styles[0]; - - destArray.add (Font (name, style, FontValues::defaultFontHeight)); - } -} - -//============================================================================== -String Font::toString() const -{ - String s; - - if (getTypefaceName() != getDefaultSansSerifFontName()) - s << getTypefaceName() << "; "; - - s << String (getHeight(), 1); - - if (getTypefaceStyle() != getDefaultStyle()) - s << ' ' << getTypefaceStyle(); - - return s; -} - -Font Font::fromString (const String& fontDescription) -{ - const int separator = fontDescription.indexOfChar (';'); - String name; - - if (separator > 0) - name = fontDescription.substring (0, separator).trim(); - - if (name.isEmpty()) - name = getDefaultSansSerifFontName(); - - String sizeAndStyle (fontDescription.substring (separator + 1).trimStart()); - - float height = sizeAndStyle.getFloatValue(); - if (height <= 0) - height = 10.0f; - - const String style (sizeAndStyle.fromFirstOccurrenceOf (" ", false, false)); - - return Font (name, style, height); -} - -} // namespace juce diff --git a/source/modules/juce_graphics/fonts/juce_Font.h b/source/modules/juce_graphics/fonts/juce_Font.h deleted file mode 100644 index cacea2d21..000000000 --- a/source/modules/juce_graphics/fonts/juce_Font.h +++ /dev/null @@ -1,478 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Represents a particular font, including its size, style, etc. - - Apart from the typeface to be used, a Font object also dictates whether - the font is bold, italic, underlined, how big it is, and its kerning and - horizontal scale factor. - - @see Typeface -*/ -class JUCE_API Font -{ -public: - //============================================================================== - /** A combination of these values is used by the constructor to specify the - style of font to use. - */ - enum FontStyleFlags - { - plain = 0, /**< indicates a plain, non-bold, non-italic version of the font. @see setStyleFlags */ - bold = 1, /**< boldens the font. @see setStyleFlags */ - italic = 2, /**< finds an italic version of the font. @see setStyleFlags */ - underlined = 4 /**< underlines the font. @see setStyleFlags */ - }; - - //============================================================================== - /** Creates a sans-serif font in a given size. - - @param fontHeight the height in pixels (can be fractional) - @param styleFlags the style to use - this can be a combination of the - Font::bold, Font::italic and Font::underlined, or - just Font::plain for the normal style. - @see FontStyleFlags, getDefaultSansSerifFontName - */ - Font (float fontHeight, int styleFlags = plain); - - /** Creates a font with a given typeface and parameters. - - @param typefaceName the font family of the typeface to use - @param fontHeight the height in pixels (can be fractional) - @param styleFlags the style to use - this can be a combination of the - Font::bold, Font::italic and Font::underlined, or - just Font::plain for the normal style. - @see FontStyleFlags, getDefaultSansSerifFontName - */ - Font (const String& typefaceName, float fontHeight, int styleFlags); - - /** Creates a font with a given typeface and parameters. - - @param typefaceName the font family of the typeface to use - @param typefaceStyle the font style of the typeface to use - @param fontHeight the height in pixels (can be fractional) - */ - Font (const String& typefaceName, const String& typefaceStyle, float fontHeight); - - /** Creates a copy of another Font object. */ - Font (const Font& other) noexcept; - - /** Creates a font for a typeface. */ - Font (const Typeface::Ptr& typeface); - - /** Creates a basic sans-serif font at a default height. - - You should use one of the other constructors for creating a font that you're planning - on drawing with - this constructor is here to help initialise objects before changing - the font's settings later. - */ - Font(); - - /** Move constructor */ - Font (Font&& other) noexcept; - - /** Move assignment operator */ - Font& operator= (Font&& other) noexcept; - - /** Copies this font from another one. */ - Font& operator= (const Font& other) noexcept; - - bool operator== (const Font& other) const noexcept; - bool operator!= (const Font& other) const noexcept; - - /** Destructor. */ - ~Font() noexcept; - - //============================================================================== - /** Changes the font family of the typeface. - - e.g. "Arial", "Courier", etc. - - This may also be set to Font::getDefaultSansSerifFontName(), Font::getDefaultSerifFontName(), - or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font family names, - but are generic font family names that are used to represent the various default fonts. - If you need to know the exact typeface font family being used, you can call - Font::getTypeface()->getName(), which will give you the platform-specific font family. - - If a suitable font isn't found on the machine, it'll just use a default instead. - */ - void setTypefaceName (const String& faceName); - - /** Returns the font family of the typeface that this font uses. - - e.g. "Arial", "Courier", etc. - - This may also be set to Font::getDefaultSansSerifFontName(), Font::getDefaultSerifFontName(), - or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font family names, - but are generic font familiy names that are used to represent the various default fonts. - - If you need to know the exact typeface font family being used, you can call - Font::getTypeface()->getName(), which will give you the platform-specific font family. - */ - const String& getTypefaceName() const noexcept; - - //============================================================================== - /** Returns the font style of the typeface that this font uses. - @see withTypefaceStyle, getAvailableStyles() - */ - const String& getTypefaceStyle() const noexcept; - - /** Changes the font style of the typeface. - @see getAvailableStyles() - */ - void setTypefaceStyle (const String& newStyle); - - /** Returns a copy of this font with a new typeface style. - @see getAvailableStyles() - */ - Font withTypefaceStyle (const String& newStyle) const; - - /** Returns a list of the styles that this font can use. */ - StringArray getAvailableStyles() const; - - //============================================================================== - /** Returns a typeface font family that represents the default sans-serif font. - - This is also the typeface that will be used when a font is created without - specifying any typeface details. - - Note that this method just returns a generic placeholder string that means "the default - sans-serif font" - it's not the actual font family of this font. - - @see setTypefaceName, getDefaultSerifFontName, getDefaultMonospacedFontName - */ - static const String& getDefaultSansSerifFontName(); - - /** Returns a typeface font family that represents the default serif font. - - Note that this method just returns a generic placeholder string that means "the default - serif font" - it's not the actual font family of this font. - - @see setTypefaceName, getDefaultSansSerifFontName, getDefaultMonospacedFontName - */ - static const String& getDefaultSerifFontName(); - - /** Returns a typeface font family that represents the default monospaced font. - - Note that this method just returns a generic placeholder string that means "the default - monospaced font" - it's not the actual font family of this font. - - @see setTypefaceName, getDefaultSansSerifFontName, getDefaultSerifFontName - */ - static const String& getDefaultMonospacedFontName(); - - /** Returns a font style name that represents the default style. - - Note that this method just returns a generic placeholder string that means "the default - font style" - it's not the actual name of the font style of any particular font. - - @see setTypefaceStyle - */ - static const String& getDefaultStyle(); - - /** Returns the default system typeface for the given font. */ - static Typeface::Ptr getDefaultTypefaceForFont (const Font& font); - - //============================================================================== - /** Returns a copy of this font with a new height. */ - Font withHeight (float height) const; - - /** Returns a copy of this font with a new height, specified in points. */ - Font withPointHeight (float heightInPoints) const; - - /** Changes the font's height. - @see getHeight, withHeight, setHeightWithoutChangingWidth - */ - void setHeight (float newHeight); - - /** Changes the font's height without changing its width. - This alters the horizontal scale to compensate for the change in height. - */ - void setHeightWithoutChangingWidth (float newHeight); - - /** Returns the total height of this font, in pixels. - This is the maximum height, from the top of the ascent to the bottom of the - descenders. - - @see withHeight, setHeightWithoutChangingWidth, getAscent - */ - float getHeight() const noexcept; - - /** Returns the total height of this font, in points. - This is the maximum height, from the top of the ascent to the bottom of the - descenders. - - @see withPointHeight, getHeight - */ - float getHeightInPoints() const; - - /** Returns the height of the font above its baseline, in pixels. - This is the maximum height from the baseline to the top. - @see getHeight, getDescent - */ - float getAscent() const; - - /** Returns the height of the font above its baseline, in points. - This is the maximum height from the baseline to the top. - @see getHeight, getDescent - */ - float getAscentInPoints() const; - - /** Returns the amount that the font descends below its baseline, in pixels. - This is calculated as (getHeight() - getAscent()). - @see getAscent, getHeight - */ - float getDescent() const; - - /** Returns the amount that the font descends below its baseline, in points. - This is calculated as (getHeight() - getAscent()). - @see getAscent, getHeight - */ - float getDescentInPoints() const; - - //============================================================================== - /** Returns the font's style flags. - This will return a bitwise-or'ed combination of values from the FontStyleFlags - enum, to describe whether the font is bold, italic, etc. - @see FontStyleFlags, withStyle - */ - int getStyleFlags() const noexcept; - - /** Returns a copy of this font with the given set of style flags. - @param styleFlags a bitwise-or'ed combination of values from the FontStyleFlags enum. - @see FontStyleFlags, getStyleFlags - */ - Font withStyle (int styleFlags) const; - - /** Changes the font's style. - @param newFlags a bitwise-or'ed combination of values from the FontStyleFlags enum. - @see FontStyleFlags, withStyle - */ - void setStyleFlags (int newFlags); - - //============================================================================== - /** Makes the font bold or non-bold. */ - void setBold (bool shouldBeBold); - - /** Returns a copy of this font with the bold attribute set. - If the font does not have a bold version, this will return the default font. - */ - Font boldened() const; - - /** Returns true if the font is bold. */ - bool isBold() const noexcept; - - /** Makes the font italic or non-italic. */ - void setItalic (bool shouldBeItalic); - /** Returns a copy of this font with the italic attribute set. */ - Font italicised() const; - /** Returns true if the font is italic. */ - bool isItalic() const noexcept; - - /** Makes the font underlined or non-underlined. */ - void setUnderline (bool shouldBeUnderlined); - /** Returns true if the font is underlined. */ - bool isUnderlined() const noexcept; - - - //============================================================================== - /** Returns the font's horizontal scale. - A value of 1.0 is the normal scale, less than this will be narrower, greater - than 1.0 will be stretched out. - - @see withHorizontalScale - */ - float getHorizontalScale() const noexcept; - - /** Returns a copy of this font with a new horizontal scale. - @param scaleFactor a value of 1.0 is the normal scale, less than this will be - narrower, greater than 1.0 will be stretched out. - @see getHorizontalScale - */ - Font withHorizontalScale (float scaleFactor) const; - - /** Changes the font's horizontal scale factor. - @param scaleFactor a value of 1.0 is the normal scale, less than this will be - narrower, greater than 1.0 will be stretched out. - */ - void setHorizontalScale (float scaleFactor); - - /** Returns the minimum horizontal scale to which fonts may be squashed when trying to - create a layout. - @see setDefaultMinimumHorizontalScaleFactor - */ - static float getDefaultMinimumHorizontalScaleFactor() noexcept; - - /** Sets the minimum horizontal scale to which fonts may be squashed when trying to - create a text layout. - @see getDefaultMinimumHorizontalScaleFactor - */ - static void setDefaultMinimumHorizontalScaleFactor (float newMinimumScaleFactor) noexcept; - - /** Returns the font's kerning. - - This is the extra space added between adjacent characters, as a proportion - of the font's height. - - A value of zero is normal spacing, positive values will spread the letters - out more, and negative values make them closer together. - */ - float getExtraKerningFactor() const noexcept; - - /** Returns a copy of this font with a new kerning factor. - @param extraKerning a multiple of the font's height that will be added - to space between the characters. So a value of zero is - normal spacing, positive values spread the letters out, - negative values make them closer together. - */ - Font withExtraKerningFactor (float extraKerning) const; - - /** Changes the font's kerning. - @param extraKerning a multiple of the font's height that will be added - to space between the characters. So a value of zero is - normal spacing, positive values spread the letters out, - negative values make them closer together. - */ - void setExtraKerningFactor (float extraKerning); - - //============================================================================== - /** Changes all the font's characteristics with one call. */ - void setSizeAndStyle (float newHeight, - int newStyleFlags, - float newHorizontalScale, - float newKerningAmount); - - /** Changes all the font's characteristics with one call. */ - void setSizeAndStyle (float newHeight, - const String& newStyle, - float newHorizontalScale, - float newKerningAmount); - - //============================================================================== - /** Returns the total width of a string as it would be drawn using this font. - For a more accurate floating-point result, use getStringWidthFloat(). - */ - int getStringWidth (const String& text) const; - - /** Returns the total width of a string as it would be drawn using this font. - @see getStringWidth - */ - float getStringWidthFloat (const String& text) const; - - /** Returns the series of glyph numbers and their x offsets needed to represent a string. - - An extra x offset is added at the end of the run, to indicate where the right hand - edge of the last character is. - */ - void getGlyphPositions (const String& text, Array & glyphs, Array & xOffsets) const; - - //============================================================================== - /** Returns the typeface used by this font. - - Note that the object returned may go out of scope if this font is deleted - or has its style changed. - */ - Typeface* getTypeface() const; - - /** Creates an array of Font objects to represent all the fonts on the system. - - If you just need the font family names of the typefaces, you can also use - findAllTypefaceNames() instead. - - @param results the array to which new Font objects will be added. - */ - static void findFonts (Array& results); - - /** Returns a list of all the available typeface font families. - - The names returned can be passed into setTypefaceName(). - - You can use this instead of findFonts() if you only need their font family names, - and not font objects. - */ - static StringArray findAllTypefaceNames(); - - /** Returns a list of all the available typeface font styles. - - The names returned can be passed into setTypefaceStyle(). - - You can use this instead of findFonts() if you only need their styles, and not - font objects. - */ - static StringArray findAllTypefaceStyles (const String& family); - - //============================================================================== - /** Returns the font family of the typeface to be used for rendering glyphs that aren't - found in the requested typeface. - */ - static const String& getFallbackFontName(); - - /** Sets the (platform-specific) font family of the typeface to use to find glyphs that - aren't available in whatever font you're trying to use. - */ - static void setFallbackFontName (const String& name); - - /** Returns the font style of the typeface to be used for rendering glyphs that aren't - found in the requested typeface. - */ - static const String& getFallbackFontStyle(); - - /** Sets the (platform-specific) font style of the typeface to use to find glyphs that - aren't available in whatever font you're trying to use. - */ - static void setFallbackFontStyle (const String& style); - - //============================================================================== - /** Creates a string to describe this font. - The string will contain information to describe the font's typeface, size, and - style. To recreate the font from this string, use fromString(). - */ - String toString() const; - - /** Recreates a font from its stringified encoding. - This method takes a string that was created by toString(), and recreates the - original font. - */ - static Font fromString (const String& fontDescription); - - -private: - //============================================================================== - class SharedFontInternal; - ReferenceCountedObjectPtr font; - void dupeInternalIfShared(); - void checkTypefaceSuitability(); - float getHeightToPointsFactor() const; - - JUCE_LEAK_DETECTOR (Font) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp b/source/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp deleted file mode 100644 index f0d05460c..000000000 --- a/source/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp +++ /dev/null @@ -1,820 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -PositionedGlyph::PositionedGlyph() noexcept - : character (0), glyph (0), x (0), y (0), w (0), whitespace (false) -{ -} - -PositionedGlyph::PositionedGlyph (const Font& font_, const juce_wchar character_, const int glyph_, - const float x_, const float y_, const float w_, const bool whitespace_) - : font (font_), character (character_), glyph (glyph_), - x (x_), y (y_), w (w_), whitespace (whitespace_) -{ -} - -PositionedGlyph::PositionedGlyph (const PositionedGlyph& other) - : font (other.font), character (other.character), glyph (other.glyph), - x (other.x), y (other.y), w (other.w), whitespace (other.whitespace) -{ -} - -PositionedGlyph::PositionedGlyph (PositionedGlyph&& other) noexcept - : font (static_cast (other.font)), - character (other.character), glyph (other.glyph), - x (other.x), y (other.y), w (other.w), whitespace (other.whitespace) -{ -} - -PositionedGlyph& PositionedGlyph::operator= (PositionedGlyph&& other) noexcept -{ - font = static_cast (other.font); - character = other.character; - glyph = other.glyph; - x = other.x; - y = other.y; - w = other.w; - whitespace = other.whitespace; - return *this; -} - -PositionedGlyph::~PositionedGlyph() {} - -PositionedGlyph& PositionedGlyph::operator= (const PositionedGlyph& other) -{ - font = other.font; - character = other.character; - glyph = other.glyph; - x = other.x; - y = other.y; - w = other.w; - whitespace = other.whitespace; - return *this; -} - -static inline void drawGlyphWithFont (Graphics& g, int glyph, const Font& font, const AffineTransform& t) -{ - LowLevelGraphicsContext& context = g.getInternalContext(); - context.setFont (font); - context.drawGlyph (glyph, t); -} - -void PositionedGlyph::draw (Graphics& g) const -{ - if (! isWhitespace()) - drawGlyphWithFont (g, glyph, font, AffineTransform::translation (x, y)); -} - -void PositionedGlyph::draw (Graphics& g, const AffineTransform& transform) const -{ - if (! isWhitespace()) - drawGlyphWithFont (g, glyph, font, AffineTransform::translation (x, y).followedBy (transform)); -} - -void PositionedGlyph::createPath (Path& path) const -{ - if (! isWhitespace()) - { - if (auto* t = font.getTypeface()) - { - Path p; - t->getOutlineForGlyph (glyph, p); - - path.addPath (p, AffineTransform::scale (font.getHeight() * font.getHorizontalScale(), font.getHeight()) - .translated (x, y)); - } - } -} - -bool PositionedGlyph::hitTest (float px, float py) const -{ - if (getBounds().contains (px, py) && ! isWhitespace()) - { - if (auto* t = font.getTypeface()) - { - Path p; - t->getOutlineForGlyph (glyph, p); - - AffineTransform::translation (-x, -y) - .scaled (1.0f / (font.getHeight() * font.getHorizontalScale()), 1.0f / font.getHeight()) - .transformPoint (px, py); - - return p.contains (px, py); - } - } - - return false; -} - -void PositionedGlyph::moveBy (const float deltaX, - const float deltaY) -{ - x += deltaX; - y += deltaY; -} - - -//============================================================================== -GlyphArrangement::GlyphArrangement() -{ - glyphs.ensureStorageAllocated (128); -} - -GlyphArrangement::GlyphArrangement (const GlyphArrangement& other) - : glyphs (other.glyphs) -{ -} - -GlyphArrangement& GlyphArrangement::operator= (const GlyphArrangement& other) -{ - glyphs = other.glyphs; - return *this; -} - -GlyphArrangement::~GlyphArrangement() -{ -} - -//============================================================================== -void GlyphArrangement::clear() -{ - glyphs.clear(); -} - -PositionedGlyph& GlyphArrangement::getGlyph (const int index) const noexcept -{ - return glyphs.getReference (index); -} - -//============================================================================== -void GlyphArrangement::addGlyphArrangement (const GlyphArrangement& other) -{ - glyphs.addArray (other.glyphs); -} - -void GlyphArrangement::addGlyph (const PositionedGlyph& glyph) -{ - glyphs.add (glyph); -} - -void GlyphArrangement::removeRangeOfGlyphs (int startIndex, const int num) -{ - glyphs.removeRange (startIndex, num < 0 ? glyphs.size() : num); -} - -//============================================================================== -void GlyphArrangement::addLineOfText (const Font& font, - const String& text, - const float xOffset, - const float yOffset) -{ - addCurtailedLineOfText (font, text, xOffset, yOffset, 1.0e10f, false); -} - -void GlyphArrangement::addCurtailedLineOfText (const Font& font, - const String& text, - const float xOffset, - const float yOffset, - const float maxWidthPixels, - const bool useEllipsis) -{ - if (text.isNotEmpty()) - { - Array newGlyphs; - Array xOffsets; - font.getGlyphPositions (text, newGlyphs, xOffsets); - const int textLen = newGlyphs.size(); - glyphs.ensureStorageAllocated (glyphs.size() + textLen); - - auto t = text.getCharPointer(); - - for (int i = 0; i < textLen; ++i) - { - const float nextX = xOffsets.getUnchecked (i + 1); - - if (nextX > maxWidthPixels + 1.0f) - { - // curtail the string if it's too wide.. - if (useEllipsis && textLen > 3 && glyphs.size() >= 3) - insertEllipsis (font, xOffset + maxWidthPixels, 0, glyphs.size()); - - break; - } - - const float thisX = xOffsets.getUnchecked (i); - const bool isWhitespace = t.isWhitespace(); - - glyphs.add (PositionedGlyph (font, t.getAndAdvance(), - newGlyphs.getUnchecked(i), - xOffset + thisX, yOffset, - nextX - thisX, isWhitespace)); - } - } -} - -int GlyphArrangement::insertEllipsis (const Font& font, const float maxXPos, - const int startIndex, int endIndex) -{ - int numDeleted = 0; - - if (glyphs.size() > 0) - { - Array dotGlyphs; - Array dotXs; - font.getGlyphPositions ("..", dotGlyphs, dotXs); - - const float dx = dotXs[1]; - float xOffset = 0.0f, yOffset = 0.0f; - - while (endIndex > startIndex) - { - auto& pg = glyphs.getReference (--endIndex); - xOffset = pg.x; - yOffset = pg.y; - - glyphs.remove (endIndex); - ++numDeleted; - - if (xOffset + dx * 3 <= maxXPos) - break; - } - - for (int i = 3; --i >= 0;) - { - glyphs.insert (endIndex++, PositionedGlyph (font, '.', dotGlyphs.getFirst(), - xOffset, yOffset, dx, false)); - --numDeleted; - xOffset += dx; - - if (xOffset > maxXPos) - break; - } - } - - return numDeleted; -} - -void GlyphArrangement::addJustifiedText (const Font& font, - const String& text, - float x, float y, - const float maxLineWidth, - Justification horizontalLayout) -{ - int lineStartIndex = glyphs.size(); - addLineOfText (font, text, x, y); - - const float originalY = y; - - while (lineStartIndex < glyphs.size()) - { - int i = lineStartIndex; - - if (glyphs.getReference(i).getCharacter() != '\n' - && glyphs.getReference(i).getCharacter() != '\r') - ++i; - - const float lineMaxX = glyphs.getReference (lineStartIndex).getLeft() + maxLineWidth; - int lastWordBreakIndex = -1; - - while (i < glyphs.size()) - { - auto& pg = glyphs.getReference (i); - const juce_wchar c = pg.getCharacter(); - - if (c == '\r' || c == '\n') - { - ++i; - - if (c == '\r' && i < glyphs.size() - && glyphs.getReference(i).getCharacter() == '\n') - ++i; - - break; - } - - if (pg.isWhitespace()) - { - lastWordBreakIndex = i + 1; - } - else if (pg.getRight() - 0.0001f >= lineMaxX) - { - if (lastWordBreakIndex >= 0) - i = lastWordBreakIndex; - - break; - } - - ++i; - } - - const float currentLineStartX = glyphs.getReference (lineStartIndex).getLeft(); - float currentLineEndX = currentLineStartX; - - for (int j = i; --j >= lineStartIndex;) - { - if (! glyphs.getReference (j).isWhitespace()) - { - currentLineEndX = glyphs.getReference (j).getRight(); - break; - } - } - - float deltaX = 0.0f; - - if (horizontalLayout.testFlags (Justification::horizontallyJustified)) - spreadOutLine (lineStartIndex, i - lineStartIndex, maxLineWidth); - else if (horizontalLayout.testFlags (Justification::horizontallyCentred)) - deltaX = (maxLineWidth - (currentLineEndX - currentLineStartX)) * 0.5f; - else if (horizontalLayout.testFlags (Justification::right)) - deltaX = maxLineWidth - (currentLineEndX - currentLineStartX); - - moveRangeOfGlyphs (lineStartIndex, i - lineStartIndex, - x + deltaX - currentLineStartX, y - originalY); - - lineStartIndex = i; - - y += font.getHeight(); - } -} - -void GlyphArrangement::addFittedText (const Font& f, - const String& text, - const float x, const float y, - const float width, const float height, - Justification layout, - int maximumLines, - float minimumHorizontalScale) -{ - if (minimumHorizontalScale == 0.0f) - minimumHorizontalScale = Font::getDefaultMinimumHorizontalScaleFactor(); - - // doesn't make much sense if this is outside a sensible range of 0.5 to 1.0 - jassert (minimumHorizontalScale > 0 && minimumHorizontalScale <= 1.0f); - - if (text.containsAnyOf ("\r\n")) - { - addLinesWithLineBreaks (text, f, x, y, width, height, layout); - } - else - { - const int startIndex = glyphs.size(); - const String trimmed (text.trim()); - addLineOfText (f, trimmed, x, y); - const int numGlyphs = glyphs.size() - startIndex; - - if (numGlyphs > 0) - { - const float lineWidth = glyphs.getReference (glyphs.size() - 1).getRight() - - glyphs.getReference (startIndex).getLeft(); - - if (lineWidth > 0) - { - if (lineWidth * minimumHorizontalScale < width) - { - if (lineWidth > width) - stretchRangeOfGlyphs (startIndex, numGlyphs, width / lineWidth); - - justifyGlyphs (startIndex, numGlyphs, x, y, width, height, layout); - } - else if (maximumLines <= 1) - { - fitLineIntoSpace (startIndex, numGlyphs, x, y, width, height, - f, layout, minimumHorizontalScale); - } - else - { - splitLines (trimmed, f, startIndex, x, y, width, height, - maximumLines, lineWidth, layout, minimumHorizontalScale); - } - } - } - } -} - -//============================================================================== -void GlyphArrangement::moveRangeOfGlyphs (int startIndex, int num, const float dx, const float dy) -{ - jassert (startIndex >= 0); - - if (dx != 0.0f || dy != 0.0f) - { - if (num < 0 || startIndex + num > glyphs.size()) - num = glyphs.size() - startIndex; - - while (--num >= 0) - glyphs.getReference (startIndex++).moveBy (dx, dy); - } -} - -void GlyphArrangement::addLinesWithLineBreaks (const String& text, const Font& f, - float x, float y, float width, float height, Justification layout) -{ - GlyphArrangement ga; - ga.addJustifiedText (f, text, x, y, width, layout); - - auto bb = ga.getBoundingBox (0, -1, false); - - float dy = y - bb.getY(); - - if (layout.testFlags (Justification::verticallyCentred)) dy += (height - bb.getHeight()) * 0.5f; - else if (layout.testFlags (Justification::bottom)) dy += (height - bb.getHeight()); - - ga.moveRangeOfGlyphs (0, -1, 0.0f, dy); - - glyphs.addArray (ga.glyphs); -} - -int GlyphArrangement::fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font& font, - Justification justification, float minimumHorizontalScale) -{ - int numDeleted = 0; - const float lineStartX = glyphs.getReference (start).getLeft(); - float lineWidth = glyphs.getReference (start + numGlyphs - 1).getRight() - lineStartX; - - if (lineWidth > w) - { - if (minimumHorizontalScale < 1.0f) - { - stretchRangeOfGlyphs (start, numGlyphs, jmax (minimumHorizontalScale, w / lineWidth)); - lineWidth = glyphs.getReference (start + numGlyphs - 1).getRight() - lineStartX - 0.5f; - } - - if (lineWidth > w) - { - numDeleted = insertEllipsis (font, lineStartX + w, start, start + numGlyphs); - numGlyphs -= numDeleted; - } - } - - justifyGlyphs (start, numGlyphs, x, y, w, h, justification); - return numDeleted; -} - -void GlyphArrangement::stretchRangeOfGlyphs (int startIndex, int num, - const float horizontalScaleFactor) -{ - jassert (startIndex >= 0); - - if (num < 0 || startIndex + num > glyphs.size()) - num = glyphs.size() - startIndex; - - if (num > 0) - { - const float xAnchor = glyphs.getReference (startIndex).getLeft(); - - while (--num >= 0) - { - auto& pg = glyphs.getReference (startIndex++); - - pg.x = xAnchor + (pg.x - xAnchor) * horizontalScaleFactor; - pg.font.setHorizontalScale (pg.font.getHorizontalScale() * horizontalScaleFactor); - pg.w *= horizontalScaleFactor; - } - } -} - -Rectangle GlyphArrangement::getBoundingBox (int startIndex, int num, const bool includeWhitespace) const -{ - jassert (startIndex >= 0); - - if (num < 0 || startIndex + num > glyphs.size()) - num = glyphs.size() - startIndex; - - Rectangle result; - - while (--num >= 0) - { - auto& pg = glyphs.getReference (startIndex++); - - if (includeWhitespace || ! pg.isWhitespace()) - result = result.getUnion (pg.getBounds()); - } - - return result; -} - -void GlyphArrangement::justifyGlyphs (const int startIndex, const int num, - const float x, const float y, const float width, const float height, - Justification justification) -{ - jassert (num >= 0 && startIndex >= 0); - - if (glyphs.size() > 0 && num > 0) - { - auto bb = getBoundingBox (startIndex, num, ! justification.testFlags (Justification::horizontallyJustified - | Justification::horizontallyCentred)); - float deltaX = 0.0f, deltaY = 0.0f; - - if (justification.testFlags (Justification::horizontallyJustified)) deltaX = x - bb.getX(); - else if (justification.testFlags (Justification::horizontallyCentred)) deltaX = x + (width - bb.getWidth()) * 0.5f - bb.getX(); - else if (justification.testFlags (Justification::right)) deltaX = x + width - bb.getRight(); - else deltaX = x - bb.getX(); - - if (justification.testFlags (Justification::top)) deltaY = y - bb.getY(); - else if (justification.testFlags (Justification::bottom)) deltaY = y + height - bb.getBottom(); - else deltaY = y + (height - bb.getHeight()) * 0.5f - bb.getY(); - - moveRangeOfGlyphs (startIndex, num, deltaX, deltaY); - - if (justification.testFlags (Justification::horizontallyJustified)) - { - int lineStart = 0; - float baseY = glyphs.getReference (startIndex).getBaselineY(); - - int i; - for (i = 0; i < num; ++i) - { - const float glyphY = glyphs.getReference (startIndex + i).getBaselineY(); - - if (glyphY != baseY) - { - spreadOutLine (startIndex + lineStart, i - lineStart, width); - - lineStart = i; - baseY = glyphY; - } - } - - if (i > lineStart) - spreadOutLine (startIndex + lineStart, i - lineStart, width); - } - } -} - -void GlyphArrangement::spreadOutLine (const int start, const int num, const float targetWidth) -{ - if (start + num < glyphs.size() - && glyphs.getReference (start + num - 1).getCharacter() != '\r' - && glyphs.getReference (start + num - 1).getCharacter() != '\n') - { - int numSpaces = 0; - int spacesAtEnd = 0; - - for (int i = 0; i < num; ++i) - { - if (glyphs.getReference (start + i).isWhitespace()) - { - ++spacesAtEnd; - ++numSpaces; - } - else - { - spacesAtEnd = 0; - } - } - - numSpaces -= spacesAtEnd; - - if (numSpaces > 0) - { - const float startX = glyphs.getReference (start).getLeft(); - const float endX = glyphs.getReference (start + num - 1 - spacesAtEnd).getRight(); - - const float extraPaddingBetweenWords = (targetWidth - (endX - startX)) / (float) numSpaces; - - float deltaX = 0.0f; - - for (int i = 0; i < num; ++i) - { - glyphs.getReference (start + i).moveBy (deltaX, 0.0f); - - if (glyphs.getReference (start + i).isWhitespace()) - deltaX += extraPaddingBetweenWords; - } - } - } -} - - -void GlyphArrangement::splitLines (const String& text, Font font, int startIndex, - float x, float y, float width, float height, int maximumLines, - float lineWidth, Justification layout, float minimumHorizontalScale) -{ - const int length = text.length(); - const int originalStartIndex = startIndex; - int numLines = 1; - - if (length <= 12 && ! text.containsAnyOf (" -\t\r\n")) - maximumLines = 1; - - maximumLines = jmin (maximumLines, length); - - while (numLines < maximumLines) - { - ++numLines; - - const float newFontHeight = height / (float) numLines; - - if (newFontHeight < font.getHeight()) - { - font.setHeight (jmax (8.0f, newFontHeight)); - - removeRangeOfGlyphs (startIndex, -1); - addLineOfText (font, text, x, y); - - lineWidth = glyphs.getReference (glyphs.size() - 1).getRight() - - glyphs.getReference (startIndex).getLeft(); - } - - // Try to estimate the point at which there are enough lines to fit the text, - // allowing for unevenness in the lengths due to differently sized words. - const float lineLengthUnevennessAllowance = 80.0f; - - if (numLines > (lineWidth + lineLengthUnevennessAllowance) / width || newFontHeight < 8.0f) - break; - } - - if (numLines < 1) - numLines = 1; - - float lineY = y; - float widthPerLine = lineWidth / numLines; - - while (lineY < y + height) - { - int i = startIndex; - const float lineStartX = glyphs.getReference (startIndex).getLeft(); - const float lineBottomY = lineY + font.getHeight(); - - if (lineBottomY >= y + height) - { - widthPerLine = width; - i = glyphs.size(); - } - else - { - while (i < glyphs.size()) - { - lineWidth = (glyphs.getReference (i).getRight() - lineStartX); - - if (lineWidth > widthPerLine) - { - // got to a point where the line's too long, so skip forward to find a - // good place to break it.. - const int searchStartIndex = i; - - while (i < glyphs.size()) - { - if ((glyphs.getReference (i).getRight() - lineStartX) * minimumHorizontalScale < width) - { - if (glyphs.getReference (i).isWhitespace() - || glyphs.getReference (i).getCharacter() == '-') - { - ++i; - break; - } - } - else - { - // can't find a suitable break, so try looking backwards.. - i = searchStartIndex; - - for (int back = 1; back < jmin (7, i - startIndex - 1); ++back) - { - if (glyphs.getReference (i - back).isWhitespace() - || glyphs.getReference (i - back).getCharacter() == '-') - { - i -= back - 1; - break; - } - } - - break; - } - - ++i; - } - - break; - } - - ++i; - } - - int wsStart = i; - while (wsStart > 0 && glyphs.getReference (wsStart - 1).isWhitespace()) - --wsStart; - - int wsEnd = i; - while (wsEnd < glyphs.size() && glyphs.getReference (wsEnd).isWhitespace()) - ++wsEnd; - - removeRangeOfGlyphs (wsStart, wsEnd - wsStart); - i = jmax (wsStart, startIndex + 1); - } - - i -= fitLineIntoSpace (startIndex, i - startIndex, - x, lineY, width, font.getHeight(), font, - layout.getOnlyHorizontalFlags() | Justification::verticallyCentred, - minimumHorizontalScale); - - startIndex = i; - lineY = lineBottomY; - - if (startIndex >= glyphs.size()) - break; - } - - justifyGlyphs (originalStartIndex, glyphs.size() - originalStartIndex, - x, y, width, height, layout.getFlags() & ~Justification::horizontallyJustified); -} - -//============================================================================== -void GlyphArrangement::drawGlyphUnderline (const Graphics& g, const PositionedGlyph& pg, - const int i, const AffineTransform& transform) const -{ - const float lineThickness = (pg.font.getDescent()) * 0.3f; - - float nextX = pg.x + pg.w; - - if (i < glyphs.size() - 1 && glyphs.getReference (i + 1).y == pg.y) - nextX = glyphs.getReference (i + 1).x; - - Path p; - p.addRectangle (pg.x, pg.y + lineThickness * 2.0f, nextX - pg.x, lineThickness); - g.fillPath (p, transform); -} - -void GlyphArrangement::draw (const Graphics& g) const -{ - draw (g, AffineTransform()); -} - -void GlyphArrangement::draw (const Graphics& g, const AffineTransform& transform) const -{ - auto& context = g.getInternalContext(); - Font lastFont (context.getFont()); - bool needToRestore = false; - - for (int i = 0; i < glyphs.size(); ++i) - { - auto& pg = glyphs.getReference(i); - - if (pg.font.isUnderlined()) - drawGlyphUnderline (g, pg, i, transform); - - if (! pg.isWhitespace()) - { - if (lastFont != pg.font) - { - lastFont = pg.font; - - if (! needToRestore) - { - needToRestore = true; - context.saveState(); - } - - context.setFont (lastFont); - } - - context.drawGlyph (pg.glyph, AffineTransform::translation (pg.x, pg.y).followedBy (transform)); - } - } - - if (needToRestore) - context.restoreState(); -} - -void GlyphArrangement::createPath (Path& path) const -{ - for (auto& g : glyphs) - g.createPath (path); -} - -int GlyphArrangement::findGlyphIndexAt (const float x, const float y) const -{ - for (int i = 0; i < glyphs.size(); ++i) - if (glyphs.getReference (i).hitTest (x, y)) - return i; - - return -1; -} - -} // namespace juce diff --git a/source/modules/juce_graphics/fonts/juce_GlyphArrangement.h b/source/modules/juce_graphics/fonts/juce_GlyphArrangement.h deleted file mode 100644 index 711e6a06f..000000000 --- a/source/modules/juce_graphics/fonts/juce_GlyphArrangement.h +++ /dev/null @@ -1,327 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A glyph from a particular font, with a particular size, style, - typeface and position. - - You should rarely need to use this class directly - for most purposes, the - GlyphArrangement class will do what you need for text layout. - - @see GlyphArrangement, Font -*/ -class JUCE_API PositionedGlyph -{ -public: - //============================================================================== - PositionedGlyph() noexcept; - PositionedGlyph (const Font& font, juce_wchar character, int glyphNumber, - float anchorX, float baselineY, float width, bool isWhitespace); - - PositionedGlyph (const PositionedGlyph&); - PositionedGlyph& operator= (const PositionedGlyph&); - - /** Move constructor */ - PositionedGlyph (PositionedGlyph&&) noexcept; - - /** Move assignment operator */ - PositionedGlyph& operator= (PositionedGlyph&&) noexcept; - - ~PositionedGlyph(); - - /** Returns the character the glyph represents. */ - juce_wchar getCharacter() const noexcept { return character; } - /** Checks whether the glyph is actually empty. */ - bool isWhitespace() const noexcept { return whitespace; } - - /** Returns the position of the glyph's left-hand edge. */ - float getLeft() const noexcept { return x; } - /** Returns the position of the glyph's right-hand edge. */ - float getRight() const noexcept { return x + w; } - /** Returns the y position of the glyph's baseline. */ - float getBaselineY() const noexcept { return y; } - /** Returns the y position of the top of the glyph. */ - float getTop() const { return y - font.getAscent(); } - /** Returns the y position of the bottom of the glyph. */ - float getBottom() const { return y + font.getDescent(); } - /** Returns the bounds of the glyph. */ - Rectangle getBounds() const { return Rectangle (x, getTop(), w, font.getHeight()); } - - //============================================================================== - /** Shifts the glyph's position by a relative amount. */ - void moveBy (float deltaX, float deltaY); - - //============================================================================== - /** Draws the glyph into a graphics context. - (Note that this may change the context's currently selected font). - */ - void draw (Graphics& g) const; - - /** Draws the glyph into a graphics context, with an extra transform applied to it. - (Note that this may change the context's currently selected font). - */ - void draw (Graphics& g, const AffineTransform& transform) const; - - /** Returns the path for this glyph. - @param path the glyph's outline will be appended to this path - */ - void createPath (Path& path) const; - - /** Checks to see if a point lies within this glyph. */ - bool hitTest (float x, float y) const; - -private: - //============================================================================== - friend class GlyphArrangement; - Font font; - juce_wchar character; - int glyph; - float x, y, w; - bool whitespace; - - JUCE_LEAK_DETECTOR (PositionedGlyph) -}; - - -//============================================================================== -/** - A set of glyphs, each with a position. - - You can create a GlyphArrangement, text to it and then draw it onto a - graphics context. It's used internally by the text methods in the - Graphics class, but can be used directly if more control is needed. - - @see Font, PositionedGlyph -*/ -class JUCE_API GlyphArrangement -{ -public: - //============================================================================== - /** Creates an empty arrangement. */ - GlyphArrangement(); - - /** Takes a copy of another arrangement. */ - GlyphArrangement (const GlyphArrangement&); - - /** Copies another arrangement onto this one. - To add another arrangement without clearing this one, use addGlyphArrangement(). - */ - GlyphArrangement& operator= (const GlyphArrangement&); - - /** Destructor. */ - ~GlyphArrangement(); - - //============================================================================== - /** Returns the total number of glyphs in the arrangement. */ - int getNumGlyphs() const noexcept { return glyphs.size(); } - - /** Returns one of the glyphs from the arrangement. - - @param index the glyph's index, from 0 to (getNumGlyphs() - 1). Be - careful not to pass an out-of-range index here, as it - doesn't do any bounds-checking. - */ - PositionedGlyph& getGlyph (int index) const noexcept; - - //============================================================================== - /** Clears all text from the arrangement and resets it. */ - void clear(); - - /** Appends a line of text to the arrangement. - - This will add the text as a single line, where x is the left-hand edge of the - first character, and y is the position for the text's baseline. - - If the text contains new-lines or carriage-returns, this will ignore them - use - addJustifiedText() to add multi-line arrangements. - */ - void addLineOfText (const Font& font, - const String& text, - float x, float y); - - /** Adds a line of text, truncating it if it's wider than a specified size. - - This is the same as addLineOfText(), but if the line's width exceeds the value - specified in maxWidthPixels, it will be truncated using either ellipsis (i.e. dots: "..."), - if useEllipsis is true, or if this is false, it will just drop any subsequent characters. - */ - void addCurtailedLineOfText (const Font& font, - const String& text, - float x, float y, - float maxWidthPixels, - bool useEllipsis); - - /** Adds some multi-line text, breaking lines at word-boundaries if they are too wide. - - This will add text to the arrangement, breaking it into new lines either where there - is a new-line or carriage-return character in the text, or where a line's width - exceeds the value set in maxLineWidth. - - Each line that is added will be laid out using the flags set in horizontalLayout, so - the lines can be left- or right-justified, or centred horizontally in the space - between x and (x + maxLineWidth). - - The y coordinate is the position of the baseline of the first line of text - subsequent - lines will be placed below it, separated by a distance of font.getHeight(). - */ - void addJustifiedText (const Font& font, - const String& text, - float x, float y, - float maxLineWidth, - Justification horizontalLayout); - - /** Tries to fit some text within a given space. - - This does its best to make the given text readable within the specified rectangle, - so it useful for labelling things. - - If the text is too big, it'll be squashed horizontally or broken over multiple lines - if the maximumLinesToUse value allows this. If the text just won't fit into the space, - it'll cram as much as possible in there, and put some ellipsis at the end to show that - it's been truncated. - - A Justification parameter lets you specify how the text is laid out within the rectangle, - both horizontally and vertically. - - The minimumHorizontalScale parameter specifies how much the text can be squashed horizontally - to try to squeeze it into the space. If you don't want any horizontal scaling to occur, you - can set this value to 1.0f. Pass 0 if you want it to use the default value. - - @see Graphics::drawFittedText - */ - void addFittedText (const Font& font, - const String& text, - float x, float y, float width, float height, - Justification layout, - int maximumLinesToUse, - float minimumHorizontalScale = 0.0f); - - /** Appends another glyph arrangement to this one. */ - void addGlyphArrangement (const GlyphArrangement&); - - /** Appends a custom glyph to the arrangement. */ - void addGlyph (const PositionedGlyph&); - - //============================================================================== - /** Draws this glyph arrangement to a graphics context. - - This uses cached bitmaps so is much faster than the draw (Graphics&, const AffineTransform&) - method, which renders the glyphs as filled vectors. - */ - void draw (const Graphics&) const; - - /** Draws this glyph arrangement to a graphics context. - - This renders the paths as filled vectors, so is far slower than the draw (Graphics&) - method for non-transformed arrangements. - */ - void draw (const Graphics&, const AffineTransform&) const; - - /** Converts the set of glyphs into a path. - @param path the glyphs' outlines will be appended to this path - */ - void createPath (Path& path) const; - - /** Looks for a glyph that contains the given coordinate. - @returns the index of the glyph, or -1 if none were found. - */ - int findGlyphIndexAt (float x, float y) const; - - //============================================================================== - /** Finds the smallest rectangle that will enclose a subset of the glyphs. - - - @param startIndex the first glyph to test - @param numGlyphs the number of glyphs to include; if this is < 0, all glyphs after - startIndex will be included - @param includeWhitespace if true, the extent of any whitespace characters will also - be taken into account - */ - Rectangle getBoundingBox (int startIndex, int numGlyphs, bool includeWhitespace) const; - - /** Shifts a set of glyphs by a given amount. - - @param startIndex the first glyph to transform - @param numGlyphs the number of glyphs to move; if this is < 0, all glyphs after - startIndex will be used - @param deltaX the amount to add to their x-positions - @param deltaY the amount to add to their y-positions - */ - void moveRangeOfGlyphs (int startIndex, int numGlyphs, - float deltaX, float deltaY); - - /** Removes a set of glyphs from the arrangement. - - @param startIndex the first glyph to remove - @param numGlyphs the number of glyphs to remove; if this is < 0, all glyphs after - startIndex will be deleted - */ - void removeRangeOfGlyphs (int startIndex, int numGlyphs); - - /** Expands or compresses a set of glyphs horizontally. - - @param startIndex the first glyph to transform - @param numGlyphs the number of glyphs to stretch; if this is < 0, all glyphs after - startIndex will be used - @param horizontalScaleFactor how much to scale their horizontal width by - */ - void stretchRangeOfGlyphs (int startIndex, int numGlyphs, - float horizontalScaleFactor); - - /** Justifies a set of glyphs within a given space. - - This moves the glyphs as a block so that the whole thing is located within the - given rectangle with the specified layout. - - If the Justification::horizontallyJustified flag is specified, each line will - be stretched out to fill the specified width. - */ - void justifyGlyphs (int startIndex, int numGlyphs, - float x, float y, float width, float height, - Justification justification); - - -private: - //============================================================================== - Array glyphs; - - int insertEllipsis (const Font&, float maxXPos, int startIndex, int endIndex); - int fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font&, - Justification, float minimumHorizontalScale); - void spreadOutLine (int start, int numGlyphs, float targetWidth); - void splitLines (const String&, Font, int start, float x, float y, float w, float h, int maxLines, - float lineWidth, Justification, float minimumHorizontalScale); - void addLinesWithLineBreaks (const String&, const Font&, float x, float y, float width, float height, Justification); - void drawGlyphUnderline (const Graphics&, const PositionedGlyph&, int, const AffineTransform&) const; - - JUCE_LEAK_DETECTOR (GlyphArrangement) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/fonts/juce_TextLayout.cpp b/source/modules/juce_graphics/fonts/juce_TextLayout.cpp deleted file mode 100644 index 1a713db55..000000000 --- a/source/modules/juce_graphics/fonts/juce_TextLayout.cpp +++ /dev/null @@ -1,592 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -TextLayout::Glyph::Glyph (const int glyph, Point anch, float w) noexcept - : glyphCode (glyph), anchor (anch), width (w) -{ -} - -TextLayout::Glyph::Glyph (const Glyph& other) noexcept - : glyphCode (other.glyphCode), anchor (other.anchor), width (other.width) -{ -} - -TextLayout::Glyph& TextLayout::Glyph::operator= (const Glyph& other) noexcept -{ - glyphCode = other.glyphCode; - anchor = other.anchor; - width = other.width; - return *this; -} - -TextLayout::Glyph::~Glyph() noexcept {} - -//============================================================================== -TextLayout::Run::Run() noexcept - : colour (0xff000000) -{ -} - -TextLayout::Run::Run (Range range, int numGlyphsToPreallocate) - : colour (0xff000000), stringRange (range) -{ - glyphs.ensureStorageAllocated (numGlyphsToPreallocate); -} - -TextLayout::Run::Run (const Run& other) - : font (other.font), - colour (other.colour), - glyphs (other.glyphs), - stringRange (other.stringRange) -{ -} - -TextLayout::Run::~Run() noexcept {} - -//============================================================================== -TextLayout::Line::Line() noexcept - : ascent (0.0f), descent (0.0f), leading (0.0f) -{ -} - -TextLayout::Line::Line (Range range, Point o, float asc, float desc, - float lead, int numRunsToPreallocate) - : stringRange (range), lineOrigin (o), - ascent (asc), descent (desc), leading (lead) -{ - runs.ensureStorageAllocated (numRunsToPreallocate); -} - -TextLayout::Line::Line (const Line& other) - : stringRange (other.stringRange), lineOrigin (other.lineOrigin), - ascent (other.ascent), descent (other.descent), leading (other.leading) -{ - runs.addCopiesOf (other.runs); -} - -TextLayout::Line::~Line() noexcept -{ -} - -Range TextLayout::Line::getLineBoundsX() const noexcept -{ - Range range; - bool isFirst = true; - - for (auto* run : runs) - { - for (auto& glyph : run->glyphs) - { - Range runRange (glyph.anchor.x, glyph.anchor.x + glyph.width); - - if (isFirst) - { - isFirst = false; - range = runRange; - } - else - { - range = range.getUnionWith (runRange); - } - } - } - - return range + lineOrigin.x; -} - -Range TextLayout::Line::getLineBoundsY() const noexcept -{ - return { lineOrigin.y - ascent, - lineOrigin.y + descent }; -} - -Rectangle TextLayout::Line::getLineBounds() const noexcept -{ - auto x = getLineBoundsX(); - auto y = getLineBoundsY(); - - return { x.getStart(), y.getStart(), x.getLength(), y.getLength() }; -} - -//============================================================================== -TextLayout::TextLayout() - : width (0), height (0), justification (Justification::topLeft) -{ -} - -TextLayout::TextLayout (const TextLayout& other) - : width (other.width), height (other.height), - justification (other.justification) -{ - lines.addCopiesOf (other.lines); -} - -TextLayout::TextLayout (TextLayout&& other) noexcept - : lines (static_cast&&> (other.lines)), - width (other.width), height (other.height), - justification (other.justification) -{ -} - -TextLayout& TextLayout::operator= (TextLayout&& other) noexcept -{ - lines = static_cast&&> (other.lines); - width = other.width; - height = other.height; - justification = other.justification; - return *this; -} - -TextLayout& TextLayout::operator= (const TextLayout& other) -{ - width = other.width; - height = other.height; - justification = other.justification; - lines.clear(); - lines.addCopiesOf (other.lines); - return *this; -} - -TextLayout::~TextLayout() -{ -} - -TextLayout::Line& TextLayout::getLine (const int index) const -{ - return *lines.getUnchecked (index); -} - -void TextLayout::ensureStorageAllocated (int numLinesNeeded) -{ - lines.ensureStorageAllocated (numLinesNeeded); -} - -void TextLayout::addLine (Line* line) -{ - lines.add (line); -} - -void TextLayout::draw (Graphics& g, Rectangle area) const -{ - auto origin = justification.appliedToRectangle (Rectangle (width, getHeight()), area).getPosition(); - - auto& context = g.getInternalContext(); - - for (auto* line : lines) - { - auto lineOrigin = origin + line->lineOrigin; - - for (auto* run : line->runs) - { - context.setFont (run->font); - context.setFill (run->colour); - - for (auto& glyph : run->glyphs) - context.drawGlyph (glyph.glyphCode, AffineTransform::translation (lineOrigin.x + glyph.anchor.x, - lineOrigin.y + glyph.anchor.y)); - - if (run->font.isUnderlined()) - { - Range runExtent; - - for (auto& glyph : run->glyphs) - { - Range glyphRange (glyph.anchor.x, glyph.anchor.x + glyph.width); - - runExtent = runExtent.isEmpty() ? glyphRange - : runExtent.getUnionWith (glyphRange); - } - - auto lineThickness = run->font.getDescent() * 0.3f; - - context.fillRect ({ runExtent.getStart() + lineOrigin.x, lineOrigin.y + lineThickness * 2.0f, - runExtent.getLength(), lineThickness }); - } - } - } -} - -void TextLayout::createLayout (const AttributedString& text, float maxWidth) -{ - createLayout (text, maxWidth, 1.0e7f); -} - -void TextLayout::createLayout (const AttributedString& text, float maxWidth, float maxHeight) -{ - lines.clear(); - width = maxWidth; - height = maxHeight; - justification = text.getJustification(); - - if (! createNativeLayout (text)) - createStandardLayout (text); - - recalculateSize(); -} - -void TextLayout::createLayoutWithBalancedLineLengths (const AttributedString& text, float maxWidth) -{ - createLayoutWithBalancedLineLengths (text, maxWidth, 1.0e7f); -} - -void TextLayout::createLayoutWithBalancedLineLengths (const AttributedString& text, float maxWidth, float maxHeight) -{ - auto minimumWidth = maxWidth / 2.0f; - auto bestWidth = maxWidth; - float bestLineProportion = 0.0f; - - while (maxWidth > minimumWidth) - { - createLayout (text, maxWidth, maxHeight); - - if (getNumLines() < 2) - return; - - auto line1 = lines.getUnchecked (lines.size() - 1)->getLineBoundsX().getLength(); - auto line2 = lines.getUnchecked (lines.size() - 2)->getLineBoundsX().getLength(); - auto shortest = jmin (line1, line2); - auto longest = jmax (line1, line2); - auto prop = shortest > 0 ? longest / shortest : 1.0f; - - if (prop > 0.9f && prop < 1.1f) - return; - - if (prop > bestLineProportion) - { - bestLineProportion = prop; - bestWidth = maxWidth; - } - - maxWidth -= 10.0f; - } - - if (bestWidth != maxWidth) - createLayout (text, bestWidth, maxHeight); -} - -//============================================================================== -namespace TextLayoutHelpers -{ - struct Token - { - Token (const String& t, const Font& f, Colour c, bool whitespace) - : text (t), font (f), colour (c), - area (font.getStringWidthFloat (t), f.getHeight()), - isWhitespace (whitespace), - isNewLine (t.containsChar ('\n') || t.containsChar ('\r')) - {} - - const String text; - const Font font; - const Colour colour; - Rectangle area; - int line; - float lineHeight; - const bool isWhitespace, isNewLine; - - Token& operator= (const Token&) = delete; - }; - - struct TokenList - { - TokenList() noexcept {} - - void createLayout (const AttributedString& text, TextLayout& layout) - { - layout.ensureStorageAllocated (totalLines); - - addTextRuns (text); - layoutRuns (layout.getWidth(), text.getLineSpacing(), text.getWordWrap()); - - int charPosition = 0; - int lineStartPosition = 0; - int runStartPosition = 0; - - ScopedPointer currentLine; - ScopedPointer currentRun; - - bool needToSetLineOrigin = true; - - for (int i = 0; i < tokens.size(); ++i) - { - auto& t = *tokens.getUnchecked (i); - - Array newGlyphs; - Array xOffsets; - t.font.getGlyphPositions (getTrimmedEndIfNotAllWhitespace (t.text), newGlyphs, xOffsets); - - if (currentRun == nullptr) currentRun = new TextLayout::Run(); - if (currentLine == nullptr) currentLine = new TextLayout::Line(); - - if (newGlyphs.size() > 0) - { - currentRun->glyphs.ensureStorageAllocated (currentRun->glyphs.size() + newGlyphs.size()); - auto tokenOrigin = t.area.getPosition().translated (0, t.font.getAscent()); - - if (needToSetLineOrigin) - { - needToSetLineOrigin = false; - currentLine->lineOrigin = tokenOrigin; - } - - auto glyphOffset = tokenOrigin - currentLine->lineOrigin; - - for (int j = 0; j < newGlyphs.size(); ++j) - { - auto x = xOffsets.getUnchecked (j); - currentRun->glyphs.add (TextLayout::Glyph (newGlyphs.getUnchecked(j), - glyphOffset.translated (x, 0), - xOffsets.getUnchecked (j + 1) - x)); - } - - charPosition += newGlyphs.size(); - } - - if (t.isWhitespace || t.isNewLine) - ++charPosition; - - if (auto* nextToken = tokens[i + 1]) - { - if (t.font != nextToken->font || t.colour != nextToken->colour) - { - addRun (*currentLine, currentRun.release(), t, runStartPosition, charPosition); - runStartPosition = charPosition; - } - - if (t.line != nextToken->line) - { - if (currentRun == nullptr) - currentRun = new TextLayout::Run(); - - addRun (*currentLine, currentRun.release(), t, runStartPosition, charPosition); - currentLine->stringRange = Range (lineStartPosition, charPosition); - - if (! needToSetLineOrigin) - layout.addLine (currentLine.release()); - - runStartPosition = charPosition; - lineStartPosition = charPosition; - needToSetLineOrigin = true; - } - } - else - { - addRun (*currentLine, currentRun.release(), t, runStartPosition, charPosition); - currentLine->stringRange = Range (lineStartPosition, charPosition); - - if (! needToSetLineOrigin) - layout.addLine (currentLine.release()); - - needToSetLineOrigin = true; - } - } - - if ((text.getJustification().getFlags() & (Justification::right | Justification::horizontallyCentred)) != 0) - { - auto totalW = layout.getWidth(); - bool isCentred = (text.getJustification().getFlags() & Justification::horizontallyCentred) != 0; - - for (int i = 0; i < layout.getNumLines(); ++i) - { - auto dx = totalW - layout.getLine(i).getLineBoundsX().getLength(); - - if (isCentred) - dx /= 2.0f; - - layout.getLine(i).lineOrigin.x += dx; - } - } - } - - private: - static void addRun (TextLayout::Line& glyphLine, TextLayout::Run* glyphRun, - const Token& t, const int start, const int end) - { - glyphRun->stringRange = { start, end }; - glyphRun->font = t.font; - glyphRun->colour = t.colour; - glyphLine.ascent = jmax (glyphLine.ascent, t.font.getAscent()); - glyphLine.descent = jmax (glyphLine.descent, t.font.getDescent()); - glyphLine.runs.add (glyphRun); - } - - static int getCharacterType (const juce_wchar c) noexcept - { - if (c == '\r' || c == '\n') - return 0; - - return CharacterFunctions::isWhitespace (c) ? 2 : 1; - } - - void appendText (const String& stringText, const Font& font, Colour colour) - { - auto t = stringText.getCharPointer(); - String currentString; - int lastCharType = 0; - - for (;;) - { - auto c = t.getAndAdvance(); - - if (c == 0) - break; - - auto charType = getCharacterType (c); - - if (charType == 0 || charType != lastCharType) - { - if (currentString.isNotEmpty()) - tokens.add (new Token (currentString, font, colour, - lastCharType == 2 || lastCharType == 0)); - - currentString = String::charToString (c); - - if (c == '\r' && *t == '\n') - currentString += t.getAndAdvance(); - } - else - { - currentString += c; - } - - lastCharType = charType; - } - - if (currentString.isNotEmpty()) - tokens.add (new Token (currentString, font, colour, lastCharType == 2)); - } - - void layoutRuns (const float maxWidth, const float extraLineSpacing, const AttributedString::WordWrap wordWrap) - { - float x = 0, y = 0, h = 0; - int i; - - for (i = 0; i < tokens.size(); ++i) - { - auto& t = *tokens.getUnchecked(i); - t.area.setPosition (x, y); - t.line = totalLines; - x += t.area.getWidth(); - h = jmax (h, t.area.getHeight() + extraLineSpacing); - - auto* nextTok = tokens[i + 1]; - - if (nextTok == nullptr) - break; - - const bool tokenTooLarge = (x + nextTok->area.getWidth() > maxWidth); - - if (t.isNewLine || ((! nextTok->isWhitespace) && (tokenTooLarge && wordWrap != AttributedString::none))) - { - setLastLineHeight (i + 1, h); - x = 0; - y += h; - h = 0; - ++totalLines; - } - } - - setLastLineHeight (jmin (i + 1, tokens.size()), h); - ++totalLines; - } - - void setLastLineHeight (int i, const float height) noexcept - { - while (--i >= 0) - { - auto& tok = *tokens.getUnchecked (i); - - if (tok.line == totalLines) - tok.lineHeight = height; - else - break; - } - } - - void addTextRuns (const AttributedString& text) - { - auto numAttributes = text.getNumAttributes(); - tokens.ensureStorageAllocated (jmax (64, numAttributes)); - - for (int i = 0; i < numAttributes; ++i) - { - auto& attr = text.getAttribute (i); - - appendText (text.getText().substring (attr.range.getStart(), attr.range.getEnd()), - attr.font, attr.colour); - } - } - - static String getTrimmedEndIfNotAllWhitespace (const String& s) - { - auto trimmed = s.trimEnd(); - - if (trimmed.isEmpty() && s.isNotEmpty()) - trimmed = s.replaceCharacters ("\r\n\t", " "); - - return trimmed; - } - - OwnedArray tokens; - int totalLines = 0; - - JUCE_DECLARE_NON_COPYABLE (TokenList) - }; -} - -//============================================================================== -void TextLayout::createStandardLayout (const AttributedString& text) -{ - TextLayoutHelpers::TokenList l; - l.createLayout (text, *this); -} - -void TextLayout::recalculateSize() -{ - if (! lines.isEmpty()) - { - auto bounds = lines.getFirst()->getLineBounds(); - - for (auto* line : lines) - bounds = bounds.getUnion (line->getLineBounds()); - - for (auto* line : lines) - line->lineOrigin.x -= bounds.getX(); - - width = bounds.getWidth(); - height = bounds.getHeight(); - } - else - { - width = 0; - height = 0; - } -} - -} // namespace juce diff --git a/source/modules/juce_graphics/fonts/juce_TextLayout.h b/source/modules/juce_graphics/fonts/juce_TextLayout.h deleted file mode 100644 index d5b201627..000000000 --- a/source/modules/juce_graphics/fonts/juce_TextLayout.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A Pre-formatted piece of text, which may contain multiple fonts and colours. - - A TextLayout is created from an AttributedString, and once created can be - quickly drawn into a Graphics context. - - @see AttributedString -*/ -class JUCE_API TextLayout -{ -public: - /** Creates an empty layout. - Having created a TextLayout, you can populate it using createLayout() or - createLayoutWithBalancedLineLengths(). - */ - TextLayout(); - TextLayout (const TextLayout&); - TextLayout& operator= (const TextLayout&); - TextLayout (TextLayout&&) noexcept; - TextLayout& operator= (TextLayout&&) noexcept; - - /** Destructor. */ - ~TextLayout(); - - //============================================================================== - /** Creates a layout from the given attributed string. - This will replace any data that is currently stored in the layout. - */ - void createLayout (const AttributedString&, float maxWidth); - - /** Creates a layout from the given attributed string, given some size constraints. - This will replace any data that is currently stored in the layout. - */ - void createLayout (const AttributedString&, float maxWidth, float maxHeight); - - /** Creates a layout, attempting to choose a width which results in lines - of a similar length. - - This will be slower than the normal createLayout method, but produces a - tidier result. - */ - void createLayoutWithBalancedLineLengths (const AttributedString&, float maxWidth); - - /** Creates a layout, attempting to choose a width which results in lines - of a similar length. - - This will be slower than the normal createLayout method, but produces a - tidier result. - */ - void createLayoutWithBalancedLineLengths (const AttributedString&, float maxWidth, float maxHeight); - - /** Draws the layout within the specified area. - The position of the text within the rectangle is controlled by the justification - flags set in the original AttributedString that was used to create this layout. - */ - void draw (Graphics&, Rectangle area) const; - - //============================================================================== - /** A positioned glyph. */ - class JUCE_API Glyph - { - public: - Glyph (int glyphCode, Point anchor, float width) noexcept; - Glyph (const Glyph&) noexcept; - Glyph& operator= (const Glyph&) noexcept; - ~Glyph() noexcept; - - /** The code number of this glyph. */ - int glyphCode; - - /** The glyph's anchor point - this is relative to the line's origin. - @see TextLayout::Line::lineOrigin - */ - Point anchor; - - float width; - - private: - JUCE_LEAK_DETECTOR (Glyph) - }; - - //============================================================================== - /** A sequence of glyphs with a common font and colour. */ - class JUCE_API Run - { - public: - Run() noexcept; - Run (const Run&); - Run (Range stringRange, int numGlyphsToPreallocate); - ~Run() noexcept; - - Font font; /**< The run's font. */ - Colour colour; /**< The run's colour. */ - Array glyphs; /**< The glyphs in this run. */ - Range stringRange; /**< The character range that this run represents in the - original string that was used to create it. */ - private: - Run& operator= (const Run&); - JUCE_LEAK_DETECTOR (Run) - }; - - //============================================================================== - /** A line containing a sequence of glyph-runs. */ - class JUCE_API Line - { - public: - Line() noexcept; - Line (const Line&); - Line (Range stringRange, Point lineOrigin, - float ascent, float descent, float leading, int numRunsToPreallocate); - ~Line() noexcept; - - /** Returns the X position range which contains all the glyphs in this line. */ - Range getLineBoundsX() const noexcept; - - /** Returns the Y position range which contains all the glyphs in this line. */ - Range getLineBoundsY() const noexcept; - - /** Returns the smallest rectangle which contains all the glyphs in this line. */ - Rectangle getLineBounds() const noexcept; - - OwnedArray runs; /**< The glyph-runs in this line. */ - Range stringRange; /**< The character range that this line represents in the - original string that was used to create it. */ - Point lineOrigin; /**< The line's baseline origin. */ - float ascent, descent, leading; - - private: - Line& operator= (const Line&); - JUCE_LEAK_DETECTOR (Line) - }; - - //============================================================================== - /** Returns the maximum width of the content. */ - float getWidth() const noexcept { return width; } - - /** Returns the maximum height of the content. */ - float getHeight() const noexcept { return height; } - - /** Returns the number of lines in the layout. */ - int getNumLines() const noexcept { return lines.size(); } - - /** Returns one of the lines. */ - Line& getLine (int index) const; - - /** Adds a line to the layout. The layout will take ownership of this line object - and will delete it when it is no longer needed. */ - void addLine (Line*); - - /** Pre-allocates space for the specified number of lines. */ - void ensureStorageAllocated (int numLinesNeeded); - -private: - OwnedArray lines; - float width, height; - Justification justification; - - void createStandardLayout (const AttributedString&); - bool createNativeLayout (const AttributedString&); - void recalculateSize(); - - JUCE_LEAK_DETECTOR (TextLayout) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/fonts/juce_Typeface.cpp b/source/modules/juce_graphics/fonts/juce_Typeface.cpp deleted file mode 100644 index d712e2d81..000000000 --- a/source/modules/juce_graphics/fonts/juce_Typeface.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -struct FontStyleHelpers -{ - static const char* getStyleName (const bool bold, - const bool italic) noexcept - { - if (bold && italic) return "Bold Italic"; - if (bold) return "Bold"; - if (italic) return "Italic"; - return "Regular"; - } - - static const char* getStyleName (const int styleFlags) noexcept - { - return getStyleName ((styleFlags & Font::bold) != 0, - (styleFlags & Font::italic) != 0); - } - - static bool isBold (const String& style) noexcept - { - return style.containsWholeWordIgnoreCase ("Bold"); - } - - static bool isItalic (const String& style) noexcept - { - return style.containsWholeWordIgnoreCase ("Italic") - || style.containsWholeWordIgnoreCase ("Oblique"); - } - - static bool isPlaceholderFamilyName (const String& family) - { - return family == Font::getDefaultSansSerifFontName() - || family == Font::getDefaultSerifFontName() - || family == Font::getDefaultMonospacedFontName(); - } - - struct ConcreteFamilyNames - { - ConcreteFamilyNames() - : sans (findName (Font::getDefaultSansSerifFontName())), - serif (findName (Font::getDefaultSerifFontName())), - mono (findName (Font::getDefaultMonospacedFontName())) - { - } - - String lookUp (const String& placeholder) - { - if (placeholder == Font::getDefaultSansSerifFontName()) return sans; - if (placeholder == Font::getDefaultSerifFontName()) return serif; - if (placeholder == Font::getDefaultMonospacedFontName()) return mono; - - return findName (placeholder); - } - - private: - static String findName (const String& placeholder) - { - const Font f (placeholder, Font::getDefaultStyle(), 15.0f); - return Font::getDefaultTypefaceForFont (f)->getName(); - } - - String sans, serif, mono; - }; - - static String getConcreteFamilyNameFromPlaceholder (const String& placeholder) - { - static ConcreteFamilyNames names; - return names.lookUp (placeholder); - } - - static String getConcreteFamilyName (const Font& font) - { - const String& family = font.getTypefaceName(); - - return isPlaceholderFamilyName (family) ? getConcreteFamilyNameFromPlaceholder (family) - : family; - } -}; - -//============================================================================== -Typeface::Typeface (const String& faceName, const String& styleName) noexcept - : name (faceName), style (styleName) -{ -} - -Typeface::~Typeface() -{ -} - -Typeface::Ptr Typeface::getFallbackTypeface() -{ - const Font fallbackFont (Font::getFallbackFontName(), Font::getFallbackFontStyle(), 10.0f); - return fallbackFont.getTypeface(); -} - -EdgeTable* Typeface::getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight) -{ - Path path; - - if (getOutlineForGlyph (glyphNumber, path) && ! path.isEmpty()) - { - applyVerticalHintingTransform (fontHeight, path); - - return new EdgeTable (path.getBoundsTransformed (transform).getSmallestIntegerContainer().expanded (1, 0), - path, transform); - } - - return nullptr; -} - -//============================================================================== -struct Typeface::HintingParams -{ - HintingParams (Typeface& t) - : cachedSize (0), top (0), middle (0), bottom (0) - { - Font font (&t); - font = font.withHeight ((float) standardHeight); - - top = getAverageY (font, "BDEFPRTZOQ", true); - middle = getAverageY (font, "acegmnopqrsuvwxy", true); - bottom = getAverageY (font, "BDELZOC", false); - } - - void applyVerticalHintingTransform (float fontSize, Path& path) - { - if (cachedSize != fontSize) - { - cachedSize = fontSize; - cachedScale = Scaling (top, middle, bottom, fontSize); - } - - if (bottom < top + 3.0f / fontSize) - return; - - Path result; - - for (Path::Iterator i (path); i.next();) - { - switch (i.elementType) - { - case Path::Iterator::startNewSubPath: result.startNewSubPath (i.x1, cachedScale.apply (i.y1)); break; - case Path::Iterator::lineTo: result.lineTo (i.x1, cachedScale.apply (i.y1)); break; - case Path::Iterator::quadraticTo: result.quadraticTo (i.x1, cachedScale.apply (i.y1), - i.x2, cachedScale.apply (i.y2)); break; - case Path::Iterator::cubicTo: result.cubicTo (i.x1, cachedScale.apply (i.y1), - i.x2, cachedScale.apply (i.y2), - i.x3, cachedScale.apply (i.y3)); break; - case Path::Iterator::closePath: result.closeSubPath(); break; - default: jassertfalse; break; - } - } - - result.swapWithPath (path); - } - -private: - struct Scaling - { - Scaling() noexcept : middle(), upperScale(), upperOffset(), lowerScale(), lowerOffset() {} - - Scaling (float t, float m, float b, float fontSize) noexcept : middle (m) - { - const float newT = std::floor (fontSize * t + 0.5f) / fontSize; - const float newB = std::floor (fontSize * b + 0.5f) / fontSize; - const float newM = std::floor (fontSize * m + 0.3f) / fontSize; // this is slightly biased so that lower-case letters - // are more likely to become taller than shorter. - upperScale = jlimit (0.9f, 1.1f, (newM - newT) / (m - t)); - lowerScale = jlimit (0.9f, 1.1f, (newB - newM) / (b - m)); - - upperOffset = newM - m * upperScale; - lowerOffset = newB - b * lowerScale; - } - - float apply (float y) const noexcept - { - return y < middle ? (y * upperScale + upperOffset) - : (y * lowerScale + lowerOffset); - } - - float middle, upperScale, upperOffset, lowerScale, lowerOffset; - }; - - float cachedSize; - Scaling cachedScale; - - static float getAverageY (const Font& font, const char* chars, bool getTop) - { - GlyphArrangement ga; - ga.addLineOfText (font, chars, 0, 0); - - Array y; - DefaultElementComparator sorter; - - for (int i = 0; i < ga.getNumGlyphs(); ++i) - { - Path p; - ga.getGlyph (i).createPath (p); - Rectangle bounds (p.getBounds()); - - if (! p.isEmpty()) - y.addSorted (sorter, getTop ? bounds.getY() : bounds.getBottom()); - } - - float median = y[y.size() / 2]; - - float total = 0; - int num = 0; - - for (int i = 0; i < y.size(); ++i) - { - if (std::abs (median - y.getUnchecked(i)) < 0.05f * (float) standardHeight) - { - total += y.getUnchecked(i); - ++num; - } - } - - return num < 4 ? 0.0f : total / (num * (float) standardHeight); - } - - enum { standardHeight = 100 }; - float top, middle, bottom; -}; - -void Typeface::applyVerticalHintingTransform (float fontSize, Path& path) -{ - if (fontSize > 3.0f && fontSize < 25.0f) - { - ScopedLock sl (hintingLock); - - if (hintingParams == nullptr) - hintingParams = new HintingParams (*this); - - return hintingParams->applyVerticalHintingTransform (fontSize, path); - } -} - -} // namespace juce diff --git a/source/modules/juce_graphics/fonts/juce_Typeface.h b/source/modules/juce_graphics/fonts/juce_Typeface.h deleted file mode 100644 index 82a2eb8f6..000000000 --- a/source/modules/juce_graphics/fonts/juce_Typeface.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A typeface represents a size-independent font. - - This base class is abstract, but calling createSystemTypefaceFor() will return - a platform-specific subclass that can be used. - - The CustomTypeface subclass allow you to build your own typeface, and to - load and save it in the Juce typeface format. - - Normally you should never need to deal directly with Typeface objects - the Font - class does everything you typically need for rendering text. - - @see CustomTypeface, Font -*/ -class JUCE_API Typeface : public ReferenceCountedObject -{ -public: - //============================================================================== - /** A handy typedef for a pointer to a typeface. */ - typedef ReferenceCountedObjectPtr Ptr; - - //============================================================================== - /** Returns the font family of the typeface. - @see Font::getTypefaceName - */ - const String& getName() const noexcept { return name; } - - //============================================================================== - /** Returns the font style of the typeface. - @see Font::getTypefaceStyle - */ - const String& getStyle() const noexcept { return style; } - - //============================================================================== - /** Creates a new system typeface. */ - static Ptr createSystemTypefaceFor (const Font& font); - - /** Attempts to create a font from some raw font file data (e.g. a TTF or OTF file image). - The system will take its own internal copy of the data, so you can free the block once - this method has returned. - */ - static Ptr createSystemTypefaceFor (const void* fontFileData, size_t fontFileDataSize); - - //============================================================================== - /** Destructor. */ - virtual ~Typeface(); - - /** Returns true if this typeface can be used to render the specified font. - When called, the font will already have been checked to make sure that its name and - style flags match the typeface. - */ - virtual bool isSuitableForFont (const Font&) const { return true; } - - /** Returns the ascent of the font, as a proportion of its height. - The height is considered to always be normalised as 1.0, so this will be a - value less that 1.0, indicating the proportion of the font that lies above - its baseline. - */ - virtual float getAscent() const = 0; - - /** Returns the descent of the font, as a proportion of its height. - The height is considered to always be normalised as 1.0, so this will be a - value less that 1.0, indicating the proportion of the font that lies below - its baseline. - */ - virtual float getDescent() const = 0; - - /** Returns the value by which you should multiply a juce font-height value to - convert it to the equivalent point-size. - */ - virtual float getHeightToPointsFactor() const = 0; - - /** Measures the width of a line of text. - The distance returned is based on the font having an normalised height of 1.0. - You should never need to call this directly! Use Font::getStringWidth() instead! - */ - virtual float getStringWidth (const String& text) = 0; - - /** Converts a line of text into its glyph numbers and their positions. - The distances returned are based on the font having an normalised height of 1.0. - You should never need to call this directly! Use Font::getGlyphPositions() instead! - */ - virtual void getGlyphPositions (const String& text, Array & glyphs, Array& xOffsets) = 0; - - /** Returns the outline for a glyph. - The path returned will be normalised to a font height of 1.0. - */ - virtual bool getOutlineForGlyph (int glyphNumber, Path& path) = 0; - - /** Returns a new EdgeTable that contains the path for the givem glyph, with the specified transform applied. */ - virtual EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight); - - /** Returns true if the typeface uses hinting. */ - virtual bool isHinted() const { return false; } - - //============================================================================== - /** Changes the number of fonts that are cached in memory. */ - static void setTypefaceCacheSize (int numFontsToCache); - - /** Clears any fonts that are currently cached in memory. */ - static void clearTypefaceCache(); - - /** On some platforms, this allows a specific path to be scanned. - Currently only available when using FreeType. - */ - static void scanFolderForFonts (const File& folder); - - /** Makes an attempt at performing a good overall distortion that will scale a font of - the given size to align vertically with the pixel grid. The path should be an unscaled - (i.e. normalised to height of 1.0) path for a glyph. - */ - void applyVerticalHintingTransform (float fontHeight, Path& path); - -protected: - //============================================================================== - String name, style; - - Typeface (const String& name, const String& style) noexcept; - - static Ptr getFallbackTypeface(); - -private: - struct HintingParams; - friend struct ContainerDeletePolicy; - ScopedPointer hintingParams; - CriticalSection hintingLock; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Typeface) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/geometry/juce_AffineTransform.cpp b/source/modules/juce_graphics/geometry/juce_AffineTransform.cpp deleted file mode 100644 index 59115696d..000000000 --- a/source/modules/juce_graphics/geometry/juce_AffineTransform.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -AffineTransform::AffineTransform() noexcept - : mat00 (1.0f), mat01 (0), mat02 (0), - mat10 (0), mat11 (1.0f), mat12 (0) -{ -} - -AffineTransform::AffineTransform (const AffineTransform& other) noexcept - : mat00 (other.mat00), mat01 (other.mat01), mat02 (other.mat02), - mat10 (other.mat10), mat11 (other.mat11), mat12 (other.mat12) -{ -} - -AffineTransform::AffineTransform (const float m00, const float m01, const float m02, - const float m10, const float m11, const float m12) noexcept - : mat00 (m00), mat01 (m01), mat02 (m02), - mat10 (m10), mat11 (m11), mat12 (m12) -{ -} - -AffineTransform& AffineTransform::operator= (const AffineTransform& other) noexcept -{ - mat00 = other.mat00; - mat01 = other.mat01; - mat02 = other.mat02; - mat10 = other.mat10; - mat11 = other.mat11; - mat12 = other.mat12; - - return *this; -} - -bool AffineTransform::operator== (const AffineTransform& other) const noexcept -{ - return mat00 == other.mat00 - && mat01 == other.mat01 - && mat02 == other.mat02 - && mat10 == other.mat10 - && mat11 == other.mat11 - && mat12 == other.mat12; -} - -bool AffineTransform::operator!= (const AffineTransform& other) const noexcept -{ - return ! operator== (other); -} - -//============================================================================== -bool AffineTransform::isIdentity() const noexcept -{ - return (mat01 == 0.0f) - && (mat02 == 0.0f) - && (mat10 == 0.0f) - && (mat12 == 0.0f) - && (mat00 == 1.0f) - && (mat11 == 1.0f); -} - -#if JUCE_ALLOW_STATIC_NULL_VARIABLES -const AffineTransform AffineTransform::identity; -#endif - -//============================================================================== -AffineTransform AffineTransform::followedBy (const AffineTransform& other) const noexcept -{ - return AffineTransform (other.mat00 * mat00 + other.mat01 * mat10, - other.mat00 * mat01 + other.mat01 * mat11, - other.mat00 * mat02 + other.mat01 * mat12 + other.mat02, - other.mat10 * mat00 + other.mat11 * mat10, - other.mat10 * mat01 + other.mat11 * mat11, - other.mat10 * mat02 + other.mat11 * mat12 + other.mat12); -} - -AffineTransform AffineTransform::translated (const float dx, const float dy) const noexcept -{ - return AffineTransform (mat00, mat01, mat02 + dx, - mat10, mat11, mat12 + dy); -} - -AffineTransform AffineTransform::translation (const float dx, const float dy) noexcept -{ - return AffineTransform (1.0f, 0, dx, - 0, 1.0f, dy); -} - -AffineTransform AffineTransform::withAbsoluteTranslation (const float tx, const float ty) const noexcept -{ - return AffineTransform (mat00, mat01, tx, - mat10, mat11, ty); -} - -AffineTransform AffineTransform::rotated (const float rad) const noexcept -{ - const float cosRad = std::cos (rad); - const float sinRad = std::sin (rad); - - return AffineTransform (cosRad * mat00 + -sinRad * mat10, - cosRad * mat01 + -sinRad * mat11, - cosRad * mat02 + -sinRad * mat12, - sinRad * mat00 + cosRad * mat10, - sinRad * mat01 + cosRad * mat11, - sinRad * mat02 + cosRad * mat12); -} - -AffineTransform AffineTransform::rotation (const float rad) noexcept -{ - const float cosRad = std::cos (rad); - const float sinRad = std::sin (rad); - - return AffineTransform (cosRad, -sinRad, 0, - sinRad, cosRad, 0); -} - -AffineTransform AffineTransform::rotation (const float rad, const float pivotX, const float pivotY) noexcept -{ - const float cosRad = std::cos (rad); - const float sinRad = std::sin (rad); - - return AffineTransform (cosRad, -sinRad, -cosRad * pivotX + sinRad * pivotY + pivotX, - sinRad, cosRad, -sinRad * pivotX + -cosRad * pivotY + pivotY); -} - -AffineTransform AffineTransform::rotated (const float angle, const float pivotX, const float pivotY) const noexcept -{ - return followedBy (rotation (angle, pivotX, pivotY)); -} - -AffineTransform AffineTransform::scaled (const float factorX, const float factorY) const noexcept -{ - return AffineTransform (factorX * mat00, factorX * mat01, factorX * mat02, - factorY * mat10, factorY * mat11, factorY * mat12); -} - -AffineTransform AffineTransform::scaled (const float factor) const noexcept -{ - return AffineTransform (factor * mat00, factor * mat01, factor * mat02, - factor * mat10, factor * mat11, factor * mat12); -} - -AffineTransform AffineTransform::scale (const float factorX, const float factorY) noexcept -{ - return AffineTransform (factorX, 0, 0, 0, factorY, 0); -} - -AffineTransform AffineTransform::scale (const float factor) noexcept -{ - return AffineTransform (factor, 0, 0, 0, factor, 0); -} - -AffineTransform AffineTransform::scaled (const float factorX, const float factorY, - const float pivotX, const float pivotY) const noexcept -{ - return AffineTransform (factorX * mat00, factorX * mat01, factorX * mat02 + pivotX * (1.0f - factorX), - factorY * mat10, factorY * mat11, factorY * mat12 + pivotY * (1.0f - factorY)); -} - -AffineTransform AffineTransform::scale (const float factorX, const float factorY, - const float pivotX, const float pivotY) noexcept -{ - return AffineTransform (factorX, 0, pivotX * (1.0f - factorX), - 0, factorY, pivotY * (1.0f - factorY)); -} - -AffineTransform AffineTransform::shear (float shearX, float shearY) noexcept -{ - return AffineTransform (1.0f, shearX, 0, - shearY, 1.0f, 0); -} - -AffineTransform AffineTransform::sheared (const float shearX, const float shearY) const noexcept -{ - return AffineTransform (mat00 + shearX * mat10, - mat01 + shearX * mat11, - mat02 + shearX * mat12, - mat10 + shearY * mat00, - mat11 + shearY * mat01, - mat12 + shearY * mat02); -} - -AffineTransform AffineTransform::verticalFlip (const float height) noexcept -{ - return AffineTransform (1.0f, 0, 0, 0, -1.0f, height); -} - -AffineTransform AffineTransform::inverted() const noexcept -{ - double determinant = (mat00 * mat11 - mat10 * mat01); - - if (determinant != 0.0) - { - determinant = 1.0 / determinant; - - const float dst00 = (float) ( mat11 * determinant); - const float dst10 = (float) (-mat10 * determinant); - const float dst01 = (float) (-mat01 * determinant); - const float dst11 = (float) ( mat00 * determinant); - - return AffineTransform (dst00, dst01, -mat02 * dst00 - mat12 * dst01, - dst10, dst11, -mat02 * dst10 - mat12 * dst11); - } - - // singularity.. - return *this; -} - -bool AffineTransform::isSingularity() const noexcept -{ - return (mat00 * mat11 - mat10 * mat01) == 0.0f; -} - -AffineTransform AffineTransform::fromTargetPoints (const float x00, const float y00, - const float x10, const float y10, - const float x01, const float y01) noexcept -{ - return AffineTransform (x10 - x00, x01 - x00, x00, - y10 - y00, y01 - y00, y00); -} - -AffineTransform AffineTransform::fromTargetPoints (const float sx1, const float sy1, const float tx1, const float ty1, - const float sx2, const float sy2, const float tx2, const float ty2, - const float sx3, const float sy3, const float tx3, const float ty3) noexcept -{ - return fromTargetPoints (sx1, sy1, sx2, sy2, sx3, sy3) - .inverted() - .followedBy (fromTargetPoints (tx1, ty1, tx2, ty2, tx3, ty3)); -} - -bool AffineTransform::isOnlyTranslation() const noexcept -{ - return (mat01 == 0.0f) - && (mat10 == 0.0f) - && (mat00 == 1.0f) - && (mat11 == 1.0f); -} - -float AffineTransform::getScaleFactor() const noexcept -{ - return (std::abs (mat00) + std::abs (mat11)) / 2.0f; -} - -} // namespace juce diff --git a/source/modules/juce_graphics/geometry/juce_AffineTransform.h b/source/modules/juce_graphics/geometry/juce_AffineTransform.h deleted file mode 100644 index a11561baf..000000000 --- a/source/modules/juce_graphics/geometry/juce_AffineTransform.h +++ /dev/null @@ -1,279 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Represents a 2D affine-transformation matrix. - - An affine transformation is a transformation such as a rotation, scale, shear, - resize or translation. - - These are used for various 2D transformation tasks, e.g. with Path objects. - - @see Path, Point, Line -*/ -class JUCE_API AffineTransform -{ -public: - //============================================================================== - /** Creates an identity transform. */ - AffineTransform() noexcept; - - /** Creates a copy of another transform. */ - AffineTransform (const AffineTransform& other) noexcept; - - /** Creates a transform from a set of raw matrix values. - - The resulting matrix is: - - (mat00 mat01 mat02) - (mat10 mat11 mat12) - ( 0 0 1 ) - */ - AffineTransform (float mat00, float mat01, float mat02, - float mat10, float mat11, float mat12) noexcept; - - /** Copies from another AffineTransform object */ - AffineTransform& operator= (const AffineTransform& other) noexcept; - - /** Compares two transforms. */ - bool operator== (const AffineTransform& other) const noexcept; - - /** Compares two transforms. */ - bool operator!= (const AffineTransform& other) const noexcept; - - #if JUCE_ALLOW_STATIC_NULL_VARIABLES - /** A ready-to-use identity transform. - Note that you should always avoid using a static variable like this, and - prefer AffineTransform() or {} if you need a default-constructed instance. - */ - static const AffineTransform identity; - #endif - - //============================================================================== - /** Transforms a 2D coordinate using this matrix. */ - template - void transformPoint (ValueType& x, ValueType& y) const noexcept - { - const ValueType oldX = x; - x = static_cast (mat00 * oldX + mat01 * y + mat02); - y = static_cast (mat10 * oldX + mat11 * y + mat12); - } - - /** Transforms two 2D coordinates using this matrix. - This is just a shortcut for calling transformPoint() on each of these pairs of - coordinates in turn. (And putting all the calculations into one function hopefully - also gives the compiler a bit more scope for pipelining it). - */ - template - void transformPoints (ValueType& x1, ValueType& y1, - ValueType& x2, ValueType& y2) const noexcept - { - const ValueType oldX1 = x1, oldX2 = x2; - x1 = static_cast (mat00 * oldX1 + mat01 * y1 + mat02); - y1 = static_cast (mat10 * oldX1 + mat11 * y1 + mat12); - x2 = static_cast (mat00 * oldX2 + mat01 * y2 + mat02); - y2 = static_cast (mat10 * oldX2 + mat11 * y2 + mat12); - } - - /** Transforms three 2D coordinates using this matrix. - This is just a shortcut for calling transformPoint() on each of these pairs of - coordinates in turn. (And putting all the calculations into one function hopefully - also gives the compiler a bit more scope for pipelining it). - */ - template - void transformPoints (ValueType& x1, ValueType& y1, - ValueType& x2, ValueType& y2, - ValueType& x3, ValueType& y3) const noexcept - { - const ValueType oldX1 = x1, oldX2 = x2, oldX3 = x3; - x1 = static_cast (mat00 * oldX1 + mat01 * y1 + mat02); - y1 = static_cast (mat10 * oldX1 + mat11 * y1 + mat12); - x2 = static_cast (mat00 * oldX2 + mat01 * y2 + mat02); - y2 = static_cast (mat10 * oldX2 + mat11 * y2 + mat12); - x3 = static_cast (mat00 * oldX3 + mat01 * y3 + mat02); - y3 = static_cast (mat10 * oldX3 + mat11 * y3 + mat12); - } - - //============================================================================== - /** Returns a new transform which is the same as this one followed by a translation. */ - AffineTransform translated (float deltaX, - float deltaY) const noexcept; - - /** Returns a new transform which is the same as this one followed by a translation. */ - template - AffineTransform translated (PointType delta) const noexcept - { - return translated ((float) delta.x, (float) delta.y); - } - - /** Returns a new transform which is a translation. */ - static AffineTransform translation (float deltaX, - float deltaY) noexcept; - - /** Returns a new transform which is a translation. */ - template - static AffineTransform translation (PointType delta) noexcept - { - return translation ((float) delta.x, (float) delta.y); - } - - /** Returns a copy of this transform with the specified translation matrix values. */ - AffineTransform withAbsoluteTranslation (float translationX, - float translationY) const noexcept; - - /** Returns a transform which is the same as this one followed by a rotation. - - The rotation is specified by a number of radians to rotate clockwise, centred around - the origin (0, 0). - */ - AffineTransform rotated (float angleInRadians) const noexcept; - - /** Returns a transform which is the same as this one followed by a rotation about a given point. - - The rotation is specified by a number of radians to rotate clockwise, centred around - the coordinates passed in. - */ - AffineTransform rotated (float angleInRadians, - float pivotX, - float pivotY) const noexcept; - - /** Returns a new transform which is a rotation about (0, 0). */ - static AffineTransform rotation (float angleInRadians) noexcept; - - /** Returns a new transform which is a rotation about a given point. */ - static AffineTransform rotation (float angleInRadians, - float pivotX, - float pivotY) noexcept; - - /** Returns a transform which is the same as this one followed by a re-scaling. - The scaling is centred around the origin (0, 0). - */ - AffineTransform scaled (float factorX, - float factorY) const noexcept; - - /** Returns a transform which is the same as this one followed by a re-scaling. - The scaling is centred around the origin (0, 0). - */ - AffineTransform scaled (float factor) const noexcept; - - /** Returns a transform which is the same as this one followed by a re-scaling. - The scaling is centred around the origin provided. - */ - AffineTransform scaled (float factorX, float factorY, - float pivotX, float pivotY) const noexcept; - - /** Returns a new transform which is a re-scale about the origin. */ - static AffineTransform scale (float factorX, - float factorY) noexcept; - - /** Returns a new transform which is a re-scale about the origin. */ - static AffineTransform scale (float factor) noexcept; - - /** Returns a new transform which is a re-scale centred around the point provided. */ - static AffineTransform scale (float factorX, float factorY, - float pivotX, float pivotY) noexcept; - - /** Returns a transform which is the same as this one followed by a shear. - The shear is centred around the origin (0, 0). - */ - AffineTransform sheared (float shearX, float shearY) const noexcept; - - /** Returns a shear transform, centred around the origin (0, 0). */ - static AffineTransform shear (float shearX, float shearY) noexcept; - - /** Returns a transform that will flip coordinates vertically within a window of the given height. - This is handy for converting between upside-down coordinate systems such as OpenGL or CoreGraphics. - */ - static AffineTransform verticalFlip (float height) noexcept; - - /** Returns a matrix which is the inverse operation of this one. - - Some matrices don't have an inverse - in this case, the method will just return - an identity transform. - */ - AffineTransform inverted() const noexcept; - - /** Returns the transform that will map three known points onto three coordinates - that are supplied. - - This returns the transform that will transform (0, 0) into (x00, y00), - (1, 0) to (x10, y10), and (0, 1) to (x01, y01). - */ - static AffineTransform fromTargetPoints (float x00, float y00, - float x10, float y10, - float x01, float y01) noexcept; - - /** Returns the transform that will map three specified points onto three target points. */ - static AffineTransform fromTargetPoints (float sourceX1, float sourceY1, float targetX1, float targetY1, - float sourceX2, float sourceY2, float targetX2, float targetY2, - float sourceX3, float sourceY3, float targetX3, float targetY3) noexcept; - - //============================================================================== - /** Returns the result of concatenating another transformation after this one. */ - AffineTransform followedBy (const AffineTransform& other) const noexcept; - - /** Returns true if this transform has no effect on points. */ - bool isIdentity() const noexcept; - - /** Returns true if this transform maps to a singularity - i.e. if it has no inverse. */ - bool isSingularity() const noexcept; - - /** Returns true if the transform only translates, and doesn't scale or rotate the - points. */ - bool isOnlyTranslation() const noexcept; - - /** If this transform is only a translation, this returns the X offset. - @see isOnlyTranslation - */ - float getTranslationX() const noexcept { return mat02; } - - /** If this transform is only a translation, this returns the X offset. - @see isOnlyTranslation - */ - float getTranslationY() const noexcept { return mat12; } - - /** Returns the approximate scale factor by which lengths will be transformed. - Obviously a length may be scaled by entirely different amounts depending on its - direction, so this is only appropriate as a rough guide. - */ - float getScaleFactor() const noexcept; - - //============================================================================== - /* The transform matrix is: - - (mat00 mat01 mat02) - (mat10 mat11 mat12) - ( 0 0 1 ) - */ - float mat00, mat01, mat02; - float mat10, mat11, mat12; -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/geometry/juce_BorderSize.h b/source/modules/juce_graphics/geometry/juce_BorderSize.h deleted file mode 100644 index 8678c2eb4..000000000 --- a/source/modules/juce_graphics/geometry/juce_BorderSize.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Specifies a set of gaps to be left around the sides of a rectangle. - - This is basically the size of the spaces at the top, bottom, left and right of - a rectangle. It's used by various component classes to specify borders. - - @see Rectangle -*/ -template -class BorderSize -{ -public: - //============================================================================== - /** Creates a null border. - All sizes are left as 0. - */ - BorderSize() noexcept - : top(), left(), bottom(), right() - { - } - - /** Creates a copy of another border. */ - BorderSize (const BorderSize& other) noexcept - : top (other.top), left (other.left), bottom (other.bottom), right (other.right) - { - } - - /** Creates a border with the given gaps. */ - BorderSize (ValueType topGap, ValueType leftGap, ValueType bottomGap, ValueType rightGap) noexcept - : top (topGap), left (leftGap), bottom (bottomGap), right (rightGap) - { - } - - /** Creates a border with the given gap on all sides. */ - explicit BorderSize (ValueType allGaps) noexcept - : top (allGaps), left (allGaps), bottom (allGaps), right (allGaps) - { - } - - //============================================================================== - /** Returns the gap that should be left at the top of the region. */ - ValueType getTop() const noexcept { return top; } - - /** Returns the gap that should be left at the top of the region. */ - ValueType getLeft() const noexcept { return left; } - - /** Returns the gap that should be left at the top of the region. */ - ValueType getBottom() const noexcept { return bottom; } - - /** Returns the gap that should be left at the top of the region. */ - ValueType getRight() const noexcept { return right; } - - /** Returns the sum of the top and bottom gaps. */ - ValueType getTopAndBottom() const noexcept { return top + bottom; } - - /** Returns the sum of the left and right gaps. */ - ValueType getLeftAndRight() const noexcept { return left + right; } - - /** Returns true if this border has no thickness along any edge. */ - bool isEmpty() const noexcept { return left + right + top + bottom == ValueType(); } - - //============================================================================== - /** Changes the top gap. */ - void setTop (ValueType newTopGap) noexcept { top = newTopGap; } - - /** Changes the left gap. */ - void setLeft (ValueType newLeftGap) noexcept { left = newLeftGap; } - - /** Changes the bottom gap. */ - void setBottom (ValueType newBottomGap) noexcept { bottom = newBottomGap; } - - /** Changes the right gap. */ - void setRight (ValueType newRightGap) noexcept { right = newRightGap; } - - //============================================================================== - /** Returns a rectangle with these borders removed from it. */ - Rectangle subtractedFrom (const Rectangle& original) const noexcept - { - return Rectangle (original.getX() + left, - original.getY() + top, - original.getWidth() - (left + right), - original.getHeight() - (top + bottom)); - } - - /** Removes this border from a given rectangle. */ - void subtractFrom (Rectangle& rectangle) const noexcept - { - rectangle = subtractedFrom (rectangle); - } - - /** Returns a rectangle with these borders added around it. */ - Rectangle addedTo (const Rectangle& original) const noexcept - { - return Rectangle (original.getX() - left, - original.getY() - top, - original.getWidth() + (left + right), - original.getHeight() + (top + bottom)); - } - - - /** Adds this border around a given rectangle. */ - void addTo (Rectangle& rectangle) const noexcept - { - rectangle = addedTo (rectangle); - } - - //============================================================================== - bool operator== (const BorderSize& other) const noexcept - { - return top == other.top && left == other.left && bottom == other.bottom && right == other.right; - } - - bool operator!= (const BorderSize& other) const noexcept - { - return ! operator== (other); - } - -private: - //============================================================================== - ValueType top, left, bottom, right; -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/geometry/juce_EdgeTable.cpp b/source/modules/juce_graphics/geometry/juce_EdgeTable.cpp deleted file mode 100644 index bfcb7c7d9..000000000 --- a/source/modules/juce_graphics/geometry/juce_EdgeTable.cpp +++ /dev/null @@ -1,838 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -const int juce_edgeTableDefaultEdgesPerLine = 32; - -//============================================================================== -EdgeTable::EdgeTable (const Rectangle& area, - const Path& path, const AffineTransform& transform) - : bounds (area), - maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine), - lineStrideElements (juce_edgeTableDefaultEdgesPerLine * 2 + 1), - needToCheckEmptiness (true) -{ - allocate(); - int* t = table; - - for (int i = bounds.getHeight(); --i >= 0;) - { - *t = 0; - t += lineStrideElements; - } - - const int leftLimit = bounds.getX() << 8; - const int topLimit = bounds.getY() << 8; - const int rightLimit = bounds.getRight() << 8; - const int heightLimit = bounds.getHeight() << 8; - - PathFlatteningIterator iter (path, transform); - - while (iter.next()) - { - int y1 = roundToInt (iter.y1 * 256.0f); - int y2 = roundToInt (iter.y2 * 256.0f); - - if (y1 != y2) - { - y1 -= topLimit; - y2 -= topLimit; - - const int startY = y1; - int direction = -1; - - if (y1 > y2) - { - std::swap (y1, y2); - direction = 1; - } - - if (y1 < 0) - y1 = 0; - - if (y2 > heightLimit) - y2 = heightLimit; - - if (y1 < y2) - { - const double startX = 256.0f * iter.x1; - const double multiplier = (iter.x2 - iter.x1) / (iter.y2 - iter.y1); - const int stepSize = jlimit (1, 256, 256 / (1 + (int) std::abs (multiplier))); - - do - { - const int step = jmin (stepSize, y2 - y1, 256 - (y1 & 255)); - int x = roundToInt (startX + multiplier * ((y1 + (step >> 1)) - startY)); - - if (x < leftLimit) - x = leftLimit; - else if (x >= rightLimit) - x = rightLimit - 1; - - addEdgePoint (x, y1 >> 8, direction * step); - y1 += step; - } - while (y1 < y2); - } - } - } - - sanitiseLevels (path.isUsingNonZeroWinding()); -} - -EdgeTable::EdgeTable (const Rectangle& rectangleToAdd) - : bounds (rectangleToAdd), - maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine), - lineStrideElements (juce_edgeTableDefaultEdgesPerLine * 2 + 1), - needToCheckEmptiness (true) -{ - allocate(); - table[0] = 0; - - const int x1 = rectangleToAdd.getX() << 8; - const int x2 = rectangleToAdd.getRight() << 8; - - int* t = table; - for (int i = rectangleToAdd.getHeight(); --i >= 0;) - { - t[0] = 2; - t[1] = x1; - t[2] = 255; - t[3] = x2; - t[4] = 0; - t += lineStrideElements; - } -} - -EdgeTable::EdgeTable (const RectangleList& rectanglesToAdd) - : bounds (rectanglesToAdd.getBounds()), - maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine), - lineStrideElements (juce_edgeTableDefaultEdgesPerLine * 2 + 1), - needToCheckEmptiness (true) -{ - allocate(); - clearLineSizes(); - - for (auto& r : rectanglesToAdd) - { - const int x1 = r.getX() << 8; - const int x2 = r.getRight() << 8; - int y = r.getY() - bounds.getY(); - - for (int j = r.getHeight(); --j >= 0;) - addEdgePointPair (x1, x2, y++, 255); - } - - sanitiseLevels (true); -} - -EdgeTable::EdgeTable (const RectangleList& rectanglesToAdd) - : bounds (rectanglesToAdd.getBounds().getSmallestIntegerContainer()), - maxEdgesPerLine (rectanglesToAdd.getNumRectangles() * 2), - lineStrideElements (rectanglesToAdd.getNumRectangles() * 4 + 1), - needToCheckEmptiness (true) -{ - bounds.setHeight (bounds.getHeight() + 1); - allocate(); - clearLineSizes(); - - for (auto& r : rectanglesToAdd) - { - const int x1 = roundToInt (r.getX() * 256.0f); - const int x2 = roundToInt (r.getRight() * 256.0f); - - const int y1 = roundToInt (r.getY() * 256.0f) - (bounds.getY() << 8); - const int y2 = roundToInt (r.getBottom() * 256.0f) - (bounds.getY() << 8); - - if (x2 <= x1 || y2 <= y1) - continue; - - int y = y1 >> 8; - const int lastLine = y2 >> 8; - - if (y == lastLine) - { - addEdgePointPair (x1, x2, y, y2 - y1); - } - else - { - addEdgePointPair (x1, x2, y++, 255 - (y1 & 255)); - - while (y < lastLine) - addEdgePointPair (x1, x2, y++, 255); - - jassert (y < bounds.getHeight()); - addEdgePointPair (x1, x2, y, y2 & 255); - } - } - - sanitiseLevels (true); -} - -EdgeTable::EdgeTable (const Rectangle& rectangleToAdd) - : bounds (Rectangle ((int) std::floor (rectangleToAdd.getX()), - roundToInt (rectangleToAdd.getY() * 256.0f) >> 8, - 2 + (int) rectangleToAdd.getWidth(), - 2 + (int) rectangleToAdd.getHeight())), - maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine), - lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1), - needToCheckEmptiness (true) -{ - jassert (! rectangleToAdd.isEmpty()); - allocate(); - table[0] = 0; - - const int x1 = roundToInt (rectangleToAdd.getX() * 256.0f); - const int x2 = roundToInt (rectangleToAdd.getRight() * 256.0f); - - int y1 = roundToInt (rectangleToAdd.getY() * 256.0f) - (bounds.getY() << 8); - jassert (y1 < 256); - int y2 = roundToInt (rectangleToAdd.getBottom() * 256.0f) - (bounds.getY() << 8); - - if (x2 <= x1 || y2 <= y1) - { - bounds.setHeight (0); - return; - } - - int lineY = 0; - int* t = table; - - if ((y1 >> 8) == (y2 >> 8)) - { - t[0] = 2; - t[1] = x1; - t[2] = y2 - y1; - t[3] = x2; - t[4] = 0; - ++lineY; - t += lineStrideElements; - } - else - { - t[0] = 2; - t[1] = x1; - t[2] = 255 - (y1 & 255); - t[3] = x2; - t[4] = 0; - ++lineY; - t += lineStrideElements; - - while (lineY < (y2 >> 8)) - { - t[0] = 2; - t[1] = x1; - t[2] = 255; - t[3] = x2; - t[4] = 0; - ++lineY; - t += lineStrideElements; - } - - jassert (lineY < bounds.getHeight()); - t[0] = 2; - t[1] = x1; - t[2] = y2 & 255; - t[3] = x2; - t[4] = 0; - ++lineY; - t += lineStrideElements; - } - - while (lineY < bounds.getHeight()) - { - t[0] = 0; - t += lineStrideElements; - ++lineY; - } -} - -EdgeTable::EdgeTable (const EdgeTable& other) -{ - operator= (other); -} - -EdgeTable& EdgeTable::operator= (const EdgeTable& other) -{ - bounds = other.bounds; - maxEdgesPerLine = other.maxEdgesPerLine; - lineStrideElements = other.lineStrideElements; - needToCheckEmptiness = other.needToCheckEmptiness; - - allocate(); - copyEdgeTableData (table, lineStrideElements, other.table, lineStrideElements, bounds.getHeight()); - return *this; -} - -EdgeTable::~EdgeTable() -{ -} - -//============================================================================== -static size_t getEdgeTableAllocationSize (int lineStride, int height) noexcept -{ - // (leave an extra line at the end for use as scratch space) - return (size_t) (lineStride * (2 + jmax (0, height))); -} - -void EdgeTable::allocate() -{ - table.malloc (getEdgeTableAllocationSize (lineStrideElements, bounds.getHeight())); -} - -void EdgeTable::clearLineSizes() noexcept -{ - int* t = table; - for (int i = bounds.getHeight(); --i >= 0;) - { - *t = 0; - t += lineStrideElements; - } -} - -void EdgeTable::copyEdgeTableData (int* dest, const int destLineStride, const int* src, const int srcLineStride, int numLines) noexcept -{ - while (--numLines >= 0) - { - memcpy (dest, src, (size_t) (src[0] * 2 + 1) * sizeof (int)); - src += srcLineStride; - dest += destLineStride; - } -} - -void EdgeTable::sanitiseLevels (const bool useNonZeroWinding) noexcept -{ - // Convert the table from relative windings to absolute levels.. - int* lineStart = table; - - for (int y = bounds.getHeight(); --y >= 0;) - { - int num = lineStart[0]; - - if (num > 0) - { - LineItem* items = reinterpret_cast (lineStart + 1); - LineItem* const itemsEnd = items + num; - - // sort the X coords - std::sort (items, itemsEnd); - - const LineItem* src = items; - int correctedNum = num; - int level = 0; - - while (src < itemsEnd) - { - level += src->level; - const int x = src->x; - ++src; - - while (src < itemsEnd && src->x == x) - { - level += src->level; - ++src; - --correctedNum; - } - - int corrected = std::abs (level); - - if (corrected >> 8) - { - if (useNonZeroWinding) - { - corrected = 255; - } - else - { - corrected &= 511; - if (corrected >> 8) - corrected = 511 - corrected; - } - } - - items->x = x; - items->level = corrected; - ++items; - } - - lineStart[0] = correctedNum; - (items - 1)->level = 0; // force the last level to 0, just in case something went wrong in creating the table - } - - lineStart += lineStrideElements; - } -} - -void EdgeTable::remapTableForNumEdges (const int newNumEdgesPerLine) -{ - if (newNumEdgesPerLine != maxEdgesPerLine) - { - maxEdgesPerLine = newNumEdgesPerLine; - - jassert (bounds.getHeight() > 0); - const int newLineStrideElements = maxEdgesPerLine * 2 + 1; - - HeapBlock newTable (getEdgeTableAllocationSize (newLineStrideElements, bounds.getHeight())); - - copyEdgeTableData (newTable, newLineStrideElements, table, lineStrideElements, bounds.getHeight()); - - table.swapWith (newTable); - lineStrideElements = newLineStrideElements; - } -} - -void EdgeTable::optimiseTable() -{ - int maxLineElements = 0; - - for (int i = bounds.getHeight(); --i >= 0;) - maxLineElements = jmax (maxLineElements, table [i * lineStrideElements]); - - remapTableForNumEdges (maxLineElements); -} - -void EdgeTable::addEdgePoint (const int x, const int y, const int winding) -{ - jassert (y >= 0 && y < bounds.getHeight()); - - int* line = table + lineStrideElements * y; - const int numPoints = line[0]; - - if (numPoints >= maxEdgesPerLine) - { - remapTableForNumEdges (maxEdgesPerLine + juce_edgeTableDefaultEdgesPerLine); - jassert (numPoints < maxEdgesPerLine); - line = table + lineStrideElements * y; - } - - line[0]++; - int n = numPoints << 1; - line [n + 1] = x; - line [n + 2] = winding; -} - -void EdgeTable::addEdgePointPair (int x1, int x2, int y, int winding) -{ - jassert (y >= 0 && y < bounds.getHeight()); - - int* line = table + lineStrideElements * y; - const int numPoints = line[0]; - - if (numPoints + 1 >= maxEdgesPerLine) - { - remapTableForNumEdges (maxEdgesPerLine + juce_edgeTableDefaultEdgesPerLine); - jassert (numPoints < maxEdgesPerLine); - line = table + lineStrideElements * y; - } - - line[0] = numPoints + 2; - line += numPoints << 1; - line[1] = x1; - line[2] = winding; - line[3] = x2; - line[4] = -winding; -} - -void EdgeTable::translate (float dx, const int dy) noexcept -{ - bounds.translate ((int) std::floor (dx), dy); - - int* lineStart = table; - const int intDx = (int) (dx * 256.0f); - - for (int i = bounds.getHeight(); --i >= 0;) - { - int* line = lineStart; - lineStart += lineStrideElements; - int num = *line++; - - while (--num >= 0) - { - *line += intDx; - line += 2; - } - } -} - -void EdgeTable::multiplyLevels (float amount) -{ - int* lineStart = table; - const int multiplier = (int) (amount * 256.0f); - - for (int y = 0; y < bounds.getHeight(); ++y) - { - int numPoints = lineStart[0]; - LineItem* item = reinterpret_cast (lineStart + 1); - lineStart += lineStrideElements; - - while (--numPoints > 0) - { - item->level = jmin (255, (item->level * multiplier) >> 8); - ++item; - } - } -} - -void EdgeTable::intersectWithEdgeTableLine (const int y, const int* const otherLine) -{ - jassert (y >= 0 && y < bounds.getHeight()); - - int* srcLine = table + lineStrideElements * y; - int srcNum1 = *srcLine; - - if (srcNum1 == 0) - return; - - int srcNum2 = *otherLine; - - if (srcNum2 == 0) - { - *srcLine = 0; - return; - } - - const int right = bounds.getRight() << 8; - - // optimise for the common case where our line lies entirely within a - // single pair of points, as happens when clipping to a simple rect. - if (srcNum2 == 2 && otherLine[2] >= 255) - { - clipEdgeTableLineToRange (srcLine, otherLine[1], jmin (right, otherLine[3])); - return; - } - - bool isUsingTempSpace = false; - - const int* src1 = srcLine + 1; - int x1 = *src1++; - - const int* src2 = otherLine + 1; - int x2 = *src2++; - - int destIndex = 0, destTotal = 0; - int level1 = 0, level2 = 0; - int lastX = std::numeric_limits::min(), lastLevel = 0; - - while (srcNum1 > 0 && srcNum2 > 0) - { - int nextX; - - if (x1 <= x2) - { - if (x1 == x2) - { - level2 = *src2++; - x2 = *src2++; - --srcNum2; - } - - nextX = x1; - level1 = *src1++; - x1 = *src1++; - --srcNum1; - } - else - { - nextX = x2; - level2 = *src2++; - x2 = *src2++; - --srcNum2; - } - - if (nextX > lastX) - { - if (nextX >= right) - break; - - lastX = nextX; - - const int nextLevel = (level1 * (level2 + 1)) >> 8; - jassert (isPositiveAndBelow (nextLevel, 256)); - - if (nextLevel != lastLevel) - { - if (destTotal >= maxEdgesPerLine) - { - srcLine[0] = destTotal; - - if (isUsingTempSpace) - { - const size_t tempSize = (size_t) srcNum1 * 2 * sizeof (int); - int* const oldTemp = static_cast (alloca (tempSize)); - memcpy (oldTemp, src1, tempSize); - - remapTableForNumEdges (jmax (256, destTotal * 2)); - srcLine = table + lineStrideElements * y; - - int* const newTemp = table + lineStrideElements * bounds.getHeight(); - memcpy (newTemp, oldTemp, tempSize); - src1 = newTemp; - } - else - { - remapTableForNumEdges (jmax (256, destTotal * 2)); - srcLine = table + lineStrideElements * y; - } - } - - ++destTotal; - lastLevel = nextLevel; - - if (! isUsingTempSpace) - { - isUsingTempSpace = true; - int* const temp = table + lineStrideElements * bounds.getHeight(); - memcpy (temp, src1, (size_t) srcNum1 * 2 * sizeof (int)); - src1 = temp; - } - - srcLine[++destIndex] = nextX; - srcLine[++destIndex] = nextLevel; - } - } - } - - if (lastLevel > 0) - { - if (destTotal >= maxEdgesPerLine) - { - srcLine[0] = destTotal; - remapTableForNumEdges (jmax (256, destTotal * 2)); - srcLine = table + lineStrideElements * y; - } - - ++destTotal; - srcLine[++destIndex] = right; - srcLine[++destIndex] = 0; - } - - srcLine[0] = destTotal; -} - -void EdgeTable::clipEdgeTableLineToRange (int* dest, const int x1, const int x2) noexcept -{ - int* lastItem = dest + (dest[0] * 2 - 1); - - if (x2 < lastItem[0]) - { - if (x2 <= dest[1]) - { - dest[0] = 0; - return; - } - - while (x2 < lastItem[-2]) - { - --(dest[0]); - lastItem -= 2; - } - - lastItem[0] = x2; - lastItem[1] = 0; - } - - if (x1 > dest[1]) - { - while (lastItem[0] > x1) - lastItem -= 2; - - const int itemsRemoved = (int) (lastItem - (dest + 1)) / 2; - - if (itemsRemoved > 0) - { - dest[0] -= itemsRemoved; - memmove (dest + 1, lastItem, (size_t) dest[0] * (sizeof (int) * 2)); - } - - dest[1] = x1; - } -} - - -//============================================================================== -void EdgeTable::clipToRectangle (const Rectangle& r) -{ - const Rectangle clipped (r.getIntersection (bounds)); - - if (clipped.isEmpty()) - { - needToCheckEmptiness = false; - bounds.setHeight (0); - } - else - { - const int top = clipped.getY() - bounds.getY(); - const int bottom = clipped.getBottom() - bounds.getY(); - - if (bottom < bounds.getHeight()) - bounds.setHeight (bottom); - - for (int i = top; --i >= 0;) - table [lineStrideElements * i] = 0; - - if (clipped.getX() > bounds.getX() || clipped.getRight() < bounds.getRight()) - { - const int x1 = clipped.getX() << 8; - const int x2 = jmin (bounds.getRight(), clipped.getRight()) << 8; - int* line = table + lineStrideElements * top; - - for (int i = bottom - top; --i >= 0;) - { - if (line[0] != 0) - clipEdgeTableLineToRange (line, x1, x2); - - line += lineStrideElements; - } - } - - needToCheckEmptiness = true; - } -} - -void EdgeTable::excludeRectangle (const Rectangle& r) -{ - const Rectangle clipped (r.getIntersection (bounds)); - - if (! clipped.isEmpty()) - { - const int top = clipped.getY() - bounds.getY(); - const int bottom = clipped.getBottom() - bounds.getY(); - - const int rectLine[] = { 4, std::numeric_limits::min(), 255, - clipped.getX() << 8, 0, - clipped.getRight() << 8, 255, - std::numeric_limits::max(), 0 }; - - for (int i = top; i < bottom; ++i) - intersectWithEdgeTableLine (i, rectLine); - - needToCheckEmptiness = true; - } -} - -void EdgeTable::clipToEdgeTable (const EdgeTable& other) -{ - const Rectangle clipped (other.bounds.getIntersection (bounds)); - - if (clipped.isEmpty()) - { - needToCheckEmptiness = false; - bounds.setHeight (0); - } - else - { - const int top = clipped.getY() - bounds.getY(); - const int bottom = clipped.getBottom() - bounds.getY(); - - if (bottom < bounds.getHeight()) - bounds.setHeight (bottom); - - if (clipped.getRight() < bounds.getRight()) - bounds.setRight (clipped.getRight()); - - for (int i = 0; i < top; ++i) - table [lineStrideElements * i] = 0; - - const int* otherLine = other.table + other.lineStrideElements * (clipped.getY() - other.bounds.getY()); - - for (int i = top; i < bottom; ++i) - { - intersectWithEdgeTableLine (i, otherLine); - otherLine += other.lineStrideElements; - } - - needToCheckEmptiness = true; - } -} - -void EdgeTable::clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels) -{ - y -= bounds.getY(); - - if (y < 0 || y >= bounds.getHeight()) - return; - - needToCheckEmptiness = true; - - if (numPixels <= 0) - { - table [lineStrideElements * y] = 0; - return; - } - - int* tempLine = static_cast (alloca ((size_t) (numPixels * 2 + 4) * sizeof (int))); - int destIndex = 0, lastLevel = 0; - - while (--numPixels >= 0) - { - const int alpha = *mask; - mask += maskStride; - - if (alpha != lastLevel) - { - tempLine[++destIndex] = (x << 8); - tempLine[++destIndex] = alpha; - lastLevel = alpha; - } - - ++x; - } - - if (lastLevel > 0) - { - tempLine[++destIndex] = (x << 8); - tempLine[++destIndex] = 0; - } - - tempLine[0] = destIndex >> 1; - - intersectWithEdgeTableLine (y, tempLine); -} - -bool EdgeTable::isEmpty() noexcept -{ - if (needToCheckEmptiness) - { - needToCheckEmptiness = false; - int* t = table; - - for (int i = bounds.getHeight(); --i >= 0;) - { - if (t[0] > 1) - return false; - - t += lineStrideElements; - } - - bounds.setHeight (0); - } - - return bounds.getHeight() == 0; -} - -} // namespace juce diff --git a/source/modules/juce_graphics/geometry/juce_EdgeTable.h b/source/modules/juce_graphics/geometry/juce_EdgeTable.h deleted file mode 100644 index 5311a894e..000000000 --- a/source/modules/juce_graphics/geometry/juce_EdgeTable.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A table of horizontal scan-line segments - used for rasterising Paths. - - @see Path, Graphics -*/ -class JUCE_API EdgeTable -{ -public: - //============================================================================== - /** Creates an edge table containing a path. - - A table is created with a fixed vertical range, and only sections of the path - which lie within this range will be added to the table. - - @param clipLimits only the region of the path that lies within this area will be added - @param pathToAdd the path to add to the table - @param transform a transform to apply to the path being added - */ - EdgeTable (const Rectangle& clipLimits, - const Path& pathToAdd, - const AffineTransform& transform); - - /** Creates an edge table containing a rectangle. */ - explicit EdgeTable (const Rectangle& rectangleToAdd); - - /** Creates an edge table containing a rectangle list. */ - explicit EdgeTable (const RectangleList& rectanglesToAdd); - - /** Creates an edge table containing a rectangle list. */ - explicit EdgeTable (const RectangleList& rectanglesToAdd); - - /** Creates an edge table containing a rectangle. */ - explicit EdgeTable (const Rectangle& rectangleToAdd); - - /** Creates a copy of another edge table. */ - EdgeTable (const EdgeTable&); - - /** Copies from another edge table. */ - EdgeTable& operator= (const EdgeTable&); - - /** Destructor. */ - ~EdgeTable(); - - //============================================================================== - void clipToRectangle (const Rectangle& r); - void excludeRectangle (const Rectangle& r); - void clipToEdgeTable (const EdgeTable&); - void clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels); - bool isEmpty() noexcept; - const Rectangle& getMaximumBounds() const noexcept { return bounds; } - void translate (float dx, int dy) noexcept; - - /** Scales all the alpha-levels in the table by the given multiplier. */ - void multiplyLevels (float factor); - - /** Reduces the amount of space the table has allocated. - - This will shrink the table down to use as little memory as possible - useful for - read-only tables that get stored and re-used for rendering. - */ - void optimiseTable(); - - - //============================================================================== - /** Iterates the lines in the table, for rendering. - - This function will iterate each line in the table, and call a user-defined class - to render each pixel or continuous line of pixels that the table contains. - - @param iterationCallback this templated class must contain the following methods: - @code - inline void setEdgeTableYPos (int y); - inline void handleEdgeTablePixel (int x, int alphaLevel) const; - inline void handleEdgeTablePixelFull (int x) const; - inline void handleEdgeTableLine (int x, int width, int alphaLevel) const; - inline void handleEdgeTableLineFull (int x, int width) const; - @endcode - (these don't necessarily have to be 'const', but it might help it go faster) - */ - template - void iterate (EdgeTableIterationCallback& iterationCallback) const noexcept - { - const int* lineStart = table; - - for (int y = 0; y < bounds.getHeight(); ++y) - { - const int* line = lineStart; - lineStart += lineStrideElements; - int numPoints = line[0]; - - if (--numPoints > 0) - { - int x = *++line; - jassert ((x >> 8) >= bounds.getX() && (x >> 8) < bounds.getRight()); - int levelAccumulator = 0; - - iterationCallback.setEdgeTableYPos (bounds.getY() + y); - - while (--numPoints >= 0) - { - const int level = *++line; - jassert (isPositiveAndBelow (level, 256)); - const int endX = *++line; - jassert (endX >= x); - const int endOfRun = (endX >> 8); - - if (endOfRun == (x >> 8)) - { - // small segment within the same pixel, so just save it for the next - // time round.. - levelAccumulator += (endX - x) * level; - } - else - { - // plot the fist pixel of this segment, including any accumulated - // levels from smaller segments that haven't been drawn yet - levelAccumulator += (0x100 - (x & 0xff)) * level; - levelAccumulator >>= 8; - x >>= 8; - - if (levelAccumulator > 0) - { - if (levelAccumulator >= 255) - iterationCallback.handleEdgeTablePixelFull (x); - else - iterationCallback.handleEdgeTablePixel (x, levelAccumulator); - } - - // if there's a run of similar pixels, do it all in one go.. - if (level > 0) - { - jassert (endOfRun <= bounds.getRight()); - const int numPix = endOfRun - ++x; - - if (numPix > 0) - iterationCallback.handleEdgeTableLine (x, numPix, level); - } - - // save the bit at the end to be drawn next time round the loop. - levelAccumulator = (endX & 0xff) * level; - } - - x = endX; - } - - levelAccumulator >>= 8; - - if (levelAccumulator > 0) - { - x >>= 8; - jassert (x >= bounds.getX() && x < bounds.getRight()); - - if (levelAccumulator >= 255) - iterationCallback.handleEdgeTablePixelFull (x); - else - iterationCallback.handleEdgeTablePixel (x, levelAccumulator); - } - } - } - } - -private: - //============================================================================== - // table line format: number of points; point0 x, point0 levelDelta, point1 x, point1 levelDelta, etc - struct LineItem - { - int x, level; - - bool operator< (const LineItem& other) const noexcept { return x < other.x; } - }; - - HeapBlock table; - Rectangle bounds; - int maxEdgesPerLine, lineStrideElements; - bool needToCheckEmptiness; - - void allocate(); - void clearLineSizes() noexcept; - void addEdgePoint (int x, int y, int winding); - void addEdgePointPair (int x1, int x2, int y, int winding); - void remapTableForNumEdges (int newNumEdgesPerLine); - void intersectWithEdgeTableLine (int y, const int* otherLine); - void clipEdgeTableLineToRange (int* line, int x1, int x2) noexcept; - void sanitiseLevels (bool useNonZeroWinding) noexcept; - static void copyEdgeTableData (int* dest, int destLineStride, const int* src, int srcLineStride, int numLines) noexcept; - - JUCE_LEAK_DETECTOR (EdgeTable) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/geometry/juce_Line.h b/source/modules/juce_graphics/geometry/juce_Line.h deleted file mode 100644 index d8db97a4e..000000000 --- a/source/modules/juce_graphics/geometry/juce_Line.h +++ /dev/null @@ -1,428 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Represents a line. - - This class contains a bunch of useful methods for various geometric - tasks. - - The ValueType template parameter should be a primitive type - float or double - are what it's designed for. Integer types will work in a basic way, but some methods - that perform mathematical operations may not compile, or they may not produce - sensible results. - - @see Point, Rectangle, Path, Graphics::drawLine -*/ -template -class Line -{ -public: - //============================================================================== - /** Creates a line, using (0, 0) as its start and end points. */ - Line() noexcept {} - - /** Creates a copy of another line. */ - Line (const Line& other) noexcept - : start (other.start), end (other.end) - { - } - - /** Creates a line based on the coordinates of its start and end points. */ - Line (ValueType startX, ValueType startY, ValueType endX, ValueType endY) noexcept - : start (startX, startY), end (endX, endY) - { - } - - /** Creates a line from its start and end points. */ - Line (Point startPoint, Point endPoint) noexcept - : start (startPoint), end (endPoint) - { - } - - /** Copies a line from another one. */ - Line& operator= (const Line& other) noexcept - { - start = other.start; - end = other.end; - return *this; - } - - /** Destructor. */ - ~Line() noexcept {} - - //============================================================================== - /** Returns the x coordinate of the line's start point. */ - inline ValueType getStartX() const noexcept { return start.x; } - - /** Returns the y coordinate of the line's start point. */ - inline ValueType getStartY() const noexcept { return start.y; } - - /** Returns the x coordinate of the line's end point. */ - inline ValueType getEndX() const noexcept { return end.x; } - - /** Returns the y coordinate of the line's end point. */ - inline ValueType getEndY() const noexcept { return end.y; } - - /** Returns the line's start point. */ - inline Point getStart() const noexcept { return start; } - - /** Returns the line's end point. */ - inline Point getEnd() const noexcept { return end; } - - /** Changes this line's start point */ - void setStart (ValueType newStartX, ValueType newStartY) noexcept { start.setXY (newStartX, newStartY); } - - /** Changes this line's end point */ - void setEnd (ValueType newEndX, ValueType newEndY) noexcept { end.setXY (newEndX, newEndY); } - - /** Changes this line's start point */ - void setStart (const Point newStart) noexcept { start = newStart; } - - /** Changes this line's end point */ - void setEnd (const Point newEnd) noexcept { end = newEnd; } - - /** Returns a line that is the same as this one, but with the start and end reversed, */ - Line reversed() const noexcept { return { end, start }; } - - /** Applies an affine transform to the line's start and end points. */ - void applyTransform (const AffineTransform& transform) noexcept - { - start.applyTransform (transform); - end.applyTransform (transform); - } - - //============================================================================== - /** Returns the length of the line. */ - ValueType getLength() const noexcept { return start.getDistanceFrom (end); } - - /** Returns the length of the line. */ - ValueType getLengthSquared() const noexcept { return start.getDistanceSquaredFrom (end); } - - /** Returns true if the line's start and end x coordinates are the same. */ - bool isVertical() const noexcept { return start.x == end.x; } - - /** Returns true if the line's start and end y coordinates are the same. */ - bool isHorizontal() const noexcept { return start.y == end.y; } - - /** Returns the line's angle. - - This value is the number of radians clockwise from the 12 o'clock direction, - where the line's start point is considered to be at the centre. - */ - typename Point::FloatType getAngle() const noexcept { return start.getAngleToPoint (end); } - - /** Creates a line from a start point, length and angle. - - This angle is the number of radians clockwise from the 12 o'clock direction, - where the line's start point is considered to be at the centre. - */ - static Line fromStartAndAngle (Point startPoint, ValueType length, ValueType angle) noexcept - { - return { startPoint, startPoint.getPointOnCircumference (length, angle) }; - } - - //============================================================================== - /** Casts this line to float coordinates. */ - Line toFloat() const noexcept { return { start.toFloat(), end.toFloat() }; } - - /** Casts this line to double coordinates. */ - Line toDouble() const noexcept { return { start.toDouble(), end.toDouble() }; } - - //============================================================================== - /** Compares two lines. */ - bool operator== (Line other) const noexcept { return start == other.start && end == other.end; } - - /** Compares two lines. */ - bool operator!= (Line other) const noexcept { return start != other.start || end != other.end; } - - //============================================================================== - /** Finds the intersection between two lines. - - @param line the line to intersect with - @returns the point at which the lines intersect, even if this lies beyond the end of the lines - */ - Point getIntersection (Line line) const noexcept - { - Point p; - findIntersection (start, end, line.start, line.end, p); - return p; - } - - /** Finds the intersection between two lines. - - @param line the other line - @param intersection the position of the point where the lines meet (or - where they would meet if they were infinitely long) - the intersection (if the lines intersect). If the lines - are parallel, this will just be set to the position - of one of the line's endpoints. - @returns true if the line segments intersect; false if they dont. Even if they - don't intersect, the intersection coordinates returned will still - be valid - */ - bool intersects (Line line, Point& intersection) const noexcept - { - return findIntersection (start, end, line.start, line.end, intersection); - } - - /** Returns true if this line intersects another. */ - bool intersects (Line other) const noexcept - { - Point ignored; - return findIntersection (start, end, other.start, other.end, ignored); - } - - //============================================================================== - /** Returns the location of the point which is a given distance along this line. - - @param distanceFromStart the distance to move along the line from its - start point. This value can be negative or longer - than the line itself - @see getPointAlongLineProportionally - */ - Point getPointAlongLine (ValueType distanceFromStart) const noexcept - { - return start + (end - start) * (distanceFromStart / getLength()); - } - - /** Returns a point which is a certain distance along and to the side of this line. - - This effectively moves a given distance along the line, then another distance - perpendicularly to this, and returns the resulting position. - - @param distanceFromStart the distance to move along the line from its - start point. This value can be negative or longer - than the line itself - @param perpendicularDistance how far to move sideways from the line. If you're - looking along the line from its start towards its - end, then a positive value here will move to the - right, negative value move to the left. - */ - Point getPointAlongLine (ValueType distanceFromStart, - ValueType perpendicularDistance) const noexcept - { - auto delta = end - start; - auto length = juce_hypot ((double) delta.x, - (double) delta.y); - if (length <= 0) - return start; - - return { start.x + static_cast ((delta.x * distanceFromStart - delta.y * perpendicularDistance) / length), - start.y + static_cast ((delta.y * distanceFromStart + delta.x * perpendicularDistance) / length) }; - } - - /** Returns the location of the point which is a given distance along this line - proportional to the line's length. - - @param proportionOfLength the distance to move along the line from its - start point, in multiples of the line's length. - So a value of 0.0 will return the line's start point - and a value of 1.0 will return its end point. (This value - can be negative or greater than 1.0). - @see getPointAlongLine - */ - Point getPointAlongLineProportionally (typename Point::FloatType proportionOfLength) const noexcept - { - return start + (end - start) * proportionOfLength; - } - - /** Returns the smallest distance between this line segment and a given point. - - So if the point is close to the line, this will return the perpendicular - distance from the line; if the point is a long way beyond one of the line's - end-point's, it'll return the straight-line distance to the nearest end-point. - - pointOnLine receives the position of the point that is found. - - @returns the point's distance from the line - @see getPositionAlongLineOfNearestPoint - */ - ValueType getDistanceFromPoint (Point targetPoint, - Point& pointOnLine) const noexcept - { - auto delta = end - start; - auto length = delta.x * delta.x + delta.y * delta.y; - - if (length > 0) - { - auto prop = ((targetPoint.x - start.x) * delta.x - + (targetPoint.y - start.y) * delta.y) / (double) length; - - if (prop >= 0 && prop <= 1.0) - { - pointOnLine = start + delta * prop; - return targetPoint.getDistanceFrom (pointOnLine); - } - } - - auto fromStart = targetPoint.getDistanceFrom (start); - auto fromEnd = targetPoint.getDistanceFrom (end); - - if (fromStart < fromEnd) - { - pointOnLine = start; - return fromStart; - } - - pointOnLine = end; - return fromEnd; - } - - /** Finds the point on this line which is nearest to a given point, and - returns its position as a proportional position along the line. - - @returns a value 0 to 1.0 which is the distance along this line from the - line's start to the point which is nearest to the point passed-in. To - turn this number into a position, use getPointAlongLineProportionally(). - @see getDistanceFromPoint, getPointAlongLineProportionally - */ - ValueType findNearestProportionalPositionTo (Point point) const noexcept - { - auto delta = end - start; - auto length = delta.x * delta.x + delta.y * delta.y; - - return length <= 0 ? 0 - : jlimit (ValueType(), static_cast (1), - static_cast ((((point.x - start.x) * delta.x - + (point.y - start.y) * delta.y) / length))); - } - - /** Finds the point on this line which is nearest to a given point. - @see getDistanceFromPoint, findNearestProportionalPositionTo - */ - Point findNearestPointTo (Point point) const noexcept - { - return getPointAlongLineProportionally (findNearestProportionalPositionTo (point)); - } - - /** Returns true if the given point lies above this line. - - The return value is true if the point's y coordinate is less than the y - coordinate of this line at the given x (assuming the line extends infinitely - in both directions). - */ - bool isPointAbove (Point point) const noexcept - { - return start.x != end.x - && point.y < ((end.y - start.y) * (point.x - start.x)) / (end.x - start.x) + start.y; - } - - //============================================================================== - /** Returns a shortened copy of this line. - - This will chop off part of the start of this line by a certain amount, (leaving the - end-point the same), and return the new line. - */ - Line withShortenedStart (ValueType distanceToShortenBy) const noexcept - { - return { getPointAlongLine (jmin (distanceToShortenBy, getLength())), end }; - } - - /** Returns a shortened copy of this line. - - This will chop off part of the end of this line by a certain amount, (leaving the - start-point the same), and return the new line. - */ - Line withShortenedEnd (ValueType distanceToShortenBy) const noexcept - { - auto length = getLength(); - return { start, getPointAlongLine (length - jmin (distanceToShortenBy, length)) }; - } - -private: - //============================================================================== - Point start, end; - - static bool isZeroToOne (ValueType v) noexcept { return v >= 0 && v <= static_cast (1); } - - static bool findIntersection (const Point p1, const Point p2, - const Point p3, const Point p4, - Point& intersection) noexcept - { - if (p2 == p3) - { - intersection = p2; - return true; - } - - auto d1 = p2 - p1; - auto d2 = p4 - p3; - auto divisor = d1.x * d2.y - d2.x * d1.y; - - if (divisor == 0) - { - if (! (d1.isOrigin() || d2.isOrigin())) - { - if (d1.y == 0 && d2.y != 0) - { - auto along = (p1.y - p3.y) / d2.y; - intersection = p1.withX (p3.x + along * d2.x); - return isZeroToOne (along); - } - - if (d2.y == 0 && d1.y != 0) - { - auto along = (p3.y - p1.y) / d1.y; - intersection = p3.withX (p1.x + along * d1.x); - return isZeroToOne (along); - } - - if (d1.x == 0 && d2.x != 0) - { - auto along = (p1.x - p3.x) / d2.x; - intersection = p1.withY (p3.y + along * d2.y); - return isZeroToOne (along); - } - - if (d2.x == 0 && d1.x != 0) - { - auto along = (p3.x - p1.x) / d1.x; - intersection = p3.withY (p1.y + along * d1.y); - return isZeroToOne (along); - } - } - - intersection = (p2 + p3) / static_cast (2); - return false; - } - - auto along1 = ((p1.y - p3.y) * d2.x - (p1.x - p3.x) * d2.y) / divisor; - intersection = p1 + d1 * along1; - - if (! isZeroToOne (along1)) - return false; - - auto along2 = ((p1.y - p3.y) * d1.x - (p1.x - p3.x) * d1.y) / divisor; - return isZeroToOne (along2); - } -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/geometry/juce_Path.cpp b/source/modules/juce_graphics/geometry/juce_Path.cpp deleted file mode 100644 index 849d4a083..000000000 --- a/source/modules/juce_graphics/geometry/juce_Path.cpp +++ /dev/null @@ -1,1638 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -// tests that some coordinates aren't NaNs -#define JUCE_CHECK_COORDS_ARE_VALID(x, y) \ - jassert (x == x && y == y); - -//============================================================================== -namespace PathHelpers -{ - const float ellipseAngularIncrement = 0.05f; - - static String nextToken (String::CharPointerType& t) - { - t = t.findEndOfWhitespace(); - - auto start = t; - size_t numChars = 0; - - while (! (t.isEmpty() || t.isWhitespace())) - { - ++t; - ++numChars; - } - - return { start, numChars }; - } - - inline double lengthOf (float x1, float y1, float x2, float y2) noexcept - { - return juce_hypot ((double) (x1 - x2), (double) (y1 - y2)); - } -} - -//============================================================================== -const float Path::lineMarker = 100001.0f; -const float Path::moveMarker = 100002.0f; -const float Path::quadMarker = 100003.0f; -const float Path::cubicMarker = 100004.0f; -const float Path::closeSubPathMarker = 100005.0f; - -const float Path::defaultToleranceForTesting = 1.0f; -const float Path::defaultToleranceForMeasurement = 0.6f; - -static inline bool isMarker (float value, float marker) noexcept -{ - return value == marker; -} - -//============================================================================== -Path::PathBounds::PathBounds() noexcept -{ -} - -Rectangle Path::PathBounds::getRectangle() const noexcept -{ - return { pathXMin, pathYMin, pathXMax - pathXMin, pathYMax - pathYMin }; -} - -void Path::PathBounds::reset() noexcept -{ - pathXMin = pathYMin = pathYMax = pathXMax = 0; -} - -void Path::PathBounds::reset (const float x, const float y) noexcept -{ - pathXMin = pathXMax = x; - pathYMin = pathYMax = y; -} - -void Path::PathBounds::extend (const float x, const float y) noexcept -{ - pathXMin = jmin (pathXMin, x); - pathXMax = jmax (pathXMax, x); - pathYMin = jmin (pathYMin, y); - pathYMax = jmax (pathYMax, y); -} - -void Path::PathBounds::extend (const float x1, const float y1, const float x2, const float y2) noexcept -{ - if (x1 < x2) - { - pathXMin = jmin (pathXMin, x1); - pathXMax = jmax (pathXMax, x2); - } - else - { - pathXMin = jmin (pathXMin, x2); - pathXMax = jmax (pathXMax, x1); - } - - if (y1 < y2) - { - pathYMin = jmin (pathYMin, y1); - pathYMax = jmax (pathYMax, y2); - } - else - { - pathYMin = jmin (pathYMin, y2); - pathYMax = jmax (pathYMax, y1); - } -} - -//============================================================================== -Path::Path() -{ -} - -Path::~Path() -{ -} - -Path::Path (const Path& other) - : numElements (other.numElements), - bounds (other.bounds), - useNonZeroWinding (other.useNonZeroWinding) -{ - if (numElements > 0) - { - data.setAllocatedSize ((int) numElements); - memcpy (data.elements, other.data.elements, numElements * sizeof (float)); - } -} - -Path& Path::operator= (const Path& other) -{ - if (this != &other) - { - data.ensureAllocatedSize ((int) other.numElements); - - numElements = other.numElements; - bounds = other.bounds; - useNonZeroWinding = other.useNonZeroWinding; - - if (numElements > 0) - memcpy (data.elements, other.data.elements, numElements * sizeof (float)); - } - - return *this; -} - -Path::Path (Path&& other) noexcept - : data (static_cast&&> (other.data)), - numElements (other.numElements), - bounds (other.bounds), - useNonZeroWinding (other.useNonZeroWinding) -{ -} - -Path& Path::operator= (Path&& other) noexcept -{ - data = static_cast&&> (other.data); - numElements = other.numElements; - bounds = other.bounds; - useNonZeroWinding = other.useNonZeroWinding; - return *this; -} - -bool Path::operator== (const Path& other) const noexcept -{ - return ! operator!= (other); -} - -bool Path::operator!= (const Path& other) const noexcept -{ - if (numElements != other.numElements || useNonZeroWinding != other.useNonZeroWinding) - return true; - - for (size_t i = 0; i < numElements; ++i) - if (data.elements[i] != other.data.elements[i]) - return true; - - return false; -} - -void Path::clear() noexcept -{ - numElements = 0; - bounds.reset(); -} - -void Path::swapWithPath (Path& other) noexcept -{ - data.swapWith (other.data); - std::swap (numElements, other.numElements); - std::swap (bounds.pathXMin, other.bounds.pathXMin); - std::swap (bounds.pathXMax, other.bounds.pathXMax); - std::swap (bounds.pathYMin, other.bounds.pathYMin); - std::swap (bounds.pathYMax, other.bounds.pathYMax); - std::swap (useNonZeroWinding, other.useNonZeroWinding); -} - -//============================================================================== -void Path::setUsingNonZeroWinding (const bool isNonZero) noexcept -{ - useNonZeroWinding = isNonZero; -} - -void Path::scaleToFit (float x, float y, float w, float h, bool preserveProportions) noexcept -{ - applyTransform (getTransformToScaleToFit (x, y, w, h, preserveProportions)); -} - -//============================================================================== -bool Path::isEmpty() const noexcept -{ - size_t i = 0; - - while (i < numElements) - { - auto type = data.elements[i++]; - - if (isMarker (type, moveMarker)) - { - i += 2; - } - else if (isMarker (type, lineMarker) - || isMarker (type, quadMarker) - || isMarker (type, cubicMarker)) - { - return false; - } - } - - return true; -} - -Rectangle Path::getBounds() const noexcept -{ - return bounds.getRectangle(); -} - -Rectangle Path::getBoundsTransformed (const AffineTransform& transform) const noexcept -{ - return getBounds().transformedBy (transform); -} - -//============================================================================== -void Path::preallocateSpace (int numExtraCoordsToMakeSpaceFor) -{ - data.ensureAllocatedSize ((int) numElements + numExtraCoordsToMakeSpaceFor); -} - -void Path::startNewSubPath (const float x, const float y) -{ - JUCE_CHECK_COORDS_ARE_VALID (x, y); - - if (numElements == 0) - bounds.reset (x, y); - else - bounds.extend (x, y); - - preallocateSpace (3); - - data.elements[numElements++] = moveMarker; - data.elements[numElements++] = x; - data.elements[numElements++] = y; -} - -void Path::startNewSubPath (Point start) -{ - startNewSubPath (start.x, start.y); -} - -void Path::lineTo (const float x, const float y) -{ - JUCE_CHECK_COORDS_ARE_VALID (x, y); - - if (numElements == 0) - startNewSubPath (0, 0); - - preallocateSpace (3); - - data.elements[numElements++] = lineMarker; - data.elements[numElements++] = x; - data.elements[numElements++] = y; - - bounds.extend (x, y); -} - -void Path::lineTo (Point end) -{ - lineTo (end.x, end.y); -} - -void Path::quadraticTo (const float x1, const float y1, - const float x2, const float y2) -{ - JUCE_CHECK_COORDS_ARE_VALID (x1, y1); - JUCE_CHECK_COORDS_ARE_VALID (x2, y2); - - if (numElements == 0) - startNewSubPath (0, 0); - - preallocateSpace (5); - - data.elements[numElements++] = quadMarker; - data.elements[numElements++] = x1; - data.elements[numElements++] = y1; - data.elements[numElements++] = x2; - data.elements[numElements++] = y2; - - bounds.extend (x1, y1, x2, y2); -} - -void Path::quadraticTo (Point controlPoint, Point endPoint) -{ - quadraticTo (controlPoint.x, controlPoint.y, - endPoint.x, endPoint.y); -} - -void Path::cubicTo (const float x1, const float y1, - const float x2, const float y2, - const float x3, const float y3) -{ - JUCE_CHECK_COORDS_ARE_VALID (x1, y1); - JUCE_CHECK_COORDS_ARE_VALID (x2, y2); - JUCE_CHECK_COORDS_ARE_VALID (x3, y3); - - if (numElements == 0) - startNewSubPath (0, 0); - - preallocateSpace (7); - - data.elements[numElements++] = cubicMarker; - data.elements[numElements++] = x1; - data.elements[numElements++] = y1; - data.elements[numElements++] = x2; - data.elements[numElements++] = y2; - data.elements[numElements++] = x3; - data.elements[numElements++] = y3; - - bounds.extend (x1, y1, x2, y2); - bounds.extend (x3, y3); -} - -void Path::cubicTo (Point controlPoint1, - Point controlPoint2, - Point endPoint) -{ - cubicTo (controlPoint1.x, controlPoint1.y, - controlPoint2.x, controlPoint2.y, - endPoint.x, endPoint.y); -} - -void Path::closeSubPath() -{ - if (numElements > 0 && ! isMarker (data.elements[numElements - 1], closeSubPathMarker)) - { - preallocateSpace (1); - data.elements[numElements++] = closeSubPathMarker; - } -} - -Point Path::getCurrentPosition() const -{ - int i = (int) numElements - 1; - - if (i > 0 && isMarker (data.elements[i], closeSubPathMarker)) - { - while (i >= 0) - { - if (isMarker (data.elements[i], moveMarker)) - { - i += 2; - break; - } - - --i; - } - } - - if (i > 0) - return { data.elements[i - 1], data.elements[i] }; - - return {}; -} - -void Path::addRectangle (const float x, const float y, - const float w, const float h) -{ - float x1 = x, y1 = y, x2 = x + w, y2 = y + h; - - if (w < 0) std::swap (x1, x2); - if (h < 0) std::swap (y1, y2); - - preallocateSpace (13); - - if (numElements == 0) - { - bounds.pathXMin = x1; - bounds.pathXMax = x2; - bounds.pathYMin = y1; - bounds.pathYMax = y2; - } - else - { - bounds.pathXMin = jmin (bounds.pathXMin, x1); - bounds.pathXMax = jmax (bounds.pathXMax, x2); - bounds.pathYMin = jmin (bounds.pathYMin, y1); - bounds.pathYMax = jmax (bounds.pathYMax, y2); - } - - data.elements[numElements++] = moveMarker; - data.elements[numElements++] = x1; - data.elements[numElements++] = y2; - data.elements[numElements++] = lineMarker; - data.elements[numElements++] = x1; - data.elements[numElements++] = y1; - data.elements[numElements++] = lineMarker; - data.elements[numElements++] = x2; - data.elements[numElements++] = y1; - data.elements[numElements++] = lineMarker; - data.elements[numElements++] = x2; - data.elements[numElements++] = y2; - data.elements[numElements++] = closeSubPathMarker; -} - -void Path::addRoundedRectangle (float x, float y, float w, float h, float csx, float csy) -{ - addRoundedRectangle (x, y, w, h, csx, csy, true, true, true, true); -} - -void Path::addRoundedRectangle (const float x, const float y, const float w, const float h, - float csx, float csy, - const bool curveTopLeft, const bool curveTopRight, - const bool curveBottomLeft, const bool curveBottomRight) -{ - csx = jmin (csx, w * 0.5f); - csy = jmin (csy, h * 0.5f); - auto cs45x = csx * 0.45f; - auto cs45y = csy * 0.45f; - auto x2 = x + w; - auto y2 = y + h; - - if (curveTopLeft) - { - startNewSubPath (x, y + csy); - cubicTo (x, y + cs45y, x + cs45x, y, x + csx, y); - } - else - { - startNewSubPath (x, y); - } - - if (curveTopRight) - { - lineTo (x2 - csx, y); - cubicTo (x2 - cs45x, y, x2, y + cs45y, x2, y + csy); - } - else - { - lineTo (x2, y); - } - - if (curveBottomRight) - { - lineTo (x2, y2 - csy); - cubicTo (x2, y2 - cs45y, x2 - cs45x, y2, x2 - csx, y2); - } - else - { - lineTo (x2, y2); - } - - if (curveBottomLeft) - { - lineTo (x + csx, y2); - cubicTo (x + cs45x, y2, x, y2 - cs45y, x, y2 - csy); - } - else - { - lineTo (x, y2); - } - - closeSubPath(); -} - -void Path::addRoundedRectangle (float x, float y, float w, float h, float cs) -{ - addRoundedRectangle (x, y, w, h, cs, cs); -} - -void Path::addTriangle (float x1, float y1, - float x2, float y2, - float x3, float y3) -{ - addTriangle (Point (x1, y1), - Point (x2, y2), - Point (x3, y3)); -} - -void Path::addTriangle (Point p1, Point p2, Point p3) -{ - startNewSubPath (p1); - lineTo (p2); - lineTo (p3); - closeSubPath(); -} - -void Path::addQuadrilateral (const float x1, const float y1, - const float x2, const float y2, - const float x3, const float y3, - const float x4, const float y4) -{ - startNewSubPath (x1, y1); - lineTo (x2, y2); - lineTo (x3, y3); - lineTo (x4, y4); - closeSubPath(); -} - -void Path::addEllipse (float x, float y, float w, float h) -{ - addEllipse (Rectangle (x, y, w, h)); -} - -void Path::addEllipse (Rectangle area) -{ - auto hw = area.getWidth() * 0.5f; - auto hw55 = hw * 0.55f; - auto hh = area.getHeight() * 0.5f; - auto hh55 = hh * 0.55f; - auto cx = area.getX() + hw; - auto cy = area.getY() + hh; - - startNewSubPath (cx, cy - hh); - cubicTo (cx + hw55, cy - hh, cx + hw, cy - hh55, cx + hw, cy); - cubicTo (cx + hw, cy + hh55, cx + hw55, cy + hh, cx, cy + hh); - cubicTo (cx - hw55, cy + hh, cx - hw, cy + hh55, cx - hw, cy); - cubicTo (cx - hw, cy - hh55, cx - hw55, cy - hh, cx, cy - hh); - closeSubPath(); -} - -void Path::addArc (const float x, const float y, - const float w, const float h, - const float fromRadians, - const float toRadians, - const bool startAsNewSubPath) -{ - auto radiusX = w / 2.0f; - auto radiusY = h / 2.0f; - - addCentredArc (x + radiusX, - y + radiusY, - radiusX, radiusY, - 0.0f, - fromRadians, toRadians, - startAsNewSubPath); -} - -void Path::addCentredArc (const float centreX, const float centreY, - const float radiusX, const float radiusY, - const float rotationOfEllipse, - const float fromRadians, - float toRadians, - const bool startAsNewSubPath) -{ - if (radiusX > 0.0f && radiusY > 0.0f) - { - const Point centre (centreX, centreY); - auto rotation = AffineTransform::rotation (rotationOfEllipse, centreX, centreY); - auto angle = fromRadians; - - if (startAsNewSubPath) - startNewSubPath (centre.getPointOnCircumference (radiusX, radiusY, angle).transformedBy (rotation)); - - if (fromRadians < toRadians) - { - if (startAsNewSubPath) - angle += PathHelpers::ellipseAngularIncrement; - - while (angle < toRadians) - { - lineTo (centre.getPointOnCircumference (radiusX, radiusY, angle).transformedBy (rotation)); - angle += PathHelpers::ellipseAngularIncrement; - } - } - else - { - if (startAsNewSubPath) - angle -= PathHelpers::ellipseAngularIncrement; - - while (angle > toRadians) - { - lineTo (centre.getPointOnCircumference (radiusX, radiusY, angle).transformedBy (rotation)); - angle -= PathHelpers::ellipseAngularIncrement; - } - } - - lineTo (centre.getPointOnCircumference (radiusX, radiusY, toRadians).transformedBy (rotation)); - } -} - -void Path::addPieSegment (const float x, const float y, - const float width, const float height, - const float fromRadians, - const float toRadians, - const float innerCircleProportionalSize) -{ - float radiusX = width * 0.5f; - float radiusY = height * 0.5f; - const Point centre (x + radiusX, y + radiusY); - - startNewSubPath (centre.getPointOnCircumference (radiusX, radiusY, fromRadians)); - addArc (x, y, width, height, fromRadians, toRadians); - - if (std::abs (fromRadians - toRadians) > float_Pi * 1.999f) - { - closeSubPath(); - - if (innerCircleProportionalSize > 0) - { - radiusX *= innerCircleProportionalSize; - radiusY *= innerCircleProportionalSize; - - startNewSubPath (centre.getPointOnCircumference (radiusX, radiusY, toRadians)); - addArc (centre.x - radiusX, centre.y - radiusY, radiusX * 2.0f, radiusY * 2.0f, toRadians, fromRadians); - } - } - else - { - if (innerCircleProportionalSize > 0) - { - radiusX *= innerCircleProportionalSize; - radiusY *= innerCircleProportionalSize; - - addArc (centre.x - radiusX, centre.y - radiusY, radiusX * 2.0f, radiusY * 2.0f, toRadians, fromRadians); - } - else - { - lineTo (centre); - } - } - - closeSubPath(); -} - -void Path::addPieSegment (Rectangle segmentBounds, - const float fromRadians, - const float toRadians, - const float innerCircleProportionalSize) -{ - addPieSegment (segmentBounds.getX(), - segmentBounds.getY(), - segmentBounds.getWidth(), - segmentBounds.getHeight(), - fromRadians, - toRadians, - innerCircleProportionalSize); -} - -//============================================================================== -void Path::addLineSegment (Line line, float lineThickness) -{ - auto reversed = line.reversed(); - lineThickness *= 0.5f; - - startNewSubPath (line.getPointAlongLine (0, lineThickness)); - lineTo (line.getPointAlongLine (0, -lineThickness)); - lineTo (reversed.getPointAlongLine (0, lineThickness)); - lineTo (reversed.getPointAlongLine (0, -lineThickness)); - closeSubPath(); -} - -void Path::addArrow (Line line, float lineThickness, - float arrowheadWidth, float arrowheadLength) -{ - auto reversed = line.reversed(); - lineThickness *= 0.5f; - arrowheadWidth *= 0.5f; - arrowheadLength = jmin (arrowheadLength, 0.8f * line.getLength()); - - startNewSubPath (line.getPointAlongLine (0, lineThickness)); - lineTo (line.getPointAlongLine (0, -lineThickness)); - lineTo (reversed.getPointAlongLine (arrowheadLength, lineThickness)); - lineTo (reversed.getPointAlongLine (arrowheadLength, arrowheadWidth)); - lineTo (line.getEnd()); - lineTo (reversed.getPointAlongLine (arrowheadLength, -arrowheadWidth)); - lineTo (reversed.getPointAlongLine (arrowheadLength, -lineThickness)); - closeSubPath(); -} - -void Path::addPolygon (Point centre, int numberOfSides, - float radius, float startAngle) -{ - jassert (numberOfSides > 1); // this would be silly. - - if (numberOfSides > 1) - { - auto angleBetweenPoints = float_Pi * 2.0f / numberOfSides; - - for (int i = 0; i < numberOfSides; ++i) - { - auto angle = startAngle + i * angleBetweenPoints; - auto p = centre.getPointOnCircumference (radius, angle); - - if (i == 0) - startNewSubPath (p); - else - lineTo (p); - } - - closeSubPath(); - } -} - -void Path::addStar (Point centre, int numberOfPoints, float innerRadius, - float outerRadius, float startAngle) -{ - jassert (numberOfPoints > 1); // this would be silly. - - if (numberOfPoints > 1) - { - auto angleBetweenPoints = float_Pi * 2.0f / numberOfPoints; - - for (int i = 0; i < numberOfPoints; ++i) - { - auto angle = startAngle + i * angleBetweenPoints; - auto p = centre.getPointOnCircumference (outerRadius, angle); - - if (i == 0) - startNewSubPath (p); - else - lineTo (p); - - lineTo (centre.getPointOnCircumference (innerRadius, angle + angleBetweenPoints * 0.5f)); - } - - closeSubPath(); - } -} - -void Path::addBubble (Rectangle bodyArea, - Rectangle maximumArea, - Point arrowTip, - const float cornerSize, - const float arrowBaseWidth) -{ - auto halfW = bodyArea.getWidth() / 2.0f; - auto halfH = bodyArea.getHeight() / 2.0f; - auto cornerSizeW = jmin (cornerSize, halfW); - auto cornerSizeH = jmin (cornerSize, halfH); - auto cornerSizeW2 = 2.0f * cornerSizeW; - auto cornerSizeH2 = 2.0f * cornerSizeH; - - startNewSubPath (bodyArea.getX() + cornerSizeW, bodyArea.getY()); - - const Rectangle targetLimit (bodyArea.reduced (jmin (halfW - 1.0f, cornerSizeW + arrowBaseWidth), - jmin (halfH - 1.0f, cornerSizeH + arrowBaseWidth))); - - if (Rectangle (targetLimit.getX(), maximumArea.getY(), - targetLimit.getWidth(), bodyArea.getY() - maximumArea.getY()).contains (arrowTip)) - { - lineTo (arrowTip.x - arrowBaseWidth, bodyArea.getY()); - lineTo (arrowTip.x, arrowTip.y); - lineTo (arrowTip.x + arrowBaseWidth, bodyArea.getY()); - } - - lineTo (bodyArea.getRight() - cornerSizeW, bodyArea.getY()); - addArc (bodyArea.getRight() - cornerSizeW2, bodyArea.getY(), cornerSizeW2, cornerSizeH2, 0, float_Pi * 0.5f); - - if (Rectangle (bodyArea.getRight(), targetLimit.getY(), - maximumArea.getRight() - bodyArea.getRight(), targetLimit.getHeight()).contains (arrowTip)) - { - lineTo (bodyArea.getRight(), arrowTip.y - arrowBaseWidth); - lineTo (arrowTip.x, arrowTip.y); - lineTo (bodyArea.getRight(), arrowTip.y + arrowBaseWidth); - } - - lineTo (bodyArea.getRight(), bodyArea.getBottom() - cornerSizeH); - addArc (bodyArea.getRight() - cornerSizeW2, bodyArea.getBottom() - cornerSizeH2, cornerSizeW2, cornerSizeH2, float_Pi * 0.5f, float_Pi); - - if (Rectangle (targetLimit.getX(), bodyArea.getBottom(), - targetLimit.getWidth(), maximumArea.getBottom() - bodyArea.getBottom()).contains (arrowTip)) - { - lineTo (arrowTip.x + arrowBaseWidth, bodyArea.getBottom()); - lineTo (arrowTip.x, arrowTip.y); - lineTo (arrowTip.x - arrowBaseWidth, bodyArea.getBottom()); - } - - lineTo (bodyArea.getX() + cornerSizeW, bodyArea.getBottom()); - addArc (bodyArea.getX(), bodyArea.getBottom() - cornerSizeH2, cornerSizeW2, cornerSizeH2, float_Pi, float_Pi * 1.5f); - - if (Rectangle (maximumArea.getX(), targetLimit.getY(), - bodyArea.getX() - maximumArea.getX(), targetLimit.getHeight()).contains (arrowTip)) - { - lineTo (bodyArea.getX(), arrowTip.y + arrowBaseWidth); - lineTo (arrowTip.x, arrowTip.y); - lineTo (bodyArea.getX(), arrowTip.y - arrowBaseWidth); - } - - lineTo (bodyArea.getX(), bodyArea.getY() + cornerSizeH); - addArc (bodyArea.getX(), bodyArea.getY(), cornerSizeW2, cornerSizeH2, float_Pi * 1.5f, float_Pi * 2.0f - 0.05f); - - closeSubPath(); -} - -void Path::addPath (const Path& other) -{ - size_t i = 0; - const float* d = other.data.elements; - - while (i < other.numElements) - { - auto type = d[i++]; - - if (isMarker (type, moveMarker)) - { - startNewSubPath (d[i], d[i + 1]); - i += 2; - } - else if (isMarker (type, lineMarker)) - { - lineTo (d[i], d[i + 1]); - i += 2; - } - else if (isMarker (type, quadMarker)) - { - quadraticTo (d[i], d[i + 1], d[i + 2], d[i + 3]); - i += 4; - } - else if (isMarker (type, cubicMarker)) - { - cubicTo (d[i], d[i + 1], d[i + 2], d[i + 3], d[i + 4], d[i + 5]); - i += 6; - } - else if (isMarker (type, closeSubPathMarker)) - { - closeSubPath(); - } - else - { - // something's gone wrong with the element list! - jassertfalse; - } - } -} - -void Path::addPath (const Path& other, - const AffineTransform& transformToApply) -{ - size_t i = 0; - const float* d = other.data.elements; - - while (i < other.numElements) - { - auto type = d[i++]; - - if (isMarker (type, closeSubPathMarker)) - { - closeSubPath(); - } - else - { - auto x = d[i++]; - auto y = d[i++]; - transformToApply.transformPoint (x, y); - - if (isMarker (type, moveMarker)) - { - startNewSubPath (x, y); - } - else if (isMarker (type, lineMarker)) - { - lineTo (x, y); - } - else if (isMarker (type, quadMarker)) - { - auto x2 = d[i++]; - auto y2 = d[i++]; - transformToApply.transformPoint (x2, y2); - - quadraticTo (x, y, x2, y2); - } - else if (isMarker (type, cubicMarker)) - { - auto x2 = d[i++]; - auto y2 = d[i++]; - auto x3 = d[i++]; - auto y3 = d[i++]; - transformToApply.transformPoints (x2, y2, x3, y3); - - cubicTo (x, y, x2, y2, x3, y3); - } - else - { - // something's gone wrong with the element list! - jassertfalse; - } - } - } -} - -//============================================================================== -void Path::applyTransform (const AffineTransform& transform) noexcept -{ - bounds.reset(); - bool firstPoint = true; - float* d = data.elements; - auto* end = d + numElements; - - while (d < end) - { - auto type = *d++; - - if (isMarker (type, moveMarker)) - { - transform.transformPoint (d[0], d[1]); - - if (firstPoint) - { - firstPoint = false; - bounds.reset (d[0], d[1]); - } - else - { - bounds.extend (d[0], d[1]); - } - - d += 2; - } - else if (isMarker (type, lineMarker)) - { - transform.transformPoint (d[0], d[1]); - bounds.extend (d[0], d[1]); - d += 2; - } - else if (isMarker (type, quadMarker)) - { - transform.transformPoints (d[0], d[1], d[2], d[3]); - bounds.extend (d[0], d[1], d[2], d[3]); - d += 4; - } - else if (isMarker (type, cubicMarker)) - { - transform.transformPoints (d[0], d[1], d[2], d[3], d[4], d[5]); - bounds.extend (d[0], d[1], d[2], d[3]); - bounds.extend (d[4], d[5]); - d += 6; - } - } -} - - -//============================================================================== -AffineTransform Path::getTransformToScaleToFit (Rectangle area, bool preserveProportions, - Justification justification) const -{ - return getTransformToScaleToFit (area.getX(), area.getY(), area.getWidth(), area.getHeight(), - preserveProportions, justification); -} - -AffineTransform Path::getTransformToScaleToFit (const float x, const float y, - const float w, const float h, - const bool preserveProportions, - Justification justification) const -{ - auto boundsRect = getBounds(); - - if (preserveProportions) - { - if (w <= 0 || h <= 0 || boundsRect.isEmpty()) - return AffineTransform(); - - float newW, newH; - auto srcRatio = boundsRect.getHeight() / boundsRect.getWidth(); - - if (srcRatio > h / w) - { - newW = h / srcRatio; - newH = h; - } - else - { - newW = w; - newH = w * srcRatio; - } - - auto newXCentre = x; - auto newYCentre = y; - - if (justification.testFlags (Justification::left)) newXCentre += newW * 0.5f; - else if (justification.testFlags (Justification::right)) newXCentre += w - newW * 0.5f; - else newXCentre += w * 0.5f; - - if (justification.testFlags (Justification::top)) newYCentre += newH * 0.5f; - else if (justification.testFlags (Justification::bottom)) newYCentre += h - newH * 0.5f; - else newYCentre += h * 0.5f; - - return AffineTransform::translation (boundsRect.getWidth() * -0.5f - boundsRect.getX(), - boundsRect.getHeight() * -0.5f - boundsRect.getY()) - .scaled (newW / boundsRect.getWidth(), - newH / boundsRect.getHeight()) - .translated (newXCentre, newYCentre); - } - else - { - return AffineTransform::translation (-boundsRect.getX(), -boundsRect.getY()) - .scaled (w / boundsRect.getWidth(), - h / boundsRect.getHeight()) - .translated (x, y); - } -} - -//============================================================================== -bool Path::contains (const float x, const float y, const float tolerance) const -{ - if (x <= bounds.pathXMin || x >= bounds.pathXMax - || y <= bounds.pathYMin || y >= bounds.pathYMax) - return false; - - PathFlatteningIterator i (*this, AffineTransform(), tolerance); - - int positiveCrossings = 0; - int negativeCrossings = 0; - - while (i.next()) - { - if ((i.y1 <= y && i.y2 > y) || (i.y2 <= y && i.y1 > y)) - { - auto intersectX = i.x1 + (i.x2 - i.x1) * (y - i.y1) / (i.y2 - i.y1); - - if (intersectX <= x) - { - if (i.y1 < i.y2) - ++positiveCrossings; - else - ++negativeCrossings; - } - } - } - - return useNonZeroWinding ? (negativeCrossings != positiveCrossings) - : ((negativeCrossings + positiveCrossings) & 1) != 0; -} - -bool Path::contains (Point point, const float tolerance) const -{ - return contains (point.x, point.y, tolerance); -} - -bool Path::intersectsLine (Line line, const float tolerance) -{ - PathFlatteningIterator i (*this, AffineTransform(), tolerance); - Point intersection; - - while (i.next()) - if (line.intersects (Line (i.x1, i.y1, i.x2, i.y2), intersection)) - return true; - - return false; -} - -Line Path::getClippedLine (Line line, const bool keepSectionOutsidePath) const -{ - Line result (line); - const bool startInside = contains (line.getStart()); - const bool endInside = contains (line.getEnd()); - - if (startInside == endInside) - { - if (keepSectionOutsidePath == startInside) - result = Line(); - } - else - { - PathFlatteningIterator i (*this, AffineTransform()); - Point intersection; - - while (i.next()) - { - if (line.intersects ({ i.x1, i.y1, i.x2, i.y2 }, intersection)) - { - if ((startInside && keepSectionOutsidePath) || (endInside && ! keepSectionOutsidePath)) - result.setStart (intersection); - else - result.setEnd (intersection); - } - } - } - - return result; -} - -float Path::getLength (const AffineTransform& transform, float tolerance) const -{ - float length = 0; - PathFlatteningIterator i (*this, transform, tolerance); - - while (i.next()) - length += Line (i.x1, i.y1, i.x2, i.y2).getLength(); - - return length; -} - -Point Path::getPointAlongPath (float distanceFromStart, - const AffineTransform& transform, - float tolerance) const -{ - PathFlatteningIterator i (*this, transform, tolerance); - - while (i.next()) - { - const Line line (i.x1, i.y1, i.x2, i.y2); - auto lineLength = line.getLength(); - - if (distanceFromStart <= lineLength) - return line.getPointAlongLine (distanceFromStart); - - distanceFromStart -= lineLength; - } - - return { i.x2, i.y2 }; -} - -float Path::getNearestPoint (Point targetPoint, Point& pointOnPath, - const AffineTransform& transform, - float tolerance) const -{ - PathFlatteningIterator i (*this, transform, tolerance); - float bestPosition = 0, bestDistance = std::numeric_limits::max(); - float length = 0; - Point pointOnLine; - - while (i.next()) - { - const Line line (i.x1, i.y1, i.x2, i.y2); - auto distance = line.getDistanceFromPoint (targetPoint, pointOnLine); - - if (distance < bestDistance) - { - bestDistance = distance; - bestPosition = length + pointOnLine.getDistanceFrom (line.getStart()); - pointOnPath = pointOnLine; - } - - length += line.getLength(); - } - - return bestPosition; -} - -//============================================================================== -Path Path::createPathWithRoundedCorners (const float cornerRadius) const -{ - if (cornerRadius <= 0.01f) - return *this; - - Path p; - size_t indexOfPathStart = 0, indexOfPathStartThis = 0; - size_t n = 0; - bool lastWasLine = false, firstWasLine = false; - - while (n < numElements) - { - auto type = data.elements[n++]; - - if (isMarker (type, moveMarker)) - { - indexOfPathStart = p.numElements; - indexOfPathStartThis = n - 1; - auto x = data.elements[n++]; - auto y = data.elements[n++]; - p.startNewSubPath (x, y); - lastWasLine = false; - firstWasLine = (isMarker (data.elements[n], lineMarker)); - } - else if (isMarker (type, lineMarker) || isMarker (type, closeSubPathMarker)) - { - float startX = 0, startY = 0, joinX = 0, joinY = 0, endX, endY; - - if (isMarker (type, lineMarker)) - { - endX = data.elements[n++]; - endY = data.elements[n++]; - - if (n > 8) - { - startX = data.elements[n - 8]; - startY = data.elements[n - 7]; - joinX = data.elements[n - 5]; - joinY = data.elements[n - 4]; - } - } - else - { - endX = data.elements[indexOfPathStartThis + 1]; - endY = data.elements[indexOfPathStartThis + 2]; - - if (n > 6) - { - startX = data.elements[n - 6]; - startY = data.elements[n - 5]; - joinX = data.elements[n - 3]; - joinY = data.elements[n - 2]; - } - } - - if (lastWasLine) - { - auto len1 = PathHelpers::lengthOf (startX, startY, joinX, joinY); - - if (len1 > 0) - { - auto propNeeded = jmin (0.5, cornerRadius / len1); - - p.data.elements[p.numElements - 2] = (float) (joinX - (joinX - startX) * propNeeded); - p.data.elements[p.numElements - 1] = (float) (joinY - (joinY - startY) * propNeeded); - } - - auto len2 = PathHelpers::lengthOf (endX, endY, joinX, joinY); - - if (len2 > 0) - { - auto propNeeded = jmin (0.5, cornerRadius / len2); - - p.quadraticTo (joinX, joinY, - (float) (joinX + (endX - joinX) * propNeeded), - (float) (joinY + (endY - joinY) * propNeeded)); - } - - p.lineTo (endX, endY); - } - else if (isMarker (type, lineMarker)) - { - p.lineTo (endX, endY); - lastWasLine = true; - } - - if (isMarker (type, closeSubPathMarker)) - { - if (firstWasLine) - { - startX = data.elements[n - 3]; - startY = data.elements[n - 2]; - joinX = endX; - joinY = endY; - endX = data.elements[indexOfPathStartThis + 4]; - endY = data.elements[indexOfPathStartThis + 5]; - - auto len1 = PathHelpers::lengthOf (startX, startY, joinX, joinY); - - if (len1 > 0) - { - auto propNeeded = jmin (0.5, cornerRadius / len1); - - p.data.elements[p.numElements - 2] = (float) (joinX - (joinX - startX) * propNeeded); - p.data.elements[p.numElements - 1] = (float) (joinY - (joinY - startY) * propNeeded); - } - - auto len2 = PathHelpers::lengthOf (endX, endY, joinX, joinY); - - if (len2 > 0) - { - auto propNeeded = jmin (0.5, cornerRadius / len2); - - endX = (float) (joinX + (endX - joinX) * propNeeded); - endY = (float) (joinY + (endY - joinY) * propNeeded); - - p.quadraticTo (joinX, joinY, endX, endY); - - p.data.elements[indexOfPathStart + 1] = endX; - p.data.elements[indexOfPathStart + 2] = endY; - } - } - - p.closeSubPath(); - } - } - else if (isMarker (type, quadMarker)) - { - lastWasLine = false; - auto x1 = data.elements[n++]; - auto y1 = data.elements[n++]; - auto x2 = data.elements[n++]; - auto y2 = data.elements[n++]; - p.quadraticTo (x1, y1, x2, y2); - } - else if (isMarker (type, cubicMarker)) - { - lastWasLine = false; - auto x1 = data.elements[n++]; - auto y1 = data.elements[n++]; - auto x2 = data.elements[n++]; - auto y2 = data.elements[n++]; - auto x3 = data.elements[n++]; - auto y3 = data.elements[n++]; - p.cubicTo (x1, y1, x2, y2, x3, y3); - } - } - - return p; -} - -//============================================================================== -void Path::loadPathFromStream (InputStream& source) -{ - while (! source.isExhausted()) - { - switch (source.readByte()) - { - case 'm': - { - auto x = source.readFloat(); - auto y = source.readFloat(); - startNewSubPath (x, y); - break; - } - - case 'l': - { - auto x = source.readFloat(); - auto y = source.readFloat(); - lineTo (x, y); - break; - } - - case 'q': - { - auto x1 = source.readFloat(); - auto y1 = source.readFloat(); - auto x2 = source.readFloat(); - auto y2 = source.readFloat(); - quadraticTo (x1, y1, x2, y2); - break; - } - - case 'b': - { - auto x1 = source.readFloat(); - auto y1 = source.readFloat(); - auto x2 = source.readFloat(); - auto y2 = source.readFloat(); - auto x3 = source.readFloat(); - auto y3 = source.readFloat(); - cubicTo (x1, y1, x2, y2, x3, y3); - break; - } - - case 'c': - closeSubPath(); - break; - - case 'n': - useNonZeroWinding = true; - break; - - case 'z': - useNonZeroWinding = false; - break; - - case 'e': - return; // end of path marker - - default: - jassertfalse; // illegal char in the stream - break; - } - } -} - -void Path::loadPathFromData (const void* const pathData, const size_t numberOfBytes) -{ - MemoryInputStream in (pathData, numberOfBytes, false); - loadPathFromStream (in); -} - -void Path::writePathToStream (OutputStream& dest) const -{ - dest.writeByte (useNonZeroWinding ? 'n' : 'z'); - - for (size_t i = 0; i < numElements;) - { - auto type = data.elements[i++]; - - if (isMarker (type, moveMarker)) - { - dest.writeByte ('m'); - dest.writeFloat (data.elements[i++]); - dest.writeFloat (data.elements[i++]); - } - else if (isMarker (type, lineMarker)) - { - dest.writeByte ('l'); - dest.writeFloat (data.elements[i++]); - dest.writeFloat (data.elements[i++]); - } - else if (isMarker (type, quadMarker)) - { - dest.writeByte ('q'); - dest.writeFloat (data.elements[i++]); - dest.writeFloat (data.elements[i++]); - dest.writeFloat (data.elements[i++]); - dest.writeFloat (data.elements[i++]); - } - else if (isMarker (type, cubicMarker)) - { - dest.writeByte ('b'); - dest.writeFloat (data.elements[i++]); - dest.writeFloat (data.elements[i++]); - dest.writeFloat (data.elements[i++]); - dest.writeFloat (data.elements[i++]); - dest.writeFloat (data.elements[i++]); - dest.writeFloat (data.elements[i++]); - } - else if (isMarker (type, closeSubPathMarker)) - { - dest.writeByte ('c'); - } - } - - dest.writeByte ('e'); // marks the end-of-path -} - -String Path::toString() const -{ - MemoryOutputStream s (2048); - if (! useNonZeroWinding) - s << 'a'; - - size_t i = 0; - float lastMarker = 0.0f; - - while (i < numElements) - { - auto type = data.elements[i++]; - char markerChar = 0; - int numCoords = 0; - - if (isMarker (type, moveMarker)) - { - markerChar = 'm'; - numCoords = 2; - } - else if (isMarker (type, lineMarker)) - { - markerChar = 'l'; - numCoords = 2; - } - else if (isMarker (type, quadMarker)) - { - markerChar = 'q'; - numCoords = 4; - } - else if (isMarker (type, cubicMarker)) - { - markerChar = 'c'; - numCoords = 6; - } - else - { - jassert (isMarker (type, closeSubPathMarker)); - markerChar = 'z'; - } - - if (! isMarker (type, lastMarker)) - { - if (s.getDataSize() != 0) - s << ' '; - - s << markerChar; - lastMarker = type; - } - - while (--numCoords >= 0 && i < numElements) - { - String coord (data.elements[i++], 3); - - while (coord.endsWithChar ('0') && coord != "0") - coord = coord.dropLastCharacters (1); - - if (coord.endsWithChar ('.')) - coord = coord.dropLastCharacters (1); - - if (s.getDataSize() != 0) - s << ' '; - - s << coord; - } - } - - return s.toUTF8(); -} - -void Path::restoreFromString (StringRef stringVersion) -{ - clear(); - setUsingNonZeroWinding (true); - - auto t = stringVersion.text; - juce_wchar marker = 'm'; - int numValues = 2; - float values[6]; - - for (;;) - { - auto token = PathHelpers::nextToken (t); - auto firstChar = token[0]; - int startNum = 0; - - if (firstChar == 0) - break; - - if (firstChar == 'm' || firstChar == 'l') - { - marker = firstChar; - numValues = 2; - } - else if (firstChar == 'q') - { - marker = firstChar; - numValues = 4; - } - else if (firstChar == 'c') - { - marker = firstChar; - numValues = 6; - } - else if (firstChar == 'z') - { - marker = firstChar; - numValues = 0; - } - else if (firstChar == 'a') - { - setUsingNonZeroWinding (false); - continue; - } - else - { - ++startNum; - values [0] = token.getFloatValue(); - } - - for (int i = startNum; i < numValues; ++i) - values [i] = PathHelpers::nextToken (t).getFloatValue(); - - switch (marker) - { - case 'm': startNewSubPath (values[0], values[1]); break; - case 'l': lineTo (values[0], values[1]); break; - case 'q': quadraticTo (values[0], values[1], values[2], values[3]); break; - case 'c': cubicTo (values[0], values[1], values[2], values[3], values[4], values[5]); break; - case 'z': closeSubPath(); break; - default: jassertfalse; break; // illegal string format? - } - } -} - -//============================================================================== -Path::Iterator::Iterator (const Path& p) noexcept - : elementType (startNewSubPath), path (p) -{ -} - -Path::Iterator::~Iterator() noexcept -{ -} - -bool Path::Iterator::next() noexcept -{ - const float* elements = path.data.elements; - - if (index < path.numElements) - { - auto type = elements[index++]; - - if (isMarker (type, moveMarker)) - { - elementType = startNewSubPath; - x1 = elements[index++]; - y1 = elements[index++]; - } - else if (isMarker (type, lineMarker)) - { - elementType = lineTo; - x1 = elements[index++]; - y1 = elements[index++]; - } - else if (isMarker (type, quadMarker)) - { - elementType = quadraticTo; - x1 = elements[index++]; - y1 = elements[index++]; - x2 = elements[index++]; - y2 = elements[index++]; - } - else if (isMarker (type, cubicMarker)) - { - elementType = cubicTo; - x1 = elements[index++]; - y1 = elements[index++]; - x2 = elements[index++]; - y2 = elements[index++]; - x3 = elements[index++]; - y3 = elements[index++]; - } - else if (isMarker (type, closeSubPathMarker)) - { - elementType = closePath; - } - - return true; - } - - return false; -} - -#undef JUCE_CHECK_COORDS_ARE_VALID - -} // namespace juce diff --git a/source/modules/juce_graphics/geometry/juce_Path.h b/source/modules/juce_graphics/geometry/juce_Path.h deleted file mode 100644 index 1a4962ac6..000000000 --- a/source/modules/juce_graphics/geometry/juce_Path.h +++ /dev/null @@ -1,833 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A path is a sequence of lines and curves that may either form a closed shape - or be open-ended. - - To use a path, you can create an empty one, then add lines and curves to it - to create shapes, then it can be rendered by a Graphics context or used - for geometric operations. - - e.g. @code - Path myPath; - - myPath.startNewSubPath (10.0f, 10.0f); // move the current position to (10, 10) - myPath.lineTo (100.0f, 200.0f); // draw a line from here to (100, 200) - myPath.quadraticTo (0.0f, 150.0f, 5.0f, 50.0f); // draw a curve that ends at (5, 50) - myPath.closeSubPath(); // close the subpath with a line back to (10, 10) - - // add an ellipse as well, which will form a second sub-path within the path.. - myPath.addEllipse (50.0f, 50.0f, 40.0f, 30.0f); - - // double the width of the whole thing.. - myPath.applyTransform (AffineTransform::scale (2.0f, 1.0f)); - - // and draw it to a graphics context with a 5-pixel thick outline. - g.strokePath (myPath, PathStrokeType (5.0f)); - - @endcode - - A path object can actually contain multiple sub-paths, which may themselves - be open or closed. - - @see PathFlatteningIterator, PathStrokeType, Graphics -*/ -class JUCE_API Path -{ -public: - //============================================================================== - /** Creates an empty path. */ - Path(); - - /** Creates a copy of another path. */ - Path (const Path&); - - /** Destructor. */ - ~Path(); - - /** Copies this path from another one. */ - Path& operator= (const Path&); - - /** Move constructor */ - Path (Path&&) noexcept; - - /** Move assignment operator */ - Path& operator= (Path&&) noexcept; - - bool operator== (const Path&) const noexcept; - bool operator!= (const Path&) const noexcept; - - static const float defaultToleranceForTesting; - static const float defaultToleranceForMeasurement; - - //============================================================================== - /** Returns true if the path doesn't contain any lines or curves. */ - bool isEmpty() const noexcept; - - /** Returns the smallest rectangle that contains all points within the path. */ - Rectangle getBounds() const noexcept; - - /** Returns the smallest rectangle that contains all points within the path - after it's been transformed with the given tranasform matrix. - */ - Rectangle getBoundsTransformed (const AffineTransform& transform) const noexcept; - - /** Checks whether a point lies within the path. - - This is only relevant for closed paths (see closeSubPath()), and - may produce false results if used on a path which has open sub-paths. - - The path's winding rule is taken into account by this method. - - The tolerance parameter is the maximum error allowed when flattening the path, - so this method could return a false positive when your point is up to this distance - outside the path's boundary. - - @see closeSubPath, setUsingNonZeroWinding - */ - bool contains (float x, float y, - float tolerance = defaultToleranceForTesting) const; - - /** Checks whether a point lies within the path. - - This is only relevant for closed paths (see closeSubPath()), and - may produce false results if used on a path which has open sub-paths. - - The path's winding rule is taken into account by this method. - - The tolerance parameter is the maximum error allowed when flattening the path, - so this method could return a false positive when your point is up to this distance - outside the path's boundary. - - @see closeSubPath, setUsingNonZeroWinding - */ - bool contains (Point point, - float tolerance = defaultToleranceForTesting) const; - - /** Checks whether a line crosses the path. - - This will return positive if the line crosses any of the paths constituent - lines or curves. It doesn't take into account whether the line is inside - or outside the path, or whether the path is open or closed. - - The tolerance parameter is the maximum error allowed when flattening the path, - so this method could return a false positive when your point is up to this distance - outside the path's boundary. - */ - bool intersectsLine (Line line, - float tolerance = defaultToleranceForTesting); - - /** Cuts off parts of a line to keep the parts that are either inside or - outside this path. - - Note that this isn't smart enough to cope with situations where the - line would need to be cut into multiple pieces to correctly clip against - a re-entrant shape. - - @param line the line to clip - @param keepSectionOutsidePath if true, it's the section outside the path - that will be kept; if false its the section inside - the path - */ - Line getClippedLine (Line line, bool keepSectionOutsidePath) const; - - /** Returns the length of the path. - @see getPointAlongPath - */ - float getLength (const AffineTransform& transform = AffineTransform(), - float tolerance = defaultToleranceForMeasurement) const; - - /** Returns a point that is the specified distance along the path. - If the distance is greater than the total length of the path, this will return the - end point. - @see getLength - */ - Point getPointAlongPath (float distanceFromStart, - const AffineTransform& transform = AffineTransform(), - float tolerance = defaultToleranceForMeasurement) const; - - /** Finds the point along the path which is nearest to a given position. - This sets pointOnPath to the nearest point, and returns the distance of this point from the start - of the path. - */ - float getNearestPoint (Point targetPoint, - Point& pointOnPath, - const AffineTransform& transform = AffineTransform(), - float tolerance = defaultToleranceForMeasurement) const; - - //============================================================================== - /** Removes all lines and curves, resetting the path completely. */ - void clear() noexcept; - - /** Begins a new subpath with a given starting position. - - This will move the path's current position to the coordinates passed in and - make it ready to draw lines or curves starting from this position. - - After adding whatever lines and curves are needed, you can either - close the current sub-path using closeSubPath() or call startNewSubPath() - to move to a new sub-path, leaving the old one open-ended. - - @see lineTo, quadraticTo, cubicTo, closeSubPath - */ - void startNewSubPath (float startX, float startY); - - /** Begins a new subpath with a given starting position. - - This will move the path's current position to the coordinates passed in and - make it ready to draw lines or curves starting from this position. - - After adding whatever lines and curves are needed, you can either - close the current sub-path using closeSubPath() or call startNewSubPath() - to move to a new sub-path, leaving the old one open-ended. - - @see lineTo, quadraticTo, cubicTo, closeSubPath - */ - void startNewSubPath (Point start); - - /** Closes a the current sub-path with a line back to its start-point. - - When creating a closed shape such as a triangle, don't use 3 lineTo() - calls - instead use two lineTo() calls, followed by a closeSubPath() - to join the final point back to the start. - - This ensures that closes shapes are recognised as such, and this is - important for tasks like drawing strokes, which needs to know whether to - draw end-caps or not. - - @see startNewSubPath, lineTo, quadraticTo, cubicTo, closeSubPath - */ - void closeSubPath(); - - /** Adds a line from the shape's last position to a new end-point. - - This will connect the end-point of the last line or curve that was added - to a new point, using a straight line. - - See the class description for an example of how to add lines and curves to a path. - - @see startNewSubPath, quadraticTo, cubicTo, closeSubPath - */ - void lineTo (float endX, float endY); - - /** Adds a line from the shape's last position to a new end-point. - - This will connect the end-point of the last line or curve that was added - to a new point, using a straight line. - - See the class description for an example of how to add lines and curves to a path. - - @see startNewSubPath, quadraticTo, cubicTo, closeSubPath - */ - void lineTo (Point end); - - /** Adds a quadratic bezier curve from the shape's last position to a new position. - - This will connect the end-point of the last line or curve that was added - to a new point, using a quadratic spline with one control-point. - - See the class description for an example of how to add lines and curves to a path. - - @see startNewSubPath, lineTo, cubicTo, closeSubPath - */ - void quadraticTo (float controlPointX, - float controlPointY, - float endPointX, - float endPointY); - - /** Adds a quadratic bezier curve from the shape's last position to a new position. - - This will connect the end-point of the last line or curve that was added - to a new point, using a quadratic spline with one control-point. - - See the class description for an example of how to add lines and curves to a path. - - @see startNewSubPath, lineTo, cubicTo, closeSubPath - */ - void quadraticTo (Point controlPoint, - Point endPoint); - - /** Adds a cubic bezier curve from the shape's last position to a new position. - - This will connect the end-point of the last line or curve that was added - to a new point, using a cubic spline with two control-points. - - See the class description for an example of how to add lines and curves to a path. - - @see startNewSubPath, lineTo, quadraticTo, closeSubPath - */ - void cubicTo (float controlPoint1X, - float controlPoint1Y, - float controlPoint2X, - float controlPoint2Y, - float endPointX, - float endPointY); - - /** Adds a cubic bezier curve from the shape's last position to a new position. - - This will connect the end-point of the last line or curve that was added - to a new point, using a cubic spline with two control-points. - - See the class description for an example of how to add lines and curves to a path. - - @see startNewSubPath, lineTo, quadraticTo, closeSubPath - */ - void cubicTo (Point controlPoint1, - Point controlPoint2, - Point endPoint); - - /** Returns the last point that was added to the path by one of the drawing methods. - */ - Point getCurrentPosition() const; - - //============================================================================== - /** Adds a rectangle to the path. - The rectangle is added as a new sub-path. (Any currently open paths will be left open). - @see addRoundedRectangle, addTriangle - */ - void addRectangle (float x, float y, float width, float height); - - /** Adds a rectangle to the path. - The rectangle is added as a new sub-path. (Any currently open paths will be left open). - @see addRoundedRectangle, addTriangle - */ - template - void addRectangle (Rectangle rectangle) - { - addRectangle (static_cast (rectangle.getX()), static_cast (rectangle.getY()), - static_cast (rectangle.getWidth()), static_cast (rectangle.getHeight())); - } - - /** Adds a rectangle with rounded corners to the path. - The rectangle is added as a new sub-path. (Any currently open paths will be left open). - @see addRectangle, addTriangle - */ - void addRoundedRectangle (float x, float y, float width, float height, - float cornerSize); - - /** Adds a rectangle with rounded corners to the path. - The rectangle is added as a new sub-path. (Any currently open paths will be left open). - @see addRectangle, addTriangle - */ - void addRoundedRectangle (float x, float y, float width, float height, - float cornerSizeX, - float cornerSizeY); - - /** Adds a rectangle with rounded corners to the path. - The rectangle is added as a new sub-path. (Any currently open paths will be left open). - @see addRectangle, addTriangle - */ - void addRoundedRectangle (float x, float y, float width, float height, - float cornerSizeX, float cornerSizeY, - bool curveTopLeft, bool curveTopRight, - bool curveBottomLeft, bool curveBottomRight); - - /** Adds a rectangle with rounded corners to the path. - The rectangle is added as a new sub-path. (Any currently open paths will be left open). - @see addRectangle, addTriangle - */ - template - void addRoundedRectangle (Rectangle rectangle, float cornerSizeX, float cornerSizeY) - { - addRoundedRectangle (static_cast (rectangle.getX()), static_cast (rectangle.getY()), - static_cast (rectangle.getWidth()), static_cast (rectangle.getHeight()), - cornerSizeX, cornerSizeY); - } - - /** Adds a rectangle with rounded corners to the path. - The rectangle is added as a new sub-path. (Any currently open paths will be left open). - @see addRectangle, addTriangle - */ - template - void addRoundedRectangle (Rectangle rectangle, float cornerSize) - { - addRoundedRectangle (rectangle, cornerSize, cornerSize); - } - - /** Adds a triangle to the path. - - The triangle is added as a new closed sub-path. (Any currently open paths will be left open). - - Note that whether the vertices are specified in clockwise or anticlockwise - order will affect how the triangle is filled when it overlaps other - shapes (the winding order setting will affect this of course). - */ - void addTriangle (float x1, float y1, - float x2, float y2, - float x3, float y3); - - /** Adds a triangle to the path. - - The triangle is added as a new closed sub-path. (Any currently open paths will be left open). - - Note that whether the vertices are specified in clockwise or anticlockwise - order will affect how the triangle is filled when it overlaps other - shapes (the winding order setting will affect this of course). - */ - void addTriangle (Point point1, - Point point2, - Point point3); - - /** Adds a quadrilateral to the path. - - The quad is added as a new closed sub-path. (Any currently open paths will be left open). - - Note that whether the vertices are specified in clockwise or anticlockwise - order will affect how the quad is filled when it overlaps other - shapes (the winding order setting will affect this of course). - */ - void addQuadrilateral (float x1, float y1, - float x2, float y2, - float x3, float y3, - float x4, float y4); - - /** Adds an ellipse to the path. - The shape is added as a new sub-path. (Any currently open paths will be left open). - @see addArc - */ - void addEllipse (float x, float y, float width, float height); - - /** Adds an ellipse to the path. - The shape is added as a new sub-path. (Any currently open paths will be left open). - @see addArc - */ - void addEllipse (Rectangle area); - - /** Adds an elliptical arc to the current path. - - Note that when specifying the start and end angles, the curve will be drawn either clockwise - or anti-clockwise according to whether the end angle is greater than the start. This means - that sometimes you may need to use values greater than 2*Pi for the end angle. - - @param x the left-hand edge of the rectangle in which the elliptical outline fits - @param y the top edge of the rectangle in which the elliptical outline fits - @param width the width of the rectangle in which the elliptical outline fits - @param height the height of the rectangle in which the elliptical outline fits - @param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the - top-centre of the ellipse) - @param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the - top-centre of the ellipse). This angle can be greater than 2*Pi, so for example to - draw a curve clockwise from the 9 o'clock position to the 3 o'clock position via - 12 o'clock, you'd use 1.5*Pi and 2.5*Pi as the start and finish points. - @param startAsNewSubPath if true, the arc will begin a new subpath from its starting point; if false, - it will be added to the current sub-path, continuing from the current postition - - @see addCentredArc, arcTo, addPieSegment, addEllipse - */ - void addArc (float x, float y, float width, float height, - float fromRadians, - float toRadians, - bool startAsNewSubPath = false); - - /** Adds an arc which is centred at a given point, and can have a rotation specified. - - Note that when specifying the start and end angles, the curve will be drawn either clockwise - or anti-clockwise according to whether the end angle is greater than the start. This means - that sometimes you may need to use values greater than 2*Pi for the end angle. - - @param centreX the centre x of the ellipse - @param centreY the centre y of the ellipse - @param radiusX the horizontal radius of the ellipse - @param radiusY the vertical radius of the ellipse - @param rotationOfEllipse an angle by which the whole ellipse should be rotated about its centre, in radians (clockwise) - @param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the - top-centre of the ellipse) - @param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the - top-centre of the ellipse). This angle can be greater than 2*Pi, so for example to - draw a curve clockwise from the 9 o'clock position to the 3 o'clock position via - 12 o'clock, you'd use 1.5*Pi and 2.5*Pi as the start and finish points. - @param startAsNewSubPath if true, the arc will begin a new subpath from its starting point; if false, - it will be added to the current sub-path, continuing from the current postition - - @see addArc, arcTo - */ - void addCentredArc (float centreX, float centreY, - float radiusX, float radiusY, - float rotationOfEllipse, - float fromRadians, - float toRadians, - bool startAsNewSubPath = false); - - /** Adds a "pie-chart" shape to the path. - - The shape is added as a new sub-path. (Any currently open paths will be - left open). - - Note that when specifying the start and end angles, the curve will be drawn either clockwise - or anti-clockwise according to whether the end angle is greater than the start. This means - that sometimes you may need to use values greater than 2*Pi for the end angle. - - @param x the left-hand edge of the rectangle in which the elliptical outline fits - @param y the top edge of the rectangle in which the elliptical outline fits - @param width the width of the rectangle in which the elliptical outline fits - @param height the height of the rectangle in which the elliptical outline fits - @param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the - top-centre of the ellipse) - @param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the - top-centre of the ellipse) - @param innerCircleProportionalSize if this is > 0, then the pie will be drawn as a curved band around a hollow - ellipse at its centre, where this value indicates the inner ellipse's size with - respect to the outer one. - @see addArc - */ - void addPieSegment (float x, float y, - float width, float height, - float fromRadians, - float toRadians, - float innerCircleProportionalSize); - - /** Adds a "pie-chart" shape to the path. - - The shape is added as a new sub-path. (Any currently open paths will be left open). - - Note that when specifying the start and end angles, the curve will be drawn either clockwise - or anti-clockwise according to whether the end angle is greater than the start. This means - that sometimes you may need to use values greater than 2*Pi for the end angle. - - @param segmentBounds the outer rectangle in which the elliptical outline fits - @param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the - top-centre of the ellipse) - @param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the - top-centre of the ellipse) - @param innerCircleProportionalSize if this is > 0, then the pie will be drawn as a curved band around a hollow - ellipse at its centre, where this value indicates the inner ellipse's size with - respect to the outer one. - @see addArc - */ - void addPieSegment (Rectangle segmentBounds, - float fromRadians, - float toRadians, - float innerCircleProportionalSize); - - /** Adds a line with a specified thickness. - - The line is added as a new closed sub-path. (Any currently open paths will be - left open). - - @see addArrow - */ - void addLineSegment (Line line, float lineThickness); - - /** Adds a line with an arrowhead on the end. - The arrow is added as a new closed sub-path. (Any currently open paths will be left open). - @see PathStrokeType::createStrokeWithArrowheads - */ - void addArrow (Line line, - float lineThickness, - float arrowheadWidth, - float arrowheadLength); - - /** Adds a polygon shape to the path. - @see addStar - */ - void addPolygon (Point centre, - int numberOfSides, - float radius, - float startAngle = 0.0f); - - /** Adds a star shape to the path. - @see addPolygon - */ - void addStar (Point centre, - int numberOfPoints, - float innerRadius, - float outerRadius, - float startAngle = 0.0f); - - /** Adds a speech-bubble shape to the path. - - @param bodyArea the area of the body of the bubble shape - @param maximumArea an area which encloses the body area and defines the limits within which - the arrow tip can be drawn - if the tip lies outside this area, the bubble - will be drawn without an arrow - @param arrowTipPosition the location of the tip of the arrow - @param cornerSize the size of the rounded corners - @param arrowBaseWidth the width of the base of the arrow where it joins the main rectangle - */ - void addBubble (Rectangle bodyArea, - Rectangle maximumArea, - const Point arrowTipPosition, - const float cornerSize, - const float arrowBaseWidth); - - /** Adds another path to this one. - - The new path is added as a new sub-path. (Any currently open paths in this - path will be left open). - - @param pathToAppend the path to add - */ - void addPath (const Path& pathToAppend); - - /** Adds another path to this one, transforming it on the way in. - - The new path is added as a new sub-path, its points being transformed by the given - matrix before being added. - - @param pathToAppend the path to add - @param transformToApply an optional transform to apply to the incoming vertices - */ - void addPath (const Path& pathToAppend, - const AffineTransform& transformToApply); - - /** Swaps the contents of this path with another one. - - The internal data of the two paths is swapped over, so this is much faster than - copying it to a temp variable and back. - */ - void swapWithPath (Path&) noexcept; - - //============================================================================== - /** Preallocates enough space for adding the given number of coordinates to the path. - If you're about to add a large number of lines or curves to the path, it can make - the task much more efficient to call this first and avoid costly reallocations - as the structure grows. - The actual value to pass is a bit tricky to calculate because the space required - depends on what you're adding - e.g. each lineTo() or startNewSubPath() will - require 3 coords (x, y and a type marker). Each quadraticTo() will need 5, and - a cubicTo() will require 7. Closing a sub-path will require 1. - */ - void preallocateSpace (int numExtraCoordsToMakeSpaceFor); - - //============================================================================== - /** Applies a 2D transform to all the vertices in the path. - - @see AffineTransform, scaleToFit, getTransformToScaleToFit - */ - void applyTransform (const AffineTransform& transform) noexcept; - - /** Rescales this path to make it fit neatly into a given space. - - This is effectively a quick way of calling - applyTransform (getTransformToScaleToFit (x, y, w, h, preserveProportions)) - - @param x the x position of the rectangle to fit the path inside - @param y the y position of the rectangle to fit the path inside - @param width the width of the rectangle to fit the path inside - @param height the height of the rectangle to fit the path inside - @param preserveProportions if true, it will fit the path into the space without altering its - horizontal/vertical scale ratio; if false, it will distort the - path to fill the specified ratio both horizontally and vertically - - @see applyTransform, getTransformToScaleToFit - */ - void scaleToFit (float x, float y, float width, float height, - bool preserveProportions) noexcept; - - /** Returns a transform that can be used to rescale the path to fit into a given space. - - @param x the x position of the rectangle to fit the path inside - @param y the y position of the rectangle to fit the path inside - @param width the width of the rectangle to fit the path inside - @param height the height of the rectangle to fit the path inside - @param preserveProportions if true, it will fit the path into the space without altering its - horizontal/vertical scale ratio; if false, it will distort the - path to fill the specified ratio both horizontally and vertically - @param justificationType if the proportions are preseved, the resultant path may be smaller - than the available rectangle, so this describes how it should be - positioned within the space. - @returns an appropriate transformation - - @see applyTransform, scaleToFit - - */ - AffineTransform getTransformToScaleToFit (float x, float y, float width, float height, - bool preserveProportions, - Justification justificationType = Justification::centred) const; - - /** Returns a transform that can be used to rescale the path to fit into a given space. - - @param area the rectangle to fit the path inside - @param preserveProportions if true, it will fit the path into the space without altering its - horizontal/vertical scale ratio; if false, it will distort the - path to fill the specified ratio both horizontally and vertically - @param justificationType if the proportions are preseved, the resultant path may be smaller - than the available rectangle, so this describes how it should be - positioned within the space. - @returns an appropriate transformation - - @see applyTransform, scaleToFit - - */ - AffineTransform getTransformToScaleToFit (Rectangle area, - bool preserveProportions, - Justification justificationType = Justification::centred) const; - - /** Creates a version of this path where all sharp corners have been replaced by curves. - - Wherever two lines meet at an angle, this will replace the corner with a curve - of the given radius. - */ - Path createPathWithRoundedCorners (float cornerRadius) const; - - //============================================================================== - /** Changes the winding-rule to be used when filling the path. - - If set to true (which is the default), then the path uses a non-zero-winding rule - to determine which points are inside the path. If set to false, it uses an - alternate-winding rule. - - The winding-rule comes into play when areas of the shape overlap other - areas, and determines whether the overlapping regions are considered to be - inside or outside. - - Changing this value just sets a flag - it doesn't affect the contents of the - path. - - @see isUsingNonZeroWinding - */ - void setUsingNonZeroWinding (bool isNonZeroWinding) noexcept; - - /** Returns the flag that indicates whether the path should use a non-zero winding rule. - - The default for a new path is true. - - @see setUsingNonZeroWinding - */ - bool isUsingNonZeroWinding() const { return useNonZeroWinding; } - - - //============================================================================== - /** Iterates the lines and curves that a path contains. - - @see Path, PathFlatteningIterator - */ - class JUCE_API Iterator - { - public: - //============================================================================== - Iterator (const Path& path) noexcept; - ~Iterator() noexcept; - - //============================================================================== - /** Moves onto the next element in the path. - - If this returns false, there are no more elements. If it returns true, - the elementType variable will be set to the type of the current element, - and some of the x and y variables will be filled in with values. - */ - bool next() noexcept; - - //============================================================================== - enum PathElementType - { - startNewSubPath, /**< For this type, x1 and y1 will be set to indicate the first point in the subpath. */ - lineTo, /**< For this type, x1 and y1 indicate the end point of the line. */ - quadraticTo, /**< For this type, x1, y1, x2, y2 indicate the control point and endpoint of a quadratic curve. */ - cubicTo, /**< For this type, x1, y1, x2, y2, x3, y3 indicate the two control points and the endpoint of a cubic curve. */ - closePath /**< Indicates that the sub-path is being closed. None of the x or y values are valid in this case. */ - }; - - PathElementType elementType; - - float x1 = 0, y1 = 0, x2 = 0, y2 = 0, x3 = 0, y3 = 0; - - //============================================================================== - private: - const Path& path; - size_t index = 0; - - JUCE_DECLARE_NON_COPYABLE (Iterator) - }; - - //============================================================================== - /** Loads a stored path from a data stream. - - The data in the stream must have been written using writePathToStream(). - - Note that this will append the stored path to whatever is currently in - this path, so you might need to call clear() beforehand. - - @see loadPathFromData, writePathToStream - */ - void loadPathFromStream (InputStream& source); - - /** Loads a stored path from a block of data. - - This is similar to loadPathFromStream(), but just reads from a block - of data. Useful if you're including stored shapes in your code as a - block of static data. - - @see loadPathFromStream, writePathToStream - */ - void loadPathFromData (const void* data, size_t numberOfBytes); - - /** Stores the path by writing it out to a stream. - - After writing out a path, you can reload it using loadPathFromStream(). - - @see loadPathFromStream, loadPathFromData - */ - void writePathToStream (OutputStream& destination) const; - - //============================================================================== - /** Creates a string containing a textual representation of this path. - @see restoreFromString - */ - String toString() const; - - /** Restores this path from a string that was created with the toString() method. - @see toString() - */ - void restoreFromString (StringRef stringVersion); - -private: - //============================================================================== - friend class PathFlatteningIterator; - friend class Path::Iterator; - ArrayAllocationBase data; - size_t numElements = 0; - - struct PathBounds - { - PathBounds() noexcept; - Rectangle getRectangle() const noexcept; - void reset() noexcept; - void reset (float, float) noexcept; - void extend (float, float) noexcept; - void extend (float, float, float, float) noexcept; - - float pathXMin = 0, pathXMax = 0, pathYMin = 0, pathYMax = 0; - }; - - PathBounds bounds; - bool useNonZeroWinding = true; - - static const float lineMarker; - static const float moveMarker; - static const float quadMarker; - static const float cubicMarker; - static const float closeSubPathMarker; - - JUCE_LEAK_DETECTOR (Path) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/geometry/juce_PathIterator.cpp b/source/modules/juce_graphics/geometry/juce_PathIterator.cpp deleted file mode 100644 index ca239d4f9..000000000 --- a/source/modules/juce_graphics/geometry/juce_PathIterator.cpp +++ /dev/null @@ -1,286 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -#if JUCE_MSVC && JUCE_DEBUG - #pragma optimize ("t", on) -#endif - -//============================================================================== -PathFlatteningIterator::PathFlatteningIterator (const Path& path_, - const AffineTransform& transform_, - const float tolerance) - : x2 (0), - y2 (0), - closesSubPath (false), - subPathIndex (-1), - path (path_), - transform (transform_), - points (path_.data.elements), - toleranceSquared (tolerance * tolerance), - isIdentityTransform (transform_.isIdentity()) -{ - stackPos = stackBase; -} - -PathFlatteningIterator::~PathFlatteningIterator() -{ -} - -bool PathFlatteningIterator::isLastInSubpath() const noexcept -{ - return stackPos == stackBase.get() - && (index >= path.numElements || isMarker (points[index], Path::moveMarker)); -} - -bool PathFlatteningIterator::next() -{ - x1 = x2; - y1 = y2; - - float x3 = 0; - float y3 = 0; - float x4 = 0; - float y4 = 0; - - for (;;) - { - float type; - - if (stackPos == stackBase) - { - if (index >= path.numElements) - return false; - - type = points [index++]; - - if (! isMarker (type, Path::closeSubPathMarker)) - { - x2 = points [index++]; - y2 = points [index++]; - - if (isMarker (type, Path::quadMarker)) - { - x3 = points [index++]; - y3 = points [index++]; - - if (! isIdentityTransform) - transform.transformPoints (x2, y2, x3, y3); - } - else if (isMarker (type, Path::cubicMarker)) - { - x3 = points [index++]; - y3 = points [index++]; - x4 = points [index++]; - y4 = points [index++]; - - if (! isIdentityTransform) - transform.transformPoints (x2, y2, x3, y3, x4, y4); - } - else - { - if (! isIdentityTransform) - transform.transformPoint (x2, y2); - } - } - } - else - { - type = *--stackPos; - - if (! isMarker (type, Path::closeSubPathMarker)) - { - x2 = *--stackPos; - y2 = *--stackPos; - - if (isMarker (type, Path::quadMarker)) - { - x3 = *--stackPos; - y3 = *--stackPos; - } - else if (isMarker (type, Path::cubicMarker)) - { - x3 = *--stackPos; - y3 = *--stackPos; - x4 = *--stackPos; - y4 = *--stackPos; - } - } - } - - if (isMarker (type, Path::lineMarker)) - { - ++subPathIndex; - - closesSubPath = (stackPos == stackBase) - && (index < path.numElements) - && (points [index] == Path::closeSubPathMarker) - && x2 == subPathCloseX - && y2 == subPathCloseY; - - return true; - } - - if (isMarker (type, Path::quadMarker)) - { - const size_t offset = (size_t) (stackPos - stackBase); - - if (offset >= stackSize - 10) - { - stackSize <<= 1; - stackBase.realloc (stackSize); - stackPos = stackBase + offset; - } - - auto m1x = (x1 + x2) * 0.5f; - auto m1y = (y1 + y2) * 0.5f; - auto m2x = (x2 + x3) * 0.5f; - auto m2y = (y2 + y3) * 0.5f; - auto m3x = (m1x + m2x) * 0.5f; - auto m3y = (m1y + m2y) * 0.5f; - - auto errorX = m3x - x2; - auto errorY = m3y - y2; - - if (errorX * errorX + errorY * errorY > toleranceSquared) - { - *stackPos++ = y3; - *stackPos++ = x3; - *stackPos++ = m2y; - *stackPos++ = m2x; - *stackPos++ = Path::quadMarker; - - *stackPos++ = m3y; - *stackPos++ = m3x; - *stackPos++ = m1y; - *stackPos++ = m1x; - *stackPos++ = Path::quadMarker; - } - else - { - *stackPos++ = y3; - *stackPos++ = x3; - *stackPos++ = Path::lineMarker; - - *stackPos++ = m3y; - *stackPos++ = m3x; - *stackPos++ = Path::lineMarker; - } - - jassert (stackPos < stackBase + stackSize); - } - else if (isMarker (type, Path::cubicMarker)) - { - const size_t offset = (size_t) (stackPos - stackBase); - - if (offset >= stackSize - 16) - { - stackSize <<= 1; - stackBase.realloc (stackSize); - stackPos = stackBase + offset; - } - - auto m1x = (x1 + x2) * 0.5f; - auto m1y = (y1 + y2) * 0.5f; - auto m2x = (x3 + x2) * 0.5f; - auto m2y = (y3 + y2) * 0.5f; - auto m3x = (x3 + x4) * 0.5f; - auto m3y = (y3 + y4) * 0.5f; - auto m4x = (m1x + m2x) * 0.5f; - auto m4y = (m1y + m2y) * 0.5f; - auto m5x = (m3x + m2x) * 0.5f; - auto m5y = (m3y + m2y) * 0.5f; - - auto error1X = m4x - x2; - auto error1Y = m4y - y2; - auto error2X = m5x - x3; - auto error2Y = m5y - y3; - - if (error1X * error1X + error1Y * error1Y > toleranceSquared - || error2X * error2X + error2Y * error2Y > toleranceSquared) - { - *stackPos++ = y4; - *stackPos++ = x4; - *stackPos++ = m3y; - *stackPos++ = m3x; - *stackPos++ = m5y; - *stackPos++ = m5x; - *stackPos++ = Path::cubicMarker; - - *stackPos++ = (m4y + m5y) * 0.5f; - *stackPos++ = (m4x + m5x) * 0.5f; - *stackPos++ = m4y; - *stackPos++ = m4x; - *stackPos++ = m1y; - *stackPos++ = m1x; - *stackPos++ = Path::cubicMarker; - } - else - { - *stackPos++ = y4; - *stackPos++ = x4; - *stackPos++ = Path::lineMarker; - - *stackPos++ = m5y; - *stackPos++ = m5x; - *stackPos++ = Path::lineMarker; - - *stackPos++ = m4y; - *stackPos++ = m4x; - *stackPos++ = Path::lineMarker; - } - } - else if (isMarker (type, Path::closeSubPathMarker)) - { - if (x2 != subPathCloseX || y2 != subPathCloseY) - { - x1 = x2; - y1 = y2; - x2 = subPathCloseX; - y2 = subPathCloseY; - closesSubPath = true; - - return true; - } - } - else - { - jassert (isMarker (type, Path::moveMarker)); - - subPathIndex = -1; - subPathCloseX = x1 = x2; - subPathCloseY = y1 = y2; - } - } -} - -#if JUCE_MSVC && JUCE_DEBUG - #pragma optimize ("", on) // resets optimisations to the project defaults -#endif - -} // namespace juce diff --git a/source/modules/juce_graphics/geometry/juce_PathIterator.h b/source/modules/juce_graphics/geometry/juce_PathIterator.h deleted file mode 100644 index d37b5407d..000000000 --- a/source/modules/juce_graphics/geometry/juce_PathIterator.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Flattens a Path object into a series of straight-line sections. - - Use one of these to iterate through a Path object, and it will convert - all the curves into line sections so it's easy to render or perform - geometric operations on. - - @see Path -*/ -class JUCE_API PathFlatteningIterator -{ -public: - //============================================================================== - /** Creates a PathFlatteningIterator. - - After creation, use the next() method to initialise the fields in the - object with the first line's position. - - @param path the path to iterate along - @param transform a transform to apply to each point in the path being iterated - @param tolerance the amount by which the curves are allowed to deviate from the lines - into which they are being broken down - a higher tolerance contains - less lines, so can be generated faster, but will be less smooth. - */ - PathFlatteningIterator (const Path& path, - const AffineTransform& transform = AffineTransform(), - float tolerance = Path::defaultToleranceForMeasurement); - - /** Destructor. */ - ~PathFlatteningIterator(); - - //============================================================================== - /** Fetches the next line segment from the path. - - This will update the member variables x1, y1, x2, y2, subPathIndex and closesSubPath - so that they describe the new line segment. - - @returns false when there are no more lines to fetch. - */ - bool next(); - - float x1; /**< The x position of the start of the current line segment. */ - float y1; /**< The y position of the start of the current line segment. */ - float x2; /**< The x position of the end of the current line segment. */ - float y2; /**< The y position of the end of the current line segment. */ - - /** Indicates whether the current line segment is closing a sub-path. - - If the current line is the one that connects the end of a sub-path - back to the start again, this will be true. - */ - bool closesSubPath; - - /** The index of the current line within the current sub-path. - - E.g. you can use this to see whether the line is the first one in the - subpath by seeing if it's 0. - */ - int subPathIndex; - - /** Returns true if the current segment is the last in the current sub-path. */ - bool isLastInSubpath() const noexcept; - -private: - //============================================================================== - const Path& path; - const AffineTransform transform; - float* points; - const float toleranceSquared; - float subPathCloseX = 0, subPathCloseY = 0; - const bool isIdentityTransform; - - HeapBlock stackBase { 32 }; - float* stackPos; - size_t index = 0, stackSize = 32; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PathFlatteningIterator) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/geometry/juce_PathStrokeType.cpp b/source/modules/juce_graphics/geometry/juce_PathStrokeType.cpp deleted file mode 100644 index 8069a696d..000000000 --- a/source/modules/juce_graphics/geometry/juce_PathStrokeType.cpp +++ /dev/null @@ -1,745 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -PathStrokeType::PathStrokeType (float strokeThickness) noexcept - : thickness (strokeThickness), jointStyle (mitered), endStyle (butt) -{ -} - -PathStrokeType::PathStrokeType (float strokeThickness, JointStyle joint, EndCapStyle end) noexcept - : thickness (strokeThickness), jointStyle (joint), endStyle (end) -{ -} - -PathStrokeType::PathStrokeType (const PathStrokeType& other) noexcept - : thickness (other.thickness), - jointStyle (other.jointStyle), - endStyle (other.endStyle) -{ -} - -PathStrokeType& PathStrokeType::operator= (const PathStrokeType& other) noexcept -{ - thickness = other.thickness; - jointStyle = other.jointStyle; - endStyle = other.endStyle; - return *this; -} - -PathStrokeType::~PathStrokeType() noexcept -{ -} - -bool PathStrokeType::operator== (const PathStrokeType& other) const noexcept -{ - return thickness == other.thickness - && jointStyle == other.jointStyle - && endStyle == other.endStyle; -} - -bool PathStrokeType::operator!= (const PathStrokeType& other) const noexcept -{ - return ! operator== (other); -} - -//============================================================================== -namespace PathStrokeHelpers -{ - static bool lineIntersection (const float x1, const float y1, - const float x2, const float y2, - const float x3, const float y3, - const float x4, const float y4, - float& intersectionX, - float& intersectionY, - float& distanceBeyondLine1EndSquared) noexcept - { - if (x2 != x3 || y2 != y3) - { - auto dx1 = x2 - x1; - auto dy1 = y2 - y1; - auto dx2 = x4 - x3; - auto dy2 = y4 - y3; - auto divisor = dx1 * dy2 - dx2 * dy1; - - if (divisor == 0.0f) - { - if (! ((dx1 == 0.0f && dy1 == 0.0f) || (dx2 == 0.0f && dy2 == 0.0f))) - { - if (dy1 == 0.0f && dy2 != 0.0f) - { - auto along = (y1 - y3) / dy2; - intersectionX = x3 + along * dx2; - intersectionY = y1; - - distanceBeyondLine1EndSquared = intersectionX - x2; - distanceBeyondLine1EndSquared *= distanceBeyondLine1EndSquared; - if ((x2 > x1) == (intersectionX < x2)) - distanceBeyondLine1EndSquared = -distanceBeyondLine1EndSquared; - - return along >= 0 && along <= 1.0f; - } - - if (dy2 == 0.0f && dy1 != 0.0f) - { - auto along = (y3 - y1) / dy1; - intersectionX = x1 + along * dx1; - intersectionY = y3; - - distanceBeyondLine1EndSquared = (along - 1.0f) * dx1; - distanceBeyondLine1EndSquared *= distanceBeyondLine1EndSquared; - if (along < 1.0f) - distanceBeyondLine1EndSquared = -distanceBeyondLine1EndSquared; - - return along >= 0 && along <= 1.0f; - } - - if (dx1 == 0.0f && dx2 != 0.0f) - { - auto along = (x1 - x3) / dx2; - intersectionX = x1; - intersectionY = y3 + along * dy2; - - distanceBeyondLine1EndSquared = intersectionY - y2; - distanceBeyondLine1EndSquared *= distanceBeyondLine1EndSquared; - - if ((y2 > y1) == (intersectionY < y2)) - distanceBeyondLine1EndSquared = -distanceBeyondLine1EndSquared; - - return along >= 0 && along <= 1.0f; - } - - if (dx2 == 0.0f && dx1 != 0.0f) - { - auto along = (x3 - x1) / dx1; - intersectionX = x3; - intersectionY = y1 + along * dy1; - - distanceBeyondLine1EndSquared = (along - 1.0f) * dy1; - distanceBeyondLine1EndSquared *= distanceBeyondLine1EndSquared; - if (along < 1.0f) - distanceBeyondLine1EndSquared = -distanceBeyondLine1EndSquared; - - return along >= 0 && along <= 1.0f; - } - } - - intersectionX = 0.5f * (x2 + x3); - intersectionY = 0.5f * (y2 + y3); - - distanceBeyondLine1EndSquared = 0.0f; - return false; - } - - auto along1 = ((y1 - y3) * dx2 - (x1 - x3) * dy2) / divisor; - - intersectionX = x1 + along1 * dx1; - intersectionY = y1 + along1 * dy1; - - if (along1 >= 0 && along1 <= 1.0f) - { - auto along2 = ((y1 - y3) * dx1 - (x1 - x3) * dy1) / divisor; - - if (along2 >= 0 && along2 <= 1.0f) - { - distanceBeyondLine1EndSquared = 0.0f; - return true; - } - } - - distanceBeyondLine1EndSquared = along1 - 1.0f; - distanceBeyondLine1EndSquared *= distanceBeyondLine1EndSquared; - distanceBeyondLine1EndSquared *= (dx1 * dx1 + dy1 * dy1); - - if (along1 < 1.0f) - distanceBeyondLine1EndSquared = -distanceBeyondLine1EndSquared; - - return false; - } - - intersectionX = x2; - intersectionY = y2; - - distanceBeyondLine1EndSquared = 0.0f; - return true; - } - - static void addEdgeAndJoint (Path& destPath, - const PathStrokeType::JointStyle style, - const float maxMiterExtensionSquared, const float width, - const float x1, const float y1, - const float x2, const float y2, - const float x3, const float y3, - const float x4, const float y4, - const float midX, const float midY) - { - if (style == PathStrokeType::beveled - || (x3 == x4 && y3 == y4) - || (x1 == x2 && y1 == y2)) - { - destPath.lineTo (x2, y2); - destPath.lineTo (x3, y3); - } - else - { - float jx, jy, distanceBeyondLine1EndSquared; - - // if they intersect, use this point.. - if (lineIntersection (x1, y1, x2, y2, - x3, y3, x4, y4, - jx, jy, distanceBeyondLine1EndSquared)) - { - destPath.lineTo (jx, jy); - } - else - { - if (style == PathStrokeType::mitered) - { - if (distanceBeyondLine1EndSquared < maxMiterExtensionSquared - && distanceBeyondLine1EndSquared > 0.0f) - { - destPath.lineTo (jx, jy); - } - else - { - // the end sticks out too far, so just use a blunt joint - destPath.lineTo (x2, y2); - destPath.lineTo (x3, y3); - } - } - else - { - // curved joints - float angle1 = std::atan2 (x2 - midX, y2 - midY); - float angle2 = std::atan2 (x3 - midX, y3 - midY); - const float angleIncrement = 0.1f; - - destPath.lineTo (x2, y2); - - if (std::abs (angle1 - angle2) > angleIncrement) - { - if (angle2 > angle1 + float_Pi - || (angle2 < angle1 && angle2 >= angle1 - float_Pi)) - { - if (angle2 > angle1) - angle2 -= float_Pi * 2.0f; - - jassert (angle1 <= angle2 + float_Pi); - - angle1 -= angleIncrement; - while (angle1 > angle2) - { - destPath.lineTo (midX + width * std::sin (angle1), - midY + width * std::cos (angle1)); - - angle1 -= angleIncrement; - } - } - else - { - if (angle1 > angle2) - angle1 -= float_Pi * 2.0f; - - jassert (angle1 >= angle2 - float_Pi); - - angle1 += angleIncrement; - while (angle1 < angle2) - { - destPath.lineTo (midX + width * std::sin (angle1), - midY + width * std::cos (angle1)); - - angle1 += angleIncrement; - } - } - } - - destPath.lineTo (x3, y3); - } - } - } - } - - static void addLineEnd (Path& destPath, - const PathStrokeType::EndCapStyle style, - const float x1, const float y1, - const float x2, const float y2, - const float width) - { - if (style == PathStrokeType::butt) - { - destPath.lineTo (x2, y2); - } - else - { - float offx1, offy1, offx2, offy2; - - auto dx = x2 - x1; - auto dy = y2 - y1; - auto len = juce_hypot (dx, dy); - - if (len == 0.0f) - { - offx1 = offx2 = x1; - offy1 = offy2 = y1; - } - else - { - auto offset = width / len; - dx *= offset; - dy *= offset; - - offx1 = x1 + dy; - offy1 = y1 - dx; - offx2 = x2 + dy; - offy2 = y2 - dx; - } - - if (style == PathStrokeType::square) - { - // square ends - destPath.lineTo (offx1, offy1); - destPath.lineTo (offx2, offy2); - destPath.lineTo (x2, y2); - } - else - { - // rounded ends - auto midx = (offx1 + offx2) * 0.5f; - auto midy = (offy1 + offy2) * 0.5f; - - destPath.cubicTo (x1 + (offx1 - x1) * 0.55f, y1 + (offy1 - y1) * 0.55f, - offx1 + (midx - offx1) * 0.45f, offy1 + (midy - offy1) * 0.45f, - midx, midy); - - destPath.cubicTo (midx + (offx2 - midx) * 0.55f, midy + (offy2 - midy) * 0.55f, - offx2 + (x2 - offx2) * 0.45f, offy2 + (y2 - offy2) * 0.45f, - x2, y2); - } - } - } - - struct Arrowhead - { - float startWidth, startLength; - float endWidth, endLength; - }; - - static void addArrowhead (Path& destPath, - const float x1, const float y1, - const float x2, const float y2, - const float tipX, const float tipY, - const float width, - const float arrowheadWidth) - { - Line line (x1, y1, x2, y2); - destPath.lineTo (line.getPointAlongLine (-(arrowheadWidth / 2.0f - width), 0)); - destPath.lineTo (tipX, tipY); - destPath.lineTo (line.getPointAlongLine (arrowheadWidth - (arrowheadWidth / 2.0f - width), 0)); - destPath.lineTo (x2, y2); - } - - struct LineSection - { - float x1, y1, x2, y2; // original line - float lx1, ly1, lx2, ly2; // the left-hand stroke - float rx1, ry1, rx2, ry2; // the right-hand stroke - }; - - static void shortenSubPath (Array& subPath, float amountAtStart, float amountAtEnd) - { - while (amountAtEnd > 0 && subPath.size() > 0) - { - auto& l = subPath.getReference (subPath.size() - 1); - auto dx = l.rx2 - l.rx1; - auto dy = l.ry2 - l.ry1; - auto len = juce_hypot (dx, dy); - - if (len <= amountAtEnd && subPath.size() > 1) - { - LineSection& prev = subPath.getReference (subPath.size() - 2); - prev.x2 = l.x2; - prev.y2 = l.y2; - subPath.removeLast(); - amountAtEnd -= len; - } - else - { - auto prop = jmin (0.9999f, amountAtEnd / len); - dx *= prop; - dy *= prop; - l.rx1 += dx; - l.ry1 += dy; - l.lx2 += dx; - l.ly2 += dy; - break; - } - } - - while (amountAtStart > 0 && subPath.size() > 0) - { - auto& l = subPath.getReference (0); - auto dx = l.rx2 - l.rx1; - auto dy = l.ry2 - l.ry1; - auto len = juce_hypot (dx, dy); - - if (len <= amountAtStart && subPath.size() > 1) - { - LineSection& next = subPath.getReference (1); - next.x1 = l.x1; - next.y1 = l.y1; - subPath.remove (0); - amountAtStart -= len; - } - else - { - auto prop = jmin (0.9999f, amountAtStart / len); - dx *= prop; - dy *= prop; - l.rx2 -= dx; - l.ry2 -= dy; - l.lx1 -= dx; - l.ly1 -= dy; - break; - } - } - } - - static void addSubPath (Path& destPath, Array& subPath, - const bool isClosed, const float width, const float maxMiterExtensionSquared, - const PathStrokeType::JointStyle jointStyle, const PathStrokeType::EndCapStyle endStyle, - const Arrowhead* const arrowhead) - { - jassert (subPath.size() > 0); - - if (arrowhead != nullptr) - shortenSubPath (subPath, arrowhead->startLength, arrowhead->endLength); - - auto& firstLine = subPath.getReference (0); - - auto lastX1 = firstLine.lx1; - auto lastY1 = firstLine.ly1; - auto lastX2 = firstLine.lx2; - auto lastY2 = firstLine.ly2; - - if (isClosed) - { - destPath.startNewSubPath (lastX1, lastY1); - } - else - { - destPath.startNewSubPath (firstLine.rx2, firstLine.ry2); - - if (arrowhead != nullptr && arrowhead->startWidth > 0.0f) - addArrowhead (destPath, firstLine.rx2, firstLine.ry2, lastX1, lastY1, firstLine.x1, firstLine.y1, - width, arrowhead->startWidth); - else - addLineEnd (destPath, endStyle, firstLine.rx2, firstLine.ry2, lastX1, lastY1, width); - } - - for (int i = 1; i < subPath.size(); ++i) - { - const LineSection& l = subPath.getReference (i); - - addEdgeAndJoint (destPath, jointStyle, - maxMiterExtensionSquared, width, - lastX1, lastY1, lastX2, lastY2, - l.lx1, l.ly1, l.lx2, l.ly2, - l.x1, l.y1); - - lastX1 = l.lx1; - lastY1 = l.ly1; - lastX2 = l.lx2; - lastY2 = l.ly2; - } - - auto& lastLine = subPath.getReference (subPath.size() - 1); - - if (isClosed) - { - auto& l = subPath.getReference (0); - - addEdgeAndJoint (destPath, jointStyle, - maxMiterExtensionSquared, width, - lastX1, lastY1, lastX2, lastY2, - l.lx1, l.ly1, l.lx2, l.ly2, - l.x1, l.y1); - - destPath.closeSubPath(); - destPath.startNewSubPath (lastLine.rx1, lastLine.ry1); - } - else - { - destPath.lineTo (lastX2, lastY2); - - if (arrowhead != nullptr && arrowhead->endWidth > 0.0f) - addArrowhead (destPath, lastX2, lastY2, lastLine.rx1, lastLine.ry1, lastLine.x2, lastLine.y2, - width, arrowhead->endWidth); - else - addLineEnd (destPath, endStyle, lastX2, lastY2, lastLine.rx1, lastLine.ry1, width); - } - - lastX1 = lastLine.rx1; - lastY1 = lastLine.ry1; - lastX2 = lastLine.rx2; - lastY2 = lastLine.ry2; - - for (int i = subPath.size() - 1; --i >= 0;) - { - auto& l = subPath.getReference (i); - - addEdgeAndJoint (destPath, jointStyle, - maxMiterExtensionSquared, width, - lastX1, lastY1, lastX2, lastY2, - l.rx1, l.ry1, l.rx2, l.ry2, - l.x2, l.y2); - - lastX1 = l.rx1; - lastY1 = l.ry1; - lastX2 = l.rx2; - lastY2 = l.ry2; - } - - if (isClosed) - { - addEdgeAndJoint (destPath, jointStyle, - maxMiterExtensionSquared, width, - lastX1, lastY1, lastX2, lastY2, - lastLine.rx1, lastLine.ry1, lastLine.rx2, lastLine.ry2, - lastLine.x2, lastLine.y2); - } - else - { - // do the last line - destPath.lineTo (lastX2, lastY2); - } - - destPath.closeSubPath(); - } - - static void createStroke (const float thickness, const PathStrokeType::JointStyle jointStyle, - const PathStrokeType::EndCapStyle endStyle, - Path& destPath, const Path& source, - const AffineTransform& transform, - const float extraAccuracy, const Arrowhead* const arrowhead) - { - jassert (extraAccuracy > 0); - - if (thickness <= 0) - { - destPath.clear(); - return; - } - - const Path* sourcePath = &source; - Path temp; - - if (sourcePath == &destPath) - { - destPath.swapWithPath (temp); - sourcePath = &temp; - } - else - { - destPath.clear(); - } - - destPath.setUsingNonZeroWinding (true); - - const float maxMiterExtensionSquared = 9.0f * thickness * thickness; - const float width = 0.5f * thickness; - - // Iterate the path, creating a list of the - // left/right-hand lines along either side of it... - PathFlatteningIterator it (*sourcePath, transform, Path::defaultToleranceForMeasurement / extraAccuracy); - - Array subPath; - subPath.ensureStorageAllocated (512); - LineSection l; - l.x1 = 0; - l.y1 = 0; - - const float minSegmentLength = 0.0001f; - - while (it.next()) - { - if (it.subPathIndex == 0) - { - if (subPath.size() > 0) - { - addSubPath (destPath, subPath, false, width, maxMiterExtensionSquared, jointStyle, endStyle, arrowhead); - subPath.clearQuick(); - } - - l.x1 = it.x1; - l.y1 = it.y1; - } - - l.x2 = it.x2; - l.y2 = it.y2; - - float dx = l.x2 - l.x1; - float dy = l.y2 - l.y1; - - auto hypotSquared = dx * dx + dy * dy; - - if (it.closesSubPath || hypotSquared > minSegmentLength || it.isLastInSubpath()) - { - auto len = std::sqrt (hypotSquared); - - if (len == 0.0f) - { - l.rx1 = l.rx2 = l.lx1 = l.lx2 = l.x1; - l.ry1 = l.ry2 = l.ly1 = l.ly2 = l.y1; - } - else - { - auto offset = width / len; - dx *= offset; - dy *= offset; - - l.rx2 = l.x1 - dy; - l.ry2 = l.y1 + dx; - l.lx1 = l.x1 + dy; - l.ly1 = l.y1 - dx; - - l.lx2 = l.x2 + dy; - l.ly2 = l.y2 - dx; - l.rx1 = l.x2 - dy; - l.ry1 = l.y2 + dx; - } - - subPath.add (l); - - if (it.closesSubPath) - { - addSubPath (destPath, subPath, true, width, maxMiterExtensionSquared, jointStyle, endStyle, arrowhead); - subPath.clearQuick(); - } - else - { - l.x1 = it.x2; - l.y1 = it.y2; - } - } - } - - if (subPath.size() > 0) - addSubPath (destPath, subPath, false, width, maxMiterExtensionSquared, jointStyle, endStyle, arrowhead); - } -} - -void PathStrokeType::createStrokedPath (Path& destPath, const Path& sourcePath, - const AffineTransform& transform, const float extraAccuracy) const -{ - PathStrokeHelpers::createStroke (thickness, jointStyle, endStyle, destPath, sourcePath, - transform, extraAccuracy, 0); -} - -void PathStrokeType::createDashedStroke (Path& destPath, - const Path& sourcePath, - const float* dashLengths, - int numDashLengths, - const AffineTransform& transform, - const float extraAccuracy) const -{ - jassert (extraAccuracy > 0); - - if (thickness <= 0) - return; - - Path newDestPath; - PathFlatteningIterator it (sourcePath, transform, Path::defaultToleranceForMeasurement / extraAccuracy); - - bool first = true; - int dashNum = 0; - float pos = 0.0f, lineLen = 0.0f, lineEndPos = 0.0f; - float dx = 0.0f, dy = 0.0f; - - for (;;) - { - const bool isSolid = ((dashNum & 1) == 0); - const float dashLen = dashLengths [dashNum++ % numDashLengths]; - - jassert (dashLen >= 0); // must be a positive increment! - if (dashLen <= 0) - continue; - - pos += dashLen; - - while (pos > lineEndPos) - { - if (! it.next()) - { - if (isSolid && ! first) - newDestPath.lineTo (it.x2, it.y2); - - createStrokedPath (destPath, newDestPath, AffineTransform(), extraAccuracy); - return; - } - - if (isSolid && ! first) - newDestPath.lineTo (it.x1, it.y1); - else - newDestPath.startNewSubPath (it.x1, it.y1); - - dx = it.x2 - it.x1; - dy = it.y2 - it.y1; - lineLen = juce_hypot (dx, dy); - lineEndPos += lineLen; - first = it.closesSubPath; - } - - const float alpha = (pos - (lineEndPos - lineLen)) / lineLen; - - if (isSolid) - newDestPath.lineTo (it.x1 + dx * alpha, - it.y1 + dy * alpha); - else - newDestPath.startNewSubPath (it.x1 + dx * alpha, - it.y1 + dy * alpha); - } -} - -void PathStrokeType::createStrokeWithArrowheads (Path& destPath, - const Path& sourcePath, - const float arrowheadStartWidth, const float arrowheadStartLength, - const float arrowheadEndWidth, const float arrowheadEndLength, - const AffineTransform& transform, - const float extraAccuracy) const -{ - PathStrokeHelpers::Arrowhead head; - head.startWidth = arrowheadStartWidth; - head.startLength = arrowheadStartLength; - head.endWidth = arrowheadEndWidth; - head.endLength = arrowheadEndLength; - - PathStrokeHelpers::createStroke (thickness, jointStyle, endStyle, - destPath, sourcePath, transform, extraAccuracy, &head); -} - -} // namespace juce diff --git a/source/modules/juce_graphics/geometry/juce_PathStrokeType.h b/source/modules/juce_graphics/geometry/juce_PathStrokeType.h deleted file mode 100644 index c84412dd9..000000000 --- a/source/modules/juce_graphics/geometry/juce_PathStrokeType.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Describes a type of stroke used to render a solid outline along a path. - - A PathStrokeType object can be used directly to create the shape of an outline - around a path, and is used by Graphics::strokePath to specify the type of - stroke to draw. - - @see Path, Graphics::strokePath -*/ -class JUCE_API PathStrokeType -{ -public: - //============================================================================== - /** The type of shape to use for the corners between two adjacent line segments. */ - enum JointStyle - { - mitered, /**< Indicates that corners should be drawn with sharp joints. - Note that for angles that curve back on themselves, drawing a - mitre could require extending the point too far away from the - path, so a mitre limit is imposed and any corners that exceed it - are drawn as bevelled instead. */ - curved, /**< Indicates that corners should be drawn as rounded-off. */ - beveled /**< Indicates that corners should be drawn with a line flattening their - outside edge. */ - }; - - /** The type shape to use for the ends of lines. */ - enum EndCapStyle - { - butt, /**< Ends of lines are flat and don't extend beyond the end point. */ - square, /**< Ends of lines are flat, but stick out beyond the end point for half - the thickness of the stroke. */ - rounded /**< Ends of lines are rounded-off with a circular shape. */ - }; - - //============================================================================== - /** Creates a stroke type with a given line-width, and default joint/end styles. */ - explicit PathStrokeType (float strokeThickness) noexcept; - - /** Creates a stroke type. - - @param strokeThickness the width of the line to use - @param jointStyle the type of joints to use for corners - @param endStyle the type of end-caps to use for the ends of open paths. - */ - PathStrokeType (float strokeThickness, - JointStyle jointStyle, - EndCapStyle endStyle = butt) noexcept; - - /** Creates a copy of another stroke type. */ - PathStrokeType (const PathStrokeType&) noexcept; - - /** Copies another stroke onto this one. */ - PathStrokeType& operator= (const PathStrokeType&) noexcept; - - /** Destructor. */ - ~PathStrokeType() noexcept; - - //============================================================================== - /** Applies this stroke type to a path and returns the resultant stroke as another Path. - - @param destPath the resultant stroked outline shape will be copied into this path. - Note that it's ok for the source and destination Paths to be - the same object, so you can easily turn a path into a stroked version - of itself. - @param sourcePath the path to use as the source - @param transform an optional transform to apply to the points from the source path - as they are being used - @param extraAccuracy if this is greater than 1.0, it will subdivide the path to - a higher resolution, which improves the quality if you'll later want - to enlarge the stroked path. So for example, if you're planning on drawing - the stroke at 3x the size that you're creating it, you should set this to 3. - - @see createDashedStroke - */ - void createStrokedPath (Path& destPath, - const Path& sourcePath, - const AffineTransform& transform = AffineTransform(), - float extraAccuracy = 1.0f) const; - - - //============================================================================== - /** Applies this stroke type to a path, creating a dashed line. - - This is similar to createStrokedPath, but uses the array passed in to - break the stroke up into a series of dashes. - - @param destPath the resultant stroked outline shape will be copied into this path. - Note that it's ok for the source and destination Paths to be - the same object, so you can easily turn a path into a stroked version - of itself. - @param sourcePath the path to use as the source - @param dashLengths An array of alternating on/off lengths. E.g. { 2, 3, 4, 5 } will create - a line of length 2, then skip a length of 3, then add a line of length 4, - skip 5, and keep repeating this pattern. - @param numDashLengths The number of lengths in the dashLengths array. This should really be - an even number, otherwise the pattern will get out of step as it - repeats. - @param transform an optional transform to apply to the points from the source path - as they are being used - @param extraAccuracy if this is greater than 1.0, it will subdivide the path to - a higher resolution, which improves the quality if you'll later want - to enlarge the stroked path. So for example, if you're planning on drawing - the stroke at 3x the size that you're creating it, you should set this to 3. - */ - void createDashedStroke (Path& destPath, - const Path& sourcePath, - const float* dashLengths, - int numDashLengths, - const AffineTransform& transform = AffineTransform(), - float extraAccuracy = 1.0f) const; - - //============================================================================== - /** Applies this stroke type to a path and returns the resultant stroke as another Path. - - @param destPath the resultant stroked outline shape will be copied into this path. - Note that it's ok for the source and destination Paths to be - the same object, so you can easily turn a path into a stroked version - of itself. - @param sourcePath the path to use as the source - @param arrowheadStartWidth the width of the arrowhead at the start of the path - @param arrowheadStartLength the length of the arrowhead at the start of the path - @param arrowheadEndWidth the width of the arrowhead at the end of the path - @param arrowheadEndLength the length of the arrowhead at the end of the path - @param transform an optional transform to apply to the points from the source path - as they are being used - @param extraAccuracy if this is greater than 1.0, it will subdivide the path to - a higher resolution, which improves the quality if you'll later want - to enlarge the stroked path. So for example, if you're planning on drawing - the stroke at 3x the size that you're creating it, you should set this to 3. - @see createDashedStroke - */ - void createStrokeWithArrowheads (Path& destPath, - const Path& sourcePath, - float arrowheadStartWidth, float arrowheadStartLength, - float arrowheadEndWidth, float arrowheadEndLength, - const AffineTransform& transform = AffineTransform(), - float extraAccuracy = 1.0f) const; - - //============================================================================== - /** Returns the stroke thickness. */ - float getStrokeThickness() const noexcept { return thickness; } - - /** Sets the stroke thickness. */ - void setStrokeThickness (float newThickness) noexcept { thickness = newThickness; } - - /** Returns the joint style. */ - JointStyle getJointStyle() const noexcept { return jointStyle; } - - /** Sets the joint style. */ - void setJointStyle (JointStyle newStyle) noexcept { jointStyle = newStyle; } - - /** Returns the end-cap style. */ - EndCapStyle getEndStyle() const noexcept { return endStyle; } - - /** Sets the end-cap style. */ - void setEndStyle (EndCapStyle newStyle) noexcept { endStyle = newStyle; } - - //============================================================================== - /** Compares the stroke thickness, joint and end styles of two stroke types. */ - bool operator== (const PathStrokeType&) const noexcept; - - /** Compares the stroke thickness, joint and end styles of two stroke types. */ - bool operator!= (const PathStrokeType&) const noexcept; - -private: - //============================================================================== - float thickness; - JointStyle jointStyle; - EndCapStyle endStyle; - - JUCE_LEAK_DETECTOR (PathStrokeType) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/geometry/juce_Point.h b/source/modules/juce_graphics/geometry/juce_Point.h deleted file mode 100644 index 2b66ae847..000000000 --- a/source/modules/juce_graphics/geometry/juce_Point.h +++ /dev/null @@ -1,243 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A pair of (x, y) coordinates. - - The ValueType template should be a primitive type such as int, float, double, - rather than a class. - - @see Line, Path, AffineTransform -*/ -template -class Point -{ -public: - /** Creates a point at the origin */ - JUCE_CONSTEXPR Point() noexcept : x(), y() {} - - /** Creates a copy of another point. */ - JUCE_CONSTEXPR Point (const Point& other) noexcept : x (other.x), y (other.y) {} - - /** Creates a point from an (x, y) position. */ - JUCE_CONSTEXPR Point (ValueType initialX, ValueType initialY) noexcept : x (initialX), y (initialY) {} - - //============================================================================== - /** Copies this point from another one. */ - Point& operator= (const Point& other) noexcept { x = other.x; y = other.y; return *this; } - - JUCE_CONSTEXPR inline bool operator== (Point other) const noexcept { return x == other.x && y == other.y; } - JUCE_CONSTEXPR inline bool operator!= (Point other) const noexcept { return x != other.x || y != other.y; } - - /** Returns true if the point is (0, 0). */ - JUCE_CONSTEXPR bool isOrigin() const noexcept { return x == ValueType() && y == ValueType(); } - - /** Returns true if the coordinates are finite values. */ - JUCE_CONSTEXPR inline bool isFinite() const noexcept { return juce_isfinite(x) && juce_isfinite(y); } - - /** Returns the point's x coordinate. */ - JUCE_CONSTEXPR inline ValueType getX() const noexcept { return x; } - - /** Returns the point's y coordinate. */ - JUCE_CONSTEXPR inline ValueType getY() const noexcept { return y; } - - /** Sets the point's x coordinate. */ - inline void setX (ValueType newX) noexcept { x = newX; } - - /** Sets the point's y coordinate. */ - inline void setY (ValueType newY) noexcept { y = newY; } - - /** Returns a point which has the same Y position as this one, but a new X. */ - JUCE_CONSTEXPR Point withX (ValueType newX) const noexcept { return Point (newX, y); } - - /** Returns a point which has the same X position as this one, but a new Y. */ - JUCE_CONSTEXPR Point withY (ValueType newY) const noexcept { return Point (x, newY); } - - /** Changes the point's x and y coordinates. */ - void setXY (ValueType newX, ValueType newY) noexcept { x = newX; y = newY; } - - /** Adds a pair of coordinates to this value. */ - void addXY (ValueType xToAdd, ValueType yToAdd) noexcept { x += xToAdd; y += yToAdd; } - - //============================================================================== - /** Returns a point with a given offset from this one. */ - JUCE_CONSTEXPR Point translated (ValueType deltaX, ValueType deltaY) const noexcept { return Point (x + deltaX, y + deltaY); } - - /** Adds two points together */ - JUCE_CONSTEXPR Point operator+ (Point other) const noexcept { return Point (x + other.x, y + other.y); } - - /** Adds another point's coordinates to this one */ - Point& operator+= (Point other) noexcept { x += other.x; y += other.y; return *this; } - - /** Subtracts one points from another */ - JUCE_CONSTEXPR Point operator- (Point other) const noexcept { return Point (x - other.x, y - other.y); } - - /** Subtracts another point's coordinates to this one */ - Point& operator-= (Point other) noexcept { x -= other.x; y -= other.y; return *this; } - - /** Multiplies two points together */ - template - JUCE_CONSTEXPR Point operator* (Point other) const noexcept { return Point ((ValueType) (x * other.x), (ValueType) (y * other.y)); } - - /** Multiplies another point's coordinates to this one */ - template - Point& operator*= (Point other) noexcept { *this = *this * other; return *this; } - - /** Divides one point by another */ - template - JUCE_CONSTEXPR Point operator/ (Point other) const noexcept { return Point ((ValueType) (x / other.x), (ValueType) (y / other.y)); } - - /** Divides this point's coordinates by another */ - template - Point& operator/= (Point other) noexcept { *this = *this / other; return *this; } - - /** Returns a point whose coordinates are multiplied by a given scalar value. */ - template - JUCE_CONSTEXPR Point operator* (FloatType multiplier) const noexcept { return Point ((ValueType) (x * multiplier), (ValueType) (y * multiplier)); } - - /** Returns a point whose coordinates are divided by a given scalar value. */ - template - JUCE_CONSTEXPR Point operator/ (FloatType divisor) const noexcept { return Point ((ValueType) (x / divisor), (ValueType) (y / divisor)); } - - /** Multiplies the point's coordinates by a scalar value. */ - template - Point& operator*= (FloatType multiplier) noexcept { x = (ValueType) (x * multiplier); y = (ValueType) (y * multiplier); return *this; } - - /** Divides the point's coordinates by a scalar value. */ - template - Point& operator/= (FloatType divisor) noexcept { x = (ValueType) (x / divisor); y = (ValueType) (y / divisor); return *this; } - - /** Returns the inverse of this point. */ - JUCE_CONSTEXPR Point operator-() const noexcept { return Point (-x, -y); } - - //============================================================================== - /** This type will be double if the Point's type is double, otherwise it will be float. */ - typedef typename TypeHelpers::SmallestFloatType::type FloatType; - - //============================================================================== - /** Returns the straight-line distance between this point and the origin. */ - ValueType getDistanceFromOrigin() const noexcept { return juce_hypot (x, y); } - - /** Returns the straight-line distance between this point and another one. */ - ValueType getDistanceFrom (Point other) const noexcept { return juce_hypot (x - other.x, y - other.y); } - - /** Returns the square of the straight-line distance between this point and the origin. */ - ValueType getDistanceSquaredFromOrigin() const noexcept { return x * x + y * y; } - - /** Returns the square of the straight-line distance between this point and another one. */ - ValueType getDistanceSquaredFrom (Point other) const noexcept { return (*this - other).getDistanceSquaredFromOrigin(); } - - /** Returns the angle from this point to another one. - - Taking this point to be the centre of a circle, and the other point being a position on - the circumference, the return value is the number of radians clockwise from the 12 o'clock - direction. - So 12 o'clock = 0, 3 o'clock = Pi/2, 6 o'clock = Pi, 9 o'clock = -Pi/2 - */ - FloatType getAngleToPoint (Point other) const noexcept - { - return static_cast (std::atan2 (static_cast (other.x - x), - static_cast (y - other.y))); - } - - /** Returns the point that would be reached by rotating this point clockwise - about the origin by the specified angle. - */ - Point rotatedAboutOrigin (ValueType angleRadians) const noexcept - { - return Point (x * std::cos (angleRadians) - y * std::sin (angleRadians), - x * std::sin (angleRadians) + y * std::cos (angleRadians)); - } - - /** Taking this point to be the centre of a circle, this returns a point on its circumference. - @param radius the radius of the circle. - @param angle the angle of the point, in radians clockwise from the 12 o'clock position. - */ - Point getPointOnCircumference (float radius, float angle) const noexcept - { - return Point (static_cast (x + radius * std::sin (angle)), - static_cast (y - radius * std::cos (angle))); - } - - /** Taking this point to be the centre of an ellipse, this returns a point on its circumference. - @param radiusX the horizontal radius of the circle. - @param radiusY the vertical radius of the circle. - @param angle the angle of the point, in radians clockwise from the 12 o'clock position. - */ - Point getPointOnCircumference (float radiusX, float radiusY, float angle) const noexcept - { - return Point (static_cast (x + radiusX * std::sin (angle)), - static_cast (y - radiusY * std::cos (angle))); - } - - /** Returns the dot-product of two points (x1 * x2 + y1 * y2). */ - FloatType getDotProduct (Point other) const noexcept { return x * other.x + y * other.y; } - - //============================================================================== - /** Uses a transform to change the point's coordinates. - This will only compile if ValueType = float! - - @see AffineTransform::transformPoint - */ - void applyTransform (const AffineTransform& transform) noexcept { transform.transformPoint (x, y); } - - /** Returns the position of this point, if it is transformed by a given AffineTransform. */ - Point transformedBy (const AffineTransform& transform) const noexcept - { - return Point (static_cast (transform.mat00 * x + transform.mat01 * y + transform.mat02), - static_cast (transform.mat10 * x + transform.mat11 * y + transform.mat12)); - } - - //============================================================================== - /** Casts this point to a Point object. */ - Point toInt() const noexcept { return Point (static_cast (x), static_cast (y)); } - - /** Casts this point to a Point object. */ - Point toFloat() const noexcept { return Point (static_cast (x), static_cast (y)); } - - /** Casts this point to a Point object. */ - Point toDouble() const noexcept { return Point (static_cast (x), static_cast (y)); } - - /** Casts this point to a Point object using roundToInt() to convert the values. */ - Point roundToInt() const noexcept { return Point (juce::roundToInt (x), juce::roundToInt (y)); } - - /** Returns the point as a string in the form "x, y". */ - String toString() const { return String (x) + ", " + String (y); } - - //============================================================================== - ValueType x; /**< The point's X coordinate. */ - ValueType y; /**< The point's Y coordinate. */ -}; - -/** Multiplies the point's coordinates by a scalar value. */ -template -Point operator* (ValueType value, Point p) noexcept { return p * value; } - -} // namespace juce diff --git a/source/modules/juce_graphics/geometry/juce_Rectangle.h b/source/modules/juce_graphics/geometry/juce_Rectangle.h deleted file mode 100644 index eb5d937be..000000000 --- a/source/modules/juce_graphics/geometry/juce_Rectangle.h +++ /dev/null @@ -1,981 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Manages a rectangle and allows geometric operations to be performed on it. - - @see RectangleList, Path, Line, Point -*/ -template -class Rectangle -{ -public: - //============================================================================== - /** Creates a rectangle of zero size. - The default coordinates will be (0, 0, 0, 0). - */ - Rectangle() noexcept - : w(), h() - { - } - - /** Creates a copy of another rectangle. */ - Rectangle (const Rectangle& other) noexcept - : pos (other.pos), w (other.w), h (other.h) - { - } - - /** Creates a rectangle with a given position and size. */ - Rectangle (ValueType initialX, ValueType initialY, - ValueType width, ValueType height) noexcept - : pos (initialX, initialY), - w (width), h (height) - { - } - - /** Creates a rectangle with a given size, and a position of (0, 0). */ - Rectangle (ValueType width, ValueType height) noexcept - : w (width), h (height) - { - } - - /** Creates a Rectangle from the positions of two opposite corners. */ - Rectangle (Point corner1, Point corner2) noexcept - : pos (jmin (corner1.x, corner2.x), - jmin (corner1.y, corner2.y)), - w (corner1.x - corner2.x), - h (corner1.y - corner2.y) - { - if (w < ValueType()) w = -w; - if (h < ValueType()) h = -h; - } - - /** Creates a Rectangle from a set of left, right, top, bottom coordinates. - The right and bottom values must be larger than the left and top ones, or the resulting - rectangle will have a negative size. - */ - static Rectangle leftTopRightBottom (ValueType left, ValueType top, - ValueType right, ValueType bottom) noexcept - { - return { left, top, right - left, bottom - top }; - } - - Rectangle& operator= (const Rectangle& other) noexcept - { - pos = other.pos; - w = other.w; h = other.h; - return *this; - } - - /** Destructor. */ - ~Rectangle() noexcept {} - - //============================================================================== - /** Returns true if the rectangle's width or height are zero or less */ - bool isEmpty() const noexcept { return w <= ValueType() || h <= ValueType(); } - - /** Returns true if the rectangle's values are all finite numbers, i.e. not NaN or infinity. */ - inline bool isFinite() const noexcept { return pos.isFinite() && juce_isfinite (w) && juce_isfinite (h); } - - /** Returns the x coordinate of the rectangle's left-hand-side. */ - inline ValueType getX() const noexcept { return pos.x; } - - /** Returns the y coordinate of the rectangle's top edge. */ - inline ValueType getY() const noexcept { return pos.y; } - - /** Returns the width of the rectangle. */ - inline ValueType getWidth() const noexcept { return w; } - - /** Returns the height of the rectangle. */ - inline ValueType getHeight() const noexcept { return h; } - - /** Returns the x coordinate of the rectangle's right-hand-side. */ - inline ValueType getRight() const noexcept { return pos.x + w; } - - /** Returns the y coordinate of the rectangle's bottom edge. */ - inline ValueType getBottom() const noexcept { return pos.y + h; } - - /** Returns the x coordinate of the rectangle's centre. */ - ValueType getCentreX() const noexcept { return pos.x + w / (ValueType) 2; } - - /** Returns the y coordinate of the rectangle's centre. */ - ValueType getCentreY() const noexcept { return pos.y + h / (ValueType) 2; } - - /** Returns the centre point of the rectangle. */ - Point getCentre() const noexcept { return { pos.x + w / (ValueType) 2, - pos.y + h / (ValueType) 2 }; } - - /** Returns the aspect ratio of the rectangle's width / height. - If widthOverHeight is true, it returns width / height; if widthOverHeight is false, - it returns height / width. */ - ValueType getAspectRatio (bool widthOverHeight = true) const noexcept { return widthOverHeight ? w / h : h / w; } - - //============================================================================== - /** Returns the rectangle's top-left position as a Point. */ - inline Point getPosition() const noexcept { return pos; } - - /** Changes the position of the rectangle's top-left corner (leaving its size unchanged). */ - inline void setPosition (Point newPos) noexcept { pos = newPos; } - - /** Changes the position of the rectangle's top-left corner (leaving its size unchanged). */ - inline void setPosition (ValueType newX, ValueType newY) noexcept { pos.setXY (newX, newY); } - - /** Returns the rectangle's top-left position as a Point. */ - Point getTopLeft() const noexcept { return pos; } - - /** Returns the rectangle's top-right position as a Point. */ - Point getTopRight() const noexcept { return { pos.x + w, pos.y }; } - - /** Returns the rectangle's bottom-left position as a Point. */ - Point getBottomLeft() const noexcept { return { pos.x, pos.y + h }; } - - /** Returns the rectangle's bottom-right position as a Point. */ - Point getBottomRight() const noexcept { return { pos.x + w, pos.y + h }; } - - /** Returns the rectangle's left and right positions as a Range. */ - Range getHorizontalRange() const noexcept { return Range::withStartAndLength (pos.x, w); } - - /** Returns the rectangle's top and bottom positions as a Range. */ - Range getVerticalRange() const noexcept { return Range::withStartAndLength (pos.y, h); } - - /** Changes the rectangle's size, leaving the position of its top-left corner unchanged. */ - void setSize (ValueType newWidth, ValueType newHeight) noexcept { w = newWidth; h = newHeight; } - - /** Changes all the rectangle's coordinates. */ - void setBounds (ValueType newX, ValueType newY, - ValueType newWidth, ValueType newHeight) noexcept { pos.x = newX; pos.y = newY; w = newWidth; h = newHeight; } - - /** Changes the rectangle's X coordinate */ - inline void setX (ValueType newX) noexcept { pos.x = newX; } - - /** Changes the rectangle's Y coordinate */ - inline void setY (ValueType newY) noexcept { pos.y = newY; } - - /** Changes the rectangle's width */ - inline void setWidth (ValueType newWidth) noexcept { w = newWidth; } - - /** Changes the rectangle's height */ - inline void setHeight (ValueType newHeight) noexcept { h = newHeight; } - - /** Changes the position of the rectangle's centre (leaving its size unchanged). */ - inline void setCentre (ValueType newCentreX, ValueType newCentreY) noexcept { pos.x = newCentreX - w / (ValueType) 2; - pos.y = newCentreY - h / (ValueType) 2; } - - /** Changes the position of the rectangle's centre (leaving its size unchanged). */ - inline void setCentre (Point newCentre) noexcept { setCentre (newCentre.x, newCentre.y); } - - /** Changes the position of the rectangle's left and right edges. */ - void setHorizontalRange (Range range) noexcept { pos.x = range.getStart(); w = range.getLength(); } - - /** Changes the position of the rectangle's top and bottom edges. */ - void setVerticalRange (Range range) noexcept { pos.y = range.getStart(); h = range.getLength(); } - - /** Returns a rectangle which has the same size and y-position as this one, but with a different x-position. */ - Rectangle withX (ValueType newX) const noexcept { return { newX, pos.y, w, h }; } - - /** Returns a rectangle which has the same size and x-position as this one, but with a different y-position. */ - Rectangle withY (ValueType newY) const noexcept { return { pos.x, newY, w, h }; } - - /** Returns a rectangle which has the same size and y-position as this one, but whose right-hand edge has the given position. */ - Rectangle withRightX (ValueType newRightX) const noexcept { return { newRightX - w, pos.y, w, h }; } - - /** Returns a rectangle which has the same size and x-position as this one, but whose bottom edge has the given position. */ - Rectangle withBottomY (ValueType newBottomY) const noexcept { return { pos.x, newBottomY - h, w, h }; } - - /** Returns a rectangle with the same size as this one, but a new position. */ - Rectangle withPosition (ValueType newX, ValueType newY) const noexcept { return { newX, newY, w, h }; } - - /** Returns a rectangle with the same size as this one, but a new position. */ - Rectangle withPosition (Point newPos) const noexcept { return { newPos.x, newPos.y, w, h }; } - - /** Returns a rectangle whose size is the same as this one, but whose top-left position is (0, 0). */ - Rectangle withZeroOrigin() const noexcept { return { w, h }; } - - /** Returns a rectangle with the same size as this one, but a new centre position. */ - Rectangle withCentre (Point newCentre) const noexcept { return { newCentre.x - w / (ValueType) 2, - newCentre.y - h / (ValueType) 2, w, h }; } - - /** Returns a rectangle which has the same position and height as this one, but with a different width. */ - Rectangle withWidth (ValueType newWidth) const noexcept { return { pos.x, pos.y, newWidth, h }; } - - /** Returns a rectangle which has the same position and width as this one, but with a different height. */ - Rectangle withHeight (ValueType newHeight) const noexcept { return { pos.x, pos.y, w, newHeight }; } - - /** Returns a rectangle with the same top-left position as this one, but a new size. */ - Rectangle withSize (ValueType newWidth, ValueType newHeight) const noexcept { return { pos.x, pos.y, newWidth, newHeight }; } - - /** Returns a rectangle with the same centre position as this one, but a new size. */ - Rectangle withSizeKeepingCentre (ValueType newWidth, ValueType newHeight) const noexcept { return { pos.x + (w - newWidth) / (ValueType) 2, - pos.y + (h - newHeight) / (ValueType) 2, newWidth, newHeight }; } - - /** Moves the x position, adjusting the width so that the right-hand edge remains in the same place. - If the x is moved to be on the right of the current right-hand edge, the width will be set to zero. - @see withLeft - */ - void setLeft (ValueType newLeft) noexcept { w = jmax (ValueType(), pos.x + w - newLeft); pos.x = newLeft; } - - /** Returns a new rectangle with a different x position, but the same right-hand edge as this one. - If the new x is beyond the right of the current right-hand edge, the width will be set to zero. - @see setLeft - */ - Rectangle withLeft (ValueType newLeft) const noexcept { return { newLeft, pos.y, jmax (ValueType(), pos.x + w - newLeft), h }; } - - /** Moves the y position, adjusting the height so that the bottom edge remains in the same place. - If the y is moved to be below the current bottom edge, the height will be set to zero. - @see withTop - */ - void setTop (ValueType newTop) noexcept { h = jmax (ValueType(), pos.y + h - newTop); pos.y = newTop; } - - /** Returns a new rectangle with a different y position, but the same bottom edge as this one. - If the new y is beyond the bottom of the current rectangle, the height will be set to zero. - @see setTop - */ - Rectangle withTop (ValueType newTop) const noexcept { return { pos.x, newTop, w, jmax (ValueType(), pos.y + h - newTop) }; } - - /** Adjusts the width so that the right-hand edge of the rectangle has this new value. - If the new right is below the current X value, the X will be pushed down to match it. - @see getRight, withRight - */ - void setRight (ValueType newRight) noexcept { pos.x = jmin (pos.x, newRight); w = newRight - pos.x; } - - /** Returns a new rectangle with a different right-hand edge position, but the same left-hand edge as this one. - If the new right edge is below the current left-hand edge, the width will be set to zero. - @see setRight - */ - Rectangle withRight (ValueType newRight) const noexcept { return { jmin (pos.x, newRight), pos.y, jmax (ValueType(), newRight - pos.x), h }; } - - /** Adjusts the height so that the bottom edge of the rectangle has this new value. - If the new bottom is lower than the current Y value, the Y will be pushed down to match it. - @see getBottom, withBottom - */ - void setBottom (ValueType newBottom) noexcept { pos.y = jmin (pos.y, newBottom); h = newBottom - pos.y; } - - /** Returns a new rectangle with a different bottom edge position, but the same top edge as this one. - If the new y is beyond the bottom of the current rectangle, the height will be set to zero. - @see setBottom - */ - Rectangle withBottom (ValueType newBottom) const noexcept { return { pos.x, jmin (pos.y, newBottom), w, jmax (ValueType(), newBottom - pos.y) }; } - - /** Returns a version of this rectangle with the given amount removed from its left-hand edge. */ - Rectangle withTrimmedLeft (ValueType amountToRemove) const noexcept { return withLeft (pos.x + amountToRemove); } - - /** Returns a version of this rectangle with the given amount removed from its right-hand edge. */ - Rectangle withTrimmedRight (ValueType amountToRemove) const noexcept { return withWidth (w - amountToRemove); } - - /** Returns a version of this rectangle with the given amount removed from its top edge. */ - Rectangle withTrimmedTop (ValueType amountToRemove) const noexcept { return withTop (pos.y + amountToRemove); } - - /** Returns a version of this rectangle with the given amount removed from its bottom edge. */ - Rectangle withTrimmedBottom (ValueType amountToRemove) const noexcept { return withHeight (h - amountToRemove); } - - //============================================================================== - /** Moves the rectangle's position by adding amount to its x and y coordinates. */ - void translate (ValueType deltaX, - ValueType deltaY) noexcept - { - pos.x += deltaX; - pos.y += deltaY; - } - - /** Returns a rectangle which is the same as this one moved by a given amount. */ - Rectangle translated (ValueType deltaX, - ValueType deltaY) const noexcept - { - return { pos.x + deltaX, pos.y + deltaY, w, h }; - } - - /** Returns a rectangle which is the same as this one moved by a given amount. */ - Rectangle operator+ (Point deltaPosition) const noexcept - { - return { pos.x + deltaPosition.x, pos.y + deltaPosition.y, w, h }; - } - - /** Moves this rectangle by a given amount. */ - Rectangle& operator+= (Point deltaPosition) noexcept - { - pos += deltaPosition; - return *this; - } - - /** Returns a rectangle which is the same as this one moved by a given amount. */ - Rectangle operator- (Point deltaPosition) const noexcept - { - return { pos.x - deltaPosition.x, pos.y - deltaPosition.y, w, h }; - } - - /** Moves this rectangle by a given amount. */ - Rectangle& operator-= (Point deltaPosition) noexcept - { - pos -= deltaPosition; - return *this; - } - - /** Returns a rectangle that has been scaled by the given amount, centred around the origin. - Note that if the rectangle has int coordinates and it's scaled by a - floating-point amount, then the result will be converted back to integer - coordinates using getSmallestIntegerContainer(). - */ - template - Rectangle operator* (FloatType scaleFactor) const noexcept - { - Rectangle r (*this); - r *= scaleFactor; - return r; - } - - /** Scales this rectangle by the given amount, centred around the origin. - Note that if the rectangle has int coordinates and it's scaled by a - floating-point amount, then the result will be converted back to integer - coordinates using getSmallestIntegerContainer(). - */ - template - Rectangle operator*= (FloatType scaleFactor) noexcept - { - Rectangle (pos.x * scaleFactor, - pos.y * scaleFactor, - w * scaleFactor, - h * scaleFactor).copyWithRounding (*this); - return *this; - } - - /** Scales this rectangle by the given X and Y factors, centred around the origin. - Note that if the rectangle has int coordinates and it's scaled by a - floating-point amount, then the result will be converted back to integer - coordinates using getSmallestIntegerContainer(). - */ - template - Rectangle operator*= (Point scaleFactor) noexcept - { - Rectangle (pos.x * scaleFactor.x, - pos.y * scaleFactor.y, - w * scaleFactor.x, - h * scaleFactor.y).copyWithRounding (*this); - return *this; - } - - /** Scales this rectangle by the given amount, centred around the origin. */ - template - Rectangle operator/ (FloatType scaleFactor) const noexcept - { - Rectangle r (*this); - r /= scaleFactor; - return r; - } - - /** Scales this rectangle by the given amount, centred around the origin. */ - template - Rectangle operator/= (FloatType scaleFactor) noexcept - { - Rectangle (pos.x / scaleFactor, - pos.y / scaleFactor, - w / scaleFactor, - h / scaleFactor).copyWithRounding (*this); - return *this; - } - - /** Scales this rectangle by the given X and Y factors, centred around the origin. */ - template - Rectangle operator/= (Point scaleFactor) noexcept - { - Rectangle (pos.x / scaleFactor.x, - pos.y / scaleFactor.y, - w / scaleFactor.x, - h / scaleFactor.y).copyWithRounding (*this); - return *this; - } - - /** Expands the rectangle by a given amount. - - Effectively, its new size is (x - deltaX, y - deltaY, w + deltaX * 2, h + deltaY * 2). - @see expanded, reduce, reduced - */ - void expand (ValueType deltaX, - ValueType deltaY) noexcept - { - auto nw = jmax (ValueType(), w + deltaX * 2); - auto nh = jmax (ValueType(), h + deltaY * 2); - setBounds (pos.x - deltaX, pos.y - deltaY, nw, nh); - } - - /** Returns a rectangle that is larger than this one by a given amount. - - Effectively, the rectangle returned is (x - deltaX, y - deltaY, w + deltaX * 2, h + deltaY * 2). - @see expand, reduce, reduced - */ - Rectangle expanded (ValueType deltaX, - ValueType deltaY) const noexcept - { - auto nw = jmax (ValueType(), w + deltaX * 2); - auto nh = jmax (ValueType(), h + deltaY * 2); - return { pos.x - deltaX, pos.y - deltaY, nw, nh }; - } - - /** Returns a rectangle that is larger than this one by a given amount. - - Effectively, the rectangle returned is (x - delta, y - delta, w + delta * 2, h + delta * 2). - @see expand, reduce, reduced - */ - Rectangle expanded (ValueType delta) const noexcept - { - return expanded (delta, delta); - } - - /** Shrinks the rectangle by a given amount. - - Effectively, its new size is (x + deltaX, y + deltaY, w - deltaX * 2, h - deltaY * 2). - @see reduced, expand, expanded - */ - void reduce (ValueType deltaX, - ValueType deltaY) noexcept - { - expand (-deltaX, -deltaY); - } - - /** Returns a rectangle that is smaller than this one by a given amount. - - Effectively, the rectangle returned is (x + deltaX, y + deltaY, w - deltaX * 2, h - deltaY * 2). - @see reduce, expand, expanded - */ - Rectangle reduced (ValueType deltaX, - ValueType deltaY) const noexcept - { - return expanded (-deltaX, -deltaY); - } - - /** Returns a rectangle that is smaller than this one by a given amount. - - Effectively, the rectangle returned is (x + delta, y + delta, w - delta * 2, h - delta * 2). - @see reduce, expand, expanded - */ - Rectangle reduced (ValueType delta) const noexcept - { - return reduced (delta, delta); - } - - /** Removes a strip from the top of this rectangle, reducing this rectangle - by the specified amount and returning the section that was removed. - - E.g. if this rectangle is (100, 100, 300, 300) and amountToRemove is 50, this will - return (100, 100, 300, 50) and leave this rectangle as (100, 150, 300, 250). - - If amountToRemove is greater than the height of this rectangle, it'll be clipped to - that value. - */ - Rectangle removeFromTop (ValueType amountToRemove) noexcept - { - const Rectangle r (pos.x, pos.y, w, jmin (amountToRemove, h)); - pos.y += r.h; h -= r.h; - return r; - } - - /** Removes a strip from the left-hand edge of this rectangle, reducing this rectangle - by the specified amount and returning the section that was removed. - - E.g. if this rectangle is (100, 100, 300, 300) and amountToRemove is 50, this will - return (100, 100, 50, 300) and leave this rectangle as (150, 100, 250, 300). - - If amountToRemove is greater than the width of this rectangle, it'll be clipped to - that value. - */ - Rectangle removeFromLeft (ValueType amountToRemove) noexcept - { - const Rectangle r (pos.x, pos.y, jmin (amountToRemove, w), h); - pos.x += r.w; w -= r.w; - return r; - } - - /** Removes a strip from the right-hand edge of this rectangle, reducing this rectangle - by the specified amount and returning the section that was removed. - - E.g. if this rectangle is (100, 100, 300, 300) and amountToRemove is 50, this will - return (250, 100, 50, 300) and leave this rectangle as (100, 100, 250, 300). - - If amountToRemove is greater than the width of this rectangle, it'll be clipped to - that value. - */ - Rectangle removeFromRight (ValueType amountToRemove) noexcept - { - amountToRemove = jmin (amountToRemove, w); - const Rectangle r (pos.x + w - amountToRemove, pos.y, amountToRemove, h); - w -= amountToRemove; - return r; - } - - /** Removes a strip from the bottom of this rectangle, reducing this rectangle - by the specified amount and returning the section that was removed. - - E.g. if this rectangle is (100, 100, 300, 300) and amountToRemove is 50, this will - return (100, 250, 300, 50) and leave this rectangle as (100, 100, 300, 250). - - If amountToRemove is greater than the height of this rectangle, it'll be clipped to - that value. - */ - Rectangle removeFromBottom (ValueType amountToRemove) noexcept - { - amountToRemove = jmin (amountToRemove, h); - const Rectangle r (pos.x, pos.y + h - amountToRemove, w, amountToRemove); - h -= amountToRemove; - return r; - } - - //============================================================================== - /** Returns the nearest point to the specified point that lies within this rectangle. */ - Point getConstrainedPoint (Point point) const noexcept - { - return { jlimit (pos.x, pos.x + w, point.x), - jlimit (pos.y, pos.y + h, point.y) }; - } - - /** Returns a point within this rectangle, specified as proportional coordinates. - The relative X and Y values should be between 0 and 1, where 0 is the left or - top of this rectangle, and 1 is the right or bottom. (Out-of-bounds values - will return a point outside the rectangle). - */ - template - Point getRelativePoint (FloatType relativeX, FloatType relativeY) const noexcept - { - return { pos.x + static_cast (w * relativeX), - pos.y + static_cast (h * relativeY) }; - } - - /** Returns a proportion of the width of this rectangle. */ - template - ValueType proportionOfWidth (FloatType proportion) const noexcept - { - return static_cast (w * proportion); - } - - /** Returns a proportion of the height of this rectangle. */ - template - ValueType proportionOfHeight (FloatType proportion) const noexcept - { - return static_cast (h * proportion); - } - - /** Returns a rectangle based on some proportional coordinates relative to this one. - So for example getProportion ({ 0.25f, 0.25f, 0.5f, 0.5f }) would return a rectangle - of half the original size, with the same centre. - */ - template - Rectangle getProportion (Rectangle proportionalRect) const noexcept - { - return { pos.x + static_cast (w * proportionalRect.pos.x), - pos.y + static_cast (h * proportionalRect.pos.y), - proportionOfWidth (proportionalRect.w), - proportionOfHeight (proportionalRect.h) }; - } - - //============================================================================== - /** Returns true if the two rectangles are identical. */ - bool operator== (const Rectangle& other) const noexcept { return pos == other.pos && w == other.w && h == other.h; } - - /** Returns true if the two rectangles are not identical. */ - bool operator!= (const Rectangle& other) const noexcept { return pos != other.pos || w != other.w || h != other.h; } - - /** Returns true if this coordinate is inside the rectangle. */ - bool contains (ValueType xCoord, ValueType yCoord) const noexcept - { - return xCoord >= pos.x && yCoord >= pos.y && xCoord < pos.x + w && yCoord < pos.y + h; - } - - /** Returns true if this coordinate is inside the rectangle. */ - bool contains (Point point) const noexcept - { - return point.x >= pos.x && point.y >= pos.y && point.x < pos.x + w && point.y < pos.y + h; - } - - /** Returns true if this other rectangle is completely inside this one. */ - bool contains (Rectangle other) const noexcept - { - return pos.x <= other.pos.x && pos.y <= other.pos.y - && pos.x + w >= other.pos.x + other.w && pos.y + h >= other.pos.y + other.h; - } - - /** Returns true if any part of another rectangle overlaps this one. */ - bool intersects (Rectangle other) const noexcept - { - return pos.x + w > other.pos.x - && pos.y + h > other.pos.y - && pos.x < other.pos.x + other.w - && pos.y < other.pos.y + other.h - && w > ValueType() && h > ValueType() - && other.w > ValueType() && other.h > ValueType(); - } - - /** Returns true if any part of the given line lies inside this rectangle. */ - bool intersects (const Line& line) const noexcept - { - return contains (line.getStart()) || contains (line.getEnd()) - || line.intersects (Line (getTopLeft(), getTopRight())) - || line.intersects (Line (getTopRight(), getBottomRight())) - || line.intersects (Line (getBottomRight(), getBottomLeft())) - || line.intersects (Line (getBottomLeft(), getTopLeft())); - } - - /** Returns the region that is the overlap between this and another rectangle. - If the two rectangles don't overlap, the rectangle returned will be empty. - */ - Rectangle getIntersection (Rectangle other) const noexcept - { - auto nx = jmax (pos.x, other.pos.x); - auto ny = jmax (pos.y, other.pos.y); - auto nw = jmin (pos.x + w, other.pos.x + other.w) - nx; - - if (nw >= ValueType()) - { - auto nh = jmin (pos.y + h, other.pos.y + other.h) - ny; - - if (nh >= ValueType()) - return { nx, ny, nw, nh }; - } - - return {}; - } - - /** Clips a set of rectangle coordinates so that they lie only within this one. - This is a non-static version of intersectRectangles(). - Returns false if the two rectangles didn't overlap. - */ - bool intersectRectangle (ValueType& otherX, ValueType& otherY, ValueType& otherW, ValueType& otherH) const noexcept - { - auto maxX = jmax (otherX, pos.x); - otherW = jmin (otherX + otherW, pos.x + w) - maxX; - - if (otherW > ValueType()) - { - auto maxY = jmax (otherY, pos.y); - otherH = jmin (otherY + otherH, pos.y + h) - maxY; - - if (otherH > ValueType()) - { - otherX = maxX; otherY = maxY; - return true; - } - } - - return false; - } - - /** Clips a rectangle so that it lies only within this one. - Returns false if the two rectangles didn't overlap. - */ - bool intersectRectangle (Rectangle& rectangleToClip) const noexcept - { - return intersectRectangle (rectangleToClip.pos.x, rectangleToClip.pos.y, - rectangleToClip.w, rectangleToClip.h); - } - - /** Returns the smallest rectangle that contains both this one and the one passed-in. - - If either this or the other rectangle are empty, they will not be counted as - part of the resulting region. - */ - Rectangle getUnion (Rectangle other) const noexcept - { - if (other.isEmpty()) return *this; - if (isEmpty()) return other; - - auto newX = jmin (pos.x, other.pos.x); - auto newY = jmin (pos.y, other.pos.y); - - return { newX, newY, - jmax (pos.x + w, other.pos.x + other.w) - newX, - jmax (pos.y + h, other.pos.y + other.h) - newY }; - } - - /** If this rectangle merged with another one results in a simple rectangle, this - will set this rectangle to the result, and return true. - - Returns false and does nothing to this rectangle if the two rectangles don't overlap, - or if they form a complex region. - */ - bool enlargeIfAdjacent (Rectangle other) noexcept - { - if (pos.x == other.pos.x && getRight() == other.getRight() - && (other.getBottom() >= pos.y && other.pos.y <= getBottom())) - { - auto newY = jmin (pos.y, other.pos.y); - h = jmax (getBottom(), other.getBottom()) - newY; - pos.y = newY; - return true; - } - - if (pos.y == other.pos.y && getBottom() == other.getBottom() - && (other.getRight() >= pos.x && other.pos.x <= getRight())) - { - auto newX = jmin (pos.x, other.pos.x); - w = jmax (getRight(), other.getRight()) - newX; - pos.x = newX; - return true; - } - - return false; - } - - /** If after removing another rectangle from this one the result is a simple rectangle, - this will set this object's bounds to be the result, and return true. - - Returns false and does nothing to this rectangle if the two rectangles don't overlap, - or if removing the other one would form a complex region. - */ - bool reduceIfPartlyContainedIn (Rectangle other) noexcept - { - int inside = 0; - auto otherR = other.getRight(); - if (pos.x >= other.pos.x && pos.x < otherR) inside = 1; - auto otherB = other.getBottom(); - if (pos.y >= other.pos.y && pos.y < otherB) inside |= 2; - auto r = pos.x + w; - if (r >= other.pos.x && r < otherR) inside |= 4; - auto b = pos.y + h; - if (b >= other.pos.y && b < otherB) inside |= 8; - - switch (inside) - { - case 1 + 2 + 8: w = r - otherR; pos.x = otherR; return true; - case 1 + 2 + 4: h = b - otherB; pos.y = otherB; return true; - case 2 + 4 + 8: w = other.pos.x - pos.x; return true; - case 1 + 4 + 8: h = other.pos.y - pos.y; return true; - } - - return false; - } - - /** Tries to fit this rectangle within a target area, returning the result. - - If this rectangle is not completely inside the target area, then it'll be - shifted (without changing its size) so that it lies within the target. If it - is larger than the target rectangle in either dimension, then that dimension - will be reduced to fit within the target. - */ - Rectangle constrainedWithin (Rectangle areaToFitWithin) const noexcept - { - auto newW = jmin (w, areaToFitWithin.getWidth()); - auto newH = jmin (h, areaToFitWithin.getHeight()); - - return { jlimit (areaToFitWithin.getX(), areaToFitWithin.getRight() - newW, pos.x), - jlimit (areaToFitWithin.getY(), areaToFitWithin.getBottom() - newH, pos.y), - newW, newH }; - } - - /** Returns the smallest rectangle that can contain the shape created by applying - a transform to this rectangle. - - This should only be used on floating point rectangles. - */ - Rectangle transformedBy (const AffineTransform& transform) const noexcept - { - typedef typename TypeHelpers::SmallestFloatType::type FloatType; - - auto x1 = static_cast (pos.x), y1 = static_cast (pos.y); - auto x2 = static_cast (pos.x + w), y2 = static_cast (pos.y); - auto x3 = static_cast (pos.x), y3 = static_cast (pos.y + h); - auto x4 = static_cast (x2), y4 = static_cast (y3); - - transform.transformPoints (x1, y1, x2, y2); - transform.transformPoints (x3, y3, x4, y4); - - auto rx1 = jmin (x1, x2, x3, x4); - auto rx2 = jmax (x1, x2, x3, x4); - auto ry1 = jmin (y1, y2, y3, y4); - auto ry2 = jmax (y1, y2, y3, y4); - - Rectangle r; - Rectangle (rx1, ry1, rx2 - rx1, ry2 - ry1).copyWithRounding (r); - return r; - } - - /** Returns the smallest integer-aligned rectangle that completely contains this one. - This is only relevant for floating-point rectangles, of course. - @see toFloat(), toNearestInt() - */ - Rectangle getSmallestIntegerContainer() const noexcept - { - return Rectangle::leftTopRightBottom (floorAsInt (pos.x), - floorAsInt (pos.y), - ceilAsInt (pos.x + w), - ceilAsInt (pos.y + h)); - } - - /** Casts this rectangle to a Rectangle. - This uses roundToInt to snap x, y, width and height to the nearest integer (losing precision). - If the rectangle already uses integers, this will simply return a copy. - @see getSmallestIntegerContainer() - */ - Rectangle toNearestInt() const noexcept - { - return { roundToInt (pos.x), roundToInt (pos.y), - roundToInt (w), roundToInt (h) }; - } - - /** Casts this rectangle to a Rectangle. - @see getSmallestIntegerContainer - */ - Rectangle toFloat() const noexcept - { - return { static_cast (pos.x), static_cast (pos.y), - static_cast (w), static_cast (h) }; - } - - /** Casts this rectangle to a Rectangle. - @see getSmallestIntegerContainer - */ - Rectangle toDouble() const noexcept - { - return { static_cast (pos.x), static_cast (pos.y), - static_cast (w), static_cast (h) }; - } - - /** Casts this rectangle to a Rectangle with the given type. - If the target type is a conversion from float to int, then the conversion - will be done using getSmallestIntegerContainer(). - */ - template - Rectangle toType() const noexcept - { - Rectangle r; - copyWithRounding (r); - return r; - } - - /** Returns the smallest Rectangle that can contain a set of points. */ - static Rectangle findAreaContainingPoints (const Point* points, int numPoints) noexcept - { - if (numPoints <= 0) - return {}; - - auto minX = points[0].x; - auto maxX = minX; - auto minY = points[0].y; - auto maxY = minY; - - for (int i = 1; i < numPoints; ++i) - { - minX = jmin (minX, points[i].x); - maxX = jmax (maxX, points[i].x); - minY = jmin (minY, points[i].y); - maxY = jmax (maxY, points[i].y); - } - - return { minX, minY, maxX - minX, maxY - minY }; - } - - //============================================================================== - /** Static utility to intersect two sets of rectangular coordinates. - Returns false if the two regions didn't overlap. - @see intersectRectangle - */ - static bool intersectRectangles (ValueType& x1, ValueType& y1, ValueType& w1, ValueType& h1, - ValueType x2, ValueType y2, ValueType w2, ValueType h2) noexcept - { - auto x = jmax (x1, x2); - w1 = jmin (x1 + w1, x2 + w2) - x; - - if (w1 > ValueType()) - { - auto y = jmax (y1, y2); - h1 = jmin (y1 + h1, y2 + h2) - y; - - if (h1 > ValueType()) - { - x1 = x; y1 = y; - return true; - } - } - - return false; - } - - //============================================================================== - /** Creates a string describing this rectangle. - - The string will be of the form "x y width height", e.g. "100 100 400 200". - - Coupled with the fromString() method, this is very handy for things like - storing rectangles (particularly component positions) in XML attributes. - - @see fromString - */ - String toString() const - { - String s; - s.preallocateBytes (32); - s << pos.x << ' ' << pos.y << ' ' << w << ' ' << h; - return s; - } - - /** Parses a string containing a rectangle's details. - - The string should contain 4 integer tokens, in the form "x y width height". They - can be comma or whitespace separated. - - This method is intended to go with the toString() method, to form an easy way - of saving/loading rectangles as strings. - - @see toString - */ - static Rectangle fromString (StringRef stringVersion) - { - StringArray toks; - toks.addTokens (stringVersion.text.findEndOfWhitespace(), ",; \t\r\n", ""); - - return { parseIntAfterSpace (toks[0]), - parseIntAfterSpace (toks[1]), - parseIntAfterSpace (toks[2]), - parseIntAfterSpace (toks[3]) }; - } - - #ifndef DOXYGEN - // This has been renamed by transformedBy, in order to match the method names used in the Point class. - JUCE_DEPRECATED_WITH_BODY (Rectangle transformed (const AffineTransform& t) const noexcept, { return transformedBy (t); }) - #endif - -private: - template friend class Rectangle; - - Point pos; - ValueType w, h; - - static ValueType parseIntAfterSpace (StringRef s) noexcept - { return static_cast (s.text.findEndOfWhitespace().getIntValue32()); } - - void copyWithRounding (Rectangle& result) const noexcept { result = getSmallestIntegerContainer(); } - void copyWithRounding (Rectangle& result) const noexcept { result = toFloat(); } - void copyWithRounding (Rectangle& result) const noexcept { result = toDouble(); } - - static int floorAsInt (int n) noexcept { return n; } - static int floorAsInt (float n) noexcept { return n > (float) std::numeric_limits::min() ? (int) std::floor (n) : std::numeric_limits::min(); } - static int floorAsInt (double n) noexcept { return n > (double) std::numeric_limits::min() ? (int) std::floor (n) : std::numeric_limits::min(); } - static int ceilAsInt (int n) noexcept { return n; } - static int ceilAsInt (float n) noexcept { return n < (float) std::numeric_limits::max() ? (int) std::ceil (n) : std::numeric_limits::max(); } - static int ceilAsInt (double n) noexcept { return n < (double) std::numeric_limits::max() ? (int) std::ceil (n) : std::numeric_limits::max(); } -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/geometry/juce_RectangleList.h b/source/modules/juce_graphics/geometry/juce_RectangleList.h deleted file mode 100644 index 55512fda1..000000000 --- a/source/modules/juce_graphics/geometry/juce_RectangleList.h +++ /dev/null @@ -1,653 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Maintains a set of rectangles as a complex region. - - This class allows a set of rectangles to be treated as a solid shape, and can - add and remove rectangular sections of it, and simplify overlapping or - adjacent rectangles. - - @see Rectangle -*/ -template -class RectangleList -{ -public: - typedef Rectangle RectangleType; - - //============================================================================== - /** Creates an empty RectangleList */ - RectangleList() noexcept {} - - /** Creates a copy of another list */ - RectangleList (const RectangleList& other) : rects (other.rects) - { - } - - /** Creates a list containing just one rectangle. */ - RectangleList (const RectangleType& rect) - { - addWithoutMerging (rect); - } - - /** Copies this list from another one. */ - RectangleList& operator= (const RectangleList& other) - { - rects = other.rects; - return *this; - } - - /** Move constructor */ - RectangleList (RectangleList&& other) noexcept - : rects (static_cast&&> (other.rects)) - { - } - - /** Move assignment operator */ - RectangleList& operator= (RectangleList&& other) noexcept - { - rects = static_cast&&> (other.rects); - return *this; - } - - //============================================================================== - /** Returns true if the region is empty. */ - bool isEmpty() const noexcept { return rects.isEmpty(); } - - /** Returns the number of rectangles in the list. */ - int getNumRectangles() const noexcept { return rects.size(); } - - /** Returns one of the rectangles at a particular index. - @returns the rectangle at the index, or an empty rectangle if the index is out-of-range. - */ - RectangleType getRectangle (int index) const noexcept { return rects[index]; } - - //============================================================================== - /** Removes all rectangles to leave an empty region. */ - void clear() - { - rects.clearQuick(); - } - - /** Merges a new rectangle into the list. - - The rectangle being added will first be clipped to remove any parts of it - that overlap existing rectangles in the list, and adjacent rectangles will be - merged into it. - - The rectangle can have any size and may be empty, but if it's floating point - then it's expected to not contain any INF values. - */ - void add (const RectangleType& rect) - { - jassert (rect.isFinite()); // You must provide a valid rectangle to this method! - - if (! rect.isEmpty()) - { - if (isEmpty()) - { - rects.add (rect); - } - else - { - bool anyOverlaps = false; - - for (int j = rects.size(); --j >= 0;) - { - auto& ourRect = rects.getReference (j); - - if (rect.intersects (ourRect)) - { - if (rect.contains (ourRect)) - rects.remove (j); - else if (! ourRect.reduceIfPartlyContainedIn (rect)) - anyOverlaps = true; - } - } - - if (anyOverlaps && ! isEmpty()) - { - RectangleList r (rect); - - for (auto& ourRect : rects) - { - if (rect.intersects (ourRect)) - { - r.subtract (ourRect); - - if (r.isEmpty()) - return; - } - } - - rects.addArray (r.rects); - } - else - { - rects.add (rect); - } - } - } - } - - /** Merges a new rectangle into the list. - - The rectangle being added will first be clipped to remove any parts of it - that overlap existing rectangles in the list. - */ - void add (ValueType x, ValueType y, ValueType width, ValueType height) - { - add (RectangleType (x, y, width, height)); - } - - /** Dumbly adds a rectangle to the list without checking for overlaps. - - This simply adds the rectangle to the end, it doesn't merge it or remove - any overlapping bits. - - The rectangle can have any size and may be empty, but if it's floating point - then it's expected to not contain any INF values. - */ - void addWithoutMerging (const RectangleType& rect) - { - jassert (rect.isFinite()); // You must provide a valid rectangle to this method! - - if (! rect.isEmpty()) - rects.add (rect); - } - - /** Merges another rectangle list into this one. - - Any overlaps between the two lists will be clipped, so that the result is - the union of both lists. - */ - void add (const RectangleList& other) - { - for (auto& r : other) - add (*r); - } - - /** Removes a rectangular region from the list. - - Any rectangles in the list which overlap this will be clipped and subdivided - if necessary. - */ - void subtract (const RectangleType& rect) - { - if (auto numRects = rects.size()) - { - auto x1 = rect.getX(); - auto y1 = rect.getY(); - auto x2 = x1 + rect.getWidth(); - auto y2 = y1 + rect.getHeight(); - - for (int i = numRects; --i >= 0;) - { - auto& r = rects.getReference (i); - - auto rx1 = r.getX(); - auto ry1 = r.getY(); - auto rx2 = rx1 + r.getWidth(); - auto ry2 = ry1 + r.getHeight(); - - if (! (x2 <= rx1 || x1 >= rx2 || y2 <= ry1 || y1 >= ry2)) - { - if (x1 > rx1 && x1 < rx2) - { - if (y1 <= ry1 && y2 >= ry2 && x2 >= rx2) - { - r.setWidth (x1 - rx1); - } - else - { - r.setX (x1); - r.setWidth (rx2 - x1); - - rects.insert (++i, RectangleType (rx1, ry1, x1 - rx1, ry2 - ry1)); - ++i; - } - } - else if (x2 > rx1 && x2 < rx2) - { - r.setX (x2); - r.setWidth (rx2 - x2); - - if (y1 > ry1 || y2 < ry2 || x1 > rx1) - { - rects.insert (++i, RectangleType (rx1, ry1, x2 - rx1, ry2 - ry1)); - ++i; - } - } - else if (y1 > ry1 && y1 < ry2) - { - if (x1 <= rx1 && x2 >= rx2 && y2 >= ry2) - { - r.setHeight (y1 - ry1); - } - else - { - r.setY (y1); - r.setHeight (ry2 - y1); - - rects.insert (++i, RectangleType (rx1, ry1, rx2 - rx1, y1 - ry1)); - ++i; - } - } - else if (y2 > ry1 && y2 < ry2) - { - r.setY (y2); - r.setHeight (ry2 - y2); - - if (x1 > rx1 || x2 < rx2 || y1 > ry1) - { - rects.insert (++i, RectangleType (rx1, ry1, rx2 - rx1, y2 - ry1)); - ++i; - } - } - else - { - rects.remove (i); - } - } - } - } - } - - /** Removes all areas in another RectangleList from this one. - - Any rectangles in the list which overlap this will be clipped and subdivided - if necessary. - - @returns true if the resulting list is non-empty. - */ - bool subtract (const RectangleList& otherList) - { - for (auto& r : otherList) - { - if (isEmpty()) - return false; - - subtract (r); - } - - return ! isEmpty(); - } - - /** Removes any areas of the region that lie outside a given rectangle. - - Any rectangles in the list which overlap this will be clipped and subdivided - if necessary. - - Returns true if the resulting region is not empty, false if it is empty. - - @see getIntersectionWith - */ - bool clipTo (const RectangleType& rect) - { - jassert (rect.isFinite()); // You must provide a valid rectangle to this method! - - bool notEmpty = false; - - if (rect.isEmpty()) - { - clear(); - } - else - { - for (int i = rects.size(); --i >= 0;) - { - auto& r = rects.getReference (i); - - if (! rect.intersectRectangle (r)) - rects.remove (i); - else - notEmpty = true; - } - } - - return notEmpty; - } - - /** Removes any areas of the region that lie outside a given rectangle list. - - Any rectangles in this object which overlap the specified list will be clipped - and subdivided if necessary. - - Returns true if the resulting region is not empty, false if it is empty. - - @see getIntersectionWith - */ - template - bool clipTo (const RectangleList& other) - { - if (isEmpty()) - return false; - - RectangleList result; - - for (auto& rect : rects) - { - for (auto& r : other) - { - auto clipped = r.template toType(); - - if (rect.intersectRectangle (clipped)) - result.rects.add (clipped); - } - } - - swapWith (result); - return ! isEmpty(); - } - - /** Creates a region which is the result of clipping this one to a given rectangle. - - Unlike the other clipTo method, this one doesn't affect this object - it puts the - resulting region into the list whose reference is passed-in. - - Returns true if the resulting region is not empty, false if it is empty. - - @see clipTo - */ - bool getIntersectionWith (const RectangleType& rect, RectangleList& destRegion) const - { - jassert (rect.isFinite()); // You must provide a valid rectangle to this method! - - destRegion.clear(); - - if (! rect.isEmpty()) - for (auto& r : rects) - if (rect.intersectRectangle (r)) - destRegion.rects.add (r); - - return ! destRegion.isEmpty(); - } - - /** Swaps the contents of this and another list. - - This swaps their internal pointers, so is hugely faster than using copy-by-value - to swap them. - */ - void swapWith (RectangleList& otherList) noexcept - { - rects.swapWith (otherList.rects); - } - - //============================================================================== - /** Checks whether the region contains a given point. - @returns true if the point lies within one of the rectangles in the list - */ - bool containsPoint (Point point) const noexcept - { - for (auto& r : rects) - if (r.contains (point)) - return true; - - return false; - } - - /** Checks whether the region contains a given point. - @returns true if the point lies within one of the rectangles in the list - */ - bool containsPoint (ValueType x, ValueType y) const noexcept - { - return containsPoint (Point (x, y)); - } - - /** Checks whether the region contains the whole of a given rectangle. - - @returns true all parts of the rectangle passed in lie within the region - defined by this object - @see intersectsRectangle, containsPoint - */ - bool containsRectangle (const RectangleType& rectangleToCheck) const - { - if (rects.size() > 1) - { - RectangleList r (rectangleToCheck); - - for (auto& rect : rects) - { - r.subtract (rect); - - if (r.isEmpty()) - return true; - } - } - else if (! isEmpty()) - { - return rects.getReference (0).contains (rectangleToCheck); - } - - return false; - } - - /** Checks whether the region contains any part of a given rectangle. - - @returns true if any part of the rectangle passed in lies within the region - defined by this object - @see containsRectangle - */ - bool intersectsRectangle (const RectangleType& rectangleToCheck) const noexcept - { - for (auto& r : rects) - if (r.intersects (rectangleToCheck)) - return true; - - return false; - } - - /** Checks whether this region intersects any part of another one. - - @see intersectsRectangle - */ - bool intersects (const RectangleList& other) const noexcept - { - for (auto& r : rects) - if (other.intersectsRectangle (r)) - return true; - - return false; - } - - //============================================================================== - /** Returns the smallest rectangle that can enclose the whole of this region. */ - RectangleType getBounds() const noexcept - { - if (isEmpty()) - return {}; - - auto& r = rects.getReference (0); - - if (rects.size() == 1) - return r; - - auto minX = r.getX(); - auto minY = r.getY(); - auto maxX = minX + r.getWidth(); - auto maxY = minY + r.getHeight(); - - for (int i = rects.size(); --i > 0;) - { - auto& r2 = rects.getReference (i); - - minX = jmin (minX, r2.getX()); - minY = jmin (minY, r2.getY()); - maxX = jmax (maxX, r2.getRight()); - maxY = jmax (maxY, r2.getBottom()); - } - - return { minX, minY, maxX - minX, maxY - minY }; - } - - /** Optimises the list into a minimum number of constituent rectangles. - - This will try to combine any adjacent rectangles into larger ones where - possible, to simplify lists that might have been fragmented by repeated - add/subtract calls. - */ - void consolidate() - { - for (int i = 0; i < rects.size() - 1; ++i) - { - auto& r = rects.getReference (i); - auto rx1 = r.getX(); - auto ry1 = r.getY(); - auto rx2 = rx1 + r.getWidth(); - auto ry2 = ry1 + r.getHeight(); - - for (int j = rects.size(); --j > i;) - { - auto& r2 = rects.getReference (j); - auto jrx1 = r2.getX(); - auto jry1 = r2.getY(); - auto jrx2 = jrx1 + r2.getWidth(); - auto jry2 = jry1 + r2.getHeight(); - - // if the vertical edges of any blocks are touching and their horizontals don't - // line up, split them horizontally.. - if (jrx1 == rx2 || jrx2 == rx1) - { - if (jry1 > ry1 && jry1 < ry2) - { - r.setHeight (jry1 - ry1); - rects.add (RectangleType (rx1, jry1, rx2 - rx1, ry2 - jry1)); - i = -1; - break; - } - - if (jry2 > ry1 && jry2 < ry2) - { - r.setHeight (jry2 - ry1); - rects.add (RectangleType (rx1, jry2, rx2 - rx1, ry2 - jry2)); - i = -1; - break; - } - else if (ry1 > jry1 && ry1 < jry2) - { - r2.setHeight (ry1 - jry1); - rects.add (RectangleType (jrx1, ry1, jrx2 - jrx1, jry2 - ry1)); - i = -1; - break; - } - else if (ry2 > jry1 && ry2 < jry2) - { - r2.setHeight (ry2 - jry1); - rects.add (RectangleType (jrx1, ry2, jrx2 - jrx1, jry2 - ry2)); - i = -1; - break; - } - } - } - } - - for (int i = 0; i < rects.size() - 1; ++i) - { - auto& r = rects.getReference (i); - - for (int j = rects.size(); --j > i;) - { - if (r.enlargeIfAdjacent (rects.getReference (j))) - { - rects.remove (j); - i = -1; - break; - } - } - } - } - - /** Adds an x and y value to all the coordinates. */ - void offsetAll (Point offset) noexcept - { - for (auto& r : rects) - r += offset; - } - - /** Adds an x and y value to all the coordinates. */ - void offsetAll (ValueType dx, ValueType dy) noexcept - { - offsetAll (Point (dx, dy)); - } - - /** Scales all the coordinates. */ - template - void scaleAll (ScaleType scaleFactor) noexcept - { - for (auto& r : rects) - r *= scaleFactor; - } - - /** Applies a transform to all the rectangles. - Obviously this will create a mess if the transform involves any - rotation or skewing. - */ - void transformAll (const AffineTransform& transform) noexcept - { - for (auto& r : rects) - r = r.transformedBy (transform); - } - - //============================================================================== - /** Creates a Path object to represent this region. */ - Path toPath() const - { - Path p; - - for (auto& r : rects) - p.addRectangle (r); - - return p; - } - - //============================================================================== - /** Standard method for iterating the rectangles in the list. */ - const RectangleType* begin() const noexcept { return rects.begin(); } - /** Standard method for iterating the rectangles in the list. */ - const RectangleType* end() const noexcept { return rects.end(); } - - /** Increases the internal storage to hold a minimum number of rectangles. - Calling this before adding a large number of rectangles means that - the array won't have to keep dynamically resizing itself as the elements - are added, and it'll therefore be more efficient. - @see Array::ensureStorageAllocated - */ - void ensureStorageAllocated (int minNumRectangles) - { - rects.ensureStorageAllocated (minNumRectangles); - } - -private: - //============================================================================== - Array rects; -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/image_formats/jpglib/README b/source/modules/juce_graphics/image_formats/jpglib/README deleted file mode 100644 index 86cc20669..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/README +++ /dev/null @@ -1,385 +0,0 @@ -The Independent JPEG Group's JPEG software -========================================== - -README for release 6b of 27-Mar-1998 -==================================== - -This distribution contains the sixth public release of the Independent JPEG -Group's free JPEG software. You are welcome to redistribute this software and -to use it for any purpose, subject to the conditions under LEGAL ISSUES, below. - -Serious users of this software (particularly those incorporating it into -larger programs) should contact IJG at jpeg-info@uunet.uu.net to be added to -our electronic mailing list. Mailing list members are notified of updates -and have a chance to participate in technical discussions, etc. - -This software is the work of Tom Lane, Philip Gladstone, Jim Boucher, -Lee Crocker, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, -Guido Vollbeding, Ge' Weijers, and other members of the Independent JPEG -Group. - -IJG is not affiliated with the official ISO JPEG standards committee. - - -DOCUMENTATION ROADMAP -===================== - -This file contains the following sections: - -OVERVIEW General description of JPEG and the IJG software. -LEGAL ISSUES Copyright, lack of warranty, terms of distribution. -REFERENCES Where to learn more about JPEG. -ARCHIVE LOCATIONS Where to find newer versions of this software. -RELATED SOFTWARE Other stuff you should get. -FILE FORMAT WARS Software *not* to get. -TO DO Plans for future IJG releases. - -Other documentation files in the distribution are: - -User documentation: - install.doc How to configure and install the IJG software. - usage.doc Usage instructions for cjpeg, djpeg, jpegtran, - rdjpgcom, and wrjpgcom. - *.1 Unix-style man pages for programs (same info as usage.doc). - wizard.doc Advanced usage instructions for JPEG wizards only. - change.log Version-to-version change highlights. -Programmer and internal documentation: - libjpeg.doc How to use the JPEG library in your own programs. - example.c Sample code for calling the JPEG library. - structure.doc Overview of the JPEG library's internal structure. - filelist.doc Road map of IJG files. - coderules.doc Coding style rules --- please read if you contribute code. - -Please read at least the files install.doc and usage.doc. Useful information -can also be found in the JPEG FAQ (Frequently Asked Questions) article. See -ARCHIVE LOCATIONS below to find out where to obtain the FAQ article. - -If you want to understand how the JPEG code works, we suggest reading one or -more of the REFERENCES, then looking at the documentation files (in roughly -the order listed) before diving into the code. - - -OVERVIEW -======== - -This package contains C software to implement JPEG image compression and -decompression. JPEG (pronounced "jay-peg") is a standardized compression -method for full-color and gray-scale images. JPEG is intended for compressing -"real-world" scenes; line drawings, cartoons and other non-realistic images -are not its strong suit. JPEG is lossy, meaning that the output image is not -exactly identical to the input image. Hence you must not use JPEG if you -have to have identical output bits. However, on typical photographic images, -very good compression levels can be obtained with no visible change, and -remarkably high compression levels are possible if you can tolerate a -low-quality image. For more details, see the references, or just experiment -with various compression settings. - -This software implements JPEG baseline, extended-sequential, and progressive -compression processes. Provision is made for supporting all variants of these -processes, although some uncommon parameter settings aren't implemented yet. -For legal reasons, we are not distributing code for the arithmetic-coding -variants of JPEG; see LEGAL ISSUES. We have made no provision for supporting -the hierarchical or lossless processes defined in the standard. - -We provide a set of library routines for reading and writing JPEG image files, -plus two sample applications "cjpeg" and "djpeg", which use the library to -perform conversion between JPEG and some other popular image file formats. -The library is intended to be reused in other applications. - -In order to support file conversion and viewing software, we have included -considerable functionality beyond the bare JPEG coding/decoding capability; -for example, the color quantization modules are not strictly part of JPEG -decoding, but they are essential for output to colormapped file formats or -colormapped displays. These extra functions can be compiled out of the -library if not required for a particular application. We have also included -"jpegtran", a utility for lossless transcoding between different JPEG -processes, and "rdjpgcom" and "wrjpgcom", two simple applications for -inserting and extracting textual comments in JFIF files. - -The emphasis in designing this software has been on achieving portability and -flexibility, while also making it fast enough to be useful. In particular, -the software is not intended to be read as a tutorial on JPEG. (See the -REFERENCES section for introductory material.) Rather, it is intended to -be reliable, portable, industrial-strength code. We do not claim to have -achieved that goal in every aspect of the software, but we strive for it. - -We welcome the use of this software as a component of commercial products. -No royalty is required, but we do ask for an acknowledgement in product -documentation, as described under LEGAL ISSUES. - - -LEGAL ISSUES -============ - -In plain English: - -1. We don't promise that this software works. (But if you find any bugs, - please let us know!) -2. You can use this software for whatever you want. You don't have to pay us. -3. You may not pretend that you wrote this software. If you use it in a - program, you must acknowledge somewhere in your documentation that - you've used the IJG code. - -In legalese: - -The authors make NO WARRANTY or representation, either express or implied, -with respect to this software, its quality, accuracy, merchantability, or -fitness for a particular purpose. This software is provided "AS IS", and you, -its user, assume the entire risk as to its quality and accuracy. - -This software is copyright (C) 1991-1998, Thomas G. Lane. -All Rights Reserved except as specified below. - -Permission is hereby granted to use, copy, modify, and distribute this -software (or portions thereof) for any purpose, without fee, subject to these -conditions: -(1) If any part of the source code for this software is distributed, then this -README file must be included, with this copyright and no-warranty notice -unaltered; and any additions, deletions, or changes to the original files -must be clearly indicated in accompanying documentation. -(2) If only executable code is distributed, then the accompanying -documentation must state that "this software is based in part on the work of -the Independent JPEG Group". -(3) Permission for use of this software is granted only if the user accepts -full responsibility for any undesirable consequences; the authors accept -NO LIABILITY for damages of any kind. - -These conditions apply to any software derived from or based on the IJG code, -not just to the unmodified library. If you use our work, you ought to -acknowledge us. - -Permission is NOT granted for the use of any IJG author's name or company name -in advertising or publicity relating to this software or products derived from -it. This software may be referred to only as "the Independent JPEG Group's -software". - -We specifically permit and encourage the use of this software as the basis of -commercial products, provided that all warranty or liability claims are -assumed by the product vendor. - - -ansi2knr.c is included in this distribution by permission of L. Peter Deutsch, -sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA. -ansi2knr.c is NOT covered by the above copyright and conditions, but instead -by the usual distribution terms of the Free Software Foundation; principally, -that you must include source code if you redistribute it. (See the file -ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part -of any program generated from the IJG code, this does not limit you more than -the foregoing paragraphs do. - -The Unix configuration script "configure" was produced with GNU Autoconf. -It is copyright by the Free Software Foundation but is freely distributable. -The same holds for its supporting scripts (config.guess, config.sub, -ltconfig, ltmain.sh). Another support script, install-sh, is copyright -by M.I.T. but is also freely distributable. - -It appears that the arithmetic coding option of the JPEG spec is covered by -patents owned by IBM, AT&T, and Mitsubishi. Hence arithmetic coding cannot -legally be used without obtaining one or more licenses. For this reason, -support for arithmetic coding has been removed from the free JPEG software. -(Since arithmetic coding provides only a marginal gain over the unpatented -Huffman mode, it is unlikely that very many implementations will support it.) -So far as we are aware, there are no patent restrictions on the remaining -code. - -The IJG distribution formerly included code to read and write GIF files. -To avoid entanglement with the Unisys LZW patent, GIF reading support has -been removed altogether, and the GIF writer has been simplified to produce -"uncompressed GIFs". This technique does not use the LZW algorithm; the -resulting GIF files are larger than usual, but are readable by all standard -GIF decoders. - -We are required to state that - "The Graphics Interchange Format(c) is the Copyright property of - CompuServe Incorporated. GIF(sm) is a Service Mark property of - CompuServe Incorporated." - - -REFERENCES -========== - -We highly recommend reading one or more of these references before trying to -understand the innards of the JPEG software. - -The best short technical introduction to the JPEG compression algorithm is - Wallace, Gregory K. "The JPEG Still Picture Compression Standard", - Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44. -(Adjacent articles in that issue discuss MPEG motion picture compression, -applications of JPEG, and related topics.) If you don't have the CACM issue -handy, a PostScript file containing a revised version of Wallace's article is -available at ftp://ftp.uu.net/graphics/jpeg/wallace.ps.gz. The file (actually -a preprint for an article that appeared in IEEE Trans. Consumer Electronics) -omits the sample images that appeared in CACM, but it includes corrections -and some added material. Note: the Wallace article is copyright ACM and IEEE, -and it may not be used for commercial purposes. - -A somewhat less technical, more leisurely introduction to JPEG can be found in -"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by -M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides -good explanations and example C code for a multitude of compression methods -including JPEG. It is an excellent source if you are comfortable reading C -code but don't know much about data compression in general. The book's JPEG -sample code is far from industrial-strength, but when you are ready to look -at a full implementation, you've got one here... - -The best full description of JPEG is the textbook "JPEG Still Image Data -Compression Standard" by William B. Pennebaker and Joan L. Mitchell, published -by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. Price US$59.95, 638 pp. -The book includes the complete text of the ISO JPEG standards (DIS 10918-1 -and draft DIS 10918-2). This is by far the most complete exposition of JPEG -in existence, and we highly recommend it. - -The JPEG standard itself is not available electronically; you must order a -paper copy through ISO or ITU. (Unless you feel a need to own a certified -official copy, we recommend buying the Pennebaker and Mitchell book instead; -it's much cheaper and includes a great deal of useful explanatory material.) -In the USA, copies of the standard may be ordered from ANSI Sales at (212) -642-4900, or from Global Engineering Documents at (800) 854-7179. (ANSI -doesn't take credit card orders, but Global does.) It's not cheap: as of -1992, ANSI was charging $95 for Part 1 and $47 for Part 2, plus 7% -shipping/handling. The standard is divided into two parts, Part 1 being the -actual specification, while Part 2 covers compliance testing methods. Part 1 -is titled "Digital Compression and Coding of Continuous-tone Still Images, -Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS -10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of -Continuous-tone Still Images, Part 2: Compliance testing" and has document -numbers ISO/IEC IS 10918-2, ITU-T T.83. - -Some extensions to the original JPEG standard are defined in JPEG Part 3, -a newer ISO standard numbered ISO/IEC IS 10918-3 and ITU-T T.84. IJG -currently does not support any Part 3 extensions. - -The JPEG standard does not specify all details of an interchangeable file -format. For the omitted details we follow the "JFIF" conventions, revision -1.02. A copy of the JFIF spec is available from: - Literature Department - C-Cube Microsystems, Inc. - 1778 McCarthy Blvd. - Milpitas, CA 95035 - phone (408) 944-6300, fax (408) 944-6314 -A PostScript version of this document is available by FTP at -ftp://ftp.uu.net/graphics/jpeg/jfif.ps.gz. There is also a plain text -version at ftp://ftp.uu.net/graphics/jpeg/jfif.txt.gz, but it is missing -the figures. - -The TIFF 6.0 file format specification can be obtained by FTP from -ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme -found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems. -IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6). -Instead, we recommend the JPEG design proposed by TIFF Technical Note #2 -(Compression tag 7). Copies of this Note can be obtained from ftp.sgi.com or -from ftp://ftp.uu.net/graphics/jpeg/. It is expected that the next revision -of the TIFF spec will replace the 6.0 JPEG design with the Note's design. -Although IJG's own code does not support TIFF/JPEG, the free libtiff library -uses our library to implement TIFF/JPEG per the Note. libtiff is available -from ftp://ftp.sgi.com/graphics/tiff/. - - -ARCHIVE LOCATIONS -================= - -The "official" archive site for this software is ftp.uu.net (Internet -address 192.48.96.9). The most recent released version can always be found -there in directory graphics/jpeg. This particular version will be archived -as ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz. If you don't have -direct Internet access, UUNET's archives are also available via UUCP; contact -help@uunet.uu.net for information on retrieving files that way. - -Numerous Internet sites maintain copies of the UUNET files. However, only -ftp.uu.net is guaranteed to have the latest official version. - -You can also obtain this software in DOS-compatible "zip" archive format from -the SimTel archives (ftp://ftp.simtel.net/pub/simtelnet/msdos/graphics/), or -on CompuServe in the Graphics Support forum (GO CIS:GRAPHSUP), library 12 -"JPEG Tools". Again, these versions may sometimes lag behind the ftp.uu.net -release. - -The JPEG FAQ (Frequently Asked Questions) article is a useful source of -general information about JPEG. It is updated constantly and therefore is -not included in this distribution. The FAQ is posted every two weeks to -Usenet newsgroups comp.graphics.misc, news.answers, and other groups. -It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/ -and other news.answers archive sites, including the official news.answers -archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/. -If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu -with body - send usenet/news.answers/jpeg-faq/part1 - send usenet/news.answers/jpeg-faq/part2 - - -RELATED SOFTWARE -================ - -Numerous viewing and image manipulation programs now support JPEG. (Quite a -few of them use this library to do so.) The JPEG FAQ described above lists -some of the more popular free and shareware viewers, and tells where to -obtain them on Internet. - -If you are on a Unix machine, we highly recommend Jef Poskanzer's free -PBMPLUS software, which provides many useful operations on PPM-format image -files. In particular, it can convert PPM images to and from a wide range of -other formats, thus making cjpeg/djpeg considerably more useful. The latest -version is distributed by the NetPBM group, and is available from numerous -sites, notably ftp://wuarchive.wustl.edu/graphics/graphics/packages/NetPBM/. -Unfortunately PBMPLUS/NETPBM is not nearly as portable as the IJG software is; -you are likely to have difficulty making it work on any non-Unix machine. - -A different free JPEG implementation, written by the PVRG group at Stanford, -is available from ftp://havefun.stanford.edu/pub/jpeg/. This program -is designed for research and experimentation rather than production use; -it is slower, harder to use, and less portable than the IJG code, but it -is easier to read and modify. Also, the PVRG code supports lossless JPEG, -which we do not. (On the other hand, it doesn't do progressive JPEG.) - - -FILE FORMAT WARS -================ - -Some JPEG programs produce files that are not compatible with our library. -The root of the problem is that the ISO JPEG committee failed to specify a -concrete file format. Some vendors "filled in the blanks" on their own, -creating proprietary formats that no one else could read. (For example, none -of the early commercial JPEG implementations for the Macintosh were able to -exchange compressed files.) - -The file format we have adopted is called JFIF (see REFERENCES). This format -has been agreed to by a number of major commercial JPEG vendors, and it has -become the de facto standard. JFIF is a minimal or "low end" representation. -We recommend the use of TIFF/JPEG (TIFF revision 6.0 as modified by TIFF -Technical Note #2) for "high end" applications that need to record a lot of -additional data about an image. TIFF/JPEG is fairly new and not yet widely -supported, unfortunately. - -The upcoming JPEG Part 3 standard defines a file format called SPIFF. -SPIFF is interoperable with JFIF, in the sense that most JFIF decoders should -be able to read the most common variant of SPIFF. SPIFF has some technical -advantages over JFIF, but its major claim to fame is simply that it is an -official standard rather than an informal one. At this point it is unclear -whether SPIFF will supersede JFIF or whether JFIF will remain the de-facto -standard. IJG intends to support SPIFF once the standard is frozen, but we -have not decided whether it should become our default output format or not. -(In any case, our decoder will remain capable of reading JFIF indefinitely.) - -Various proprietary file formats incorporating JPEG compression also exist. -We have little or no sympathy for the existence of these formats. Indeed, -one of the original reasons for developing this free software was to help -force convergence on common, open format standards for JPEG files. Don't -use a proprietary file format! - - -TO DO -===== - -The major thrust for v7 will probably be improvement of visual quality. -The current method for scaling the quantization tables is known not to be -very good at low Q values. We also intend to investigate block boundary -smoothing, "poor man's variable quantization", and other means of improving -quality-vs-file-size performance without sacrificing compatibility. - -In future versions, we are considering supporting some of the upcoming JPEG -Part 3 extensions --- principally, variable quantization and the SPIFF file -format. - -As always, speeding things up is of great interest. - -Please send bug reports, offers of help, etc. to jpeg-info@uunet.uu.net. diff --git a/source/modules/juce_graphics/image_formats/jpglib/cderror.h b/source/modules/juce_graphics/image_formats/jpglib/cderror.h deleted file mode 100644 index c19d38fb4..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/cderror.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * cderror.h - * - * Copyright (C) 1994-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file defines the error and message codes for the cjpeg/djpeg - * applications. These strings are not needed as part of the JPEG library - * proper. - * Edit this file to add new codes, or to translate the message strings to - * some other language. - */ - -/* - * To define the enum list of message codes, include this file without - * defining macro JMESSAGE. To create a message string table, include it - * again with a suitable JMESSAGE definition (see jerror.c for an example). - */ -#ifndef JMESSAGE -#ifndef CDERROR_H -#define CDERROR_H -/* First time through, define the enum list */ -#define JMAKE_ENUM_LIST -#else -/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ -#define JMESSAGE(code,string) -#endif /* CDERROR_H */ -#endif /* JMESSAGE */ - -#ifdef JMAKE_ENUM_LIST - -typedef enum { - -#define JMESSAGE(code,string) code , - -#endif /* JMAKE_ENUM_LIST */ - -JMESSAGE(JMSG_FIRSTADDONCODE=1000, NULL) /* Must be first entry! */ - -#ifdef BMP_SUPPORTED -JMESSAGE(JERR_BMP_BADCMAP, "Unsupported BMP colormap format") -JMESSAGE(JERR_BMP_BADDEPTH, "Only 8- and 24-bit BMP files are supported") -JMESSAGE(JERR_BMP_BADHEADER, "Invalid BMP file: bad header length") -JMESSAGE(JERR_BMP_BADPLANES, "Invalid BMP file: biPlanes not equal to 1") -JMESSAGE(JERR_BMP_COLORSPACE, "BMP output must be grayscale or RGB") -JMESSAGE(JERR_BMP_COMPRESSED, "Sorry, compressed BMPs not yet supported") -JMESSAGE(JERR_BMP_NOT, "Not a BMP file - does not start with BM") -JMESSAGE(JTRC_BMP, "%ux%u 24-bit BMP image") -JMESSAGE(JTRC_BMP_MAPPED, "%ux%u 8-bit colormapped BMP image") -JMESSAGE(JTRC_BMP_OS2, "%ux%u 24-bit OS2 BMP image") -JMESSAGE(JTRC_BMP_OS2_MAPPED, "%ux%u 8-bit colormapped OS2 BMP image") -#endif /* BMP_SUPPORTED */ - -#ifdef GIF_SUPPORTED -JMESSAGE(JERR_GIF_BUG, "GIF output got confused") -JMESSAGE(JERR_GIF_CODESIZE, "Bogus GIF codesize %d") -JMESSAGE(JERR_GIF_COLORSPACE, "GIF output must be grayscale or RGB") -JMESSAGE(JERR_GIF_IMAGENOTFOUND, "Too few images in GIF file") -JMESSAGE(JERR_GIF_NOT, "Not a GIF file") -JMESSAGE(JTRC_GIF, "%ux%ux%d GIF image") -JMESSAGE(JTRC_GIF_BADVERSION, - "Warning: unexpected GIF version number '%c%c%c'") -JMESSAGE(JTRC_GIF_EXTENSION, "Ignoring GIF extension block of type 0x%02x") -JMESSAGE(JTRC_GIF_NONSQUARE, "Caution: nonsquare pixels in input") -JMESSAGE(JWRN_GIF_BADDATA, "Corrupt data in GIF file") -JMESSAGE(JWRN_GIF_CHAR, "Bogus char 0x%02x in GIF file, ignoring") -JMESSAGE(JWRN_GIF_ENDCODE, "Premature end of GIF image") -JMESSAGE(JWRN_GIF_NOMOREDATA, "Ran out of GIF bits") -#endif /* GIF_SUPPORTED */ - -#ifdef PPM_SUPPORTED -JMESSAGE(JERR_PPM_COLORSPACE, "PPM output must be grayscale or RGB") -JMESSAGE(JERR_PPM_NONNUMERIC, "Nonnumeric data in PPM file") -JMESSAGE(JERR_PPM_NOT, "Not a PPM/PGM file") -JMESSAGE(JTRC_PGM, "%ux%u PGM image") -JMESSAGE(JTRC_PGM_TEXT, "%ux%u text PGM image") -JMESSAGE(JTRC_PPM, "%ux%u PPM image") -JMESSAGE(JTRC_PPM_TEXT, "%ux%u text PPM image") -#endif /* PPM_SUPPORTED */ - -#ifdef RLE_SUPPORTED -JMESSAGE(JERR_RLE_BADERROR, "Bogus error code from RLE library") -JMESSAGE(JERR_RLE_COLORSPACE, "RLE output must be grayscale or RGB") -JMESSAGE(JERR_RLE_DIMENSIONS, "Image dimensions (%ux%u) too large for RLE") -JMESSAGE(JERR_RLE_EMPTY, "Empty RLE file") -JMESSAGE(JERR_RLE_EOF, "Premature EOF in RLE header") -JMESSAGE(JERR_RLE_MEM, "Insufficient memory for RLE header") -JMESSAGE(JERR_RLE_NOT, "Not an RLE file") -JMESSAGE(JERR_RLE_TOOMANYCHANNELS, "Cannot handle %d output channels for RLE") -JMESSAGE(JERR_RLE_UNSUPPORTED, "Cannot handle this RLE setup") -JMESSAGE(JTRC_RLE, "%ux%u full-color RLE file") -JMESSAGE(JTRC_RLE_FULLMAP, "%ux%u full-color RLE file with map of length %d") -JMESSAGE(JTRC_RLE_GRAY, "%ux%u grayscale RLE file") -JMESSAGE(JTRC_RLE_MAPGRAY, "%ux%u grayscale RLE file with map of length %d") -JMESSAGE(JTRC_RLE_MAPPED, "%ux%u colormapped RLE file with map of length %d") -#endif /* RLE_SUPPORTED */ - -#ifdef TARGA_SUPPORTED -JMESSAGE(JERR_TGA_BADCMAP, "Unsupported Targa colormap format") -JMESSAGE(JERR_TGA_BADPARMS, "Invalid or unsupported Targa file") -JMESSAGE(JERR_TGA_COLORSPACE, "Targa output must be grayscale or RGB") -JMESSAGE(JTRC_TGA, "%ux%u RGB Targa image") -JMESSAGE(JTRC_TGA_GRAY, "%ux%u grayscale Targa image") -JMESSAGE(JTRC_TGA_MAPPED, "%ux%u colormapped Targa image") -#else -JMESSAGE(JERR_TGA_NOTCOMP, "Targa support was not compiled") -#endif /* TARGA_SUPPORTED */ - -JMESSAGE(JERR_BAD_CMAP_FILE, - "Color map file is invalid or of unsupported format") -JMESSAGE(JERR_TOO_MANY_COLORS, - "Output file format cannot handle %d colormap entries") -JMESSAGE(JERR_UNGETC_FAILED, "ungetc failed") -#ifdef TARGA_SUPPORTED -JMESSAGE(JERR_UNKNOWN_FORMAT, - "Unrecognized input file format --- perhaps you need -targa") -#else -JMESSAGE(JERR_UNKNOWN_FORMAT, "Unrecognized input file format") -#endif -JMESSAGE(JERR_UNSUPPORTED_FORMAT, "Unsupported output file format") - -#ifdef JMAKE_ENUM_LIST - - JMSG_LASTADDONCODE -} ADDON_MESSAGE_CODE; - -#undef JMAKE_ENUM_LIST -#endif /* JMAKE_ENUM_LIST */ - -/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ -#undef JMESSAGE diff --git a/source/modules/juce_graphics/image_formats/jpglib/changes to libjpeg for JUCE.txt b/source/modules/juce_graphics/image_formats/jpglib/changes to libjpeg for JUCE.txt deleted file mode 100644 index d4924fe9d..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/changes to libjpeg for JUCE.txt +++ /dev/null @@ -1,16 +0,0 @@ - -I've included libjpeg in the JUCE tree because loading jpegs is a pretty useful thing to -be able to do, but I've left out as many files as possible to keep it lean-and-mean. - -If you want to get hold of the full version of libjpeg, it's freely available at: - -http://www.ijg.org/ - - -Please note that part of the IJG's license for libjpeg states that: - - "If you use it in a program, you must acknowledge somewhere in - your documentation that you've used the IJG code". - -..so if you release a JUCE program that reads JPEGs, you should probably give them a mention. - diff --git a/source/modules/juce_graphics/image_formats/jpglib/jcapimin.c b/source/modules/juce_graphics/image_formats/jpglib/jcapimin.c deleted file mode 100644 index 55e2c9b18..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jcapimin.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * jcapimin.c - * - * Copyright (C) 1994-1998, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains application interface code for the compression half - * of the JPEG library. These are the "minimum" API routines that may be - * needed in either the normal full-compression case or the transcoding-only - * case. - * - * Most of the routines intended to be called directly by an application - * are in this file or in jcapistd.c. But also see jcparam.c for - * parameter-setup helper routines, jcomapi.c for routines shared by - * compression and decompression, and jctrans.c for the transcoding case. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* - * Initialization of a JPEG compression object. - * The error manager must already be set up (in case memory manager fails). - */ - -GLOBAL(void) -jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize) -{ - int i; - - /* Guard against version mismatches between library and caller. */ - cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */ - if (version != JPEG_LIB_VERSION) - ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version); - if (structsize != SIZEOF(struct jpeg_compress_struct)) - ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, - (int) SIZEOF(struct jpeg_compress_struct), (int) structsize); - - /* For debugging purposes, we zero the whole master structure. - * But the application has already set the err pointer, and may have set - * client_data, so we have to save and restore those fields. - * Note: if application hasn't set client_data, tools like Purify may - * complain here. - */ - { - struct jpeg_error_mgr * err = cinfo->err; - void * client_data = cinfo->client_data; /* ignore Purify complaint here */ - MEMZERO(cinfo, SIZEOF(struct jpeg_compress_struct)); - cinfo->err = err; - cinfo->client_data = client_data; - } - cinfo->is_decompressor = FALSE; - - /* Initialize a memory manager instance for this object */ - jinit_memory_mgr((j_common_ptr) cinfo); - - /* Zero out pointers to permanent structures. */ - cinfo->progress = NULL; - cinfo->dest = NULL; - - cinfo->comp_info = NULL; - - for (i = 0; i < NUM_QUANT_TBLS; i++) - cinfo->quant_tbl_ptrs[i] = NULL; - - for (i = 0; i < NUM_HUFF_TBLS; i++) { - cinfo->dc_huff_tbl_ptrs[i] = NULL; - cinfo->ac_huff_tbl_ptrs[i] = NULL; - } - - cinfo->script_space = NULL; - - cinfo->input_gamma = 1.0; /* in case application forgets */ - - /* OK, I'm ready */ - cinfo->global_state = CSTATE_START; -} - - -/* - * Destruction of a JPEG compression object - */ - -GLOBAL(void) -jpeg_destroy_compress (j_compress_ptr cinfo) -{ - jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ -} - - -/* - * Abort processing of a JPEG compression operation, - * but don't destroy the object itself. - */ - -GLOBAL(void) -jpeg_abort_compress (j_compress_ptr cinfo) -{ - jpeg_abort((j_common_ptr) cinfo); /* use common routine */ -} - - -/* - * Forcibly suppress or un-suppress all quantization and Huffman tables. - * Marks all currently defined tables as already written (if suppress) - * or not written (if !suppress). This will control whether they get emitted - * by a subsequent jpeg_start_compress call. - * - * This routine is exported for use by applications that want to produce - * abbreviated JPEG datastreams. It logically belongs in jcparam.c, but - * since it is called by jpeg_start_compress, we put it here --- otherwise - * jcparam.o would be linked whether the application used it or not. - */ - -GLOBAL(void) -jpeg_suppress_tables (j_compress_ptr cinfo, boolean suppress) -{ - int i; - JQUANT_TBL * qtbl; - JHUFF_TBL * htbl; - - for (i = 0; i < NUM_QUANT_TBLS; i++) { - if ((qtbl = cinfo->quant_tbl_ptrs[i]) != NULL) - qtbl->sent_table = suppress; - } - - for (i = 0; i < NUM_HUFF_TBLS; i++) { - if ((htbl = cinfo->dc_huff_tbl_ptrs[i]) != NULL) - htbl->sent_table = suppress; - if ((htbl = cinfo->ac_huff_tbl_ptrs[i]) != NULL) - htbl->sent_table = suppress; - } -} - - -/* - * Finish JPEG compression. - * - * If a multipass operating mode was selected, this may do a great deal of - * work including most of the actual output. - */ - -GLOBAL(void) -jpeg_finish_compress (j_compress_ptr cinfo) -{ - JDIMENSION iMCU_row; - - if (cinfo->global_state == CSTATE_SCANNING || - cinfo->global_state == CSTATE_RAW_OK) { - /* Terminate first pass */ - if (cinfo->next_scanline < cinfo->image_height) - ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); - (*cinfo->master->finish_pass) (cinfo); - } else if (cinfo->global_state != CSTATE_WRCOEFS) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - /* Perform any remaining passes */ - while (! cinfo->master->is_last_pass) { - (*cinfo->master->prepare_for_pass) (cinfo); - for (iMCU_row = 0; iMCU_row < cinfo->total_iMCU_rows; iMCU_row++) { - if (cinfo->progress != NULL) { - cinfo->progress->pass_counter = (long) iMCU_row; - cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows; - (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); - } - /* We bypass the main controller and invoke coef controller directly; - * all work is being done from the coefficient buffer. - */ - if (! (*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE) NULL)) - ERREXIT(cinfo, JERR_CANT_SUSPEND); - } - (*cinfo->master->finish_pass) (cinfo); - } - /* Write EOI, do final cleanup */ - (*cinfo->marker->write_file_trailer) (cinfo); - (*cinfo->dest->term_destination) (cinfo); - /* We can use jpeg_abort to release memory and reset global_state */ - jpeg_abort((j_common_ptr) cinfo); -} - - -/* - * Write a special marker. - * This is only recommended for writing COM or APPn markers. - * Must be called after jpeg_start_compress() and before - * first call to jpeg_write_scanlines() or jpeg_write_raw_data(). - */ - -GLOBAL(void) -jpeg_write_marker (j_compress_ptr cinfo, int marker, - const JOCTET *dataptr, unsigned int datalen) -{ - JMETHOD(void, write_marker_byte, (j_compress_ptr info, int val)); - - if (cinfo->next_scanline != 0 || - (cinfo->global_state != CSTATE_SCANNING && - cinfo->global_state != CSTATE_RAW_OK && - cinfo->global_state != CSTATE_WRCOEFS)) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - - (*cinfo->marker->write_marker_header) (cinfo, marker, datalen); - write_marker_byte = cinfo->marker->write_marker_byte; /* copy for speed */ - while (datalen--) { - (*write_marker_byte) (cinfo, *dataptr); - dataptr++; - } -} - -/* Same, but piecemeal. */ - -GLOBAL(void) -jpeg_write_m_header (j_compress_ptr cinfo, int marker, unsigned int datalen) -{ - if (cinfo->next_scanline != 0 || - (cinfo->global_state != CSTATE_SCANNING && - cinfo->global_state != CSTATE_RAW_OK && - cinfo->global_state != CSTATE_WRCOEFS)) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - - (*cinfo->marker->write_marker_header) (cinfo, marker, datalen); -} - -GLOBAL(void) -jpeg_write_m_byte (j_compress_ptr cinfo, int val) -{ - (*cinfo->marker->write_marker_byte) (cinfo, val); -} - - -/* - * Alternate compression function: just write an abbreviated table file. - * Before calling this, all parameters and a data destination must be set up. - * - * To produce a pair of files containing abbreviated tables and abbreviated - * image data, one would proceed as follows: - * - * initialize JPEG object - * set JPEG parameters - * set destination to table file - * jpeg_write_tables(cinfo); - * set destination to image file - * jpeg_start_compress(cinfo, FALSE); - * write data... - * jpeg_finish_compress(cinfo); - * - * jpeg_write_tables has the side effect of marking all tables written - * (same as jpeg_suppress_tables(..., TRUE)). Thus a subsequent start_compress - * will not re-emit the tables unless it is passed write_all_tables=TRUE. - */ - -GLOBAL(void) -jpeg_write_tables (j_compress_ptr cinfo) -{ - if (cinfo->global_state != CSTATE_START) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - - /* (Re)initialize error mgr and destination modules */ - (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); - (*cinfo->dest->init_destination) (cinfo); - /* Initialize the marker writer ... bit of a crock to do it here. */ - jinit_marker_writer(cinfo); - /* Write them tables! */ - (*cinfo->marker->write_tables_only) (cinfo); - /* And clean up. */ - (*cinfo->dest->term_destination) (cinfo); - /* - * In library releases up through v6a, we called jpeg_abort() here to free - * any working memory allocated by the destination manager and marker - * writer. Some applications had a problem with that: they allocated space - * of their own from the library memory manager, and didn't want it to go - * away during write_tables. So now we do nothing. This will cause a - * memory leak if an app calls write_tables repeatedly without doing a full - * compression cycle or otherwise resetting the JPEG object. However, that - * seems less bad than unexpectedly freeing memory in the normal case. - * An app that prefers the old behavior can call jpeg_abort for itself after - * each call to jpeg_write_tables(). - */ -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jcapistd.c b/source/modules/juce_graphics/image_formats/jpglib/jcapistd.c deleted file mode 100644 index fed66caf1..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jcapistd.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * jcapistd.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains application interface code for the compression half - * of the JPEG library. These are the "standard" API routines that are - * used in the normal full-compression case. They are not used by a - * transcoding-only application. Note that if an application links in - * jpeg_start_compress, it will end up linking in the entire compressor. - * We thus must separate this file from jcapimin.c to avoid linking the - * whole compression library into a transcoder. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* - * Compression initialization. - * Before calling this, all parameters and a data destination must be set up. - * - * We require a write_all_tables parameter as a failsafe check when writing - * multiple datastreams from the same compression object. Since prior runs - * will have left all the tables marked sent_table=TRUE, a subsequent run - * would emit an abbreviated stream (no tables) by default. This may be what - * is wanted, but for safety's sake it should not be the default behavior: - * programmers should have to make a deliberate choice to emit abbreviated - * images. Therefore the documentation and examples should encourage people - * to pass write_all_tables=TRUE; then it will take active thought to do the - * wrong thing. - */ - -GLOBAL(void) -jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables) -{ - if (cinfo->global_state != CSTATE_START) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - - if (write_all_tables) - jpeg_suppress_tables(cinfo, FALSE); /* mark all tables to be written */ - - /* (Re)initialize error mgr and destination modules */ - (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); - (*cinfo->dest->init_destination) (cinfo); - /* Perform master selection of active modules */ - jinit_compress_master(cinfo); - /* Set up for the first pass */ - (*cinfo->master->prepare_for_pass) (cinfo); - /* Ready for application to drive first pass through jpeg_write_scanlines - * or jpeg_write_raw_data. - */ - cinfo->next_scanline = 0; - cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING); -} - - -/* - * Write some scanlines of data to the JPEG compressor. - * - * The return value will be the number of lines actually written. - * This should be less than the supplied num_lines only in case that - * the data destination module has requested suspension of the compressor, - * or if more than image_height scanlines are passed in. - * - * Note: we warn about excess calls to jpeg_write_scanlines() since - * this likely signals an application programmer error. However, - * excess scanlines passed in the last valid call are *silently* ignored, - * so that the application need not adjust num_lines for end-of-image - * when using a multiple-scanline buffer. - */ - -GLOBAL(JDIMENSION) -jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines, - JDIMENSION num_lines) -{ - JDIMENSION row_ctr, rows_left; - - if (cinfo->global_state != CSTATE_SCANNING) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - if (cinfo->next_scanline >= cinfo->image_height) - WARNMS(cinfo, JWRN_TOO_MUCH_DATA); - - /* Call progress monitor hook if present */ - if (cinfo->progress != NULL) { - cinfo->progress->pass_counter = (long) cinfo->next_scanline; - cinfo->progress->pass_limit = (long) cinfo->image_height; - (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); - } - - /* Give master control module another chance if this is first call to - * jpeg_write_scanlines. This lets output of the frame/scan headers be - * delayed so that application can write COM, etc, markers between - * jpeg_start_compress and jpeg_write_scanlines. - */ - if (cinfo->master->call_pass_startup) - (*cinfo->master->pass_startup) (cinfo); - - /* Ignore any extra scanlines at bottom of image. */ - rows_left = cinfo->image_height - cinfo->next_scanline; - if (num_lines > rows_left) - num_lines = rows_left; - - row_ctr = 0; - (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines); - cinfo->next_scanline += row_ctr; - return row_ctr; -} - - -/* - * Alternate entry point to write raw data. - * Processes exactly one iMCU row per call, unless suspended. - */ - -GLOBAL(JDIMENSION) -jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data, - JDIMENSION num_lines) -{ - JDIMENSION lines_per_iMCU_row; - - if (cinfo->global_state != CSTATE_RAW_OK) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - if (cinfo->next_scanline >= cinfo->image_height) { - WARNMS(cinfo, JWRN_TOO_MUCH_DATA); - return 0; - } - - /* Call progress monitor hook if present */ - if (cinfo->progress != NULL) { - cinfo->progress->pass_counter = (long) cinfo->next_scanline; - cinfo->progress->pass_limit = (long) cinfo->image_height; - (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); - } - - /* Give master control module another chance if this is first call to - * jpeg_write_raw_data. This lets output of the frame/scan headers be - * delayed so that application can write COM, etc, markers between - * jpeg_start_compress and jpeg_write_raw_data. - */ - if (cinfo->master->call_pass_startup) - (*cinfo->master->pass_startup) (cinfo); - - /* Verify that at least one iMCU row has been passed. */ - lines_per_iMCU_row = cinfo->max_v_samp_factor * DCTSIZE; - if (num_lines < lines_per_iMCU_row) - ERREXIT(cinfo, JERR_BUFFER_SIZE); - - /* Directly compress the row. */ - if (! (*cinfo->coef->compress_data) (cinfo, data)) { - /* If compressor did not consume the whole row, suspend processing. */ - return 0; - } - - /* OK, we processed one iMCU row. */ - cinfo->next_scanline += lines_per_iMCU_row; - return lines_per_iMCU_row; -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jccoefct.c b/source/modules/juce_graphics/image_formats/jpglib/jccoefct.c deleted file mode 100644 index 554a21e3b..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jccoefct.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * jccoefct.c - * - * Copyright (C) 1994-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains the coefficient buffer controller for compression. - * This controller is the top level of the JPEG compressor proper. - * The coefficient buffer lies between forward-DCT and entropy encoding steps. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* We use a full-image coefficient buffer when doing Huffman optimization, - * and also for writing multiple-scan JPEG files. In all cases, the DCT - * step is run during the first pass, and subsequent passes need only read - * the buffered coefficients. - */ -#ifdef ENTROPY_OPT_SUPPORTED -#define FULL_COEF_BUFFER_SUPPORTED -#else -#ifdef C_MULTISCAN_FILES_SUPPORTED -#define FULL_COEF_BUFFER_SUPPORTED -#endif -#endif - - -/* Private buffer controller object */ - -typedef struct { - struct jpeg_c_coef_controller pub; /* public fields */ - - JDIMENSION iMCU_row_num; /* iMCU row # within image */ - JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ - int MCU_vert_offset; /* counts MCU rows within iMCU row */ - int MCU_rows_per_iMCU_row; /* number of such rows needed */ - - /* For single-pass compression, it's sufficient to buffer just one MCU - * (although this may prove a bit slow in practice). We allocate a - * workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it for each - * MCU constructed and sent. (On 80x86, the workspace is FAR even though - * it's not really very big; this is to keep the module interfaces unchanged - * when a large coefficient buffer is necessary.) - * In multi-pass modes, this array points to the current MCU's blocks - * within the virtual arrays. - */ - JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU]; - - /* In multi-pass modes, we need a virtual block array for each component. */ - jvirt_barray_ptr whole_image[MAX_COMPONENTS]; -} my_coef_controller; - -typedef my_coef_controller * my_coef_ptr; - - -/* Forward declarations */ -METHODDEF(boolean) compress_data - JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); -#ifdef FULL_COEF_BUFFER_SUPPORTED -METHODDEF(boolean) compress_first_pass - JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); -METHODDEF(boolean) compress_output - JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); -#endif - - -LOCAL(void) -start_iMCU_row (j_compress_ptr cinfo) -/* Reset within-iMCU-row counters for a new row */ -{ - my_coef_ptr coef = (my_coef_ptr) cinfo->coef; - - /* In an interleaved scan, an MCU row is the same as an iMCU row. - * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. - * But at the bottom of the image, process only what's left. - */ - if (cinfo->comps_in_scan > 1) { - coef->MCU_rows_per_iMCU_row = 1; - } else { - if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1)) - coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; - else - coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; - } - - coef->mcu_ctr = 0; - coef->MCU_vert_offset = 0; -} - - -/* - * Initialize for a processing pass. - */ - -METHODDEF(void) -start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode) -{ - my_coef_ptr coef = (my_coef_ptr) cinfo->coef; - - coef->iMCU_row_num = 0; - start_iMCU_row(cinfo); - - switch (pass_mode) { - case JBUF_PASS_THRU: - if (coef->whole_image[0] != NULL) - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - coef->pub.compress_data = compress_data; - break; -#ifdef FULL_COEF_BUFFER_SUPPORTED - case JBUF_SAVE_AND_PASS: - if (coef->whole_image[0] == NULL) - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - coef->pub.compress_data = compress_first_pass; - break; - case JBUF_CRANK_DEST: - if (coef->whole_image[0] == NULL) - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - coef->pub.compress_data = compress_output; - break; -#endif - default: - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - break; - } -} - - -/* - * Process some data in the single-pass case. - * We process the equivalent of one fully interleaved MCU row ("iMCU" row) - * per call, ie, v_samp_factor block rows for each component in the image. - * Returns TRUE if the iMCU row is completed, FALSE if suspended. - * - * NB: input_buf contains a plane for each component in image, - * which we index according to the component's SOF position. - */ - -METHODDEF(boolean) -compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf) -{ - my_coef_ptr coef = (my_coef_ptr) cinfo->coef; - JDIMENSION MCU_col_num; /* index of current MCU within row */ - JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; - JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; - int blkn, bi, ci, yindex, yoffset, blockcnt; - JDIMENSION ypos, xpos; - jpeg_component_info *compptr; - - /* Loop to write as much as one whole iMCU row */ - for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; - yoffset++) { - for (MCU_col_num = coef->mcu_ctr; MCU_col_num <= last_MCU_col; - MCU_col_num++) { - /* Determine where data comes from in input_buf and do the DCT thing. - * Each call on forward_DCT processes a horizontal row of DCT blocks - * as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks - * sequentially. Dummy blocks at the right or bottom edge are filled in - * specially. The data in them does not matter for image reconstruction, - * so we fill them with values that will encode to the smallest amount of - * data, viz: all zeroes in the AC entries, DC entries equal to previous - * block's DC value. (Thanks to Thomas Kinsman for this idea.) - */ - blkn = 0; - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width - : compptr->last_col_width; - xpos = MCU_col_num * compptr->MCU_sample_width; - ypos = yoffset * DCTSIZE; /* ypos == (yoffset+yindex) * DCTSIZE */ - for (yindex = 0; yindex < compptr->MCU_height; yindex++) { - if (coef->iMCU_row_num < last_iMCU_row || - yoffset+yindex < compptr->last_row_height) { - (*cinfo->fdct->forward_DCT) (cinfo, compptr, - input_buf[compptr->component_index], - coef->MCU_buffer[blkn], - ypos, xpos, (JDIMENSION) blockcnt); - if (blockcnt < compptr->MCU_width) { - /* Create some dummy blocks at the right edge of the image. */ - jzero_far((void FAR *) coef->MCU_buffer[blkn + blockcnt], - (compptr->MCU_width - blockcnt) * SIZEOF(JBLOCK)); - for (bi = blockcnt; bi < compptr->MCU_width; bi++) { - coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn+bi-1][0][0]; - } - } - } else { - /* Create a row of dummy blocks at the bottom of the image. */ - jzero_far((void FAR *) coef->MCU_buffer[blkn], - compptr->MCU_width * SIZEOF(JBLOCK)); - for (bi = 0; bi < compptr->MCU_width; bi++) { - coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn-1][0][0]; - } - } - blkn += compptr->MCU_width; - ypos += DCTSIZE; - } - } - /* Try to write the MCU. In event of a suspension failure, we will - * re-DCT the MCU on restart (a bit inefficient, could be fixed...) - */ - if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) { - /* Suspension forced; update state counters and exit */ - coef->MCU_vert_offset = yoffset; - coef->mcu_ctr = MCU_col_num; - return FALSE; - } - } - /* Completed an MCU row, but perhaps not an iMCU row */ - coef->mcu_ctr = 0; - } - /* Completed the iMCU row, advance counters for next one */ - coef->iMCU_row_num++; - start_iMCU_row(cinfo); - return TRUE; -} - - -#ifdef FULL_COEF_BUFFER_SUPPORTED - -/* - * Process some data in the first pass of a multi-pass case. - * We process the equivalent of one fully interleaved MCU row ("iMCU" row) - * per call, ie, v_samp_factor block rows for each component in the image. - * This amount of data is read from the source buffer, DCT'd and quantized, - * and saved into the virtual arrays. We also generate suitable dummy blocks - * as needed at the right and lower edges. (The dummy blocks are constructed - * in the virtual arrays, which have been padded appropriately.) This makes - * it possible for subsequent passes not to worry about real vs. dummy blocks. - * - * We must also emit the data to the entropy encoder. This is conveniently - * done by calling compress_output() after we've loaded the current strip - * of the virtual arrays. - * - * NB: input_buf contains a plane for each component in image. All - * components are DCT'd and loaded into the virtual arrays in this pass. - * However, it may be that only a subset of the components are emitted to - * the entropy encoder during this first pass; be careful about looking - * at the scan-dependent variables (MCU dimensions, etc). - */ - -METHODDEF(boolean) -compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf) -{ - my_coef_ptr coef = (my_coef_ptr) cinfo->coef; - JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; - JDIMENSION blocks_across, MCUs_across, MCUindex; - int bi, ci, h_samp_factor, block_row, block_rows, ndummy; - JCOEF lastDC; - jpeg_component_info *compptr; - JBLOCKARRAY buffer; - JBLOCKROW thisblockrow, lastblockrow; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Align the virtual buffer for this component. */ - buffer = (*cinfo->mem->access_virt_barray) - ((j_common_ptr) cinfo, coef->whole_image[ci], - coef->iMCU_row_num * compptr->v_samp_factor, - (JDIMENSION) compptr->v_samp_factor, TRUE); - /* Count non-dummy DCT block rows in this iMCU row. */ - if (coef->iMCU_row_num < last_iMCU_row) - block_rows = compptr->v_samp_factor; - else { - /* NB: can't use last_row_height here, since may not be set! */ - block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); - if (block_rows == 0) block_rows = compptr->v_samp_factor; - } - blocks_across = compptr->width_in_blocks; - h_samp_factor = compptr->h_samp_factor; - /* Count number of dummy blocks to be added at the right margin. */ - ndummy = (int) (blocks_across % h_samp_factor); - if (ndummy > 0) - ndummy = h_samp_factor - ndummy; - /* Perform DCT for all non-dummy blocks in this iMCU row. Each call - * on forward_DCT processes a complete horizontal row of DCT blocks. - */ - for (block_row = 0; block_row < block_rows; block_row++) { - thisblockrow = buffer[block_row]; - (*cinfo->fdct->forward_DCT) (cinfo, compptr, - input_buf[ci], thisblockrow, - (JDIMENSION) (block_row * DCTSIZE), - (JDIMENSION) 0, blocks_across); - if (ndummy > 0) { - /* Create dummy blocks at the right edge of the image. */ - thisblockrow += blocks_across; /* => first dummy block */ - jzero_far((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK)); - lastDC = thisblockrow[-1][0]; - for (bi = 0; bi < ndummy; bi++) { - thisblockrow[bi][0] = lastDC; - } - } - } - /* If at end of image, create dummy block rows as needed. - * The tricky part here is that within each MCU, we want the DC values - * of the dummy blocks to match the last real block's DC value. - * This squeezes a few more bytes out of the resulting file... - */ - if (coef->iMCU_row_num == last_iMCU_row) { - blocks_across += ndummy; /* include lower right corner */ - MCUs_across = blocks_across / h_samp_factor; - for (block_row = block_rows; block_row < compptr->v_samp_factor; - block_row++) { - thisblockrow = buffer[block_row]; - lastblockrow = buffer[block_row-1]; - jzero_far((void FAR *) thisblockrow, - (size_t) (blocks_across * SIZEOF(JBLOCK))); - for (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) { - lastDC = lastblockrow[h_samp_factor-1][0]; - for (bi = 0; bi < h_samp_factor; bi++) { - thisblockrow[bi][0] = lastDC; - } - thisblockrow += h_samp_factor; /* advance to next MCU in row */ - lastblockrow += h_samp_factor; - } - } - } - } - /* NB: compress_output will increment iMCU_row_num if successful. - * A suspension return will result in redoing all the work above next time. - */ - - /* Emit data to the entropy encoder, sharing code with subsequent passes */ - return compress_output(cinfo, input_buf); -} - - -/* - * Process some data in subsequent passes of a multi-pass case. - * We process the equivalent of one fully interleaved MCU row ("iMCU" row) - * per call, ie, v_samp_factor block rows for each component in the scan. - * The data is obtained from the virtual arrays and fed to the entropy coder. - * Returns TRUE if the iMCU row is completed, FALSE if suspended. - * - * NB: input_buf is ignored; it is likely to be a NULL pointer. - */ - -METHODDEF(boolean) -compress_output (j_compress_ptr cinfo, JSAMPIMAGE) -{ - my_coef_ptr coef = (my_coef_ptr) cinfo->coef; - JDIMENSION MCU_col_num; /* index of current MCU within row */ - int blkn, ci, xindex, yindex, yoffset; - JDIMENSION start_col; - JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; - JBLOCKROW buffer_ptr; - jpeg_component_info *compptr; - - /* Align the virtual buffers for the components used in this scan. - * NB: during first pass, this is safe only because the buffers will - * already be aligned properly, so jmemmgr.c won't need to do any I/O. - */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - buffer[ci] = (*cinfo->mem->access_virt_barray) - ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], - coef->iMCU_row_num * compptr->v_samp_factor, - (JDIMENSION) compptr->v_samp_factor, FALSE); - } - - /* Loop to process one whole iMCU row */ - for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; - yoffset++) { - for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row; - MCU_col_num++) { - /* Construct list of pointers to DCT blocks belonging to this MCU */ - blkn = 0; /* index of current DCT block within MCU */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - start_col = MCU_col_num * compptr->MCU_width; - for (yindex = 0; yindex < compptr->MCU_height; yindex++) { - buffer_ptr = buffer[ci][yindex+yoffset] + start_col; - for (xindex = 0; xindex < compptr->MCU_width; xindex++) { - coef->MCU_buffer[blkn++] = buffer_ptr++; - } - } - } - /* Try to write the MCU. */ - if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) { - /* Suspension forced; update state counters and exit */ - coef->MCU_vert_offset = yoffset; - coef->mcu_ctr = MCU_col_num; - return FALSE; - } - } - /* Completed an MCU row, but perhaps not an iMCU row */ - coef->mcu_ctr = 0; - } - /* Completed the iMCU row, advance counters for next one */ - coef->iMCU_row_num++; - start_iMCU_row(cinfo); - return TRUE; -} - -#endif /* FULL_COEF_BUFFER_SUPPORTED */ - - -/* - * Initialize coefficient buffer controller. - */ - -GLOBAL(void) -jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer) -{ - my_coef_ptr coef; - - coef = (my_coef_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_coef_controller)); - cinfo->coef = (struct jpeg_c_coef_controller *) coef; - coef->pub.start_pass = start_pass_coef; - - /* Create the coefficient buffer. */ - if (need_full_buffer) { -#ifdef FULL_COEF_BUFFER_SUPPORTED - /* Allocate a full-image virtual array for each component, */ - /* padded to a multiple of samp_factor DCT blocks in each direction. */ - int ci; - jpeg_component_info *compptr; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, - (JDIMENSION) jround_up((long) compptr->width_in_blocks, - (long) compptr->h_samp_factor), - (JDIMENSION) jround_up((long) compptr->height_in_blocks, - (long) compptr->v_samp_factor), - (JDIMENSION) compptr->v_samp_factor); - } -#else - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); -#endif - } else { - /* We only need a single-MCU buffer. */ - JBLOCKROW buffer; - int i; - - buffer = (JBLOCKROW) - (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, - C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); - for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) { - coef->MCU_buffer[i] = buffer + i; - } - coef->whole_image[0] = NULL; /* flag for no virtual arrays */ - } -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jccolor.c b/source/modules/juce_graphics/image_formats/jpglib/jccolor.c deleted file mode 100644 index 8ad78efc6..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jccolor.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - * jccolor.c - * - * Copyright (C) 1991-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains input colorspace conversion routines. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Private subobject */ - -typedef struct { - struct jpeg_color_converter pub; /* public fields */ - - /* Private state for RGB->YCC conversion */ - INT32 * rgb_ycc_tab; /* => table for RGB to YCbCr conversion */ -} my_color_converter; - -typedef my_color_converter * my_cconvert_ptr; - - -/**************** RGB -> YCbCr conversion: most common case **************/ - -/* - * YCbCr is defined per CCIR 601-1, except that Cb and Cr are - * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. - * The conversion equations to be implemented are therefore - * Y = 0.29900 * R + 0.58700 * G + 0.11400 * B - * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE - * Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE - * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) - * Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2, - * rather than CENTERJSAMPLE, for Cb and Cr. This gave equal positive and - * negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0) - * were not represented exactly. Now we sacrifice exact representation of - * maximum red and maximum blue in order to get exact grayscales. - * - * To avoid floating-point arithmetic, we represent the fractional constants - * as integers scaled up by 2^16 (about 4 digits precision); we have to divide - * the products by 2^16, with appropriate rounding, to get the correct answer. - * - * For even more speed, we avoid doing any multiplications in the inner loop - * by precalculating the constants times R,G,B for all possible values. - * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); - * for 12-bit samples it is still acceptable. It's not very reasonable for - * 16-bit samples, but if you want lossless storage you shouldn't be changing - * colorspace anyway. - * The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included - * in the tables to save adding them separately in the inner loop. - */ - -#define SCALEBITS 16 /* speediest right-shift on some machines */ -#define CBCR_OFFSET ((INT32) CENTERJSAMPLE << SCALEBITS) -#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) -#define FIX(x) ((INT32) ((x) * (1L< Y section */ -#define G_Y_OFF (1*(MAXJSAMPLE+1)) /* offset to G => Y section */ -#define B_Y_OFF (2*(MAXJSAMPLE+1)) /* etc. */ -#define R_CB_OFF (3*(MAXJSAMPLE+1)) -#define G_CB_OFF (4*(MAXJSAMPLE+1)) -#define B_CB_OFF (5*(MAXJSAMPLE+1)) -#define R_CR_OFF B_CB_OFF /* B=>Cb, R=>Cr are the same */ -#define G_CR_OFF (6*(MAXJSAMPLE+1)) -#define B_CR_OFF (7*(MAXJSAMPLE+1)) -#define TABLE_SIZE (8*(MAXJSAMPLE+1)) - - -/* - * Initialize for RGB->YCC colorspace conversion. - */ - -METHODDEF(void) -rgb_ycc_start (j_compress_ptr cinfo) -{ - my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; - INT32 * rgb_ycc_tab; - INT32 i; - - /* Allocate and fill in the conversion tables. */ - cconvert->rgb_ycc_tab = rgb_ycc_tab = (INT32 *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (TABLE_SIZE * SIZEOF(INT32))); - - for (i = 0; i <= MAXJSAMPLE; i++) { - rgb_ycc_tab[i+R_Y_OFF] = FIX(0.29900) * i; - rgb_ycc_tab[i+G_Y_OFF] = FIX(0.58700) * i; - rgb_ycc_tab[i+B_Y_OFF] = FIX(0.11400) * i + ONE_HALF; - rgb_ycc_tab[i+R_CB_OFF] = (-FIX(0.16874)) * i; - rgb_ycc_tab[i+G_CB_OFF] = (-FIX(0.33126)) * i; - /* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr. - * This ensures that the maximum output will round to MAXJSAMPLE - * not MAXJSAMPLE+1, and thus that we don't have to range-limit. - */ - rgb_ycc_tab[i+B_CB_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1; -/* B=>Cb and R=>Cr tables are the same - rgb_ycc_tab[i+R_CR_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1; -*/ - rgb_ycc_tab[i+G_CR_OFF] = (-FIX(0.41869)) * i; - rgb_ycc_tab[i+B_CR_OFF] = (-FIX(0.08131)) * i; - } -} - - -/* - * Convert some rows of samples to the JPEG colorspace. - * - * Note that we change from the application's interleaved-pixel format - * to our internal noninterleaved, one-plane-per-component format. - * The input buffer is therefore three times as wide as the output buffer. - * - * A starting row offset is provided only for the output buffer. The caller - * can easily adjust the passed input_buf value to accommodate any row - * offset required on that side. - */ - -METHODDEF(void) -rgb_ycc_convert (j_compress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPIMAGE output_buf, - JDIMENSION output_row, int num_rows) -{ - my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; - int r, g, b; - INT32 * ctab = cconvert->rgb_ycc_tab; - JSAMPROW inptr; - JSAMPROW outptr0, outptr1, outptr2; - JDIMENSION col; - JDIMENSION num_cols = cinfo->image_width; - - while (--num_rows >= 0) { - inptr = *input_buf++; - outptr0 = output_buf[0][output_row]; - outptr1 = output_buf[1][output_row]; - outptr2 = output_buf[2][output_row]; - output_row++; - for (col = 0; col < num_cols; col++) { - r = GETJSAMPLE(inptr[RGB_RED]); - g = GETJSAMPLE(inptr[RGB_GREEN]); - b = GETJSAMPLE(inptr[RGB_BLUE]); - inptr += RGB_PIXELSIZE; - /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations - * must be too; we do not need an explicit range-limiting operation. - * Hence the value being shifted is never negative, and we don't - * need the general RIGHT_SHIFT macro. - */ - /* Y */ - outptr0[col] = (JSAMPLE) - ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) - >> SCALEBITS); - /* Cb */ - outptr1[col] = (JSAMPLE) - ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF]) - >> SCALEBITS); - /* Cr */ - outptr2[col] = (JSAMPLE) - ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF]) - >> SCALEBITS); - } - } -} - - -/**************** Cases other than RGB -> YCbCr **************/ - - -/* - * Convert some rows of samples to the JPEG colorspace. - * This version handles RGB->grayscale conversion, which is the same - * as the RGB->Y portion of RGB->YCbCr. - * We assume rgb_ycc_start has been called (we only use the Y tables). - */ - -METHODDEF(void) -rgb_gray_convert (j_compress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPIMAGE output_buf, - JDIMENSION output_row, int num_rows) -{ - my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; - int r, g, b; - INT32 * ctab = cconvert->rgb_ycc_tab; - JSAMPROW inptr; - JSAMPROW outptr; - JDIMENSION col; - JDIMENSION num_cols = cinfo->image_width; - - while (--num_rows >= 0) { - inptr = *input_buf++; - outptr = output_buf[0][output_row]; - output_row++; - for (col = 0; col < num_cols; col++) { - r = GETJSAMPLE(inptr[RGB_RED]); - g = GETJSAMPLE(inptr[RGB_GREEN]); - b = GETJSAMPLE(inptr[RGB_BLUE]); - inptr += RGB_PIXELSIZE; - /* Y */ - outptr[col] = (JSAMPLE) - ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) - >> SCALEBITS); - } - } -} - - -/* - * Convert some rows of samples to the JPEG colorspace. - * This version handles Adobe-style CMYK->YCCK conversion, - * where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the same - * conversion as above, while passing K (black) unchanged. - * We assume rgb_ycc_start has been called. - */ - -METHODDEF(void) -cmyk_ycck_convert (j_compress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPIMAGE output_buf, - JDIMENSION output_row, int num_rows) -{ - my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; - int r, g, b; - INT32 * ctab = cconvert->rgb_ycc_tab; - JSAMPROW inptr; - JSAMPROW outptr0, outptr1, outptr2, outptr3; - JDIMENSION col; - JDIMENSION num_cols = cinfo->image_width; - - while (--num_rows >= 0) { - inptr = *input_buf++; - outptr0 = output_buf[0][output_row]; - outptr1 = output_buf[1][output_row]; - outptr2 = output_buf[2][output_row]; - outptr3 = output_buf[3][output_row]; - output_row++; - for (col = 0; col < num_cols; col++) { - r = MAXJSAMPLE - GETJSAMPLE(inptr[0]); - g = MAXJSAMPLE - GETJSAMPLE(inptr[1]); - b = MAXJSAMPLE - GETJSAMPLE(inptr[2]); - /* K passes through as-is */ - outptr3[col] = inptr[3]; /* don't need GETJSAMPLE here */ - inptr += 4; - /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations - * must be too; we do not need an explicit range-limiting operation. - * Hence the value being shifted is never negative, and we don't - * need the general RIGHT_SHIFT macro. - */ - /* Y */ - outptr0[col] = (JSAMPLE) - ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) - >> SCALEBITS); - /* Cb */ - outptr1[col] = (JSAMPLE) - ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF]) - >> SCALEBITS); - /* Cr */ - outptr2[col] = (JSAMPLE) - ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF]) - >> SCALEBITS); - } - } -} - - -/* - * Convert some rows of samples to the JPEG colorspace. - * This version handles grayscale output with no conversion. - * The source can be either plain grayscale or YCbCr (since Y == gray). - */ - -METHODDEF(void) -grayscale_convert (j_compress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPIMAGE output_buf, - JDIMENSION output_row, int num_rows) -{ - JSAMPROW inptr; - JSAMPROW outptr; - JDIMENSION col; - JDIMENSION num_cols = cinfo->image_width; - int instride = cinfo->input_components; - - while (--num_rows >= 0) { - inptr = *input_buf++; - outptr = output_buf[0][output_row]; - output_row++; - for (col = 0; col < num_cols; col++) { - outptr[col] = inptr[0]; /* don't need GETJSAMPLE() here */ - inptr += instride; - } - } -} - - -/* - * Convert some rows of samples to the JPEG colorspace. - * This version handles multi-component colorspaces without conversion. - * We assume input_components == num_components. - */ - -METHODDEF(void) -null_convert (j_compress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPIMAGE output_buf, - JDIMENSION output_row, int num_rows) -{ - JSAMPROW inptr; - JSAMPROW outptr; - JDIMENSION col; - int ci; - int nc = cinfo->num_components; - JDIMENSION num_cols = cinfo->image_width; - - while (--num_rows >= 0) { - /* It seems fastest to make a separate pass for each component. */ - for (ci = 0; ci < nc; ci++) { - inptr = *input_buf; - outptr = output_buf[ci][output_row]; - for (col = 0; col < num_cols; col++) { - outptr[col] = inptr[ci]; /* don't need GETJSAMPLE() here */ - inptr += nc; - } - } - input_buf++; - output_row++; - } -} - - -/* - * Empty method for start_pass. - */ - -METHODDEF(void) -null_method (j_compress_ptr) -{ - /* no work needed */ -} - - -/* - * Module initialization routine for input colorspace conversion. - */ - -GLOBAL(void) -jinit_color_converter (j_compress_ptr cinfo) -{ - my_cconvert_ptr cconvert; - - cconvert = (my_cconvert_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_color_converter)); - cinfo->cconvert = (struct jpeg_color_converter *) cconvert; - /* set start_pass to null method until we find out differently */ - cconvert->pub.start_pass = null_method; - - /* Make sure input_components agrees with in_color_space */ - switch (cinfo->in_color_space) { - case JCS_GRAYSCALE: - if (cinfo->input_components != 1) - ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); - break; - - case JCS_RGB: -#if RGB_PIXELSIZE != 3 - if (cinfo->input_components != RGB_PIXELSIZE) - ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); - break; -#endif /* else share code with YCbCr */ - - case JCS_YCbCr: - if (cinfo->input_components != 3) - ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); - break; - - case JCS_CMYK: - case JCS_YCCK: - if (cinfo->input_components != 4) - ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); - break; - - default: /* JCS_UNKNOWN can be anything */ - if (cinfo->input_components < 1) - ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); - break; - } - - /* Check num_components, set conversion method based on requested space */ - switch (cinfo->jpeg_color_space) { - case JCS_GRAYSCALE: - if (cinfo->num_components != 1) - ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); - if (cinfo->in_color_space == JCS_GRAYSCALE) - cconvert->pub.color_convert = grayscale_convert; - else if (cinfo->in_color_space == JCS_RGB) { - cconvert->pub.start_pass = rgb_ycc_start; - cconvert->pub.color_convert = rgb_gray_convert; - } else if (cinfo->in_color_space == JCS_YCbCr) - cconvert->pub.color_convert = grayscale_convert; - else - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - break; - - case JCS_RGB: - if (cinfo->num_components != 3) - ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); - if (cinfo->in_color_space == JCS_RGB && RGB_PIXELSIZE == 3) - cconvert->pub.color_convert = null_convert; - else - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - break; - - case JCS_YCbCr: - if (cinfo->num_components != 3) - ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); - if (cinfo->in_color_space == JCS_RGB) { - cconvert->pub.start_pass = rgb_ycc_start; - cconvert->pub.color_convert = rgb_ycc_convert; - } else if (cinfo->in_color_space == JCS_YCbCr) - cconvert->pub.color_convert = null_convert; - else - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - break; - - case JCS_CMYK: - if (cinfo->num_components != 4) - ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); - if (cinfo->in_color_space == JCS_CMYK) - cconvert->pub.color_convert = null_convert; - else - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - break; - - case JCS_YCCK: - if (cinfo->num_components != 4) - ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); - if (cinfo->in_color_space == JCS_CMYK) { - cconvert->pub.start_pass = rgb_ycc_start; - cconvert->pub.color_convert = cmyk_ycck_convert; - } else if (cinfo->in_color_space == JCS_YCCK) - cconvert->pub.color_convert = null_convert; - else - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - break; - - default: /* allow null conversion of JCS_UNKNOWN */ - if (cinfo->jpeg_color_space != cinfo->in_color_space || - cinfo->num_components != cinfo->input_components) - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - cconvert->pub.color_convert = null_convert; - break; - } -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jcdctmgr.c b/source/modules/juce_graphics/image_formats/jpglib/jcdctmgr.c deleted file mode 100644 index 0589ccdf6..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jcdctmgr.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - * jcdctmgr.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains the forward-DCT management logic. - * This code selects a particular DCT implementation to be used, - * and it performs related housekeeping chores including coefficient - * quantization. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jdct.h" /* Private declarations for DCT subsystem */ - - -/* Private subobject for this module */ - -typedef struct { - struct jpeg_forward_dct pub; /* public fields */ - - /* Pointer to the DCT routine actually in use */ - forward_DCT_method_ptr do_dct; - - /* The actual post-DCT divisors --- not identical to the quant table - * entries, because of scaling (especially for an unnormalized DCT). - * Each table is given in normal array order. - */ - DCTELEM * divisors[NUM_QUANT_TBLS]; - -#ifdef DCT_FLOAT_SUPPORTED - /* Same as above for the floating-point case. */ - float_DCT_method_ptr do_float_dct; - FAST_FLOAT * float_divisors[NUM_QUANT_TBLS]; -#endif -} my_fdct_controller; - -typedef my_fdct_controller * my_fdct_ptr; - - -/* - * Initialize for a processing pass. - * Verify that all referenced Q-tables are present, and set up - * the divisor table for each one. - * In the current implementation, DCT of all components is done during - * the first pass, even if only some components will be output in the - * first scan. Hence all components should be examined here. - */ - -METHODDEF(void) -start_pass_fdctmgr (j_compress_ptr cinfo) -{ - my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; - int ci, qtblno, i; - jpeg_component_info *compptr; - JQUANT_TBL * qtbl; - DCTELEM * dtbl; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - qtblno = compptr->quant_tbl_no; - /* Make sure specified quantization table is present */ - if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || - cinfo->quant_tbl_ptrs[qtblno] == NULL) - ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); - qtbl = cinfo->quant_tbl_ptrs[qtblno]; - /* Compute divisors for this quant table */ - /* We may do this more than once for same table, but it's not a big deal */ - switch (cinfo->dct_method) { -#ifdef DCT_ISLOW_SUPPORTED - case JDCT_ISLOW: - /* For LL&M IDCT method, divisors are equal to raw quantization - * coefficients multiplied by 8 (to counteract scaling). - */ - if (fdct->divisors[qtblno] == NULL) { - fdct->divisors[qtblno] = (DCTELEM *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - DCTSIZE2 * SIZEOF(DCTELEM)); - } - dtbl = fdct->divisors[qtblno]; - for (i = 0; i < DCTSIZE2; i++) { - dtbl[i] = ((DCTELEM) qtbl->quantval[i]) << 3; - } - break; -#endif -#ifdef DCT_IFAST_SUPPORTED - case JDCT_IFAST: - { - /* For AA&N IDCT method, divisors are equal to quantization - * coefficients scaled by scalefactor[row]*scalefactor[col], where - * scalefactor[0] = 1 - * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 - * We apply a further scale factor of 8. - */ -#define CONST_BITS 14 - static const INT16 aanscales[DCTSIZE2] = { - /* precomputed values scaled up by 14 bits */ - 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, - 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, - 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, - 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, - 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, - 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, - 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, - 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 - }; - SHIFT_TEMPS - - if (fdct->divisors[qtblno] == NULL) { - fdct->divisors[qtblno] = (DCTELEM *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - DCTSIZE2 * SIZEOF(DCTELEM)); - } - dtbl = fdct->divisors[qtblno]; - for (i = 0; i < DCTSIZE2; i++) { - dtbl[i] = (DCTELEM) - DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i], - (INT32) aanscales[i]), - CONST_BITS-3); - } - } - break; -#endif -#ifdef DCT_FLOAT_SUPPORTED - case JDCT_FLOAT: - { - /* For float AA&N IDCT method, divisors are equal to quantization - * coefficients scaled by scalefactor[row]*scalefactor[col], where - * scalefactor[0] = 1 - * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 - * We apply a further scale factor of 8. - * What's actually stored is 1/divisor so that the inner loop can - * use a multiplication rather than a division. - */ - FAST_FLOAT * fdtbl; - int row, col; - static const double aanscalefactor[DCTSIZE] = { - 1.0, 1.387039845, 1.306562965, 1.175875602, - 1.0, 0.785694958, 0.541196100, 0.275899379 - }; - - if (fdct->float_divisors[qtblno] == NULL) { - fdct->float_divisors[qtblno] = (FAST_FLOAT *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - DCTSIZE2 * SIZEOF(FAST_FLOAT)); - } - fdtbl = fdct->float_divisors[qtblno]; - i = 0; - for (row = 0; row < DCTSIZE; row++) { - for (col = 0; col < DCTSIZE; col++) { - fdtbl[i] = (FAST_FLOAT) - (1.0 / (((double) qtbl->quantval[i] * - aanscalefactor[row] * aanscalefactor[col] * 8.0))); - i++; - } - } - } - break; -#endif - default: - ERREXIT(cinfo, JERR_NOT_COMPILED); - break; - } - } -} - - -/* - * Perform forward DCT on one or more blocks of a component. - * - * The input samples are taken from the sample_data[] array starting at - * position start_row/start_col, and moving to the right for any additional - * blocks. The quantized coefficients are returned in coef_blocks[]. - */ - -METHODDEF(void) -forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY sample_data, JBLOCKROW coef_blocks, - JDIMENSION start_row, JDIMENSION start_col, - JDIMENSION num_blocks) -/* This version is used for integer DCT implementations. */ -{ - /* This routine is heavily used, so it's worth coding it tightly. */ - my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; - forward_DCT_method_ptr do_dct = fdct->do_dct; - DCTELEM * divisors = fdct->divisors[compptr->quant_tbl_no]; - DCTELEM workspace[DCTSIZE2]; /* work area for FDCT subroutine */ - JDIMENSION bi; - - sample_data += start_row; /* fold in the vertical offset once */ - - for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) { - /* Load data into workspace, applying unsigned->signed conversion */ - { DCTELEM *workspaceptr; - JSAMPROW elemptr; - int elemr; - - workspaceptr = workspace; - for (elemr = 0; elemr < DCTSIZE; elemr++) { - elemptr = sample_data[elemr] + start_col; -#if DCTSIZE == 8 /* unroll the inner loop */ - *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; - *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; - *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; - *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; - *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; - *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; - *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; - *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; -#else - { int elemc; - for (elemc = DCTSIZE; elemc > 0; elemc--) { - *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; - } - } -#endif - } - } - - /* Perform the DCT */ - (*do_dct) (workspace); - - /* Quantize/descale the coefficients, and store into coef_blocks[] */ - { DCTELEM temp, qval; - int i; - JCOEFPTR output_ptr = coef_blocks[bi]; - - for (i = 0; i < DCTSIZE2; i++) { - qval = divisors[i]; - temp = workspace[i]; - /* Divide the coefficient value by qval, ensuring proper rounding. - * Since C does not specify the direction of rounding for negative - * quotients, we have to force the dividend positive for portability. - * - * In most files, at least half of the output values will be zero - * (at default quantization settings, more like three-quarters...) - * so we should ensure that this case is fast. On many machines, - * a comparison is enough cheaper than a divide to make a special test - * a win. Since both inputs will be nonnegative, we need only test - * for a < b to discover whether a/b is 0. - * If your machine's division is fast enough, define FAST_DIVIDE. - */ -#ifdef FAST_DIVIDE -#define DIVIDE_BY(a,b) a /= b -#else -#define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0 -#endif - if (temp < 0) { - temp = -temp; - temp += qval>>1; /* for rounding */ - DIVIDE_BY(temp, qval); - temp = -temp; - } else { - temp += qval>>1; /* for rounding */ - DIVIDE_BY(temp, qval); - } - output_ptr[i] = (JCOEF) temp; - } - } - } -} - - -#ifdef DCT_FLOAT_SUPPORTED - -METHODDEF(void) -forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY sample_data, JBLOCKROW coef_blocks, - JDIMENSION start_row, JDIMENSION start_col, - JDIMENSION num_blocks) -/* This version is used for floating-point DCT implementations. */ -{ - /* This routine is heavily used, so it's worth coding it tightly. */ - my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; - float_DCT_method_ptr do_dct = fdct->do_float_dct; - FAST_FLOAT * divisors = fdct->float_divisors[compptr->quant_tbl_no]; - FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */ - JDIMENSION bi; - - sample_data += start_row; /* fold in the vertical offset once */ - - for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) { - /* Load data into workspace, applying unsigned->signed conversion */ - { FAST_FLOAT *workspaceptr; - JSAMPROW elemptr; - int elemr; - - workspaceptr = workspace; - for (elemr = 0; elemr < DCTSIZE; elemr++) { - elemptr = sample_data[elemr] + start_col; -#if DCTSIZE == 8 /* unroll the inner loop */ - *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); - *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); - *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); - *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); - *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); - *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); - *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); - *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); -#else - { int elemc; - for (elemc = DCTSIZE; elemc > 0; elemc--) { - *workspaceptr++ = (FAST_FLOAT) - (GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); - } - } -#endif - } - } - - /* Perform the DCT */ - (*do_dct) (workspace); - - /* Quantize/descale the coefficients, and store into coef_blocks[] */ - { FAST_FLOAT temp; - int i; - JCOEFPTR output_ptr = coef_blocks[bi]; - - for (i = 0; i < DCTSIZE2; i++) { - /* Apply the quantization and scaling factor */ - temp = workspace[i] * divisors[i]; - /* Round to nearest integer. - * Since C does not specify the direction of rounding for negative - * quotients, we have to force the dividend positive for portability. - * The maximum coefficient size is +-16K (for 12-bit data), so this - * code should work for either 16-bit or 32-bit ints. - */ - output_ptr[i] = (JCOEF) ((int) (temp + (FAST_FLOAT) 16384.5) - 16384); - } - } - } -} - -#endif /* DCT_FLOAT_SUPPORTED */ - - -/* - * Initialize FDCT manager. - */ - -GLOBAL(void) -jinit_forward_dct (j_compress_ptr cinfo) -{ - my_fdct_ptr fdct; - int i; - - fdct = (my_fdct_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_fdct_controller)); - cinfo->fdct = (struct jpeg_forward_dct *) fdct; - fdct->pub.start_pass = start_pass_fdctmgr; - - switch (cinfo->dct_method) { -#ifdef DCT_ISLOW_SUPPORTED - case JDCT_ISLOW: - fdct->pub.forward_DCT = forward_DCT; - fdct->do_dct = jpeg_fdct_islow; - break; -#endif -#ifdef DCT_IFAST_SUPPORTED - case JDCT_IFAST: - fdct->pub.forward_DCT = forward_DCT; - fdct->do_dct = jpeg_fdct_ifast; - break; -#endif -#ifdef DCT_FLOAT_SUPPORTED - case JDCT_FLOAT: - fdct->pub.forward_DCT = forward_DCT_float; - fdct->do_float_dct = jpeg_fdct_float; - break; -#endif - default: - ERREXIT(cinfo, JERR_NOT_COMPILED); - break; - } - - /* Mark divisor tables unallocated */ - for (i = 0; i < NUM_QUANT_TBLS; i++) { - fdct->divisors[i] = NULL; -#ifdef DCT_FLOAT_SUPPORTED - fdct->float_divisors[i] = NULL; -#endif - } -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jchuff.c b/source/modules/juce_graphics/image_formats/jpglib/jchuff.c deleted file mode 100644 index e718cf50a..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jchuff.c +++ /dev/null @@ -1,909 +0,0 @@ -/* - * jchuff.c - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains Huffman entropy encoding routines. - * - * Much of the complexity here has to do with supporting output suspension. - * If the data destination module demands suspension, we want to be able to - * back up to the start of the current MCU. To do this, we copy state - * variables into local working storage, and update them back to the - * permanent JPEG objects only upon successful completion of an MCU. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jchuff.h" /* Declarations shared with jcphuff.c */ - - -/* Expanded entropy encoder object for Huffman encoding. - * - * The savable_state subrecord contains fields that change within an MCU, - * but must not be updated permanently until we complete the MCU. - */ - -typedef struct { - INT32 put_buffer; /* current bit-accumulation buffer */ - int put_bits; /* # of bits now in it */ - int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ -} savable_state; - -/* This macro is to work around compilers with missing or broken - * structure assignment. You'll need to fix this code if you have - * such a compiler and you change MAX_COMPS_IN_SCAN. - */ - -#ifndef NO_STRUCT_ASSIGN -#define ASSIGN_STATE(dest,src) ((dest) = (src)) -#else -#if MAX_COMPS_IN_SCAN == 4 -#define ASSIGN_STATE(dest,src) \ - ((dest).put_buffer = (src).put_buffer, \ - (dest).put_bits = (src).put_bits, \ - (dest).last_dc_val[0] = (src).last_dc_val[0], \ - (dest).last_dc_val[1] = (src).last_dc_val[1], \ - (dest).last_dc_val[2] = (src).last_dc_val[2], \ - (dest).last_dc_val[3] = (src).last_dc_val[3]) -#endif -#endif - - -typedef struct { - struct jpeg_entropy_encoder pub; /* public fields */ - - savable_state saved; /* Bit buffer & DC state at start of MCU */ - - /* These fields are NOT loaded into local working state. */ - unsigned int restarts_to_go; /* MCUs left in this restart interval */ - int next_restart_num; /* next restart number to write (0-7) */ - - /* Pointers to derived tables (these workspaces have image lifespan) */ - c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; - c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; - -#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */ - long * dc_count_ptrs[NUM_HUFF_TBLS]; - long * ac_count_ptrs[NUM_HUFF_TBLS]; -#endif -} huff_entropy_encoder; - -typedef huff_entropy_encoder * huff_entropy_ptr; - -/* Working state while writing an MCU. - * This struct contains all the fields that are needed by subroutines. - */ - -typedef struct { - JOCTET * next_output_byte; /* => next byte to write in buffer */ - size_t free_in_buffer; /* # of byte spaces remaining in buffer */ - savable_state cur; /* Current bit buffer & DC state */ - j_compress_ptr cinfo; /* dump_buffer needs access to this */ -} working_state; - - -/* Forward declarations */ -METHODDEF(boolean) encode_mcu_huff JPP((j_compress_ptr cinfo, - JBLOCKROW *MCU_data)); -METHODDEF(void) finish_pass_huff JPP((j_compress_ptr cinfo)); -#ifdef ENTROPY_OPT_SUPPORTED -METHODDEF(boolean) encode_mcu_gather JPP((j_compress_ptr cinfo, - JBLOCKROW *MCU_data)); -METHODDEF(void) finish_pass_gather JPP((j_compress_ptr cinfo)); -#endif - - -/* - * Initialize for a Huffman-compressed scan. - * If gather_statistics is TRUE, we do not output anything during the scan, - * just count the Huffman symbols used and generate Huffman code tables. - */ - -METHODDEF(void) -start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics) -{ - huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; - int ci, dctbl, actbl; - jpeg_component_info * compptr; - - if (gather_statistics) { -#ifdef ENTROPY_OPT_SUPPORTED - entropy->pub.encode_mcu = encode_mcu_gather; - entropy->pub.finish_pass = finish_pass_gather; -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif - } else { - entropy->pub.encode_mcu = encode_mcu_huff; - entropy->pub.finish_pass = finish_pass_huff; - } - - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - dctbl = compptr->dc_tbl_no; - actbl = compptr->ac_tbl_no; - if (gather_statistics) { -#ifdef ENTROPY_OPT_SUPPORTED - /* Check for invalid table indexes */ - /* (make_c_derived_tbl does this in the other path) */ - if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS) - ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl); - if (actbl < 0 || actbl >= NUM_HUFF_TBLS) - ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, actbl); - /* Allocate and zero the statistics tables */ - /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */ - if (entropy->dc_count_ptrs[dctbl] == NULL) - entropy->dc_count_ptrs[dctbl] = (long *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - 257 * SIZEOF(long)); - MEMZERO(entropy->dc_count_ptrs[dctbl], 257 * SIZEOF(long)); - if (entropy->ac_count_ptrs[actbl] == NULL) - entropy->ac_count_ptrs[actbl] = (long *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - 257 * SIZEOF(long)); - MEMZERO(entropy->ac_count_ptrs[actbl], 257 * SIZEOF(long)); -#endif - } else { - /* Compute derived values for Huffman tables */ - /* We may do this more than once for a table, but it's not expensive */ - jpeg_make_c_derived_tbl(cinfo, TRUE, dctbl, - & entropy->dc_derived_tbls[dctbl]); - jpeg_make_c_derived_tbl(cinfo, FALSE, actbl, - & entropy->ac_derived_tbls[actbl]); - } - /* Initialize DC predictions to 0 */ - entropy->saved.last_dc_val[ci] = 0; - } - - /* Initialize bit buffer to empty */ - entropy->saved.put_buffer = 0; - entropy->saved.put_bits = 0; - - /* Initialize restart stuff */ - entropy->restarts_to_go = cinfo->restart_interval; - entropy->next_restart_num = 0; -} - - -/* - * Compute the derived values for a Huffman table. - * This routine also performs some validation checks on the table. - * - * Note this is also used by jcphuff.c. - */ - -GLOBAL(void) -jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno, - c_derived_tbl ** pdtbl) -{ - JHUFF_TBL *htbl; - c_derived_tbl *dtbl; - int p, i, l, lastp, si, maxsymbol; - char huffsize[257]; - unsigned int huffcode[257]; - unsigned int code; - - /* Note that huffsize[] and huffcode[] are filled in code-length order, - * paralleling the order of the symbols themselves in htbl->huffval[]. - */ - - /* Find the input Huffman table */ - if (tblno < 0 || tblno >= NUM_HUFF_TBLS) - ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); - htbl = - isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno]; - if (htbl == NULL) - ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); - - /* Allocate a workspace if we haven't already done so. */ - if (*pdtbl == NULL) - *pdtbl = (c_derived_tbl *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(c_derived_tbl)); - dtbl = *pdtbl; - - /* Figure C.1: make table of Huffman code length for each symbol */ - - p = 0; - for (l = 1; l <= 16; l++) { - i = (int) htbl->bits[l]; - if (i < 0 || p + i > 256) /* protect against table overrun */ - ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); - while (i--) - huffsize[p++] = (char) l; - } - huffsize[p] = 0; - lastp = p; - - /* Figure C.2: generate the codes themselves */ - /* We also validate that the counts represent a legal Huffman code tree. */ - - code = 0; - si = huffsize[0]; - p = 0; - while (huffsize[p]) { - while (((int) huffsize[p]) == si) { - huffcode[p++] = code; - code++; - } - /* code is now 1 more than the last code used for codelength si; but - * it must still fit in si bits, since no code is allowed to be all ones. - */ - if (((INT32) code) >= (((INT32) 1) << si)) - ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); - code <<= 1; - si++; - } - - /* Figure C.3: generate encoding tables */ - /* These are code and size indexed by symbol value */ - - /* Set all codeless symbols to have code length 0; - * this lets us detect duplicate VAL entries here, and later - * allows emit_bits to detect any attempt to emit such symbols. - */ - MEMZERO(dtbl->ehufsi, SIZEOF(dtbl->ehufsi)); - - /* This is also a convenient place to check for out-of-range - * and duplicated VAL entries. We allow 0..255 for AC symbols - * but only 0..15 for DC. (We could constrain them further - * based on data depth and mode, but this seems enough.) - */ - maxsymbol = isDC ? 15 : 255; - - for (p = 0; p < lastp; p++) { - i = htbl->huffval[p]; - if (i < 0 || i > maxsymbol || dtbl->ehufsi[i]) - ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); - dtbl->ehufco[i] = huffcode[p]; - dtbl->ehufsi[i] = huffsize[p]; - } -} - - -/* Outputting bytes to the file */ - -/* Emit a byte, taking 'action' if must suspend. */ -#define emit_byte(state,val,action) \ - { *(state)->next_output_byte++ = (JOCTET) (val); \ - if (--(state)->free_in_buffer == 0) \ - if (! dump_buffer(state)) \ - { action; } } - - -LOCAL(boolean) -dump_buffer (working_state * state) -/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */ -{ - struct jpeg_destination_mgr * dest = state->cinfo->dest; - - if (! (*dest->empty_output_buffer) (state->cinfo)) - return FALSE; - /* After a successful buffer dump, must reset buffer pointers */ - state->next_output_byte = dest->next_output_byte; - state->free_in_buffer = dest->free_in_buffer; - return TRUE; -} - - -/* Outputting bits to the file */ - -/* Only the right 24 bits of put_buffer are used; the valid bits are - * left-justified in this part. At most 16 bits can be passed to emit_bits - * in one call, and we never retain more than 7 bits in put_buffer - * between calls, so 24 bits are sufficient. - */ - -INLINE -LOCAL(boolean) -emit_bits (working_state * state, unsigned int code, int size) -/* Emit some bits; return TRUE if successful, FALSE if must suspend */ -{ - /* This routine is heavily used, so it's worth coding tightly. */ - INT32 put_buffer = (INT32) code; - int put_bits = state->cur.put_bits; - - /* if size is 0, caller used an invalid Huffman table entry */ - if (size == 0) - ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE); - - put_buffer &= (((INT32) 1)<cur.put_buffer; /* and merge with old buffer contents */ - - while (put_bits >= 8) { - int c = (int) ((put_buffer >> 16) & 0xFF); - - emit_byte(state, c, return FALSE); - if (c == 0xFF) { /* need to stuff a zero byte? */ - emit_byte(state, 0, return FALSE); - } - put_buffer <<= 8; - put_bits -= 8; - } - - state->cur.put_buffer = put_buffer; /* update state variables */ - state->cur.put_bits = put_bits; - - return TRUE; -} - - -LOCAL(boolean) -flush_bits (working_state * state) -{ - if (! emit_bits(state, 0x7F, 7)) /* fill any partial byte with ones */ - return FALSE; - state->cur.put_buffer = 0; /* and reset bit-buffer to empty */ - state->cur.put_bits = 0; - return TRUE; -} - - -/* Encode a single block's worth of coefficients */ - -LOCAL(boolean) -encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val, - c_derived_tbl *dctbl, c_derived_tbl *actbl) -{ - int temp, temp2; - int nbits; - int k, r, i; - - /* Encode the DC coefficient difference per section F.1.2.1 */ - - temp = temp2 = block[0] - last_dc_val; - - if (temp < 0) { - temp = -temp; /* temp is abs value of input */ - /* For a negative input, want temp2 = bitwise complement of abs(input) */ - /* This code assumes we are on a two's complement machine */ - temp2--; - } - - /* Find the number of bits needed for the magnitude of the coefficient */ - nbits = 0; - while (temp) { - nbits++; - temp >>= 1; - } - /* Check for out-of-range coefficient values. - * Since we're encoding a difference, the range limit is twice as much. - */ - if (nbits > MAX_COEF_BITS+1) - ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); - - /* Emit the Huffman-coded symbol for the number of bits */ - if (! emit_bits(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits])) - return FALSE; - - /* Emit that number of bits of the value, if positive, */ - /* or the complement of its magnitude, if negative. */ - if (nbits) /* emit_bits rejects calls with size 0 */ - if (! emit_bits(state, (unsigned int) temp2, nbits)) - return FALSE; - - /* Encode the AC coefficients per section F.1.2.2 */ - - r = 0; /* r = run length of zeros */ - - for (k = 1; k < DCTSIZE2; k++) { - if ((temp = block[jpeg_natural_order[k]]) == 0) { - r++; - } else { - /* if run length > 15, must emit special run-length-16 codes (0xF0) */ - while (r > 15) { - if (! emit_bits(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0])) - return FALSE; - r -= 16; - } - - temp2 = temp; - if (temp < 0) { - temp = -temp; /* temp is abs value of input */ - /* This code assumes we are on a two's complement machine */ - temp2--; - } - - /* Find the number of bits needed for the magnitude of the coefficient */ - nbits = 1; /* there must be at least one 1 bit */ - while ((temp >>= 1)) - nbits++; - /* Check for out-of-range coefficient values */ - if (nbits > MAX_COEF_BITS) - ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); - - /* Emit Huffman symbol for run length / number of bits */ - i = (r << 4) + nbits; - if (! emit_bits(state, actbl->ehufco[i], actbl->ehufsi[i])) - return FALSE; - - /* Emit that number of bits of the value, if positive, */ - /* or the complement of its magnitude, if negative. */ - if (! emit_bits(state, (unsigned int) temp2, nbits)) - return FALSE; - - r = 0; - } - } - - /* If the last coef(s) were zero, emit an end-of-block code */ - if (r > 0) - if (! emit_bits(state, actbl->ehufco[0], actbl->ehufsi[0])) - return FALSE; - - return TRUE; -} - - -/* - * Emit a restart marker & resynchronize predictions. - */ - -LOCAL(boolean) -emit_restart (working_state * state, int restart_num) -{ - int ci; - - if (! flush_bits(state)) - return FALSE; - - emit_byte(state, 0xFF, return FALSE); - emit_byte(state, JPEG_RST0 + restart_num, return FALSE); - - /* Re-initialize DC predictions to 0 */ - for (ci = 0; ci < state->cinfo->comps_in_scan; ci++) - state->cur.last_dc_val[ci] = 0; - - /* The restart counter is not updated until we successfully write the MCU. */ - - return TRUE; -} - - -/* - * Encode and output one MCU's worth of Huffman-compressed coefficients. - */ - -METHODDEF(boolean) -encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data) -{ - huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; - working_state state; - int blkn, ci; - jpeg_component_info * compptr; - - /* Load up working state */ - state.next_output_byte = cinfo->dest->next_output_byte; - state.free_in_buffer = cinfo->dest->free_in_buffer; - ASSIGN_STATE(state.cur, entropy->saved); - state.cinfo = cinfo; - - /* Emit restart marker if needed */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) - if (! emit_restart(&state, entropy->next_restart_num)) - return FALSE; - } - - /* Encode the MCU data blocks */ - for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - ci = cinfo->MCU_membership[blkn]; - compptr = cinfo->cur_comp_info[ci]; - if (! encode_one_block(&state, - MCU_data[blkn][0], state.cur.last_dc_val[ci], - entropy->dc_derived_tbls[compptr->dc_tbl_no], - entropy->ac_derived_tbls[compptr->ac_tbl_no])) - return FALSE; - /* Update last_dc_val */ - state.cur.last_dc_val[ci] = MCU_data[blkn][0][0]; - } - - /* Completed MCU, so update state */ - cinfo->dest->next_output_byte = state.next_output_byte; - cinfo->dest->free_in_buffer = state.free_in_buffer; - ASSIGN_STATE(entropy->saved, state.cur); - - /* Update restart-interval state too */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) { - entropy->restarts_to_go = cinfo->restart_interval; - entropy->next_restart_num++; - entropy->next_restart_num &= 7; - } - entropy->restarts_to_go--; - } - - return TRUE; -} - - -/* - * Finish up at the end of a Huffman-compressed scan. - */ - -METHODDEF(void) -finish_pass_huff (j_compress_ptr cinfo) -{ - huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; - working_state state; - - /* Load up working state ... flush_bits needs it */ - state.next_output_byte = cinfo->dest->next_output_byte; - state.free_in_buffer = cinfo->dest->free_in_buffer; - ASSIGN_STATE(state.cur, entropy->saved); - state.cinfo = cinfo; - - /* Flush out the last data */ - if (! flush_bits(&state)) - ERREXIT(cinfo, JERR_CANT_SUSPEND); - - /* Update state */ - cinfo->dest->next_output_byte = state.next_output_byte; - cinfo->dest->free_in_buffer = state.free_in_buffer; - ASSIGN_STATE(entropy->saved, state.cur); -} - - -/* - * Huffman coding optimization. - * - * We first scan the supplied data and count the number of uses of each symbol - * that is to be Huffman-coded. (This process MUST agree with the code above.) - * Then we build a Huffman coding tree for the observed counts. - * Symbols which are not needed at all for the particular image are not - * assigned any code, which saves space in the DHT marker as well as in - * the compressed data. - */ - -#ifdef ENTROPY_OPT_SUPPORTED - - -/* Process a single block's worth of coefficients */ - -LOCAL(void) -htest_one_block (j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val, - long dc_counts[], long ac_counts[]) -{ - int temp; - int nbits; - int k, r; - - /* Encode the DC coefficient difference per section F.1.2.1 */ - - temp = block[0] - last_dc_val; - if (temp < 0) - temp = -temp; - - /* Find the number of bits needed for the magnitude of the coefficient */ - nbits = 0; - while (temp) { - nbits++; - temp >>= 1; - } - /* Check for out-of-range coefficient values. - * Since we're encoding a difference, the range limit is twice as much. - */ - if (nbits > MAX_COEF_BITS+1) - ERREXIT(cinfo, JERR_BAD_DCT_COEF); - - /* Count the Huffman symbol for the number of bits */ - dc_counts[nbits]++; - - /* Encode the AC coefficients per section F.1.2.2 */ - - r = 0; /* r = run length of zeros */ - - for (k = 1; k < DCTSIZE2; k++) { - if ((temp = block[jpeg_natural_order[k]]) == 0) { - r++; - } else { - /* if run length > 15, must emit special run-length-16 codes (0xF0) */ - while (r > 15) { - ac_counts[0xF0]++; - r -= 16; - } - - /* Find the number of bits needed for the magnitude of the coefficient */ - if (temp < 0) - temp = -temp; - - /* Find the number of bits needed for the magnitude of the coefficient */ - nbits = 1; /* there must be at least one 1 bit */ - while ((temp >>= 1)) - nbits++; - /* Check for out-of-range coefficient values */ - if (nbits > MAX_COEF_BITS) - ERREXIT(cinfo, JERR_BAD_DCT_COEF); - - /* Count Huffman symbol for run length / number of bits */ - ac_counts[(r << 4) + nbits]++; - - r = 0; - } - } - - /* If the last coef(s) were zero, emit an end-of-block code */ - if (r > 0) - ac_counts[0]++; -} - - -/* - * Trial-encode one MCU's worth of Huffman-compressed coefficients. - * No data is actually output, so no suspension return is possible. - */ - -METHODDEF(boolean) -encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data) -{ - huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; - int blkn, ci; - jpeg_component_info * compptr; - - /* Take care of restart intervals if needed */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) { - /* Re-initialize DC predictions to 0 */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) - entropy->saved.last_dc_val[ci] = 0; - /* Update restart state */ - entropy->restarts_to_go = cinfo->restart_interval; - } - entropy->restarts_to_go--; - } - - for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - ci = cinfo->MCU_membership[blkn]; - compptr = cinfo->cur_comp_info[ci]; - htest_one_block(cinfo, MCU_data[blkn][0], entropy->saved.last_dc_val[ci], - entropy->dc_count_ptrs[compptr->dc_tbl_no], - entropy->ac_count_ptrs[compptr->ac_tbl_no]); - entropy->saved.last_dc_val[ci] = MCU_data[blkn][0][0]; - } - - return TRUE; -} - - -/* - * Generate the best Huffman code table for the given counts, fill htbl. - * Note this is also used by jcphuff.c. - * - * The JPEG standard requires that no symbol be assigned a codeword of all - * one bits (so that padding bits added at the end of a compressed segment - * can't look like a valid code). Because of the canonical ordering of - * codewords, this just means that there must be an unused slot in the - * longest codeword length category. Section K.2 of the JPEG spec suggests - * reserving such a slot by pretending that symbol 256 is a valid symbol - * with count 1. In theory that's not optimal; giving it count zero but - * including it in the symbol set anyway should give a better Huffman code. - * But the theoretically better code actually seems to come out worse in - * practice, because it produces more all-ones bytes (which incur stuffed - * zero bytes in the final file). In any case the difference is tiny. - * - * The JPEG standard requires Huffman codes to be no more than 16 bits long. - * If some symbols have a very small but nonzero probability, the Huffman tree - * must be adjusted to meet the code length restriction. We currently use - * the adjustment method suggested in JPEG section K.2. This method is *not* - * optimal; it may not choose the best possible limited-length code. But - * typically only very-low-frequency symbols will be given less-than-optimal - * lengths, so the code is almost optimal. Experimental comparisons against - * an optimal limited-length-code algorithm indicate that the difference is - * microscopic --- usually less than a hundredth of a percent of total size. - * So the extra complexity of an optimal algorithm doesn't seem worthwhile. - */ - -GLOBAL(void) -jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[]) -{ -#define MAX_CLEN 32 /* assumed maximum initial code length */ - UINT8 bits[MAX_CLEN+1]; /* bits[k] = # of symbols with code length k */ - int codesize[257]; /* codesize[k] = code length of symbol k */ - int others[257]; /* next symbol in current branch of tree */ - int c1, c2; - int p, i, j; - long v; - - /* This algorithm is explained in section K.2 of the JPEG standard */ - - MEMZERO(bits, SIZEOF(bits)); - MEMZERO(codesize, SIZEOF(codesize)); - for (i = 0; i < 257; i++) - others[i] = -1; /* init links to empty */ - - freq[256] = 1; /* make sure 256 has a nonzero count */ - /* Including the pseudo-symbol 256 in the Huffman procedure guarantees - * that no real symbol is given code-value of all ones, because 256 - * will be placed last in the largest codeword category. - */ - - /* Huffman's basic algorithm to assign optimal code lengths to symbols */ - - for (;;) { - /* Find the smallest nonzero frequency, set c1 = its symbol */ - /* In case of ties, take the larger symbol number */ - c1 = -1; - v = 1000000000L; - for (i = 0; i <= 256; i++) { - if (freq[i] && freq[i] <= v) { - v = freq[i]; - c1 = i; - } - } - - /* Find the next smallest nonzero frequency, set c2 = its symbol */ - /* In case of ties, take the larger symbol number */ - c2 = -1; - v = 1000000000L; - for (i = 0; i <= 256; i++) { - if (freq[i] && freq[i] <= v && i != c1) { - v = freq[i]; - c2 = i; - } - } - - /* Done if we've merged everything into one frequency */ - if (c2 < 0) - break; - - /* Else merge the two counts/trees */ - freq[c1] += freq[c2]; - freq[c2] = 0; - - /* Increment the codesize of everything in c1's tree branch */ - codesize[c1]++; - while (others[c1] >= 0) { - c1 = others[c1]; - codesize[c1]++; - } - - others[c1] = c2; /* chain c2 onto c1's tree branch */ - - /* Increment the codesize of everything in c2's tree branch */ - codesize[c2]++; - while (others[c2] >= 0) { - c2 = others[c2]; - codesize[c2]++; - } - } - - /* Now count the number of symbols of each code length */ - for (i = 0; i <= 256; i++) { - if (codesize[i]) { - /* The JPEG standard seems to think that this can't happen, */ - /* but I'm paranoid... */ - if (codesize[i] > MAX_CLEN) - ERREXIT(cinfo, JERR_HUFF_CLEN_OVERFLOW); - - bits[codesize[i]]++; - } - } - - /* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure - * Huffman procedure assigned any such lengths, we must adjust the coding. - * Here is what the JPEG spec says about how this next bit works: - * Since symbols are paired for the longest Huffman code, the symbols are - * removed from this length category two at a time. The prefix for the pair - * (which is one bit shorter) is allocated to one of the pair; then, - * skipping the BITS entry for that prefix length, a code word from the next - * shortest nonzero BITS entry is converted into a prefix for two code words - * one bit longer. - */ - - for (i = MAX_CLEN; i > 16; i--) { - while (bits[i] > 0) { - j = i - 2; /* find length of new prefix to be used */ - while (bits[j] == 0) - j--; - - bits[i] -= 2; /* remove two symbols */ - bits[i-1]++; /* one goes in this length */ - bits[j+1] += 2; /* two new symbols in this length */ - bits[j]--; /* symbol of this length is now a prefix */ - } - } - - /* Remove the count for the pseudo-symbol 256 from the largest codelength */ - while (bits[i] == 0) /* find largest codelength still in use */ - i--; - bits[i]--; - - /* Return final symbol counts (only for lengths 0..16) */ - MEMCOPY(htbl->bits, bits, SIZEOF(htbl->bits)); - - /* Return a list of the symbols sorted by code length */ - /* It's not real clear to me why we don't need to consider the codelength - * changes made above, but the JPEG spec seems to think this works. - */ - p = 0; - for (i = 1; i <= MAX_CLEN; i++) { - for (j = 0; j <= 255; j++) { - if (codesize[j] == i) { - htbl->huffval[p] = (UINT8) j; - p++; - } - } - } - - /* Set sent_table FALSE so updated table will be written to JPEG file. */ - htbl->sent_table = FALSE; -} - - -/* - * Finish up a statistics-gathering pass and create the new Huffman tables. - */ - -METHODDEF(void) -finish_pass_gather (j_compress_ptr cinfo) -{ - huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; - int ci, dctbl, actbl; - jpeg_component_info * compptr; - JHUFF_TBL **htblptr; - boolean did_dc[NUM_HUFF_TBLS]; - boolean did_ac[NUM_HUFF_TBLS]; - - /* It's important not to apply jpeg_gen_optimal_table more than once - * per table, because it clobbers the input frequency counts! - */ - MEMZERO(did_dc, SIZEOF(did_dc)); - MEMZERO(did_ac, SIZEOF(did_ac)); - - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - dctbl = compptr->dc_tbl_no; - actbl = compptr->ac_tbl_no; - if (! did_dc[dctbl]) { - htblptr = & cinfo->dc_huff_tbl_ptrs[dctbl]; - if (*htblptr == NULL) - *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); - jpeg_gen_optimal_table(cinfo, *htblptr, entropy->dc_count_ptrs[dctbl]); - did_dc[dctbl] = TRUE; - } - if (! did_ac[actbl]) { - htblptr = & cinfo->ac_huff_tbl_ptrs[actbl]; - if (*htblptr == NULL) - *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); - jpeg_gen_optimal_table(cinfo, *htblptr, entropy->ac_count_ptrs[actbl]); - did_ac[actbl] = TRUE; - } - } -} - - -#endif /* ENTROPY_OPT_SUPPORTED */ - - -/* - * Module initialization routine for Huffman entropy encoding. - */ - -GLOBAL(void) -jinit_huff_encoder (j_compress_ptr cinfo) -{ - huff_entropy_ptr entropy; - int i; - - entropy = (huff_entropy_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(huff_entropy_encoder)); - cinfo->entropy = (struct jpeg_entropy_encoder *) entropy; - entropy->pub.start_pass = start_pass_huff; - - /* Mark tables unallocated */ - for (i = 0; i < NUM_HUFF_TBLS; i++) { - entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; -#ifdef ENTROPY_OPT_SUPPORTED - entropy->dc_count_ptrs[i] = entropy->ac_count_ptrs[i] = NULL; -#endif - } -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jchuff.h b/source/modules/juce_graphics/image_formats/jpglib/jchuff.h deleted file mode 100644 index 783b32be7..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jchuff.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * jchuff.h - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains declarations for Huffman entropy encoding routines - * that are shared between the sequential encoder (jchuff.c) and the - * progressive encoder (jcphuff.c). No other modules need to see these. - */ - -/* The legal range of a DCT coefficient is - * -1024 .. +1023 for 8-bit data; - * -16384 .. +16383 for 12-bit data. - * Hence the magnitude should always fit in 10 or 14 bits respectively. - */ - -#ifndef _jchuff_h_ -#define _jchuff_h_ - -#if BITS_IN_JSAMPLE == 8 -#define MAX_COEF_BITS 10 -#else -#define MAX_COEF_BITS 14 -#endif - -/* Derived data constructed for each Huffman table */ - -typedef struct { - unsigned int ehufco[256]; /* code for each symbol */ - char ehufsi[256]; /* length of code for each symbol */ - /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */ -} c_derived_tbl; - -/* Short forms of external names for systems with brain-damaged linkers. */ - -#ifdef NEED_SHORT_EXTERNAL_NAMES -#define jpeg_make_c_derived_tbl jMkCDerived -#define jpeg_gen_optimal_table jGenOptTbl -#endif /* NEED_SHORT_EXTERNAL_NAMES */ - -/* Expand a Huffman table definition into the derived format */ -EXTERN(void) jpeg_make_c_derived_tbl - JPP((j_compress_ptr cinfo, boolean isDC, int tblno, - c_derived_tbl ** pdtbl)); - -/* Generate an optimal table definition given the specified counts */ -EXTERN(void) jpeg_gen_optimal_table - JPP((j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])); - -#endif diff --git a/source/modules/juce_graphics/image_formats/jpglib/jcinit.c b/source/modules/juce_graphics/image_formats/jpglib/jcinit.c deleted file mode 100644 index 19de8d0e0..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jcinit.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * jcinit.c - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains initialization logic for the JPEG compressor. - * This routine is in charge of selecting the modules to be executed and - * making an initialization call to each one. - * - * Logically, this code belongs in jcmaster.c. It's split out because - * linking this routine implies linking the entire compression library. - * For a transcoding-only application, we want to be able to use jcmaster.c - * without linking in the whole library. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* - * Master selection of compression modules. - * This is done once at the start of processing an image. We determine - * which modules will be used and give them appropriate initialization calls. - */ - -GLOBAL(void) -jinit_compress_master (j_compress_ptr cinfo) -{ - /* Initialize master control (includes parameter checking/processing) */ - jinit_c_master_control(cinfo, FALSE /* full compression */); - - /* Preprocessing */ - if (! cinfo->raw_data_in) { - jinit_color_converter(cinfo); - jinit_downsampler(cinfo); - jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */); - } - /* Forward DCT */ - jinit_forward_dct(cinfo); - /* Entropy encoding: either Huffman or arithmetic coding. */ - if (cinfo->arith_code) { - ERREXIT(cinfo, JERR_ARITH_NOTIMPL); - } else { - if (cinfo->progressive_mode) { -#ifdef C_PROGRESSIVE_SUPPORTED - jinit_phuff_encoder(cinfo); -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif - } else - jinit_huff_encoder(cinfo); - } - - /* Need a full-image coefficient buffer in any multi-pass mode. */ - jinit_c_coef_controller(cinfo, - (boolean) (cinfo->num_scans > 1 || cinfo->optimize_coding)); - jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */); - - jinit_marker_writer(cinfo); - - /* We can now tell the memory manager to allocate virtual arrays. */ - (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); - - /* Write the datastream header (SOI) immediately. - * Frame and scan headers are postponed till later. - * This lets application insert special markers after the SOI. - */ - (*cinfo->marker->write_file_header) (cinfo); -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jcmainct.c b/source/modules/juce_graphics/image_formats/jpglib/jcmainct.c deleted file mode 100644 index 261b2845c..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jcmainct.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * jcmainct.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains the main buffer controller for compression. - * The main buffer lies between the pre-processor and the JPEG - * compressor proper; it holds downsampled data in the JPEG colorspace. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Note: currently, there is no operating mode in which a full-image buffer - * is needed at this step. If there were, that mode could not be used with - * "raw data" input, since this module is bypassed in that case. However, - * we've left the code here for possible use in special applications. - */ -#undef FULL_MAIN_BUFFER_SUPPORTED - - -/* Private buffer controller object */ - -typedef struct { - struct jpeg_c_main_controller pub; /* public fields */ - - JDIMENSION cur_iMCU_row; /* number of current iMCU row */ - JDIMENSION rowgroup_ctr; /* counts row groups received in iMCU row */ - boolean suspended; /* remember if we suspended output */ - J_BUF_MODE pass_mode; /* current operating mode */ - - /* If using just a strip buffer, this points to the entire set of buffers - * (we allocate one for each component). In the full-image case, this - * points to the currently accessible strips of the virtual arrays. - */ - JSAMPARRAY buffer[MAX_COMPONENTS]; - -#ifdef FULL_MAIN_BUFFER_SUPPORTED - /* If using full-image storage, this array holds pointers to virtual-array - * control blocks for each component. Unused if not full-image storage. - */ - jvirt_sarray_ptr whole_image[MAX_COMPONENTS]; -#endif -} my_main_controller; - -typedef my_main_controller * my_main_ptr; - - -/* Forward declarations */ -METHODDEF(void) process_data_simple_main - JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, - JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); -#ifdef FULL_MAIN_BUFFER_SUPPORTED -METHODDEF(void) process_data_buffer_main - JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, - JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); -#endif - - -/* - * Initialize for a processing pass. - */ - -METHODDEF(void) -start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode) -{ - my_main_ptr main_ = (my_main_ptr) cinfo->main; - - /* Do nothing in raw-data mode. */ - if (cinfo->raw_data_in) - return; - - main_->cur_iMCU_row = 0; /* initialize counters */ - main_->rowgroup_ctr = 0; - main_->suspended = FALSE; - main_->pass_mode = pass_mode; /* save mode for use by process_data */ - - switch (pass_mode) { - case JBUF_PASS_THRU: -#ifdef FULL_MAIN_BUFFER_SUPPORTED - if (main_->whole_image[0] != NULL) - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); -#endif - main_->pub.process_data = process_data_simple_main; - break; -#ifdef FULL_MAIN_BUFFER_SUPPORTED - case JBUF_SAVE_SOURCE: - case JBUF_CRANK_DEST: - case JBUF_SAVE_AND_PASS: - if (main_->whole_image[0] == NULL) - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - main_->pub.process_data = process_data_buffer_main; - break; -#endif - default: - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - break; - } -} - - -/* - * Process some data. - * This routine handles the simple pass-through mode, - * where we have only a strip buffer. - */ - -METHODDEF(void) -process_data_simple_main (j_compress_ptr cinfo, - JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, - JDIMENSION in_rows_avail) -{ - my_main_ptr main_ = (my_main_ptr) cinfo->main; - - while (main_->cur_iMCU_row < cinfo->total_iMCU_rows) { - /* Read input data if we haven't filled the main buffer yet */ - if (main_->rowgroup_ctr < DCTSIZE) - (*cinfo->prep->pre_process_data) (cinfo, - input_buf, in_row_ctr, in_rows_avail, - main_->buffer, &main_->rowgroup_ctr, - (JDIMENSION) DCTSIZE); - - /* If we don't have a full iMCU row buffered, return to application for - * more data. Note that preprocessor will always pad to fill the iMCU row - * at the bottom of the image. - */ - if (main_->rowgroup_ctr != DCTSIZE) - return; - - /* Send the completed row to the compressor */ - if (! (*cinfo->coef->compress_data) (cinfo, main_->buffer)) { - /* If compressor did not consume the whole row, then we must need to - * suspend processing and return to the application. In this situation - * we pretend we didn't yet consume the last input row; otherwise, if - * it happened to be the last row of the image, the application would - * think we were done. - */ - if (! main_->suspended) { - (*in_row_ctr)--; - main_->suspended = TRUE; - } - return; - } - /* We did finish the row. Undo our little suspension hack if a previous - * call suspended; then mark the main buffer empty. - */ - if (main_->suspended) { - (*in_row_ctr)++; - main_->suspended = FALSE; - } - main_->rowgroup_ctr = 0; - main_->cur_iMCU_row++; - } -} - - -#ifdef FULL_MAIN_BUFFER_SUPPORTED - -/* - * Process some data. - * This routine handles all of the modes that use a full-size buffer. - */ - -METHODDEF(void) -process_data_buffer_main (j_compress_ptr cinfo, - JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, - JDIMENSION in_rows_avail) -{ - my_main_ptr main = (my_main_ptr) cinfo->main; - int ci; - jpeg_component_info *compptr; - boolean writing = (main->pass_mode != JBUF_CRANK_DEST); - - while (main->cur_iMCU_row < cinfo->total_iMCU_rows) { - /* Realign the virtual buffers if at the start of an iMCU row. */ - if (main->rowgroup_ctr == 0) { - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - main->buffer[ci] = (*cinfo->mem->access_virt_sarray) - ((j_common_ptr) cinfo, main->whole_image[ci], - main->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE), - (JDIMENSION) (compptr->v_samp_factor * DCTSIZE), writing); - } - /* In a read pass, pretend we just read some source data. */ - if (! writing) { - *in_row_ctr += cinfo->max_v_samp_factor * DCTSIZE; - main->rowgroup_ctr = DCTSIZE; - } - } - - /* If a write pass, read input data until the current iMCU row is full. */ - /* Note: preprocessor will pad if necessary to fill the last iMCU row. */ - if (writing) { - (*cinfo->prep->pre_process_data) (cinfo, - input_buf, in_row_ctr, in_rows_avail, - main->buffer, &main->rowgroup_ctr, - (JDIMENSION) DCTSIZE); - /* Return to application if we need more data to fill the iMCU row. */ - if (main->rowgroup_ctr < DCTSIZE) - return; - } - - /* Emit data, unless this is a sink-only pass. */ - if (main->pass_mode != JBUF_SAVE_SOURCE) { - if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) { - /* If compressor did not consume the whole row, then we must need to - * suspend processing and return to the application. In this situation - * we pretend we didn't yet consume the last input row; otherwise, if - * it happened to be the last row of the image, the application would - * think we were done. - */ - if (! main->suspended) { - (*in_row_ctr)--; - main->suspended = TRUE; - } - return; - } - /* We did finish the row. Undo our little suspension hack if a previous - * call suspended; then mark the main buffer empty. - */ - if (main->suspended) { - (*in_row_ctr)++; - main->suspended = FALSE; - } - } - - /* If get here, we are done with this iMCU row. Mark buffer empty. */ - main->rowgroup_ctr = 0; - main->cur_iMCU_row++; - } -} - -#endif /* FULL_MAIN_BUFFER_SUPPORTED */ - - -/* - * Initialize main buffer controller. - */ - -GLOBAL(void) -jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer) -{ - my_main_ptr main_; - int ci; - jpeg_component_info *compptr; - - main_ = (my_main_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_main_controller)); - cinfo->main = (struct jpeg_c_main_controller *) main_; - main_->pub.start_pass = start_pass_main; - - /* We don't need to create a buffer in raw-data mode. */ - if (cinfo->raw_data_in) - return; - - /* Create the buffer. It holds downsampled data, so each component - * may be of a different size. - */ - if (need_full_buffer) { -#ifdef FULL_MAIN_BUFFER_SUPPORTED - /* Allocate a full-image virtual array for each component */ - /* Note we pad the bottom to a multiple of the iMCU height */ - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - main->whole_image[ci] = (*cinfo->mem->request_virt_sarray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, - compptr->width_in_blocks * DCTSIZE, - (JDIMENSION) jround_up((long) compptr->height_in_blocks, - (long) compptr->v_samp_factor) * DCTSIZE, - (JDIMENSION) (compptr->v_samp_factor * DCTSIZE)); - } -#else - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); -#endif - } else { -#ifdef FULL_MAIN_BUFFER_SUPPORTED - main_->whole_image[0] = NULL; /* flag for no virtual arrays */ -#endif - /* Allocate a strip buffer for each component */ - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - main_->buffer[ci] = (*cinfo->mem->alloc_sarray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - compptr->width_in_blocks * DCTSIZE, - (JDIMENSION) (compptr->v_samp_factor * DCTSIZE)); - } - } -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jcmarker.c b/source/modules/juce_graphics/image_formats/jpglib/jcmarker.c deleted file mode 100644 index be90314b0..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jcmarker.c +++ /dev/null @@ -1,597 +0,0 @@ -/* - * jcmarker.c - * - * Copyright (C) 1991-1998, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains routines to write JPEG datastream markers. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - - -/* Private state */ - -typedef struct { - struct jpeg_marker_writer pub; /* public fields */ - - unsigned int last_restart_interval; /* last DRI value emitted; 0 after SOI */ -} my_marker_writer; - -typedef my_marker_writer * my_marker_ptr; - - -/* - * Basic output routines. - * - * Note that we do not support suspension while writing a marker. - * Therefore, an application using suspension must ensure that there is - * enough buffer space for the initial markers (typ. 600-700 bytes) before - * calling jpeg_start_compress, and enough space to write the trailing EOI - * (a few bytes) before calling jpeg_finish_compress. Multipass compression - * modes are not supported at all with suspension, so those two are the only - * points where markers will be written. - */ - -LOCAL(void) -emit_byte (j_compress_ptr cinfo, int val) -/* Emit a byte */ -{ - struct jpeg_destination_mgr * dest = cinfo->dest; - - *(dest->next_output_byte)++ = (JOCTET) val; - if (--dest->free_in_buffer == 0) { - if (! (*dest->empty_output_buffer) (cinfo)) - ERREXIT(cinfo, JERR_CANT_SUSPEND); - } -} - - -LOCAL(void) -emit_marker (j_compress_ptr cinfo, JPEG_MARKER mark) -/* Emit a marker code */ -{ - emit_byte(cinfo, 0xFF); - emit_byte(cinfo, (int) mark); -} - - -LOCAL(void) -emit_2bytes (j_compress_ptr cinfo, int value) -/* Emit a 2-byte integer; these are always MSB first in JPEG files */ -{ - emit_byte(cinfo, (value >> 8) & 0xFF); - emit_byte(cinfo, value & 0xFF); -} - - -/* - * Routines to write specific marker types. - */ - -LOCAL(int) -emit_dqt (j_compress_ptr cinfo, int index) -/* Emit a DQT marker */ -/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */ -{ - JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[index]; - int prec; - int i; - - if (qtbl == NULL) - ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, index); - - prec = 0; - for (i = 0; i < DCTSIZE2; i++) { - if (qtbl->quantval[i] > 255) - prec = 1; - } - - if (! qtbl->sent_table) { - emit_marker(cinfo, M_DQT); - - emit_2bytes(cinfo, prec ? DCTSIZE2*2 + 1 + 2 : DCTSIZE2 + 1 + 2); - - emit_byte(cinfo, index + (prec<<4)); - - for (i = 0; i < DCTSIZE2; i++) { - /* The table entries must be emitted in zigzag order. */ - unsigned int qval = qtbl->quantval[jpeg_natural_order[i]]; - if (prec) - emit_byte(cinfo, (int) (qval >> 8)); - emit_byte(cinfo, (int) (qval & 0xFF)); - } - - qtbl->sent_table = TRUE; - } - - return prec; -} - - -LOCAL(void) -emit_dht (j_compress_ptr cinfo, int index, boolean is_ac) -/* Emit a DHT marker */ -{ - JHUFF_TBL * htbl; - int length, i; - - if (is_ac) { - htbl = cinfo->ac_huff_tbl_ptrs[index]; - index += 0x10; /* output index has AC bit set */ - } else { - htbl = cinfo->dc_huff_tbl_ptrs[index]; - } - - if (htbl == NULL) - ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, index); - - if (! htbl->sent_table) { - emit_marker(cinfo, M_DHT); - - length = 0; - for (i = 1; i <= 16; i++) - length += htbl->bits[i]; - - emit_2bytes(cinfo, length + 2 + 1 + 16); - emit_byte(cinfo, index); - - for (i = 1; i <= 16; i++) - emit_byte(cinfo, htbl->bits[i]); - - for (i = 0; i < length; i++) - emit_byte(cinfo, htbl->huffval[i]); - - htbl->sent_table = TRUE; - } -} - - -LOCAL(void) -emit_dac (j_compress_ptr) -/* Emit a DAC marker */ -/* Since the useful info is so small, we want to emit all the tables in */ -/* one DAC marker. Therefore this routine does its own scan of the table. */ -{ -#ifdef C_ARITH_CODING_SUPPORTED - char dc_in_use[NUM_ARITH_TBLS]; - char ac_in_use[NUM_ARITH_TBLS]; - int length, i; - jpeg_component_info *compptr; - - for (i = 0; i < NUM_ARITH_TBLS; i++) - dc_in_use[i] = ac_in_use[i] = 0; - - for (i = 0; i < cinfo->comps_in_scan; i++) { - compptr = cinfo->cur_comp_info[i]; - dc_in_use[compptr->dc_tbl_no] = 1; - ac_in_use[compptr->ac_tbl_no] = 1; - } - - length = 0; - for (i = 0; i < NUM_ARITH_TBLS; i++) - length += dc_in_use[i] + ac_in_use[i]; - - emit_marker(cinfo, M_DAC); - - emit_2bytes(cinfo, length*2 + 2); - - for (i = 0; i < NUM_ARITH_TBLS; i++) { - if (dc_in_use[i]) { - emit_byte(cinfo, i); - emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4)); - } - if (ac_in_use[i]) { - emit_byte(cinfo, i + 0x10); - emit_byte(cinfo, cinfo->arith_ac_K[i]); - } - } -#endif /* C_ARITH_CODING_SUPPORTED */ -} - - -LOCAL(void) -emit_dri (j_compress_ptr cinfo) -/* Emit a DRI marker */ -{ - emit_marker(cinfo, M_DRI); - - emit_2bytes(cinfo, 4); /* fixed length */ - - emit_2bytes(cinfo, (int) cinfo->restart_interval); -} - - -LOCAL(void) -emit_sof (j_compress_ptr cinfo, JPEG_MARKER code) -/* Emit a SOF marker */ -{ - int ci; - jpeg_component_info *compptr; - - emit_marker(cinfo, code); - - emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */ - - /* Make sure image isn't bigger than SOF field can handle */ - if ((long) cinfo->image_height > 65535L || - (long) cinfo->image_width > 65535L) - ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535); - - emit_byte(cinfo, cinfo->data_precision); - emit_2bytes(cinfo, (int) cinfo->image_height); - emit_2bytes(cinfo, (int) cinfo->image_width); - - emit_byte(cinfo, cinfo->num_components); - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - emit_byte(cinfo, compptr->component_id); - emit_byte(cinfo, (compptr->h_samp_factor << 4) + compptr->v_samp_factor); - emit_byte(cinfo, compptr->quant_tbl_no); - } -} - - -LOCAL(void) -emit_sos (j_compress_ptr cinfo) -/* Emit a SOS marker */ -{ - int i, td, ta; - jpeg_component_info *compptr; - - emit_marker(cinfo, M_SOS); - - emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */ - - emit_byte(cinfo, cinfo->comps_in_scan); - - for (i = 0; i < cinfo->comps_in_scan; i++) { - compptr = cinfo->cur_comp_info[i]; - emit_byte(cinfo, compptr->component_id); - td = compptr->dc_tbl_no; - ta = compptr->ac_tbl_no; - if (cinfo->progressive_mode) { - /* Progressive mode: only DC or only AC tables are used in one scan; - * furthermore, Huffman coding of DC refinement uses no table at all. - * We emit 0 for unused field(s); this is recommended by the P&M text - * but does not seem to be specified in the standard. - */ - if (cinfo->Ss == 0) { - ta = 0; /* DC scan */ - if (cinfo->Ah != 0 && !cinfo->arith_code) - td = 0; /* no DC table either */ - } else { - td = 0; /* AC scan */ - } - } - emit_byte(cinfo, (td << 4) + ta); - } - - emit_byte(cinfo, cinfo->Ss); - emit_byte(cinfo, cinfo->Se); - emit_byte(cinfo, (cinfo->Ah << 4) + cinfo->Al); -} - - -LOCAL(void) -emit_jfif_app0 (j_compress_ptr cinfo) -/* Emit a JFIF-compliant APP0 marker */ -{ - /* - * Length of APP0 block (2 bytes) - * Block ID (4 bytes - ASCII "JFIF") - * Zero byte (1 byte to terminate the ID string) - * Version Major, Minor (2 bytes - major first) - * Units (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm) - * Xdpu (2 bytes - dots per unit horizontal) - * Ydpu (2 bytes - dots per unit vertical) - * Thumbnail X size (1 byte) - * Thumbnail Y size (1 byte) - */ - - emit_marker(cinfo, M_APP0); - - emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */ - - emit_byte(cinfo, 0x4A); /* Identifier: ASCII "JFIF" */ - emit_byte(cinfo, 0x46); - emit_byte(cinfo, 0x49); - emit_byte(cinfo, 0x46); - emit_byte(cinfo, 0); - emit_byte(cinfo, cinfo->JFIF_major_version); /* Version fields */ - emit_byte(cinfo, cinfo->JFIF_minor_version); - emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */ - emit_2bytes(cinfo, (int) cinfo->X_density); - emit_2bytes(cinfo, (int) cinfo->Y_density); - emit_byte(cinfo, 0); /* No thumbnail image */ - emit_byte(cinfo, 0); -} - - -LOCAL(void) -emit_adobe_app14 (j_compress_ptr cinfo) -/* Emit an Adobe APP14 marker */ -{ - /* - * Length of APP14 block (2 bytes) - * Block ID (5 bytes - ASCII "Adobe") - * Version Number (2 bytes - currently 100) - * Flags0 (2 bytes - currently 0) - * Flags1 (2 bytes - currently 0) - * Color transform (1 byte) - * - * Although Adobe TN 5116 mentions Version = 101, all the Adobe files - * now in circulation seem to use Version = 100, so that's what we write. - * - * We write the color transform byte as 1 if the JPEG color space is - * YCbCr, 2 if it's YCCK, 0 otherwise. Adobe's definition has to do with - * whether the encoder performed a transformation, which is pretty useless. - */ - - emit_marker(cinfo, M_APP14); - - emit_2bytes(cinfo, 2 + 5 + 2 + 2 + 2 + 1); /* length */ - - emit_byte(cinfo, 0x41); /* Identifier: ASCII "Adobe" */ - emit_byte(cinfo, 0x64); - emit_byte(cinfo, 0x6F); - emit_byte(cinfo, 0x62); - emit_byte(cinfo, 0x65); - emit_2bytes(cinfo, 100); /* Version */ - emit_2bytes(cinfo, 0); /* Flags0 */ - emit_2bytes(cinfo, 0); /* Flags1 */ - switch (cinfo->jpeg_color_space) { - case JCS_YCbCr: - emit_byte(cinfo, 1); /* Color transform = 1 */ - break; - case JCS_YCCK: - emit_byte(cinfo, 2); /* Color transform = 2 */ - break; - default: - emit_byte(cinfo, 0); /* Color transform = 0 */ - break; - } -} - - -/* - * These routines allow writing an arbitrary marker with parameters. - * The only intended use is to emit COM or APPn markers after calling - * write_file_header and before calling write_frame_header. - * Other uses are not guaranteed to produce desirable results. - * Counting the parameter bytes properly is the caller's responsibility. - */ - -METHODDEF(void) -write_marker_header (j_compress_ptr cinfo, int marker, unsigned int datalen) -/* Emit an arbitrary marker header */ -{ - if (datalen > (unsigned int) 65533) /* safety check */ - ERREXIT(cinfo, JERR_BAD_LENGTH); - - emit_marker(cinfo, (JPEG_MARKER) marker); - - emit_2bytes(cinfo, (int) (datalen + 2)); /* total length */ -} - -METHODDEF(void) -write_marker_byte (j_compress_ptr cinfo, int val) -/* Emit one byte of marker parameters following write_marker_header */ -{ - emit_byte(cinfo, val); -} - - -/* - * Write datastream header. - * This consists of an SOI and optional APPn markers. - * We recommend use of the JFIF marker, but not the Adobe marker, - * when using YCbCr or grayscale data. The JFIF marker should NOT - * be used for any other JPEG colorspace. The Adobe marker is helpful - * to distinguish RGB, CMYK, and YCCK colorspaces. - * Note that an application can write additional header markers after - * jpeg_start_compress returns. - */ - -METHODDEF(void) -write_file_header (j_compress_ptr cinfo) -{ - my_marker_ptr marker = (my_marker_ptr) cinfo->marker; - - emit_marker(cinfo, M_SOI); /* first the SOI */ - - /* SOI is defined to reset restart interval to 0 */ - marker->last_restart_interval = 0; - - if (cinfo->write_JFIF_header) /* next an optional JFIF APP0 */ - emit_jfif_app0(cinfo); - if (cinfo->write_Adobe_marker) /* next an optional Adobe APP14 */ - emit_adobe_app14(cinfo); -} - - -/* - * Write frame header. - * This consists of DQT and SOFn markers. - * Note that we do not emit the SOF until we have emitted the DQT(s). - * This avoids compatibility problems with incorrect implementations that - * try to error-check the quant table numbers as soon as they see the SOF. - */ - -METHODDEF(void) -write_frame_header (j_compress_ptr cinfo) -{ - int ci, prec; - boolean is_baseline; - jpeg_component_info *compptr; - - /* Emit DQT for each quantization table. - * Note that emit_dqt() suppresses any duplicate tables. - */ - prec = 0; - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - prec += emit_dqt(cinfo, compptr->quant_tbl_no); - } - /* now prec is nonzero iff there are any 16-bit quant tables. */ - - /* Check for a non-baseline specification. - * Note we assume that Huffman table numbers won't be changed later. - */ - if (cinfo->arith_code || cinfo->progressive_mode || - cinfo->data_precision != 8) { - is_baseline = FALSE; - } else { - is_baseline = TRUE; - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - if (compptr->dc_tbl_no > 1 || compptr->ac_tbl_no > 1) - is_baseline = FALSE; - } - if (prec && is_baseline) { - is_baseline = FALSE; - /* If it's baseline except for quantizer size, warn the user */ - TRACEMS(cinfo, 0, JTRC_16BIT_TABLES); - } - } - - /* Emit the proper SOF marker */ - if (cinfo->arith_code) { - emit_sof(cinfo, M_SOF9); /* SOF code for arithmetic coding */ - } else { - if (cinfo->progressive_mode) - emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */ - else if (is_baseline) - emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */ - else - emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */ - } -} - - -/* - * Write scan header. - * This consists of DHT or DAC markers, optional DRI, and SOS. - * Compressed data will be written following the SOS. - */ - -METHODDEF(void) -write_scan_header (j_compress_ptr cinfo) -{ - my_marker_ptr marker = (my_marker_ptr) cinfo->marker; - int i; - jpeg_component_info *compptr; - - if (cinfo->arith_code) { - /* Emit arith conditioning info. We may have some duplication - * if the file has multiple scans, but it's so small it's hardly - * worth worrying about. - */ - emit_dac(cinfo); - } else { - /* Emit Huffman tables. - * Note that emit_dht() suppresses any duplicate tables. - */ - for (i = 0; i < cinfo->comps_in_scan; i++) { - compptr = cinfo->cur_comp_info[i]; - if (cinfo->progressive_mode) { - /* Progressive mode: only DC or only AC tables are used in one scan */ - if (cinfo->Ss == 0) { - if (cinfo->Ah == 0) /* DC needs no table for refinement scan */ - emit_dht(cinfo, compptr->dc_tbl_no, FALSE); - } else { - emit_dht(cinfo, compptr->ac_tbl_no, TRUE); - } - } else { - /* Sequential mode: need both DC and AC tables */ - emit_dht(cinfo, compptr->dc_tbl_no, FALSE); - emit_dht(cinfo, compptr->ac_tbl_no, TRUE); - } - } - } - - /* Emit DRI if required --- note that DRI value could change for each scan. - * We avoid wasting space with unnecessary DRIs, however. - */ - if (cinfo->restart_interval != marker->last_restart_interval) { - emit_dri(cinfo); - marker->last_restart_interval = cinfo->restart_interval; - } - - emit_sos(cinfo); -} - - -/* - * Write datastream trailer. - */ - -METHODDEF(void) -write_file_trailer (j_compress_ptr cinfo) -{ - emit_marker(cinfo, M_EOI); -} - - -/* - * Write an abbreviated table-specification datastream. - * This consists of SOI, DQT and DHT tables, and EOI. - * Any table that is defined and not marked sent_table = TRUE will be - * emitted. Note that all tables will be marked sent_table = TRUE at exit. - */ - -METHODDEF(void) -write_tables_only (j_compress_ptr cinfo) -{ - int i; - - emit_marker(cinfo, M_SOI); - - for (i = 0; i < NUM_QUANT_TBLS; i++) { - if (cinfo->quant_tbl_ptrs[i] != NULL) - (void) emit_dqt(cinfo, i); - } - - if (! cinfo->arith_code) { - for (i = 0; i < NUM_HUFF_TBLS; i++) { - if (cinfo->dc_huff_tbl_ptrs[i] != NULL) - emit_dht(cinfo, i, FALSE); - if (cinfo->ac_huff_tbl_ptrs[i] != NULL) - emit_dht(cinfo, i, TRUE); - } - } - - emit_marker(cinfo, M_EOI); -} - - -/* - * Initialize the marker writer module. - */ - -GLOBAL(void) -jinit_marker_writer (j_compress_ptr cinfo) -{ - my_marker_ptr marker; - - /* Create the subobject */ - marker = (my_marker_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_marker_writer)); - cinfo->marker = (struct jpeg_marker_writer *) marker; - /* Initialize method pointers */ - marker->pub.write_file_header = write_file_header; - marker->pub.write_frame_header = write_frame_header; - marker->pub.write_scan_header = write_scan_header; - marker->pub.write_file_trailer = write_file_trailer; - marker->pub.write_tables_only = write_tables_only; - marker->pub.write_marker_header = write_marker_header; - marker->pub.write_marker_byte = write_marker_byte; - /* Initialize private state */ - marker->last_restart_interval = 0; -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jcmaster.c b/source/modules/juce_graphics/image_formats/jpglib/jcmaster.c deleted file mode 100644 index a45b03b64..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jcmaster.c +++ /dev/null @@ -1,590 +0,0 @@ -/* - * jcmaster.c - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains master control logic for the JPEG compressor. - * These routines are concerned with parameter validation, initial setup, - * and inter-pass control (determining the number of passes and the work - * to be done in each pass). - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Private state */ - -typedef enum { - main_pass, /* input data, also do first output step */ - huff_opt_pass, /* Huffman code optimization pass */ - output_pass /* data output pass */ -} c_pass_type; - -typedef struct { - struct jpeg_comp_master pub; /* public fields */ - - c_pass_type pass_type; /* the type of the current pass */ - - int pass_number; /* # of passes completed */ - int total_passes; /* total # of passes needed */ - - int scan_number; /* current index in scan_info[] */ -} my_comp_master; - -typedef my_comp_master * my_master_ptr; - - -/* - * Support routines that do various essential calculations. - */ - -LOCAL(void) -initial_setup (j_compress_ptr cinfo) -/* Do computations that are needed before master selection phase */ -{ - int ci; - jpeg_component_info *compptr; - long samplesperrow; - JDIMENSION jd_samplesperrow; - - /* Sanity check on image dimensions */ - if (cinfo->image_height <= 0 || cinfo->image_width <= 0 - || cinfo->num_components <= 0 || cinfo->input_components <= 0) - ERREXIT(cinfo, JERR_EMPTY_IMAGE); - - /* Make sure image isn't bigger than I can handle */ - if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || - (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) - ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); - - /* Width of an input scanline must be representable as JDIMENSION. */ - samplesperrow = (long) cinfo->image_width * (long) cinfo->input_components; - jd_samplesperrow = (JDIMENSION) samplesperrow; - if ((long) jd_samplesperrow != samplesperrow) - ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); - - /* For now, precision must match compiled-in value... */ - if (cinfo->data_precision != BITS_IN_JSAMPLE) - ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); - - /* Check that number of components won't exceed internal array sizes */ - if (cinfo->num_components > MAX_COMPONENTS) - ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, - MAX_COMPONENTS); - - /* Compute maximum sampling factors; check factor validity */ - cinfo->max_h_samp_factor = 1; - cinfo->max_v_samp_factor = 1; - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || - compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) - ERREXIT(cinfo, JERR_BAD_SAMPLING); - cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, - compptr->h_samp_factor); - cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, - compptr->v_samp_factor); - } - - /* Compute dimensions of components */ - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Fill in the correct component_index value; don't rely on application */ - compptr->component_index = ci; - /* For compression, we never do DCT scaling. */ - compptr->DCT_scaled_size = DCTSIZE; - /* Size in DCT blocks */ - compptr->width_in_blocks = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, - (long) (cinfo->max_h_samp_factor * DCTSIZE)); - compptr->height_in_blocks = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, - (long) (cinfo->max_v_samp_factor * DCTSIZE)); - /* Size in samples */ - compptr->downsampled_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, - (long) cinfo->max_h_samp_factor); - compptr->downsampled_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, - (long) cinfo->max_v_samp_factor); - /* Mark component needed (this flag isn't actually used for compression) */ - compptr->component_needed = TRUE; - } - - /* Compute number of fully interleaved MCU rows (number of times that - * main controller will call coefficient controller). - */ - cinfo->total_iMCU_rows = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height, - (long) (cinfo->max_v_samp_factor*DCTSIZE)); -} - - -#ifdef C_MULTISCAN_FILES_SUPPORTED - -LOCAL(void) -validate_script (j_compress_ptr cinfo) -/* Verify that the scan script in cinfo->scan_info[] is valid; also - * determine whether it uses progressive JPEG, and set cinfo->progressive_mode. - */ -{ - const jpeg_scan_info * scanptr; - int scanno, ncomps, ci, coefi, thisi; - int Ss, Se, Ah, Al; - boolean component_sent[MAX_COMPONENTS]; -#ifdef C_PROGRESSIVE_SUPPORTED - int * last_bitpos_ptr; - int last_bitpos[MAX_COMPONENTS][DCTSIZE2]; - /* -1 until that coefficient has been seen; then last Al for it */ -#endif - - if (cinfo->num_scans <= 0) - ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, 0); - - /* For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1; - * for progressive JPEG, no scan can have this. - */ - scanptr = cinfo->scan_info; - if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2-1) { -#ifdef C_PROGRESSIVE_SUPPORTED - cinfo->progressive_mode = TRUE; - last_bitpos_ptr = & last_bitpos[0][0]; - for (ci = 0; ci < cinfo->num_components; ci++) - for (coefi = 0; coefi < DCTSIZE2; coefi++) - *last_bitpos_ptr++ = -1; -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif - } else { - cinfo->progressive_mode = FALSE; - for (ci = 0; ci < cinfo->num_components; ci++) - component_sent[ci] = FALSE; - } - - for (scanno = 1; scanno <= cinfo->num_scans; scanptr++, scanno++) { - /* Validate component indexes */ - ncomps = scanptr->comps_in_scan; - if (ncomps <= 0 || ncomps > MAX_COMPS_IN_SCAN) - ERREXIT2(cinfo, JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN); - for (ci = 0; ci < ncomps; ci++) { - thisi = scanptr->component_index[ci]; - if (thisi < 0 || thisi >= cinfo->num_components) - ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); - /* Components must appear in SOF order within each scan */ - if (ci > 0 && thisi <= scanptr->component_index[ci-1]) - ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); - } - /* Validate progression parameters */ - Ss = scanptr->Ss; - Se = scanptr->Se; - Ah = scanptr->Ah; - Al = scanptr->Al; - if (cinfo->progressive_mode) { -#ifdef C_PROGRESSIVE_SUPPORTED - /* The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that - * seems wrong: the upper bound ought to depend on data precision. - * Perhaps they really meant 0..N+1 for N-bit precision. - * Here we allow 0..10 for 8-bit data; Al larger than 10 results in - * out-of-range reconstructed DC values during the first DC scan, - * which might cause problems for some decoders. - */ -#if BITS_IN_JSAMPLE == 8 -#define MAX_AH_AL 10 -#else -#define MAX_AH_AL 13 -#endif - if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 || - Ah < 0 || Ah > MAX_AH_AL || Al < 0 || Al > MAX_AH_AL) - ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); - if (Ss == 0) { - if (Se != 0) /* DC and AC together not OK */ - ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); - } else { - if (ncomps != 1) /* AC scans must be for only one component */ - ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); - } - for (ci = 0; ci < ncomps; ci++) { - last_bitpos_ptr = & last_bitpos[scanptr->component_index[ci]][0]; - if (Ss != 0 && last_bitpos_ptr[0] < 0) /* AC without prior DC scan */ - ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); - for (coefi = Ss; coefi <= Se; coefi++) { - if (last_bitpos_ptr[coefi] < 0) { - /* first scan of this coefficient */ - if (Ah != 0) - ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); - } else { - /* not first scan */ - if (Ah != last_bitpos_ptr[coefi] || Al != Ah-1) - ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); - } - last_bitpos_ptr[coefi] = Al; - } - } -#endif - } else { - /* For sequential JPEG, all progression parameters must be these: */ - if (Ss != 0 || Se != DCTSIZE2-1 || Ah != 0 || Al != 0) - ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); - /* Make sure components are not sent twice */ - for (ci = 0; ci < ncomps; ci++) { - thisi = scanptr->component_index[ci]; - if (component_sent[thisi]) - ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); - component_sent[thisi] = TRUE; - } - } - } - - /* Now verify that everything got sent. */ - if (cinfo->progressive_mode) { -#ifdef C_PROGRESSIVE_SUPPORTED - /* For progressive mode, we only check that at least some DC data - * got sent for each component; the spec does not require that all bits - * of all coefficients be transmitted. Would it be wiser to enforce - * transmission of all coefficient bits?? - */ - for (ci = 0; ci < cinfo->num_components; ci++) { - if (last_bitpos[ci][0] < 0) - ERREXIT(cinfo, JERR_MISSING_DATA); - } -#endif - } else { - for (ci = 0; ci < cinfo->num_components; ci++) { - if (! component_sent[ci]) - ERREXIT(cinfo, JERR_MISSING_DATA); - } - } -} - -#endif /* C_MULTISCAN_FILES_SUPPORTED */ - - -LOCAL(void) -select_scan_parameters (j_compress_ptr cinfo) -/* Set up the scan parameters for the current scan */ -{ - int ci; - -#ifdef C_MULTISCAN_FILES_SUPPORTED - if (cinfo->scan_info != NULL) { - /* Prepare for current scan --- the script is already validated */ - my_master_ptr master = (my_master_ptr) cinfo->master; - const jpeg_scan_info * scanptr = cinfo->scan_info + master->scan_number; - - cinfo->comps_in_scan = scanptr->comps_in_scan; - for (ci = 0; ci < scanptr->comps_in_scan; ci++) { - cinfo->cur_comp_info[ci] = - &cinfo->comp_info[scanptr->component_index[ci]]; - } - cinfo->Ss = scanptr->Ss; - cinfo->Se = scanptr->Se; - cinfo->Ah = scanptr->Ah; - cinfo->Al = scanptr->Al; - } - else -#endif - { - /* Prepare for single sequential-JPEG scan containing all components */ - if (cinfo->num_components > MAX_COMPS_IN_SCAN) - ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, - MAX_COMPS_IN_SCAN); - cinfo->comps_in_scan = cinfo->num_components; - for (ci = 0; ci < cinfo->num_components; ci++) { - cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci]; - } - cinfo->Ss = 0; - cinfo->Se = DCTSIZE2-1; - cinfo->Ah = 0; - cinfo->Al = 0; - } -} - - -LOCAL(void) -per_scan_setup (j_compress_ptr cinfo) -/* Do computations that are needed before processing a JPEG scan */ -/* cinfo->comps_in_scan and cinfo->cur_comp_info[] are already set */ -{ - int ci, mcublks, tmp; - jpeg_component_info *compptr; - - if (cinfo->comps_in_scan == 1) { - - /* Noninterleaved (single-component) scan */ - compptr = cinfo->cur_comp_info[0]; - - /* Overall image size in MCUs */ - cinfo->MCUs_per_row = compptr->width_in_blocks; - cinfo->MCU_rows_in_scan = compptr->height_in_blocks; - - /* For noninterleaved scan, always one block per MCU */ - compptr->MCU_width = 1; - compptr->MCU_height = 1; - compptr->MCU_blocks = 1; - compptr->MCU_sample_width = DCTSIZE; - compptr->last_col_width = 1; - /* For noninterleaved scans, it is convenient to define last_row_height - * as the number of block rows present in the last iMCU row. - */ - tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor); - if (tmp == 0) tmp = compptr->v_samp_factor; - compptr->last_row_height = tmp; - - /* Prepare array describing MCU composition */ - cinfo->blocks_in_MCU = 1; - cinfo->MCU_membership[0] = 0; - - } else { - - /* Interleaved (multi-component) scan */ - if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) - ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, - MAX_COMPS_IN_SCAN); - - /* Overall image size in MCUs */ - cinfo->MCUs_per_row = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width, - (long) (cinfo->max_h_samp_factor*DCTSIZE)); - cinfo->MCU_rows_in_scan = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height, - (long) (cinfo->max_v_samp_factor*DCTSIZE)); - - cinfo->blocks_in_MCU = 0; - - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - /* Sampling factors give # of blocks of component in each MCU */ - compptr->MCU_width = compptr->h_samp_factor; - compptr->MCU_height = compptr->v_samp_factor; - compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; - compptr->MCU_sample_width = compptr->MCU_width * DCTSIZE; - /* Figure number of non-dummy blocks in last MCU column & row */ - tmp = (int) (compptr->width_in_blocks % compptr->MCU_width); - if (tmp == 0) tmp = compptr->MCU_width; - compptr->last_col_width = tmp; - tmp = (int) (compptr->height_in_blocks % compptr->MCU_height); - if (tmp == 0) tmp = compptr->MCU_height; - compptr->last_row_height = tmp; - /* Prepare array describing MCU composition */ - mcublks = compptr->MCU_blocks; - if (cinfo->blocks_in_MCU + mcublks > C_MAX_BLOCKS_IN_MCU) - ERREXIT(cinfo, JERR_BAD_MCU_SIZE); - while (mcublks-- > 0) { - cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; - } - } - - } - - /* Convert restart specified in rows to actual MCU count. */ - /* Note that count must fit in 16 bits, so we provide limiting. */ - if (cinfo->restart_in_rows > 0) { - long nominal = (long) cinfo->restart_in_rows * (long) cinfo->MCUs_per_row; - cinfo->restart_interval = (unsigned int) MIN(nominal, 65535L); - } -} - - -/* - * Per-pass setup. - * This is called at the beginning of each pass. We determine which modules - * will be active during this pass and give them appropriate start_pass calls. - * We also set is_last_pass to indicate whether any more passes will be - * required. - */ - -METHODDEF(void) -prepare_for_pass (j_compress_ptr cinfo) -{ - my_master_ptr master = (my_master_ptr) cinfo->master; - - switch (master->pass_type) { - case main_pass: - /* Initial pass: will collect input data, and do either Huffman - * optimization or data output for the first scan. - */ - select_scan_parameters(cinfo); - per_scan_setup(cinfo); - if (! cinfo->raw_data_in) { - (*cinfo->cconvert->start_pass) (cinfo); - (*cinfo->downsample->start_pass) (cinfo); - (*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU); - } - (*cinfo->fdct->start_pass) (cinfo); - (*cinfo->entropy->start_pass) (cinfo, cinfo->optimize_coding); - (*cinfo->coef->start_pass) (cinfo, - (master->total_passes > 1 ? - JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); - (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); - if (cinfo->optimize_coding) { - /* No immediate data output; postpone writing frame/scan headers */ - master->pub.call_pass_startup = FALSE; - } else { - /* Will write frame/scan headers at first jpeg_write_scanlines call */ - master->pub.call_pass_startup = TRUE; - } - break; -#ifdef ENTROPY_OPT_SUPPORTED - case huff_opt_pass: - /* Do Huffman optimization for a scan after the first one. */ - select_scan_parameters(cinfo); - per_scan_setup(cinfo); - if (cinfo->Ss != 0 || cinfo->Ah == 0 || cinfo->arith_code) { - (*cinfo->entropy->start_pass) (cinfo, TRUE); - (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST); - master->pub.call_pass_startup = FALSE; - break; - } - /* Special case: Huffman DC refinement scans need no Huffman table - * and therefore we can skip the optimization pass for them. - */ - master->pass_type = output_pass; - master->pass_number++; - /*FALLTHROUGH*/ -#endif - case output_pass: - /* Do a data-output pass. */ - /* We need not repeat per-scan setup if prior optimization pass did it. */ - if (! cinfo->optimize_coding) { - select_scan_parameters(cinfo); - per_scan_setup(cinfo); - } - (*cinfo->entropy->start_pass) (cinfo, FALSE); - (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST); - /* We emit frame/scan headers now */ - if (master->scan_number == 0) - (*cinfo->marker->write_frame_header) (cinfo); - (*cinfo->marker->write_scan_header) (cinfo); - master->pub.call_pass_startup = FALSE; - break; - default: - ERREXIT(cinfo, JERR_NOT_COMPILED); - } - - master->pub.is_last_pass = (master->pass_number == master->total_passes-1); - - /* Set up progress monitor's pass info if present */ - if (cinfo->progress != NULL) { - cinfo->progress->completed_passes = master->pass_number; - cinfo->progress->total_passes = master->total_passes; - } -} - - -/* - * Special start-of-pass hook. - * This is called by jpeg_write_scanlines if call_pass_startup is TRUE. - * In single-pass processing, we need this hook because we don't want to - * write frame/scan headers during jpeg_start_compress; we want to let the - * application write COM markers etc. between jpeg_start_compress and the - * jpeg_write_scanlines loop. - * In multi-pass processing, this routine is not used. - */ - -METHODDEF(void) -pass_startup (j_compress_ptr cinfo) -{ - cinfo->master->call_pass_startup = FALSE; /* reset flag so call only once */ - - (*cinfo->marker->write_frame_header) (cinfo); - (*cinfo->marker->write_scan_header) (cinfo); -} - - -/* - * Finish up at end of pass. - */ - -METHODDEF(void) -finish_pass_master (j_compress_ptr cinfo) -{ - my_master_ptr master = (my_master_ptr) cinfo->master; - - /* The entropy coder always needs an end-of-pass call, - * either to analyze statistics or to flush its output buffer. - */ - (*cinfo->entropy->finish_pass) (cinfo); - - /* Update state for next pass */ - switch (master->pass_type) { - case main_pass: - /* next pass is either output of scan 0 (after optimization) - * or output of scan 1 (if no optimization). - */ - master->pass_type = output_pass; - if (! cinfo->optimize_coding) - master->scan_number++; - break; - case huff_opt_pass: - /* next pass is always output of current scan */ - master->pass_type = output_pass; - break; - case output_pass: - /* next pass is either optimization or output of next scan */ - if (cinfo->optimize_coding) - master->pass_type = huff_opt_pass; - master->scan_number++; - break; - } - - master->pass_number++; -} - - -/* - * Initialize master compression control. - */ - -GLOBAL(void) -jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only) -{ - my_master_ptr master; - - master = (my_master_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_comp_master)); - cinfo->master = (struct jpeg_comp_master *) master; - master->pub.prepare_for_pass = prepare_for_pass; - master->pub.pass_startup = pass_startup; - master->pub.finish_pass = finish_pass_master; - master->pub.is_last_pass = FALSE; - - /* Validate parameters, determine derived values */ - initial_setup(cinfo); - - if (cinfo->scan_info != NULL) { -#ifdef C_MULTISCAN_FILES_SUPPORTED - validate_script(cinfo); -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif - } else { - cinfo->progressive_mode = FALSE; - cinfo->num_scans = 1; - } - - if (cinfo->progressive_mode) /* TEMPORARY HACK ??? */ - cinfo->optimize_coding = TRUE; /* assume default tables no good for progressive mode */ - - /* Initialize my private state */ - if (transcode_only) { - /* no main pass in transcoding */ - if (cinfo->optimize_coding) - master->pass_type = huff_opt_pass; - else - master->pass_type = output_pass; - } else { - /* for normal compression, first pass is always this type: */ - master->pass_type = main_pass; - } - master->scan_number = 0; - master->pass_number = 0; - if (cinfo->optimize_coding) - master->total_passes = cinfo->num_scans * 2; - else - master->total_passes = cinfo->num_scans; -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jcomapi.c b/source/modules/juce_graphics/image_formats/jpglib/jcomapi.c deleted file mode 100644 index 1b1a340c1..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jcomapi.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * jcomapi.c - * - * Copyright (C) 1994-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains application interface routines that are used for both - * compression and decompression. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* - * Abort processing of a JPEG compression or decompression operation, - * but don't destroy the object itself. - * - * For this, we merely clean up all the nonpermanent memory pools. - * Note that temp files (virtual arrays) are not allowed to belong to - * the permanent pool, so we will be able to close all temp files here. - * Closing a data source or destination, if necessary, is the application's - * responsibility. - */ - -GLOBAL(void) -jpeg_abort (j_common_ptr cinfo) -{ - int pool; - - /* Do nothing if called on a not-initialized or destroyed JPEG object. */ - if (cinfo->mem == NULL) - return; - - /* Releasing pools in reverse order might help avoid fragmentation - * with some (brain-damaged) malloc libraries. - */ - for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) { - (*cinfo->mem->free_pool) (cinfo, pool); - } - - /* Reset overall state for possible reuse of object */ - if (cinfo->is_decompressor) { - cinfo->global_state = DSTATE_START; - /* Try to keep application from accessing now-deleted marker list. - * A bit kludgy to do it here, but this is the most central place. - */ - ((j_decompress_ptr) cinfo)->marker_list = NULL; - } else { - cinfo->global_state = CSTATE_START; - } -} - - -/* - * Destruction of a JPEG object. - * - * Everything gets deallocated except the master jpeg_compress_struct itself - * and the error manager struct. Both of these are supplied by the application - * and must be freed, if necessary, by the application. (Often they are on - * the stack and so don't need to be freed anyway.) - * Closing a data source or destination, if necessary, is the application's - * responsibility. - */ - -GLOBAL(void) -jpeg_destroy (j_common_ptr cinfo) -{ - /* We need only tell the memory manager to release everything. */ - /* NB: mem pointer is NULL if memory mgr failed to initialize. */ - if (cinfo->mem != NULL) - (*cinfo->mem->self_destruct) (cinfo); - cinfo->mem = NULL; /* be safe if jpeg_destroy is called twice */ - cinfo->global_state = 0; /* mark it destroyed */ -} - - -/* - * Convenience routines for allocating quantization and Huffman tables. - * (Would jutils.c be a more reasonable place to put these?) - */ - -GLOBAL(JQUANT_TBL *) -jpeg_alloc_quant_table (j_common_ptr cinfo) -{ - JQUANT_TBL *tbl; - - tbl = (JQUANT_TBL *) - (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL)); - tbl->sent_table = FALSE; /* make sure this is false in any new table */ - return tbl; -} - - -GLOBAL(JHUFF_TBL *) -jpeg_alloc_huff_table (j_common_ptr cinfo) -{ - JHUFF_TBL *tbl; - - tbl = (JHUFF_TBL *) - (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL)); - tbl->sent_table = FALSE; /* make sure this is false in any new table */ - return tbl; -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jconfig.h b/source/modules/juce_graphics/image_formats/jpglib/jconfig.h deleted file mode 100644 index 217ac449a..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jconfig.h +++ /dev/null @@ -1,59 +0,0 @@ -/* jconfig.vc --- jconfig.h for Microsoft Visual C++ on Windows 95 or NT. */ -/* see jconfig.doc for explanations */ - -// disable all the warnings under MSVC -#ifdef _MSC_VER -#pragma warning (disable: 4996 4267 4100 4127 4702 4244) -#endif - -#ifdef __BORLANDC__ -#pragma warn -8057 -#pragma warn -8019 -#pragma warn -8004 -#pragma warn -8008 -#endif - -#define HAVE_PROTOTYPES -#define HAVE_UNSIGNED_CHAR -#define HAVE_UNSIGNED_SHORT -/* #define void char */ -/* #define const */ -#undef CHAR_IS_UNSIGNED -#define HAVE_STDDEF_H -#ifndef HAVE_STDLIB_H - #define HAVE_STDLIB_H -#endif -#undef NEED_BSD_STRINGS -#undef NEED_SYS_TYPES_H -#undef NEED_FAR_POINTERS /* we presume a 32-bit flat memory model */ -#undef NEED_SHORT_EXTERNAL_NAMES -#undef INCOMPLETE_TYPES_BROKEN - -/* Define "boolean" as unsigned char, not int, per Windows custom */ -#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ -typedef unsigned char boolean; -#endif -#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ - - -#ifdef JPEG_INTERNALS - -#undef RIGHT_SHIFT_IS_UNSIGNED - -#endif /* JPEG_INTERNALS */ - -#ifdef JPEG_CJPEG_DJPEG - -#define BMP_SUPPORTED /* BMP image file format */ -#define GIF_SUPPORTED /* GIF image file format */ -#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ -#undef RLE_SUPPORTED /* Utah RLE image file format */ -#define TARGA_SUPPORTED /* Targa image file format */ - -#define TWO_FILE_COMMANDLINE /* optional */ -#define USE_SETMODE /* Microsoft has setmode() */ -#undef NEED_SIGNAL_CATCHER -#undef DONT_USE_B_MODE -#undef PROGRESS_REPORT /* optional */ - -#endif /* JPEG_CJPEG_DJPEG */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jcparam.c b/source/modules/juce_graphics/image_formats/jpglib/jcparam.c deleted file mode 100644 index 739dcdf4f..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jcparam.c +++ /dev/null @@ -1,610 +0,0 @@ -/* - * jcparam.c - * - * Copyright (C) 1991-1998, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains optional default-setting code for the JPEG compressor. - * Applications do not have to use this file, but those that don't use it - * must know a lot more about the innards of the JPEG code. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* - * Quantization table setup routines - */ - -GLOBAL(void) -jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl, - const unsigned int *basic_table, - int scale_factor, boolean force_baseline) -/* Define a quantization table equal to the basic_table times - * a scale factor (given as a percentage). - * If force_baseline is TRUE, the computed quantization table entries - * are limited to 1..255 for JPEG baseline compatibility. - */ -{ - JQUANT_TBL ** qtblptr; - int i; - long temp; - - /* Safety check to ensure start_compress not called yet. */ - if (cinfo->global_state != CSTATE_START) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - - if (which_tbl < 0 || which_tbl >= NUM_QUANT_TBLS) - ERREXIT1(cinfo, JERR_DQT_INDEX, which_tbl); - - qtblptr = & cinfo->quant_tbl_ptrs[which_tbl]; - - if (*qtblptr == NULL) - *qtblptr = jpeg_alloc_quant_table((j_common_ptr) cinfo); - - for (i = 0; i < DCTSIZE2; i++) { - temp = ((long) basic_table[i] * scale_factor + 50L) / 100L; - /* limit the values to the valid range */ - if (temp <= 0L) temp = 1L; - if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */ - if (force_baseline && temp > 255L) - temp = 255L; /* limit to baseline range if requested */ - (*qtblptr)->quantval[i] = (UINT16) temp; - } - - /* Initialize sent_table FALSE so table will be written to JPEG file. */ - (*qtblptr)->sent_table = FALSE; -} - - -GLOBAL(void) -jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor, - boolean force_baseline) -/* Set or change the 'quality' (quantization) setting, using default tables - * and a straight percentage-scaling quality scale. In most cases it's better - * to use jpeg_set_quality (below); this entry point is provided for - * applications that insist on a linear percentage scaling. - */ -{ - /* These are the sample quantization tables given in JPEG spec section K.1. - * The spec says that the values given produce "good" quality, and - * when divided by 2, "very good" quality. - */ - static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = { - 16, 11, 10, 16, 24, 40, 51, 61, - 12, 12, 14, 19, 26, 58, 60, 55, - 14, 13, 16, 24, 40, 57, 69, 56, - 14, 17, 22, 29, 51, 87, 80, 62, - 18, 22, 37, 56, 68, 109, 103, 77, - 24, 35, 55, 64, 81, 104, 113, 92, - 49, 64, 78, 87, 103, 121, 120, 101, - 72, 92, 95, 98, 112, 100, 103, 99 - }; - static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = { - 17, 18, 24, 47, 99, 99, 99, 99, - 18, 21, 26, 66, 99, 99, 99, 99, - 24, 26, 56, 99, 99, 99, 99, 99, - 47, 66, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99 - }; - - /* Set up two quantization tables using the specified scaling */ - jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl, - scale_factor, force_baseline); - jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl, - scale_factor, force_baseline); -} - - -GLOBAL(int) -jpeg_quality_scaling (int quality) -/* Convert a user-specified quality rating to a percentage scaling factor - * for an underlying quantization table, using our recommended scaling curve. - * The input 'quality' factor should be 0 (terrible) to 100 (very good). - */ -{ - /* Safety limit on quality factor. Convert 0 to 1 to avoid zero divide. */ - if (quality <= 0) quality = 1; - if (quality > 100) quality = 100; - - /* The basic table is used as-is (scaling 100) for a quality of 50. - * Qualities 50..100 are converted to scaling percentage 200 - 2*Q; - * note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table - * to make all the table entries 1 (hence, minimum quantization loss). - * Qualities 1..50 are converted to scaling percentage 5000/Q. - */ - if (quality < 50) - quality = 5000 / quality; - else - quality = 200 - quality*2; - - return quality; -} - - -GLOBAL(void) -jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline) -/* Set or change the 'quality' (quantization) setting, using default tables. - * This is the standard quality-adjusting entry point for typical user - * interfaces; only those who want detailed control over quantization tables - * would use the preceding three routines directly. - */ -{ - /* Convert user 0-100 rating to percentage scaling */ - quality = jpeg_quality_scaling(quality); - - /* Set up standard quality tables */ - jpeg_set_linear_quality(cinfo, quality, force_baseline); -} - - -/* - * Huffman table setup routines - */ - -LOCAL(void) -add_huff_table (j_compress_ptr cinfo, - JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val) -/* Define a Huffman table */ -{ - int nsymbols, len; - - if (*htblptr == NULL) - *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); - - /* Copy the number-of-symbols-of-each-code-length counts */ - MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); - - /* Validate the counts. We do this here mainly so we can copy the right - * number of symbols from the val[] array, without risking marching off - * the end of memory. jchuff.c will do a more thorough test later. - */ - nsymbols = 0; - for (len = 1; len <= 16; len++) - nsymbols += bits[len]; - if (nsymbols < 1 || nsymbols > 256) - ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); - - MEMCOPY((*htblptr)->huffval, val, nsymbols * SIZEOF(UINT8)); - - /* Initialize sent_table FALSE so table will be written to JPEG file. */ - (*htblptr)->sent_table = FALSE; -} - - -LOCAL(void) -std_huff_tables (j_compress_ptr cinfo) -/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */ -/* IMPORTANT: these are only valid for 8-bit data precision! */ -{ - static const UINT8 bits_dc_luminance[17] = - { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }; - static const UINT8 val_dc_luminance[] = - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; - - static const UINT8 bits_dc_chrominance[17] = - { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }; - static const UINT8 val_dc_chrominance[] = - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; - - static const UINT8 bits_ac_luminance[17] = - { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d }; - static const UINT8 val_ac_luminance[] = - { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, - 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, - 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, - 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, - 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, - 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, - 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, - 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, - 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, - 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, - 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, - 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa }; - - static const UINT8 bits_ac_chrominance[17] = - { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 }; - static const UINT8 val_ac_chrominance[] = - { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, - 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, - 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, - 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, - 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, - 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, - 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, - 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, - 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, - 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, - 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, - 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, - 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, - 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, - 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, - 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa }; - - add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[0], - bits_dc_luminance, val_dc_luminance); - add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[0], - bits_ac_luminance, val_ac_luminance); - add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[1], - bits_dc_chrominance, val_dc_chrominance); - add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[1], - bits_ac_chrominance, val_ac_chrominance); -} - - -/* - * Default parameter setup for compression. - * - * Applications that don't choose to use this routine must do their - * own setup of all these parameters. Alternately, you can call this - * to establish defaults and then alter parameters selectively. This - * is the recommended approach since, if we add any new parameters, - * your code will still work (they'll be set to reasonable defaults). - */ - -GLOBAL(void) -jpeg_set_defaults (j_compress_ptr cinfo) -{ - int i; - - /* Safety check to ensure start_compress not called yet. */ - if (cinfo->global_state != CSTATE_START) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - - /* Allocate comp_info array large enough for maximum component count. - * Array is made permanent in case application wants to compress - * multiple images at same param settings. - */ - if (cinfo->comp_info == NULL) - cinfo->comp_info = (jpeg_component_info *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - MAX_COMPONENTS * SIZEOF(jpeg_component_info)); - - /* Initialize everything not dependent on the color space */ - - cinfo->data_precision = BITS_IN_JSAMPLE; - /* Set up two quantization tables using default quality of 75 */ - jpeg_set_quality(cinfo, 75, TRUE); - /* Set up two Huffman tables */ - std_huff_tables(cinfo); - - /* Initialize default arithmetic coding conditioning */ - for (i = 0; i < NUM_ARITH_TBLS; i++) { - cinfo->arith_dc_L[i] = 0; - cinfo->arith_dc_U[i] = 1; - cinfo->arith_ac_K[i] = 5; - } - - /* Default is no multiple-scan output */ - cinfo->scan_info = NULL; - cinfo->num_scans = 0; - - /* Expect normal source image, not raw downsampled data */ - cinfo->raw_data_in = FALSE; - - /* Use Huffman coding, not arithmetic coding, by default */ - cinfo->arith_code = FALSE; - - /* By default, don't do extra passes to optimize entropy coding */ - cinfo->optimize_coding = FALSE; - /* The standard Huffman tables are only valid for 8-bit data precision. - * If the precision is higher, force optimization on so that usable - * tables will be computed. This test can be removed if default tables - * are supplied that are valid for the desired precision. - */ - if (cinfo->data_precision > 8) - cinfo->optimize_coding = TRUE; - - /* By default, use the simpler non-cosited sampling alignment */ - cinfo->CCIR601_sampling = FALSE; - - /* No input smoothing */ - cinfo->smoothing_factor = 0; - - /* DCT algorithm preference */ - cinfo->dct_method = JDCT_DEFAULT; - - /* No restart markers */ - cinfo->restart_interval = 0; - cinfo->restart_in_rows = 0; - - /* Fill in default JFIF marker parameters. Note that whether the marker - * will actually be written is determined by jpeg_set_colorspace. - * - * By default, the library emits JFIF version code 1.01. - * An application that wants to emit JFIF 1.02 extension markers should set - * JFIF_minor_version to 2. We could probably get away with just defaulting - * to 1.02, but there may still be some decoders in use that will complain - * about that; saying 1.01 should minimize compatibility problems. - */ - cinfo->JFIF_major_version = 1; /* Default JFIF version = 1.01 */ - cinfo->JFIF_minor_version = 1; - cinfo->density_unit = 0; /* Pixel size is unknown by default */ - cinfo->X_density = 1; /* Pixel aspect ratio is square by default */ - cinfo->Y_density = 1; - - /* Choose JPEG colorspace based on input space, set defaults accordingly */ - - jpeg_default_colorspace(cinfo); -} - - -/* - * Select an appropriate JPEG colorspace for in_color_space. - */ - -GLOBAL(void) -jpeg_default_colorspace (j_compress_ptr cinfo) -{ - switch (cinfo->in_color_space) { - case JCS_GRAYSCALE: - jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); - break; - case JCS_RGB: - jpeg_set_colorspace(cinfo, JCS_YCbCr); - break; - case JCS_YCbCr: - jpeg_set_colorspace(cinfo, JCS_YCbCr); - break; - case JCS_CMYK: - jpeg_set_colorspace(cinfo, JCS_CMYK); /* By default, no translation */ - break; - case JCS_YCCK: - jpeg_set_colorspace(cinfo, JCS_YCCK); - break; - case JCS_UNKNOWN: - jpeg_set_colorspace(cinfo, JCS_UNKNOWN); - break; - default: - ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); - } -} - - -/* - * Set the JPEG colorspace, and choose colorspace-dependent default values. - */ - -GLOBAL(void) -jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace) -{ - jpeg_component_info * compptr; - int ci; - -#define SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl) \ - (compptr = &cinfo->comp_info[index], \ - compptr->component_id = (id), \ - compptr->h_samp_factor = (hsamp), \ - compptr->v_samp_factor = (vsamp), \ - compptr->quant_tbl_no = (quant), \ - compptr->dc_tbl_no = (dctbl), \ - compptr->ac_tbl_no = (actbl) ) - - /* Safety check to ensure start_compress not called yet. */ - if (cinfo->global_state != CSTATE_START) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - - /* For all colorspaces, we use Q and Huff tables 0 for luminance components, - * tables 1 for chrominance components. - */ - - cinfo->jpeg_color_space = colorspace; - - cinfo->write_JFIF_header = FALSE; /* No marker for non-JFIF colorspaces */ - cinfo->write_Adobe_marker = FALSE; /* write no Adobe marker by default */ - - switch (colorspace) { - case JCS_GRAYSCALE: - cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ - cinfo->num_components = 1; - /* JFIF specifies component ID 1 */ - SET_COMP(0, 1, 1,1, 0, 0,0); - break; - case JCS_RGB: - cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag RGB */ - cinfo->num_components = 3; - SET_COMP(0, 0x52 /* 'R' */, 1,1, 0, 0,0); - SET_COMP(1, 0x47 /* 'G' */, 1,1, 0, 0,0); - SET_COMP(2, 0x42 /* 'B' */, 1,1, 0, 0,0); - break; - case JCS_YCbCr: - cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ - cinfo->num_components = 3; - /* JFIF specifies component IDs 1,2,3 */ - /* We default to 2x2 subsamples of chrominance */ - SET_COMP(0, 1, 2,2, 0, 0,0); - SET_COMP(1, 2, 1,1, 1, 1,1); - SET_COMP(2, 3, 1,1, 1, 1,1); - break; - case JCS_CMYK: - cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag CMYK */ - cinfo->num_components = 4; - SET_COMP(0, 0x43 /* 'C' */, 1,1, 0, 0,0); - SET_COMP(1, 0x4D /* 'M' */, 1,1, 0, 0,0); - SET_COMP(2, 0x59 /* 'Y' */, 1,1, 0, 0,0); - SET_COMP(3, 0x4B /* 'K' */, 1,1, 0, 0,0); - break; - case JCS_YCCK: - cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag YCCK */ - cinfo->num_components = 4; - SET_COMP(0, 1, 2,2, 0, 0,0); - SET_COMP(1, 2, 1,1, 1, 1,1); - SET_COMP(2, 3, 1,1, 1, 1,1); - SET_COMP(3, 4, 2,2, 0, 0,0); - break; - case JCS_UNKNOWN: - cinfo->num_components = cinfo->input_components; - if (cinfo->num_components < 1 || cinfo->num_components > MAX_COMPONENTS) - ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, - MAX_COMPONENTS); - for (ci = 0; ci < cinfo->num_components; ci++) { - SET_COMP(ci, ci, 1,1, 0, 0,0); - } - break; - default: - ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); - } -} - - -#ifdef C_PROGRESSIVE_SUPPORTED - -LOCAL(jpeg_scan_info *) -fill_a_scan (jpeg_scan_info * scanptr, int ci, - int Ss, int Se, int Ah, int Al) -/* Support routine: generate one scan for specified component */ -{ - scanptr->comps_in_scan = 1; - scanptr->component_index[0] = ci; - scanptr->Ss = Ss; - scanptr->Se = Se; - scanptr->Ah = Ah; - scanptr->Al = Al; - scanptr++; - return scanptr; -} - -LOCAL(jpeg_scan_info *) -fill_scans (jpeg_scan_info * scanptr, int ncomps, - int Ss, int Se, int Ah, int Al) -/* Support routine: generate one scan for each component */ -{ - int ci; - - for (ci = 0; ci < ncomps; ci++) { - scanptr->comps_in_scan = 1; - scanptr->component_index[0] = ci; - scanptr->Ss = Ss; - scanptr->Se = Se; - scanptr->Ah = Ah; - scanptr->Al = Al; - scanptr++; - } - return scanptr; -} - -LOCAL(jpeg_scan_info *) -fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al) -/* Support routine: generate interleaved DC scan if possible, else N scans */ -{ - int ci; - - if (ncomps <= MAX_COMPS_IN_SCAN) { - /* Single interleaved DC scan */ - scanptr->comps_in_scan = ncomps; - for (ci = 0; ci < ncomps; ci++) - scanptr->component_index[ci] = ci; - scanptr->Ss = scanptr->Se = 0; - scanptr->Ah = Ah; - scanptr->Al = Al; - scanptr++; - } else { - /* Noninterleaved DC scan for each component */ - scanptr = fill_scans(scanptr, ncomps, 0, 0, Ah, Al); - } - return scanptr; -} - - -/* - * Create a recommended progressive-JPEG script. - * cinfo->num_components and cinfo->jpeg_color_space must be correct. - */ - -GLOBAL(void) -jpeg_simple_progression (j_compress_ptr cinfo) -{ - int ncomps = cinfo->num_components; - int nscans; - jpeg_scan_info * scanptr; - - /* Safety check to ensure start_compress not called yet. */ - if (cinfo->global_state != CSTATE_START) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - - /* Figure space needed for script. Calculation must match code below! */ - if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) { - /* Custom script for YCbCr color images. */ - nscans = 10; - } else { - /* All-purpose script for other color spaces. */ - if (ncomps > MAX_COMPS_IN_SCAN) - nscans = 6 * ncomps; /* 2 DC + 4 AC scans per component */ - else - nscans = 2 + 4 * ncomps; /* 2 DC scans; 4 AC scans per component */ - } - - /* Allocate space for script. - * We need to put it in the permanent pool in case the application performs - * multiple compressions without changing the settings. To avoid a memory - * leak if jpeg_simple_progression is called repeatedly for the same JPEG - * object, we try to re-use previously allocated space, and we allocate - * enough space to handle YCbCr even if initially asked for grayscale. - */ - if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) { - cinfo->script_space_size = MAX(nscans, 10); - cinfo->script_space = (jpeg_scan_info *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - cinfo->script_space_size * SIZEOF(jpeg_scan_info)); - } - scanptr = cinfo->script_space; - cinfo->scan_info = scanptr; - cinfo->num_scans = nscans; - - if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) { - /* Custom script for YCbCr color images. */ - /* Initial DC scan */ - scanptr = fill_dc_scans(scanptr, ncomps, 0, 1); - /* Initial AC scan: get some luma data out in a hurry */ - scanptr = fill_a_scan(scanptr, 0, 1, 5, 0, 2); - /* Chroma data is too small to be worth expending many scans on */ - scanptr = fill_a_scan(scanptr, 2, 1, 63, 0, 1); - scanptr = fill_a_scan(scanptr, 1, 1, 63, 0, 1); - /* Complete spectral selection for luma AC */ - scanptr = fill_a_scan(scanptr, 0, 6, 63, 0, 2); - /* Refine next bit of luma AC */ - scanptr = fill_a_scan(scanptr, 0, 1, 63, 2, 1); - /* Finish DC successive approximation */ - scanptr = fill_dc_scans(scanptr, ncomps, 1, 0); - /* Finish AC successive approximation */ - scanptr = fill_a_scan(scanptr, 2, 1, 63, 1, 0); - scanptr = fill_a_scan(scanptr, 1, 1, 63, 1, 0); - /* Luma bottom bit comes last since it's usually largest scan */ - fill_a_scan(scanptr, 0, 1, 63, 1, 0); - } else { - /* All-purpose script for other color spaces. */ - /* Successive approximation first pass */ - scanptr = fill_dc_scans(scanptr, ncomps, 0, 1); - scanptr = fill_scans(scanptr, ncomps, 1, 5, 0, 2); - scanptr = fill_scans(scanptr, ncomps, 6, 63, 0, 2); - /* Successive approximation second pass */ - scanptr = fill_scans(scanptr, ncomps, 1, 63, 2, 1); - /* Successive approximation final pass */ - scanptr = fill_dc_scans(scanptr, ncomps, 1, 0); - fill_scans(scanptr, ncomps, 1, 63, 1, 0); - } -} - -#endif /* C_PROGRESSIVE_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jcphuff.c b/source/modules/juce_graphics/image_formats/jpglib/jcphuff.c deleted file mode 100644 index f35e75a26..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jcphuff.c +++ /dev/null @@ -1,833 +0,0 @@ -/* - * jcphuff.c - * - * Copyright (C) 1995-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains Huffman entropy encoding routines for progressive JPEG. - * - * We do not support output suspension in this module, since the library - * currently does not allow multiple-scan files to be written with output - * suspension. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jchuff.h" /* Declarations shared with jchuff.c */ - -#ifdef C_PROGRESSIVE_SUPPORTED - -/* Expanded entropy encoder object for progressive Huffman encoding. */ - -typedef struct { - struct jpeg_entropy_encoder pub; /* public fields */ - - /* Mode flag: TRUE for optimization, FALSE for actual data output */ - boolean gather_statistics; - - /* Bit-level coding status. - * next_output_byte/free_in_buffer are local copies of cinfo->dest fields. - */ - JOCTET * next_output_byte; /* => next byte to write in buffer */ - size_t free_in_buffer; /* # of byte spaces remaining in buffer */ - INT32 put_buffer; /* current bit-accumulation buffer */ - int put_bits; /* # of bits now in it */ - j_compress_ptr cinfo; /* link to cinfo (needed for dump_buffer) */ - - /* Coding status for DC components */ - int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ - - /* Coding status for AC components */ - int ac_tbl_no; /* the table number of the single component */ - unsigned int EOBRUN; /* run length of EOBs */ - unsigned int BE; /* # of buffered correction bits before MCU */ - char * bit_buffer; /* buffer for correction bits (1 per char) */ - /* packing correction bits tightly would save some space but cost time... */ - - unsigned int restarts_to_go; /* MCUs left in this restart interval */ - int next_restart_num; /* next restart number to write (0-7) */ - - /* Pointers to derived tables (these workspaces have image lifespan). - * Since any one scan codes only DC or only AC, we only need one set - * of tables, not one for DC and one for AC. - */ - c_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; - - /* Statistics tables for optimization; again, one set is enough */ - long * count_ptrs[NUM_HUFF_TBLS]; -} phuff_entropy_encoder; - -typedef phuff_entropy_encoder * phuff_entropy_ptr; - -/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit - * buffer can hold. Larger sizes may slightly improve compression, but - * 1000 is already well into the realm of overkill. - * The minimum safe size is 64 bits. - */ - -#define MAX_CORR_BITS 1000 /* Max # of correction bits I can buffer */ - -/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32. - * We assume that int right shift is unsigned if INT32 right shift is, - * which should be safe. - */ - -#ifdef RIGHT_SHIFT_IS_UNSIGNED -#define ISHIFT_TEMPS int ishift_temp; -#define IRIGHT_SHIFT(x,shft) \ - ((ishift_temp = (x)) < 0 ? \ - (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \ - (ishift_temp >> (shft))) -#else -#define ISHIFT_TEMPS -#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) -#endif - -/* Forward declarations */ -METHODDEF(boolean) encode_mcu_DC_first JPP((j_compress_ptr cinfo, - JBLOCKROW *MCU_data)); -METHODDEF(boolean) encode_mcu_AC_first JPP((j_compress_ptr cinfo, - JBLOCKROW *MCU_data)); -METHODDEF(boolean) encode_mcu_DC_refine JPP((j_compress_ptr cinfo, - JBLOCKROW *MCU_data)); -METHODDEF(boolean) encode_mcu_AC_refine JPP((j_compress_ptr cinfo, - JBLOCKROW *MCU_data)); -METHODDEF(void) finish_pass_phuff JPP((j_compress_ptr cinfo)); -METHODDEF(void) finish_pass_gather_phuff JPP((j_compress_ptr cinfo)); - - -/* - * Initialize for a Huffman-compressed scan using progressive JPEG. - */ - -METHODDEF(void) -start_pass_phuff (j_compress_ptr cinfo, boolean gather_statistics) -{ - phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; - boolean is_DC_band; - int ci, tbl; - jpeg_component_info * compptr; - - entropy->cinfo = cinfo; - entropy->gather_statistics = gather_statistics; - - is_DC_band = (cinfo->Ss == 0); - - /* We assume jcmaster.c already validated the scan parameters. */ - - /* Select execution routines */ - if (cinfo->Ah == 0) { - if (is_DC_band) - entropy->pub.encode_mcu = encode_mcu_DC_first; - else - entropy->pub.encode_mcu = encode_mcu_AC_first; - } else { - if (is_DC_band) - entropy->pub.encode_mcu = encode_mcu_DC_refine; - else { - entropy->pub.encode_mcu = encode_mcu_AC_refine; - /* AC refinement needs a correction bit buffer */ - if (entropy->bit_buffer == NULL) - entropy->bit_buffer = (char *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - MAX_CORR_BITS * SIZEOF(char)); - } - } - if (gather_statistics) - entropy->pub.finish_pass = finish_pass_gather_phuff; - else - entropy->pub.finish_pass = finish_pass_phuff; - - /* Only DC coefficients may be interleaved, so cinfo->comps_in_scan = 1 - * for AC coefficients. - */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - /* Initialize DC predictions to 0 */ - entropy->last_dc_val[ci] = 0; - /* Get table index */ - if (is_DC_band) { - if (cinfo->Ah != 0) /* DC refinement needs no table */ - continue; - tbl = compptr->dc_tbl_no; - } else { - entropy->ac_tbl_no = tbl = compptr->ac_tbl_no; - } - if (gather_statistics) { - /* Check for invalid table index */ - /* (make_c_derived_tbl does this in the other path) */ - if (tbl < 0 || tbl >= NUM_HUFF_TBLS) - ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl); - /* Allocate and zero the statistics tables */ - /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */ - if (entropy->count_ptrs[tbl] == NULL) - entropy->count_ptrs[tbl] = (long *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - 257 * SIZEOF(long)); - MEMZERO(entropy->count_ptrs[tbl], 257 * SIZEOF(long)); - } else { - /* Compute derived values for Huffman table */ - /* We may do this more than once for a table, but it's not expensive */ - jpeg_make_c_derived_tbl(cinfo, is_DC_band, tbl, - & entropy->derived_tbls[tbl]); - } - } - - /* Initialize AC stuff */ - entropy->EOBRUN = 0; - entropy->BE = 0; - - /* Initialize bit buffer to empty */ - entropy->put_buffer = 0; - entropy->put_bits = 0; - - /* Initialize restart stuff */ - entropy->restarts_to_go = cinfo->restart_interval; - entropy->next_restart_num = 0; -} - - -/* Outputting bytes to the file. - * NB: these must be called only when actually outputting, - * that is, entropy->gather_statistics == FALSE. - */ - -/* Emit a byte */ -#define emit_byte(entropy,val) \ - { *(entropy)->next_output_byte++ = (JOCTET) (val); \ - if (--(entropy)->free_in_buffer == 0) \ - dump_buffer_p(entropy); } - - -LOCAL(void) -dump_buffer_p (phuff_entropy_ptr entropy) -/* Empty the output buffer; we do not support suspension in this module. */ -{ - struct jpeg_destination_mgr * dest = entropy->cinfo->dest; - - if (! (*dest->empty_output_buffer) (entropy->cinfo)) - ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND); - /* After a successful buffer dump, must reset buffer pointers */ - entropy->next_output_byte = dest->next_output_byte; - entropy->free_in_buffer = dest->free_in_buffer; -} - - -/* Outputting bits to the file */ - -/* Only the right 24 bits of put_buffer are used; the valid bits are - * left-justified in this part. At most 16 bits can be passed to emit_bits - * in one call, and we never retain more than 7 bits in put_buffer - * between calls, so 24 bits are sufficient. - */ - -INLINE -LOCAL(void) -emit_bits_p (phuff_entropy_ptr entropy, unsigned int code, int size) -/* Emit some bits, unless we are in gather mode */ -{ - /* This routine is heavily used, so it's worth coding tightly. */ - INT32 put_buffer = (INT32) code; - int put_bits = entropy->put_bits; - - /* if size is 0, caller used an invalid Huffman table entry */ - if (size == 0) - ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE); - - if (entropy->gather_statistics) - return; /* do nothing if we're only getting stats */ - - put_buffer &= (((INT32) 1)<put_buffer; /* and merge with old buffer contents */ - - while (put_bits >= 8) { - int c = (int) ((put_buffer >> 16) & 0xFF); - - emit_byte(entropy, c); - if (c == 0xFF) { /* need to stuff a zero byte? */ - emit_byte(entropy, 0); - } - put_buffer <<= 8; - put_bits -= 8; - } - - entropy->put_buffer = put_buffer; /* update variables */ - entropy->put_bits = put_bits; -} - - -LOCAL(void) -flush_bits_p (phuff_entropy_ptr entropy) -{ - emit_bits_p(entropy, 0x7F, 7); /* fill any partial byte with ones */ - entropy->put_buffer = 0; /* and reset bit-buffer to empty */ - entropy->put_bits = 0; -} - - -/* - * Emit (or just count) a Huffman symbol. - */ - -INLINE -LOCAL(void) -emit_symbol (phuff_entropy_ptr entropy, int tbl_no, int symbol) -{ - if (entropy->gather_statistics) - entropy->count_ptrs[tbl_no][symbol]++; - else { - c_derived_tbl * tbl = entropy->derived_tbls[tbl_no]; - emit_bits_p(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]); - } -} - - -/* - * Emit bits from a correction bit buffer. - */ - -LOCAL(void) -emit_buffered_bits (phuff_entropy_ptr entropy, char * bufstart, - unsigned int nbits) -{ - if (entropy->gather_statistics) - return; /* no real work */ - - while (nbits > 0) { - emit_bits_p(entropy, (unsigned int) (*bufstart), 1); - bufstart++; - nbits--; - } -} - - -/* - * Emit any pending EOBRUN symbol. - */ - -LOCAL(void) -emit_eobrun (phuff_entropy_ptr entropy) -{ - int temp, nbits; - - if (entropy->EOBRUN > 0) { /* if there is any pending EOBRUN */ - temp = entropy->EOBRUN; - nbits = 0; - while ((temp >>= 1)) - nbits++; - /* safety check: shouldn't happen given limited correction-bit buffer */ - if (nbits > 14) - ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE); - - emit_symbol(entropy, entropy->ac_tbl_no, nbits << 4); - if (nbits) - emit_bits_p(entropy, entropy->EOBRUN, nbits); - - entropy->EOBRUN = 0; - - /* Emit any buffered correction bits */ - emit_buffered_bits(entropy, entropy->bit_buffer, entropy->BE); - entropy->BE = 0; - } -} - - -/* - * Emit a restart marker & resynchronize predictions. - */ - -LOCAL(void) -emit_restart_p (phuff_entropy_ptr entropy, int restart_num) -{ - int ci; - - emit_eobrun(entropy); - - if (! entropy->gather_statistics) { - flush_bits_p(entropy); - emit_byte(entropy, 0xFF); - emit_byte(entropy, JPEG_RST0 + restart_num); - } - - if (entropy->cinfo->Ss == 0) { - /* Re-initialize DC predictions to 0 */ - for (ci = 0; ci < entropy->cinfo->comps_in_scan; ci++) - entropy->last_dc_val[ci] = 0; - } else { - /* Re-initialize all AC-related fields to 0 */ - entropy->EOBRUN = 0; - entropy->BE = 0; - } -} - - -/* - * MCU encoding for DC initial scan (either spectral selection, - * or first pass of successive approximation). - */ - -METHODDEF(boolean) -encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) -{ - phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; - int temp, temp2; - int nbits; - int blkn, ci; - int Al = cinfo->Al; - JBLOCKROW block; - jpeg_component_info * compptr; - ISHIFT_TEMPS - - entropy->next_output_byte = cinfo->dest->next_output_byte; - entropy->free_in_buffer = cinfo->dest->free_in_buffer; - - /* Emit restart marker if needed */ - if (cinfo->restart_interval) - if (entropy->restarts_to_go == 0) - emit_restart_p(entropy, entropy->next_restart_num); - - /* Encode the MCU data blocks */ - for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - block = MCU_data[blkn]; - ci = cinfo->MCU_membership[blkn]; - compptr = cinfo->cur_comp_info[ci]; - - /* Compute the DC value after the required point transform by Al. - * This is simply an arithmetic right shift. - */ - temp2 = IRIGHT_SHIFT((int) ((*block)[0]), Al); - - /* DC differences are figured on the point-transformed values. */ - temp = temp2 - entropy->last_dc_val[ci]; - entropy->last_dc_val[ci] = temp2; - - /* Encode the DC coefficient difference per section G.1.2.1 */ - temp2 = temp; - if (temp < 0) { - temp = -temp; /* temp is abs value of input */ - /* For a negative input, want temp2 = bitwise complement of abs(input) */ - /* This code assumes we are on a two's complement machine */ - temp2--; - } - - /* Find the number of bits needed for the magnitude of the coefficient */ - nbits = 0; - while (temp) { - nbits++; - temp >>= 1; - } - /* Check for out-of-range coefficient values. - * Since we're encoding a difference, the range limit is twice as much. - */ - if (nbits > MAX_COEF_BITS+1) - ERREXIT(cinfo, JERR_BAD_DCT_COEF); - - /* Count/emit the Huffman-coded symbol for the number of bits */ - emit_symbol(entropy, compptr->dc_tbl_no, nbits); - - /* Emit that number of bits of the value, if positive, */ - /* or the complement of its magnitude, if negative. */ - if (nbits) /* emit_bits rejects calls with size 0 */ - emit_bits_p(entropy, (unsigned int) temp2, nbits); - } - - cinfo->dest->next_output_byte = entropy->next_output_byte; - cinfo->dest->free_in_buffer = entropy->free_in_buffer; - - /* Update restart-interval state too */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) { - entropy->restarts_to_go = cinfo->restart_interval; - entropy->next_restart_num++; - entropy->next_restart_num &= 7; - } - entropy->restarts_to_go--; - } - - return TRUE; -} - - -/* - * MCU encoding for AC initial scan (either spectral selection, - * or first pass of successive approximation). - */ - -METHODDEF(boolean) -encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) -{ - phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; - int temp, temp2; - int nbits; - int r, k; - int Se = cinfo->Se; - int Al = cinfo->Al; - JBLOCKROW block; - - entropy->next_output_byte = cinfo->dest->next_output_byte; - entropy->free_in_buffer = cinfo->dest->free_in_buffer; - - /* Emit restart marker if needed */ - if (cinfo->restart_interval) - if (entropy->restarts_to_go == 0) - emit_restart_p(entropy, entropy->next_restart_num); - - /* Encode the MCU data block */ - block = MCU_data[0]; - - /* Encode the AC coefficients per section G.1.2.2, fig. G.3 */ - - r = 0; /* r = run length of zeros */ - - for (k = cinfo->Ss; k <= Se; k++) { - if ((temp = (*block)[jpeg_natural_order[k]]) == 0) { - r++; - continue; - } - /* We must apply the point transform by Al. For AC coefficients this - * is an integer division with rounding towards 0. To do this portably - * in C, we shift after obtaining the absolute value; so the code is - * interwoven with finding the abs value (temp) and output bits (temp2). - */ - if (temp < 0) { - temp = -temp; /* temp is abs value of input */ - temp >>= Al; /* apply the point transform */ - /* For a negative coef, want temp2 = bitwise complement of abs(coef) */ - temp2 = ~temp; - } else { - temp >>= Al; /* apply the point transform */ - temp2 = temp; - } - /* Watch out for case that nonzero coef is zero after point transform */ - if (temp == 0) { - r++; - continue; - } - - /* Emit any pending EOBRUN */ - if (entropy->EOBRUN > 0) - emit_eobrun(entropy); - /* if run length > 15, must emit special run-length-16 codes (0xF0) */ - while (r > 15) { - emit_symbol(entropy, entropy->ac_tbl_no, 0xF0); - r -= 16; - } - - /* Find the number of bits needed for the magnitude of the coefficient */ - nbits = 1; /* there must be at least one 1 bit */ - while ((temp >>= 1)) - nbits++; - /* Check for out-of-range coefficient values */ - if (nbits > MAX_COEF_BITS) - ERREXIT(cinfo, JERR_BAD_DCT_COEF); - - /* Count/emit Huffman symbol for run length / number of bits */ - emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + nbits); - - /* Emit that number of bits of the value, if positive, */ - /* or the complement of its magnitude, if negative. */ - emit_bits_p(entropy, (unsigned int) temp2, nbits); - - r = 0; /* reset zero run length */ - } - - if (r > 0) { /* If there are trailing zeroes, */ - entropy->EOBRUN++; /* count an EOB */ - if (entropy->EOBRUN == 0x7FFF) - emit_eobrun(entropy); /* force it out to avoid overflow */ - } - - cinfo->dest->next_output_byte = entropy->next_output_byte; - cinfo->dest->free_in_buffer = entropy->free_in_buffer; - - /* Update restart-interval state too */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) { - entropy->restarts_to_go = cinfo->restart_interval; - entropy->next_restart_num++; - entropy->next_restart_num &= 7; - } - entropy->restarts_to_go--; - } - - return TRUE; -} - - -/* - * MCU encoding for DC successive approximation refinement scan. - * Note: we assume such scans can be multi-component, although the spec - * is not very clear on the point. - */ - -METHODDEF(boolean) -encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) -{ - phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; - int temp; - int blkn; - int Al = cinfo->Al; - JBLOCKROW block; - - entropy->next_output_byte = cinfo->dest->next_output_byte; - entropy->free_in_buffer = cinfo->dest->free_in_buffer; - - /* Emit restart marker if needed */ - if (cinfo->restart_interval) - if (entropy->restarts_to_go == 0) - emit_restart_p(entropy, entropy->next_restart_num); - - /* Encode the MCU data blocks */ - for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - block = MCU_data[blkn]; - - /* We simply emit the Al'th bit of the DC coefficient value. */ - temp = (*block)[0]; - emit_bits_p(entropy, (unsigned int) (temp >> Al), 1); - } - - cinfo->dest->next_output_byte = entropy->next_output_byte; - cinfo->dest->free_in_buffer = entropy->free_in_buffer; - - /* Update restart-interval state too */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) { - entropy->restarts_to_go = cinfo->restart_interval; - entropy->next_restart_num++; - entropy->next_restart_num &= 7; - } - entropy->restarts_to_go--; - } - - return TRUE; -} - - -/* - * MCU encoding for AC successive approximation refinement scan. - */ - -METHODDEF(boolean) -encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) -{ - phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; - int temp; - int r, k; - int EOB; - char *BR_buffer; - unsigned int BR; - int Se = cinfo->Se; - int Al = cinfo->Al; - JBLOCKROW block; - int absvalues[DCTSIZE2]; - - entropy->next_output_byte = cinfo->dest->next_output_byte; - entropy->free_in_buffer = cinfo->dest->free_in_buffer; - - /* Emit restart marker if needed */ - if (cinfo->restart_interval) - if (entropy->restarts_to_go == 0) - emit_restart_p(entropy, entropy->next_restart_num); - - /* Encode the MCU data block */ - block = MCU_data[0]; - - /* It is convenient to make a pre-pass to determine the transformed - * coefficients' absolute values and the EOB position. - */ - EOB = 0; - for (k = cinfo->Ss; k <= Se; k++) { - temp = (*block)[jpeg_natural_order[k]]; - /* We must apply the point transform by Al. For AC coefficients this - * is an integer division with rounding towards 0. To do this portably - * in C, we shift after obtaining the absolute value. - */ - if (temp < 0) - temp = -temp; /* temp is abs value of input */ - temp >>= Al; /* apply the point transform */ - absvalues[k] = temp; /* save abs value for main pass */ - if (temp == 1) - EOB = k; /* EOB = index of last newly-nonzero coef */ - } - - /* Encode the AC coefficients per section G.1.2.3, fig. G.7 */ - - r = 0; /* r = run length of zeros */ - BR = 0; /* BR = count of buffered bits added now */ - BR_buffer = entropy->bit_buffer + entropy->BE; /* Append bits to buffer */ - - for (k = cinfo->Ss; k <= Se; k++) { - if ((temp = absvalues[k]) == 0) { - r++; - continue; - } - - /* Emit any required ZRLs, but not if they can be folded into EOB */ - while (r > 15 && k <= EOB) { - /* emit any pending EOBRUN and the BE correction bits */ - emit_eobrun(entropy); - /* Emit ZRL */ - emit_symbol(entropy, entropy->ac_tbl_no, 0xF0); - r -= 16; - /* Emit buffered correction bits that must be associated with ZRL */ - emit_buffered_bits(entropy, BR_buffer, BR); - BR_buffer = entropy->bit_buffer; /* BE bits are gone now */ - BR = 0; - } - - /* If the coef was previously nonzero, it only needs a correction bit. - * NOTE: a straight translation of the spec's figure G.7 would suggest - * that we also need to test r > 15. But if r > 15, we can only get here - * if k > EOB, which implies that this coefficient is not 1. - */ - if (temp > 1) { - /* The correction bit is the next bit of the absolute value. */ - BR_buffer[BR++] = (char) (temp & 1); - continue; - } - - /* Emit any pending EOBRUN and the BE correction bits */ - emit_eobrun(entropy); - - /* Count/emit Huffman symbol for run length / number of bits */ - emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + 1); - - /* Emit output bit for newly-nonzero coef */ - temp = ((*block)[jpeg_natural_order[k]] < 0) ? 0 : 1; - emit_bits_p(entropy, (unsigned int) temp, 1); - - /* Emit buffered correction bits that must be associated with this code */ - emit_buffered_bits(entropy, BR_buffer, BR); - BR_buffer = entropy->bit_buffer; /* BE bits are gone now */ - BR = 0; - r = 0; /* reset zero run length */ - } - - if (r > 0 || BR > 0) { /* If there are trailing zeroes, */ - entropy->EOBRUN++; /* count an EOB */ - entropy->BE += BR; /* concat my correction bits to older ones */ - /* We force out the EOB if we risk either: - * 1. overflow of the EOB counter; - * 2. overflow of the correction bit buffer during the next MCU. - */ - if (entropy->EOBRUN == 0x7FFF || entropy->BE > (MAX_CORR_BITS-DCTSIZE2+1)) - emit_eobrun(entropy); - } - - cinfo->dest->next_output_byte = entropy->next_output_byte; - cinfo->dest->free_in_buffer = entropy->free_in_buffer; - - /* Update restart-interval state too */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) { - entropy->restarts_to_go = cinfo->restart_interval; - entropy->next_restart_num++; - entropy->next_restart_num &= 7; - } - entropy->restarts_to_go--; - } - - return TRUE; -} - - -/* - * Finish up at the end of a Huffman-compressed progressive scan. - */ - -METHODDEF(void) -finish_pass_phuff (j_compress_ptr cinfo) -{ - phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; - - entropy->next_output_byte = cinfo->dest->next_output_byte; - entropy->free_in_buffer = cinfo->dest->free_in_buffer; - - /* Flush out any buffered data */ - emit_eobrun(entropy); - flush_bits_p(entropy); - - cinfo->dest->next_output_byte = entropy->next_output_byte; - cinfo->dest->free_in_buffer = entropy->free_in_buffer; -} - - -/* - * Finish up a statistics-gathering pass and create the new Huffman tables. - */ - -METHODDEF(void) -finish_pass_gather_phuff (j_compress_ptr cinfo) -{ - phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; - boolean is_DC_band; - int ci, tbl; - jpeg_component_info * compptr; - JHUFF_TBL **htblptr; - boolean did[NUM_HUFF_TBLS]; - - /* Flush out buffered data (all we care about is counting the EOB symbol) */ - emit_eobrun(entropy); - - is_DC_band = (cinfo->Ss == 0); - - /* It's important not to apply jpeg_gen_optimal_table more than once - * per table, because it clobbers the input frequency counts! - */ - MEMZERO(did, SIZEOF(did)); - - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - if (is_DC_band) { - if (cinfo->Ah != 0) /* DC refinement needs no table */ - continue; - tbl = compptr->dc_tbl_no; - } else { - tbl = compptr->ac_tbl_no; - } - if (! did[tbl]) { - if (is_DC_band) - htblptr = & cinfo->dc_huff_tbl_ptrs[tbl]; - else - htblptr = & cinfo->ac_huff_tbl_ptrs[tbl]; - if (*htblptr == NULL) - *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); - jpeg_gen_optimal_table(cinfo, *htblptr, entropy->count_ptrs[tbl]); - did[tbl] = TRUE; - } - } -} - - -/* - * Module initialization routine for progressive Huffman entropy encoding. - */ - -GLOBAL(void) -jinit_phuff_encoder (j_compress_ptr cinfo) -{ - phuff_entropy_ptr entropy; - int i; - - entropy = (phuff_entropy_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(phuff_entropy_encoder)); - cinfo->entropy = (struct jpeg_entropy_encoder *) entropy; - entropy->pub.start_pass = start_pass_phuff; - - /* Mark tables unallocated */ - for (i = 0; i < NUM_HUFF_TBLS; i++) { - entropy->derived_tbls[i] = NULL; - entropy->count_ptrs[i] = NULL; - } - entropy->bit_buffer = NULL; /* needed only in AC refinement scan */ -} - -#endif /* C_PROGRESSIVE_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jcprepct.c b/source/modules/juce_graphics/image_formats/jpglib/jcprepct.c deleted file mode 100644 index 463d6137a..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jcprepct.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - * jcprepct.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains the compression preprocessing controller. - * This controller manages the color conversion, downsampling, - * and edge expansion steps. - * - * Most of the complexity here is associated with buffering input rows - * as required by the downsampler. See the comments at the head of - * jcsample.c for the downsampler's needs. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* At present, jcsample.c can request context rows only for smoothing. - * In the future, we might also need context rows for CCIR601 sampling - * or other more-complex downsampling procedures. The code to support - * context rows should be compiled only if needed. - */ -#ifdef INPUT_SMOOTHING_SUPPORTED -#define CONTEXT_ROWS_SUPPORTED -#endif - - -/* - * For the simple (no-context-row) case, we just need to buffer one - * row group's worth of pixels for the downsampling step. At the bottom of - * the image, we pad to a full row group by replicating the last pixel row. - * The downsampler's last output row is then replicated if needed to pad - * out to a full iMCU row. - * - * When providing context rows, we must buffer three row groups' worth of - * pixels. Three row groups are physically allocated, but the row pointer - * arrays are made five row groups high, with the extra pointers above and - * below "wrapping around" to point to the last and first real row groups. - * This allows the downsampler to access the proper context rows. - * At the top and bottom of the image, we create dummy context rows by - * copying the first or last real pixel row. This copying could be avoided - * by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the - * trouble on the compression side. - */ - - -/* Private buffer controller object */ - -typedef struct { - struct jpeg_c_prep_controller pub; /* public fields */ - - /* Downsampling input buffer. This buffer holds color-converted data - * until we have enough to do a downsample step. - */ - JSAMPARRAY color_buf[MAX_COMPONENTS]; - - JDIMENSION rows_to_go; /* counts rows remaining in source image */ - int next_buf_row; /* index of next row to store in color_buf */ - -#ifdef CONTEXT_ROWS_SUPPORTED /* only needed for context case */ - int this_row_group; /* starting row index of group to process */ - int next_buf_stop; /* downsample when we reach this index */ -#endif -} my_prep_controller; - -typedef my_prep_controller * my_prep_ptr; - - -/* - * Initialize for a processing pass. - */ - -METHODDEF(void) -start_pass_prep (j_compress_ptr cinfo, J_BUF_MODE pass_mode) -{ - my_prep_ptr prep = (my_prep_ptr) cinfo->prep; - - if (pass_mode != JBUF_PASS_THRU) - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - - /* Initialize total-height counter for detecting bottom of image */ - prep->rows_to_go = cinfo->image_height; - /* Mark the conversion buffer empty */ - prep->next_buf_row = 0; -#ifdef CONTEXT_ROWS_SUPPORTED - /* Preset additional state variables for context mode. - * These aren't used in non-context mode, so we needn't test which mode. - */ - prep->this_row_group = 0; - /* Set next_buf_stop to stop after two row groups have been read in. */ - prep->next_buf_stop = 2 * cinfo->max_v_samp_factor; -#endif -} - - -/* - * Expand an image vertically from height input_rows to height output_rows, - * by duplicating the bottom row. - */ - -LOCAL(void) -expand_bottom_edge (JSAMPARRAY image_data, JDIMENSION num_cols, - int input_rows, int output_rows) -{ - int row; - - for (row = input_rows; row < output_rows; row++) { - jcopy_sample_rows(image_data, input_rows-1, image_data, row, - 1, num_cols); - } -} - - -/* - * Process some data in the simple no-context case. - * - * Preprocessor output data is counted in "row groups". A row group - * is defined to be v_samp_factor sample rows of each component. - * Downsampling will produce this much data from each max_v_samp_factor - * input rows. - */ - -METHODDEF(void) -pre_process_data (j_compress_ptr cinfo, - JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, - JDIMENSION in_rows_avail, - JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, - JDIMENSION out_row_groups_avail) -{ - my_prep_ptr prep = (my_prep_ptr) cinfo->prep; - int numrows, ci; - JDIMENSION inrows; - jpeg_component_info * compptr; - - while (*in_row_ctr < in_rows_avail && - *out_row_group_ctr < out_row_groups_avail) { - /* Do color conversion to fill the conversion buffer. */ - inrows = in_rows_avail - *in_row_ctr; - numrows = cinfo->max_v_samp_factor - prep->next_buf_row; - numrows = (int) MIN((JDIMENSION) numrows, inrows); - (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, - prep->color_buf, - (JDIMENSION) prep->next_buf_row, - numrows); - *in_row_ctr += numrows; - prep->next_buf_row += numrows; - prep->rows_to_go -= numrows; - /* If at bottom of image, pad to fill the conversion buffer. */ - if (prep->rows_to_go == 0 && - prep->next_buf_row < cinfo->max_v_samp_factor) { - for (ci = 0; ci < cinfo->num_components; ci++) { - expand_bottom_edge(prep->color_buf[ci], cinfo->image_width, - prep->next_buf_row, cinfo->max_v_samp_factor); - } - prep->next_buf_row = cinfo->max_v_samp_factor; - } - /* If we've filled the conversion buffer, empty it. */ - if (prep->next_buf_row == cinfo->max_v_samp_factor) { - (*cinfo->downsample->downsample) (cinfo, - prep->color_buf, (JDIMENSION) 0, - output_buf, *out_row_group_ctr); - prep->next_buf_row = 0; - (*out_row_group_ctr)++; - } - /* If at bottom of image, pad the output to a full iMCU height. - * Note we assume the caller is providing a one-iMCU-height output buffer! - */ - if (prep->rows_to_go == 0 && - *out_row_group_ctr < out_row_groups_avail) { - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - expand_bottom_edge(output_buf[ci], - compptr->width_in_blocks * DCTSIZE, - (int) (*out_row_group_ctr * compptr->v_samp_factor), - (int) (out_row_groups_avail * compptr->v_samp_factor)); - } - *out_row_group_ctr = out_row_groups_avail; - break; /* can exit outer loop without test */ - } - } -} - - -#ifdef CONTEXT_ROWS_SUPPORTED - -/* - * Process some data in the context case. - */ - -METHODDEF(void) -pre_process_context (j_compress_ptr cinfo, - JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, - JDIMENSION in_rows_avail, - JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, - JDIMENSION out_row_groups_avail) -{ - my_prep_ptr prep = (my_prep_ptr) cinfo->prep; - int numrows, ci; - int buf_height = cinfo->max_v_samp_factor * 3; - JDIMENSION inrows; - - while (*out_row_group_ctr < out_row_groups_avail) { - if (*in_row_ctr < in_rows_avail) { - /* Do color conversion to fill the conversion buffer. */ - inrows = in_rows_avail - *in_row_ctr; - numrows = prep->next_buf_stop - prep->next_buf_row; - numrows = (int) MIN((JDIMENSION) numrows, inrows); - (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, - prep->color_buf, - (JDIMENSION) prep->next_buf_row, - numrows); - /* Pad at top of image, if first time through */ - if (prep->rows_to_go == cinfo->image_height) { - for (ci = 0; ci < cinfo->num_components; ci++) { - int row; - for (row = 1; row <= cinfo->max_v_samp_factor; row++) { - jcopy_sample_rows(prep->color_buf[ci], 0, - prep->color_buf[ci], -row, - 1, cinfo->image_width); - } - } - } - *in_row_ctr += numrows; - prep->next_buf_row += numrows; - prep->rows_to_go -= numrows; - } else { - /* Return for more data, unless we are at the bottom of the image. */ - if (prep->rows_to_go != 0) - break; - /* When at bottom of image, pad to fill the conversion buffer. */ - if (prep->next_buf_row < prep->next_buf_stop) { - for (ci = 0; ci < cinfo->num_components; ci++) { - expand_bottom_edge(prep->color_buf[ci], cinfo->image_width, - prep->next_buf_row, prep->next_buf_stop); - } - prep->next_buf_row = prep->next_buf_stop; - } - } - /* If we've gotten enough data, downsample a row group. */ - if (prep->next_buf_row == prep->next_buf_stop) { - (*cinfo->downsample->downsample) (cinfo, - prep->color_buf, - (JDIMENSION) prep->this_row_group, - output_buf, *out_row_group_ctr); - (*out_row_group_ctr)++; - /* Advance pointers with wraparound as necessary. */ - prep->this_row_group += cinfo->max_v_samp_factor; - if (prep->this_row_group >= buf_height) - prep->this_row_group = 0; - if (prep->next_buf_row >= buf_height) - prep->next_buf_row = 0; - prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor; - } - } -} - - -/* - * Create the wrapped-around downsampling input buffer needed for context mode. - */ - -LOCAL(void) -create_context_buffer (j_compress_ptr cinfo) -{ - my_prep_ptr prep = (my_prep_ptr) cinfo->prep; - int rgroup_height = cinfo->max_v_samp_factor; - int ci, i; - jpeg_component_info * compptr; - JSAMPARRAY true_buffer, fake_buffer; - - /* Grab enough space for fake row pointers for all the components; - * we need five row groups' worth of pointers for each component. - */ - fake_buffer = (JSAMPARRAY) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (cinfo->num_components * 5 * rgroup_height) * - SIZEOF(JSAMPROW)); - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Allocate the actual buffer space (3 row groups) for this component. - * We make the buffer wide enough to allow the downsampler to edge-expand - * horizontally within the buffer, if it so chooses. - */ - true_buffer = (*cinfo->mem->alloc_sarray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - (JDIMENSION) (((long) compptr->width_in_blocks * DCTSIZE * - cinfo->max_h_samp_factor) / compptr->h_samp_factor), - (JDIMENSION) (3 * rgroup_height)); - /* Copy true buffer row pointers into the middle of the fake row array */ - MEMCOPY(fake_buffer + rgroup_height, true_buffer, - 3 * rgroup_height * SIZEOF(JSAMPROW)); - /* Fill in the above and below wraparound pointers */ - for (i = 0; i < rgroup_height; i++) { - fake_buffer[i] = true_buffer[2 * rgroup_height + i]; - fake_buffer[4 * rgroup_height + i] = true_buffer[i]; - } - prep->color_buf[ci] = fake_buffer + rgroup_height; - fake_buffer += 5 * rgroup_height; /* point to space for next component */ - } -} - -#endif /* CONTEXT_ROWS_SUPPORTED */ - - -/* - * Initialize preprocessing controller. - */ - -GLOBAL(void) -jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer) -{ - my_prep_ptr prep; - int ci; - jpeg_component_info * compptr; - - if (need_full_buffer) /* safety check */ - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - - prep = (my_prep_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_prep_controller)); - cinfo->prep = (struct jpeg_c_prep_controller *) prep; - prep->pub.start_pass = start_pass_prep; - - /* Allocate the color conversion buffer. - * We make the buffer wide enough to allow the downsampler to edge-expand - * horizontally within the buffer, if it so chooses. - */ - if (cinfo->downsample->need_context_rows) { - /* Set up to provide context rows */ -#ifdef CONTEXT_ROWS_SUPPORTED - prep->pub.pre_process_data = pre_process_context; - create_context_buffer(cinfo); -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif - } else { - /* No context, just make it tall enough for one row group */ - prep->pub.pre_process_data = pre_process_data; - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - prep->color_buf[ci] = (*cinfo->mem->alloc_sarray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - (JDIMENSION) (((long) compptr->width_in_blocks * DCTSIZE * - cinfo->max_h_samp_factor) / compptr->h_samp_factor), - (JDIMENSION) cinfo->max_v_samp_factor); - } - } -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jcsample.c b/source/modules/juce_graphics/image_formats/jpglib/jcsample.c deleted file mode 100644 index 13f3cbcb5..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jcsample.c +++ /dev/null @@ -1,519 +0,0 @@ -/* - * jcsample.c - * - * Copyright (C) 1991-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains downsampling routines. - * - * Downsampling input data is counted in "row groups". A row group - * is defined to be max_v_samp_factor pixel rows of each component, - * from which the downsampler produces v_samp_factor sample rows. - * A single row group is processed in each call to the downsampler module. - * - * The downsampler is responsible for edge-expansion of its output data - * to fill an integral number of DCT blocks horizontally. The source buffer - * may be modified if it is helpful for this purpose (the source buffer is - * allocated wide enough to correspond to the desired output width). - * The caller (the prep controller) is responsible for vertical padding. - * - * The downsampler may request "context rows" by setting need_context_rows - * during startup. In this case, the input arrays will contain at least - * one row group's worth of pixels above and below the passed-in data; - * the caller will create dummy rows at image top and bottom by replicating - * the first or last real pixel row. - * - * An excellent reference for image resampling is - * Digital Image Warping, George Wolberg, 1990. - * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. - * - * The downsampling algorithm used here is a simple average of the source - * pixels covered by the output pixel. The hi-falutin sampling literature - * refers to this as a "box filter". In general the characteristics of a box - * filter are not very good, but for the specific cases we normally use (1:1 - * and 2:1 ratios) the box is equivalent to a "triangle filter" which is not - * nearly so bad. If you intend to use other sampling ratios, you'd be well - * advised to improve this code. - * - * A simple input-smoothing capability is provided. This is mainly intended - * for cleaning up color-dithered GIF input files (if you find it inadequate, - * we suggest using an external filtering program such as pnmconvol). When - * enabled, each input pixel P is replaced by a weighted sum of itself and its - * eight neighbors. P's weight is 1-8*SF and each neighbor's weight is SF, - * where SF = (smoothing_factor / 1024). - * Currently, smoothing is only supported for 2h2v sampling factors. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Pointer to routine to downsample a single component */ -typedef JMETHOD(void, downsample1_ptr, - (j_compress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY input_data, JSAMPARRAY output_data)); - -/* Private subobject */ - -typedef struct { - struct jpeg_downsampler pub; /* public fields */ - - /* Downsampling method pointers, one per component */ - downsample1_ptr methods[MAX_COMPONENTS]; -} my_downsampler; - -typedef my_downsampler * my_downsample_ptr; - - -/* - * Initialize for a downsampling pass. - */ - -METHODDEF(void) -start_pass_downsample (j_compress_ptr) -{ - /* no work for now */ -} - - -/* - * Expand a component horizontally from width input_cols to width output_cols, - * by duplicating the rightmost samples. - */ - -LOCAL(void) -expand_right_edge (JSAMPARRAY image_data, int num_rows, - JDIMENSION input_cols, JDIMENSION output_cols) -{ - JSAMPROW ptr; - JSAMPLE pixval; - int count; - int row; - int numcols = (int) (output_cols - input_cols); - - if (numcols > 0) { - for (row = 0; row < num_rows; row++) { - ptr = image_data[row] + input_cols; - pixval = ptr[-1]; /* don't need GETJSAMPLE() here */ - for (count = numcols; count > 0; count--) - *ptr++ = pixval; - } - } -} - - -/* - * Do downsampling for a whole row group (all components). - * - * In this version we simply downsample each component independently. - */ - -METHODDEF(void) -sep_downsample (j_compress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION in_row_index, - JSAMPIMAGE output_buf, JDIMENSION out_row_group_index) -{ - my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample; - int ci; - jpeg_component_info * compptr; - JSAMPARRAY in_ptr, out_ptr; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - in_ptr = input_buf[ci] + in_row_index; - out_ptr = output_buf[ci] + (out_row_group_index * compptr->v_samp_factor); - (*downsample->methods[ci]) (cinfo, compptr, in_ptr, out_ptr); - } -} - - -/* - * Downsample pixel values of a single component. - * One row group is processed per call. - * This version handles arbitrary integral sampling ratios, without smoothing. - * Note that this version is not actually used for customary sampling ratios. - */ - -METHODDEF(void) -int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY input_data, JSAMPARRAY output_data) -{ - int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v; - JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */ - JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; - JSAMPROW inptr, outptr; - INT32 outvalue; - - h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor; - v_expand = cinfo->max_v_samp_factor / compptr->v_samp_factor; - numpix = h_expand * v_expand; - numpix2 = numpix/2; - - /* Expand input data enough to let all the output samples be generated - * by the standard loop. Special-casing padded output would be more - * efficient. - */ - expand_right_edge(input_data, cinfo->max_v_samp_factor, - cinfo->image_width, output_cols * h_expand); - - inrow = 0; - for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { - outptr = output_data[outrow]; - for (outcol = 0, outcol_h = 0; outcol < output_cols; - outcol++, outcol_h += h_expand) { - outvalue = 0; - for (v = 0; v < v_expand; v++) { - inptr = input_data[inrow+v] + outcol_h; - for (h = 0; h < h_expand; h++) { - outvalue += (INT32) GETJSAMPLE(*inptr++); - } - } - *outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix); - } - inrow += v_expand; - } -} - - -/* - * Downsample pixel values of a single component. - * This version handles the special case of a full-size component, - * without smoothing. - */ - -METHODDEF(void) -fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY input_data, JSAMPARRAY output_data) -{ - /* Copy the data */ - jcopy_sample_rows(input_data, 0, output_data, 0, - cinfo->max_v_samp_factor, cinfo->image_width); - /* Edge-expand */ - expand_right_edge(output_data, cinfo->max_v_samp_factor, - cinfo->image_width, compptr->width_in_blocks * DCTSIZE); -} - - -/* - * Downsample pixel values of a single component. - * This version handles the common case of 2:1 horizontal and 1:1 vertical, - * without smoothing. - * - * A note about the "bias" calculations: when rounding fractional values to - * integer, we do not want to always round 0.5 up to the next integer. - * If we did that, we'd introduce a noticeable bias towards larger values. - * Instead, this code is arranged so that 0.5 will be rounded up or down at - * alternate pixel locations (a simple ordered dither pattern). - */ - -METHODDEF(void) -h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY input_data, JSAMPARRAY output_data) -{ - int outrow; - JDIMENSION outcol; - JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; - JSAMPROW inptr, outptr; - int bias; - - /* Expand input data enough to let all the output samples be generated - * by the standard loop. Special-casing padded output would be more - * efficient. - */ - expand_right_edge(input_data, cinfo->max_v_samp_factor, - cinfo->image_width, output_cols * 2); - - for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { - outptr = output_data[outrow]; - inptr = input_data[outrow]; - bias = 0; /* bias = 0,1,0,1,... for successive samples */ - for (outcol = 0; outcol < output_cols; outcol++) { - *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr) + GETJSAMPLE(inptr[1]) - + bias) >> 1); - bias ^= 1; /* 0=>1, 1=>0 */ - inptr += 2; - } - } -} - - -/* - * Downsample pixel values of a single component. - * This version handles the standard case of 2:1 horizontal and 2:1 vertical, - * without smoothing. - */ - -METHODDEF(void) -h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY input_data, JSAMPARRAY output_data) -{ - int inrow, outrow; - JDIMENSION outcol; - JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; - JSAMPROW inptr0, inptr1, outptr; - int bias; - - /* Expand input data enough to let all the output samples be generated - * by the standard loop. Special-casing padded output would be more - * efficient. - */ - expand_right_edge(input_data, cinfo->max_v_samp_factor, - cinfo->image_width, output_cols * 2); - - inrow = 0; - for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { - outptr = output_data[outrow]; - inptr0 = input_data[inrow]; - inptr1 = input_data[inrow+1]; - bias = 1; /* bias = 1,2,1,2,... for successive samples */ - for (outcol = 0; outcol < output_cols; outcol++) { - *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + - GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]) - + bias) >> 2); - bias ^= 3; /* 1=>2, 2=>1 */ - inptr0 += 2; inptr1 += 2; - } - inrow += 2; - } -} - - -#ifdef INPUT_SMOOTHING_SUPPORTED - -/* - * Downsample pixel values of a single component. - * This version handles the standard case of 2:1 horizontal and 2:1 vertical, - * with smoothing. One row of context is required. - */ - -METHODDEF(void) -h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY input_data, JSAMPARRAY output_data) -{ - int inrow, outrow; - JDIMENSION colctr; - JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; - JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr; - INT32 membersum, neighsum, memberscale, neighscale; - - /* Expand input data enough to let all the output samples be generated - * by the standard loop. Special-casing padded output would be more - * efficient. - */ - expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, - cinfo->image_width, output_cols * 2); - - /* We don't bother to form the individual "smoothed" input pixel values; - * we can directly compute the output which is the average of the four - * smoothed values. Each of the four member pixels contributes a fraction - * (1-8*SF) to its own smoothed image and a fraction SF to each of the three - * other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final - * output. The four corner-adjacent neighbor pixels contribute a fraction - * SF to just one smoothed pixel, or SF/4 to the final output; while the - * eight edge-adjacent neighbors contribute SF to each of two smoothed - * pixels, or SF/2 overall. In order to use integer arithmetic, these - * factors are scaled by 2^16 = 65536. - * Also recall that SF = smoothing_factor / 1024. - */ - - memberscale = 16384 - cinfo->smoothing_factor * 80; /* scaled (1-5*SF)/4 */ - neighscale = cinfo->smoothing_factor * 16; /* scaled SF/4 */ - - inrow = 0; - for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { - outptr = output_data[outrow]; - inptr0 = input_data[inrow]; - inptr1 = input_data[inrow+1]; - above_ptr = input_data[inrow-1]; - below_ptr = input_data[inrow+2]; - - /* Special case for first column: pretend column -1 is same as column 0 */ - membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + - GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); - neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + - GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + - GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) + - GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]); - neighsum += neighsum; - neighsum += GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[2]) + - GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]); - membersum = membersum * memberscale + neighsum * neighscale; - *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); - inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2; - - for (colctr = output_cols - 2; colctr > 0; colctr--) { - /* sum of pixels directly mapped to this output element */ - membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + - GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); - /* sum of edge-neighbor pixels */ - neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + - GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + - GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) + - GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]); - /* The edge-neighbors count twice as much as corner-neighbors */ - neighsum += neighsum; - /* Add in the corner-neighbors */ - neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[2]) + - GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]); - /* form final output scaled up by 2^16 */ - membersum = membersum * memberscale + neighsum * neighscale; - /* round, descale and output it */ - *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); - inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2; - } - - /* Special case for last column */ - membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + - GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); - neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + - GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + - GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) + - GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]); - neighsum += neighsum; - neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[1]) + - GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]); - membersum = membersum * memberscale + neighsum * neighscale; - *outptr = (JSAMPLE) ((membersum + 32768) >> 16); - - inrow += 2; - } -} - - -/* - * Downsample pixel values of a single component. - * This version handles the special case of a full-size component, - * with smoothing. One row of context is required. - */ - -METHODDEF(void) -fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr, - JSAMPARRAY input_data, JSAMPARRAY output_data) -{ - int outrow; - JDIMENSION colctr; - JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; - JSAMPROW inptr, above_ptr, below_ptr, outptr; - INT32 membersum, neighsum, memberscale, neighscale; - int colsum, lastcolsum, nextcolsum; - - /* Expand input data enough to let all the output samples be generated - * by the standard loop. Special-casing padded output would be more - * efficient. - */ - expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, - cinfo->image_width, output_cols); - - /* Each of the eight neighbor pixels contributes a fraction SF to the - * smoothed pixel, while the main pixel contributes (1-8*SF). In order - * to use integer arithmetic, these factors are multiplied by 2^16 = 65536. - * Also recall that SF = smoothing_factor / 1024. - */ - - memberscale = 65536L - cinfo->smoothing_factor * 512L; /* scaled 1-8*SF */ - neighscale = cinfo->smoothing_factor * 64; /* scaled SF */ - - for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { - outptr = output_data[outrow]; - inptr = input_data[outrow]; - above_ptr = input_data[outrow-1]; - below_ptr = input_data[outrow+1]; - - /* Special case for first column */ - colsum = GETJSAMPLE(*above_ptr++) + GETJSAMPLE(*below_ptr++) + - GETJSAMPLE(*inptr); - membersum = GETJSAMPLE(*inptr++); - nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) + - GETJSAMPLE(*inptr); - neighsum = colsum + (colsum - membersum) + nextcolsum; - membersum = membersum * memberscale + neighsum * neighscale; - *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); - lastcolsum = colsum; colsum = nextcolsum; - - for (colctr = output_cols - 2; colctr > 0; colctr--) { - membersum = GETJSAMPLE(*inptr++); - above_ptr++; below_ptr++; - nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) + - GETJSAMPLE(*inptr); - neighsum = lastcolsum + (colsum - membersum) + nextcolsum; - membersum = membersum * memberscale + neighsum * neighscale; - *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); - lastcolsum = colsum; colsum = nextcolsum; - } - - /* Special case for last column */ - membersum = GETJSAMPLE(*inptr); - neighsum = lastcolsum + (colsum - membersum) + colsum; - membersum = membersum * memberscale + neighsum * neighscale; - *outptr = (JSAMPLE) ((membersum + 32768) >> 16); - - } -} - -#endif /* INPUT_SMOOTHING_SUPPORTED */ - - -/* - * Module initialization routine for downsampling. - * Note that we must select a routine for each component. - */ - -GLOBAL(void) -jinit_downsampler (j_compress_ptr cinfo) -{ - my_downsample_ptr downsample; - int ci; - jpeg_component_info * compptr; - boolean smoothok = TRUE; - - downsample = (my_downsample_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_downsampler)); - cinfo->downsample = (struct jpeg_downsampler *) downsample; - downsample->pub.start_pass = start_pass_downsample; - downsample->pub.downsample = sep_downsample; - downsample->pub.need_context_rows = FALSE; - - if (cinfo->CCIR601_sampling) - ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); - - /* Verify we can handle the sampling factors, and set up method pointers */ - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - if (compptr->h_samp_factor == cinfo->max_h_samp_factor && - compptr->v_samp_factor == cinfo->max_v_samp_factor) { -#ifdef INPUT_SMOOTHING_SUPPORTED - if (cinfo->smoothing_factor) { - downsample->methods[ci] = fullsize_smooth_downsample; - downsample->pub.need_context_rows = TRUE; - } else -#endif - downsample->methods[ci] = fullsize_downsample; - } else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor && - compptr->v_samp_factor == cinfo->max_v_samp_factor) { - smoothok = FALSE; - downsample->methods[ci] = h2v1_downsample; - } else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor && - compptr->v_samp_factor * 2 == cinfo->max_v_samp_factor) { -#ifdef INPUT_SMOOTHING_SUPPORTED - if (cinfo->smoothing_factor) { - downsample->methods[ci] = h2v2_smooth_downsample; - downsample->pub.need_context_rows = TRUE; - } else -#endif - downsample->methods[ci] = h2v2_downsample; - } else if ((cinfo->max_h_samp_factor % compptr->h_samp_factor) == 0 && - (cinfo->max_v_samp_factor % compptr->v_samp_factor) == 0) { - smoothok = FALSE; - downsample->methods[ci] = int_downsample; - } else - ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); - } - -#ifdef INPUT_SMOOTHING_SUPPORTED - if (cinfo->smoothing_factor && !smoothok) - TRACEMS(cinfo, 0, JTRC_SMOOTH_NOTIMPL); -#endif -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jctrans.c b/source/modules/juce_graphics/image_formats/jpglib/jctrans.c deleted file mode 100644 index 7e209f955..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jctrans.c +++ /dev/null @@ -1,388 +0,0 @@ -/* - * jctrans.c - * - * Copyright (C) 1995-1998, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains library routines for transcoding compression, - * that is, writing raw DCT coefficient arrays to an output JPEG file. - * The routines in jcapimin.c will also be needed by a transcoder. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Forward declarations */ -LOCAL(void) transencode_master_selection - JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); -LOCAL(void) transencode_coef_controller - JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); - - -/* - * Compression initialization for writing raw-coefficient data. - * Before calling this, all parameters and a data destination must be set up. - * Call jpeg_finish_compress() to actually write the data. - * - * The number of passed virtual arrays must match cinfo->num_components. - * Note that the virtual arrays need not be filled or even realized at - * the time write_coefficients is called; indeed, if the virtual arrays - * were requested from this compression object's memory manager, they - * typically will be realized during this routine and filled afterwards. - */ - -GLOBAL(void) -jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays) -{ - if (cinfo->global_state != CSTATE_START) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - /* Mark all tables to be written */ - jpeg_suppress_tables(cinfo, FALSE); - /* (Re)initialize error mgr and destination modules */ - (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); - (*cinfo->dest->init_destination) (cinfo); - /* Perform master selection of active modules */ - transencode_master_selection(cinfo, coef_arrays); - /* Wait for jpeg_finish_compress() call */ - cinfo->next_scanline = 0; /* so jpeg_write_marker works */ - cinfo->global_state = CSTATE_WRCOEFS; -} - - -/* - * Initialize the compression object with default parameters, - * then copy from the source object all parameters needed for lossless - * transcoding. Parameters that can be varied without loss (such as - * scan script and Huffman optimization) are left in their default states. - */ - -GLOBAL(void) -jpeg_copy_critical_parameters (j_decompress_ptr srcinfo, - j_compress_ptr dstinfo) -{ - JQUANT_TBL ** qtblptr; - jpeg_component_info *incomp, *outcomp; - JQUANT_TBL *c_quant, *slot_quant; - int tblno, ci, coefi; - - /* Safety check to ensure start_compress not called yet. */ - if (dstinfo->global_state != CSTATE_START) - ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state); - /* Copy fundamental image dimensions */ - dstinfo->image_width = srcinfo->image_width; - dstinfo->image_height = srcinfo->image_height; - dstinfo->input_components = srcinfo->num_components; - dstinfo->in_color_space = srcinfo->jpeg_color_space; - /* Initialize all parameters to default values */ - jpeg_set_defaults(dstinfo); - /* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB. - * Fix it to get the right header markers for the image colorspace. - */ - jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space); - dstinfo->data_precision = srcinfo->data_precision; - dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling; - /* Copy the source's quantization tables. */ - for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { - if (srcinfo->quant_tbl_ptrs[tblno] != NULL) { - qtblptr = & dstinfo->quant_tbl_ptrs[tblno]; - if (*qtblptr == NULL) - *qtblptr = jpeg_alloc_quant_table((j_common_ptr) dstinfo); - MEMCOPY((*qtblptr)->quantval, - srcinfo->quant_tbl_ptrs[tblno]->quantval, - SIZEOF((*qtblptr)->quantval)); - (*qtblptr)->sent_table = FALSE; - } - } - /* Copy the source's per-component info. - * Note we assume jpeg_set_defaults has allocated the dest comp_info array. - */ - dstinfo->num_components = srcinfo->num_components; - if (dstinfo->num_components < 1 || dstinfo->num_components > MAX_COMPONENTS) - ERREXIT2(dstinfo, JERR_COMPONENT_COUNT, dstinfo->num_components, - MAX_COMPONENTS); - for (ci = 0, incomp = srcinfo->comp_info, outcomp = dstinfo->comp_info; - ci < dstinfo->num_components; ci++, incomp++, outcomp++) { - outcomp->component_id = incomp->component_id; - outcomp->h_samp_factor = incomp->h_samp_factor; - outcomp->v_samp_factor = incomp->v_samp_factor; - outcomp->quant_tbl_no = incomp->quant_tbl_no; - /* Make sure saved quantization table for component matches the qtable - * slot. If not, the input file re-used this qtable slot. - * IJG encoder currently cannot duplicate this. - */ - tblno = outcomp->quant_tbl_no; - if (tblno < 0 || tblno >= NUM_QUANT_TBLS || - srcinfo->quant_tbl_ptrs[tblno] == NULL) - ERREXIT1(dstinfo, JERR_NO_QUANT_TABLE, tblno); - slot_quant = srcinfo->quant_tbl_ptrs[tblno]; - c_quant = incomp->quant_table; - if (c_quant != NULL) { - for (coefi = 0; coefi < DCTSIZE2; coefi++) { - if (c_quant->quantval[coefi] != slot_quant->quantval[coefi]) - ERREXIT1(dstinfo, JERR_MISMATCHED_QUANT_TABLE, tblno); - } - } - /* Note: we do not copy the source's Huffman table assignments; - * instead we rely on jpeg_set_colorspace to have made a suitable choice. - */ - } - /* Also copy JFIF version and resolution information, if available. - * Strictly speaking this isn't "critical" info, but it's nearly - * always appropriate to copy it if available. In particular, - * if the application chooses to copy JFIF 1.02 extension markers from - * the source file, we need to copy the version to make sure we don't - * emit a file that has 1.02 extensions but a claimed version of 1.01. - * We will *not*, however, copy version info from mislabeled "2.01" files. - */ - if (srcinfo->saw_JFIF_marker) { - if (srcinfo->JFIF_major_version == 1) { - dstinfo->JFIF_major_version = srcinfo->JFIF_major_version; - dstinfo->JFIF_minor_version = srcinfo->JFIF_minor_version; - } - dstinfo->density_unit = srcinfo->density_unit; - dstinfo->X_density = srcinfo->X_density; - dstinfo->Y_density = srcinfo->Y_density; - } -} - - -/* - * Master selection of compression modules for transcoding. - * This substitutes for jcinit.c's initialization of the full compressor. - */ - -LOCAL(void) -transencode_master_selection (j_compress_ptr cinfo, - jvirt_barray_ptr * coef_arrays) -{ - /* Although we don't actually use input_components for transcoding, - * jcmaster.c's initial_setup will complain if input_components is 0. - */ - cinfo->input_components = 1; - /* Initialize master control (includes parameter checking/processing) */ - jinit_c_master_control(cinfo, TRUE /* transcode only */); - - /* Entropy encoding: either Huffman or arithmetic coding. */ - if (cinfo->arith_code) { - ERREXIT(cinfo, JERR_ARITH_NOTIMPL); - } else { - if (cinfo->progressive_mode) { -#ifdef C_PROGRESSIVE_SUPPORTED - jinit_phuff_encoder(cinfo); -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif - } else - jinit_huff_encoder(cinfo); - } - - /* We need a special coefficient buffer controller. */ - transencode_coef_controller(cinfo, coef_arrays); - - jinit_marker_writer(cinfo); - - /* We can now tell the memory manager to allocate virtual arrays. */ - (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); - - /* Write the datastream header (SOI, JFIF) immediately. - * Frame and scan headers are postponed till later. - * This lets application insert special markers after the SOI. - */ - (*cinfo->marker->write_file_header) (cinfo); -} - - -/* - * The rest of this file is a special implementation of the coefficient - * buffer controller. This is similar to jccoefct.c, but it handles only - * output from presupplied virtual arrays. Furthermore, we generate any - * dummy padding blocks on-the-fly rather than expecting them to be present - * in the arrays. - */ - -/* Private buffer controller object */ - -typedef struct { - struct jpeg_c_coef_controller pub; /* public fields */ - - JDIMENSION iMCU_row_num; /* iMCU row # within image */ - JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ - int MCU_vert_offset; /* counts MCU rows within iMCU row */ - int MCU_rows_per_iMCU_row; /* number of such rows needed */ - - /* Virtual block array for each component. */ - jvirt_barray_ptr * whole_image; - - /* Workspace for constructing dummy blocks at right/bottom edges. */ - JBLOCKROW dummy_buffer[C_MAX_BLOCKS_IN_MCU]; -} my_coef_controller2; - -typedef my_coef_controller2 * my_coef_ptr2; - - -LOCAL(void) -start_iMCU_row2 (j_compress_ptr cinfo) -/* Reset within-iMCU-row counters for a new row */ -{ - my_coef_ptr2 coef = (my_coef_ptr2) cinfo->coef; - - /* In an interleaved scan, an MCU row is the same as an iMCU row. - * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. - * But at the bottom of the image, process only what's left. - */ - if (cinfo->comps_in_scan > 1) { - coef->MCU_rows_per_iMCU_row = 1; - } else { - if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1)) - coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; - else - coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; - } - - coef->mcu_ctr = 0; - coef->MCU_vert_offset = 0; -} - - -/* - * Initialize for a processing pass. - */ - -METHODDEF(void) -start_pass_coef2 (j_compress_ptr cinfo, J_BUF_MODE pass_mode) -{ - my_coef_ptr2 coef = (my_coef_ptr2) cinfo->coef; - - if (pass_mode != JBUF_CRANK_DEST) - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - - coef->iMCU_row_num = 0; - start_iMCU_row2(cinfo); -} - - -/* - * Process some data. - * We process the equivalent of one fully interleaved MCU row ("iMCU" row) - * per call, ie, v_samp_factor block rows for each component in the scan. - * The data is obtained from the virtual arrays and fed to the entropy coder. - * Returns TRUE if the iMCU row is completed, FALSE if suspended. - * - * NB: input_buf is ignored; it is likely to be a NULL pointer. - */ - -METHODDEF(boolean) -compress_output2 (j_compress_ptr cinfo, JSAMPIMAGE) -{ - my_coef_ptr2 coef = (my_coef_ptr2) cinfo->coef; - JDIMENSION MCU_col_num; /* index of current MCU within row */ - JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; - JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; - int blkn, ci, xindex, yindex, yoffset, blockcnt; - JDIMENSION start_col; - JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; - JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU]; - JBLOCKROW buffer_ptr; - jpeg_component_info *compptr; - - /* Align the virtual buffers for the components used in this scan. */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - buffer[ci] = (*cinfo->mem->access_virt_barray) - ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], - coef->iMCU_row_num * compptr->v_samp_factor, - (JDIMENSION) compptr->v_samp_factor, FALSE); - } - - /* Loop to process one whole iMCU row */ - for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; - yoffset++) { - for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row; - MCU_col_num++) { - /* Construct list of pointers to DCT blocks belonging to this MCU */ - blkn = 0; /* index of current DCT block within MCU */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - start_col = MCU_col_num * compptr->MCU_width; - blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width - : compptr->last_col_width; - for (yindex = 0; yindex < compptr->MCU_height; yindex++) { - if (coef->iMCU_row_num < last_iMCU_row || - yindex+yoffset < compptr->last_row_height) { - /* Fill in pointers to real blocks in this row */ - buffer_ptr = buffer[ci][yindex+yoffset] + start_col; - for (xindex = 0; xindex < blockcnt; xindex++) - MCU_buffer[blkn++] = buffer_ptr++; - } else { - /* At bottom of image, need a whole row of dummy blocks */ - xindex = 0; - } - /* Fill in any dummy blocks needed in this row. - * Dummy blocks are filled in the same way as in jccoefct.c: - * all zeroes in the AC entries, DC entries equal to previous - * block's DC value. The init routine has already zeroed the - * AC entries, so we need only set the DC entries correctly. - */ - for (; xindex < compptr->MCU_width; xindex++) { - MCU_buffer[blkn] = coef->dummy_buffer[blkn]; - MCU_buffer[blkn][0][0] = MCU_buffer[blkn-1][0][0]; - blkn++; - } - } - } - /* Try to write the MCU. */ - if (! (*cinfo->entropy->encode_mcu) (cinfo, MCU_buffer)) { - /* Suspension forced; update state counters and exit */ - coef->MCU_vert_offset = yoffset; - coef->mcu_ctr = MCU_col_num; - return FALSE; - } - } - /* Completed an MCU row, but perhaps not an iMCU row */ - coef->mcu_ctr = 0; - } - /* Completed the iMCU row, advance counters for next one */ - coef->iMCU_row_num++; - start_iMCU_row2(cinfo); - return TRUE; -} - - -/* - * Initialize coefficient buffer controller. - * - * Each passed coefficient array must be the right size for that - * coefficient: width_in_blocks wide and height_in_blocks high, - * with unitheight at least v_samp_factor. - */ - -LOCAL(void) -transencode_coef_controller (j_compress_ptr cinfo, - jvirt_barray_ptr * coef_arrays) -{ - my_coef_ptr2 coef; - JBLOCKROW buffer; - int i; - - coef = (my_coef_ptr2) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_coef_controller2)); - cinfo->coef = (struct jpeg_c_coef_controller *) coef; - coef->pub.start_pass = start_pass_coef2; - coef->pub.compress_data = compress_output2; - - /* Save pointer to virtual arrays */ - coef->whole_image = coef_arrays; - - /* Allocate and pre-zero space for dummy DCT blocks. */ - buffer = (JBLOCKROW) - (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, - C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); - jzero_far((void FAR *) buffer, C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); - for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) { - coef->dummy_buffer[i] = buffer + i; - } -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jdapimin.c b/source/modules/juce_graphics/image_formats/jpglib/jdapimin.c deleted file mode 100644 index bdff21b8b..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jdapimin.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - * jdapimin.c - * - * Copyright (C) 1994-1998, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains application interface code for the decompression half - * of the JPEG library. These are the "minimum" API routines that may be - * needed in either the normal full-decompression case or the - * transcoding-only case. - * - * Most of the routines intended to be called directly by an application - * are in this file or in jdapistd.c. But also see jcomapi.c for routines - * shared by compression and decompression, and jdtrans.c for the transcoding - * case. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* - * Initialization of a JPEG decompression object. - * The error manager must already be set up (in case memory manager fails). - */ - -GLOBAL(void) -jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize) -{ - int i; - - /* Guard against version mismatches between library and caller. */ - cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */ - if (version != JPEG_LIB_VERSION) - ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version); - if (structsize != SIZEOF(struct jpeg_decompress_struct)) - ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, - (int) SIZEOF(struct jpeg_decompress_struct), (int) structsize); - - /* For debugging purposes, we zero the whole master structure. - * But the application has already set the err pointer, and may have set - * client_data, so we have to save and restore those fields. - * Note: if application hasn't set client_data, tools like Purify may - * complain here. - */ - { - struct jpeg_error_mgr * err = cinfo->err; - void * client_data = cinfo->client_data; /* ignore Purify complaint here */ - MEMZERO(cinfo, SIZEOF(struct jpeg_decompress_struct)); - cinfo->err = err; - cinfo->client_data = client_data; - } - cinfo->is_decompressor = TRUE; - - /* Initialize a memory manager instance for this object */ - jinit_memory_mgr((j_common_ptr) cinfo); - - /* Zero out pointers to permanent structures. */ - cinfo->progress = NULL; - cinfo->src = NULL; - - for (i = 0; i < NUM_QUANT_TBLS; i++) - cinfo->quant_tbl_ptrs[i] = NULL; - - for (i = 0; i < NUM_HUFF_TBLS; i++) { - cinfo->dc_huff_tbl_ptrs[i] = NULL; - cinfo->ac_huff_tbl_ptrs[i] = NULL; - } - - /* Initialize marker processor so application can override methods - * for COM, APPn markers before calling jpeg_read_header. - */ - cinfo->marker_list = NULL; - jinit_marker_reader(cinfo); - - /* And initialize the overall input controller. */ - jinit_input_controller(cinfo); - - /* OK, I'm ready */ - cinfo->global_state = DSTATE_START; -} - - -/* - * Destruction of a JPEG decompression object - */ - -GLOBAL(void) -jpeg_destroy_decompress (j_decompress_ptr cinfo) -{ - jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ -} - - -/* - * Abort processing of a JPEG decompression operation, - * but don't destroy the object itself. - */ - -GLOBAL(void) -jpeg_abort_decompress (j_decompress_ptr cinfo) -{ - jpeg_abort((j_common_ptr) cinfo); /* use common routine */ -} - - -/* - * Set default decompression parameters. - */ - -LOCAL(void) -default_decompress_parms (j_decompress_ptr cinfo) -{ - /* Guess the input colorspace, and set output colorspace accordingly. */ - /* (Wish JPEG committee had provided a real way to specify this...) */ - /* Note application may override our guesses. */ - switch (cinfo->num_components) { - case 1: - cinfo->jpeg_color_space = JCS_GRAYSCALE; - cinfo->out_color_space = JCS_GRAYSCALE; - break; - - case 3: - if (cinfo->saw_JFIF_marker) { - cinfo->jpeg_color_space = JCS_YCbCr; /* JFIF implies YCbCr */ - } else if (cinfo->saw_Adobe_marker) { - switch (cinfo->Adobe_transform) { - case 0: - cinfo->jpeg_color_space = JCS_RGB; - break; - case 1: - cinfo->jpeg_color_space = JCS_YCbCr; - break; - default: - WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); - cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ - break; - } - } else { - /* Saw no special markers, try to guess from the component IDs */ - int cid0 = cinfo->comp_info[0].component_id; - int cid1 = cinfo->comp_info[1].component_id; - int cid2 = cinfo->comp_info[2].component_id; - - if (cid0 == 1 && cid1 == 2 && cid2 == 3) - cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */ - else if (cid0 == 82 && cid1 == 71 && cid2 == 66) - cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */ - else { - TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2); - cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ - } - } - /* Always guess RGB is proper output colorspace. */ - cinfo->out_color_space = JCS_RGB; - break; - - case 4: - if (cinfo->saw_Adobe_marker) { - switch (cinfo->Adobe_transform) { - case 0: - cinfo->jpeg_color_space = JCS_CMYK; - break; - case 2: - cinfo->jpeg_color_space = JCS_YCCK; - break; - default: - WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); - cinfo->jpeg_color_space = JCS_YCCK; /* assume it's YCCK */ - break; - } - } else { - /* No special markers, assume straight CMYK. */ - cinfo->jpeg_color_space = JCS_CMYK; - } - cinfo->out_color_space = JCS_CMYK; - break; - - default: - cinfo->jpeg_color_space = JCS_UNKNOWN; - cinfo->out_color_space = JCS_UNKNOWN; - break; - } - - /* Set defaults for other decompression parameters. */ - cinfo->scale_num = 1; /* 1:1 scaling */ - cinfo->scale_denom = 1; - cinfo->output_gamma = 1.0; - cinfo->buffered_image = FALSE; - cinfo->raw_data_out = FALSE; - cinfo->dct_method = JDCT_DEFAULT; - cinfo->do_fancy_upsampling = TRUE; - cinfo->do_block_smoothing = TRUE; - cinfo->quantize_colors = FALSE; - /* We set these in case application only sets quantize_colors. */ - cinfo->dither_mode = JDITHER_FS; -#ifdef QUANT_2PASS_SUPPORTED - cinfo->two_pass_quantize = TRUE; -#else - cinfo->two_pass_quantize = FALSE; -#endif - cinfo->desired_number_of_colors = 256; - cinfo->colormap = NULL; - /* Initialize for no mode change in buffered-image mode. */ - cinfo->enable_1pass_quant = FALSE; - cinfo->enable_external_quant = FALSE; - cinfo->enable_2pass_quant = FALSE; -} - - -/* - * Decompression startup: read start of JPEG datastream to see what's there. - * Need only initialize JPEG object and supply a data source before calling. - * - * This routine will read as far as the first SOS marker (ie, actual start of - * compressed data), and will save all tables and parameters in the JPEG - * object. It will also initialize the decompression parameters to default - * values, and finally return JPEG_HEADER_OK. On return, the application may - * adjust the decompression parameters and then call jpeg_start_decompress. - * (Or, if the application only wanted to determine the image parameters, - * the data need not be decompressed. In that case, call jpeg_abort or - * jpeg_destroy to release any temporary space.) - * If an abbreviated (tables only) datastream is presented, the routine will - * return JPEG_HEADER_TABLES_ONLY upon reaching EOI. The application may then - * re-use the JPEG object to read the abbreviated image datastream(s). - * It is unnecessary (but OK) to call jpeg_abort in this case. - * The JPEG_SUSPENDED return code only occurs if the data source module - * requests suspension of the decompressor. In this case the application - * should load more source data and then re-call jpeg_read_header to resume - * processing. - * If a non-suspending data source is used and require_image is TRUE, then the - * return code need not be inspected since only JPEG_HEADER_OK is possible. - * - * This routine is now just a front end to jpeg_consume_input, with some - * extra error checking. - */ - -GLOBAL(int) -jpeg_read_header (j_decompress_ptr cinfo, boolean require_image) -{ - int retcode; - - if (cinfo->global_state != DSTATE_START && - cinfo->global_state != DSTATE_INHEADER) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - - retcode = jpeg_consume_input(cinfo); - - switch (retcode) { - case JPEG_REACHED_SOS: - retcode = JPEG_HEADER_OK; - break; - case JPEG_REACHED_EOI: - if (require_image) /* Complain if application wanted an image */ - ERREXIT(cinfo, JERR_NO_IMAGE); - /* Reset to start state; it would be safer to require the application to - * call jpeg_abort, but we can't change it now for compatibility reasons. - * A side effect is to free any temporary memory (there shouldn't be any). - */ - jpeg_abort((j_common_ptr) cinfo); /* sets state = DSTATE_START */ - retcode = JPEG_HEADER_TABLES_ONLY; - break; - case JPEG_SUSPENDED: - /* no work */ - break; - } - - return retcode; -} - - -/* - * Consume data in advance of what the decompressor requires. - * This can be called at any time once the decompressor object has - * been created and a data source has been set up. - * - * This routine is essentially a state machine that handles a couple - * of critical state-transition actions, namely initial setup and - * transition from header scanning to ready-for-start_decompress. - * All the actual input is done via the input controller's consume_input - * method. - */ - -GLOBAL(int) -jpeg_consume_input (j_decompress_ptr cinfo) -{ - int retcode = JPEG_SUSPENDED; - - /* NB: every possible DSTATE value should be listed in this switch */ - switch (cinfo->global_state) { - case DSTATE_START: - /* Start-of-datastream actions: reset appropriate modules */ - (*cinfo->inputctl->reset_input_controller) (cinfo); - /* Initialize application's data source module */ - (*cinfo->src->init_source) (cinfo); - cinfo->global_state = DSTATE_INHEADER; - /*FALLTHROUGH*/ - case DSTATE_INHEADER: - retcode = (*cinfo->inputctl->consume_input) (cinfo); - if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */ - /* Set up default parameters based on header data */ - default_decompress_parms(cinfo); - /* Set global state: ready for start_decompress */ - cinfo->global_state = DSTATE_READY; - } - break; - case DSTATE_READY: - /* Can't advance past first SOS until start_decompress is called */ - retcode = JPEG_REACHED_SOS; - break; - case DSTATE_PRELOAD: - case DSTATE_PRESCAN: - case DSTATE_SCANNING: - case DSTATE_RAW_OK: - case DSTATE_BUFIMAGE: - case DSTATE_BUFPOST: - case DSTATE_STOPPING: - retcode = (*cinfo->inputctl->consume_input) (cinfo); - break; - default: - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - } - return retcode; -} - - -/* - * Have we finished reading the input file? - */ - -GLOBAL(boolean) -jpeg_input_complete (j_decompress_ptr cinfo) -{ - /* Check for valid jpeg object */ - if (cinfo->global_state < DSTATE_START || - cinfo->global_state > DSTATE_STOPPING) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - return cinfo->inputctl->eoi_reached; -} - - -/* - * Is there more than one scan? - */ - -GLOBAL(boolean) -jpeg_has_multiple_scans (j_decompress_ptr cinfo) -{ - /* Only valid after jpeg_read_header completes */ - if (cinfo->global_state < DSTATE_READY || - cinfo->global_state > DSTATE_STOPPING) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - return cinfo->inputctl->has_multiple_scans; -} - - -/* - * Finish JPEG decompression. - * - * This will normally just verify the file trailer and release temp storage. - * - * Returns FALSE if suspended. The return value need be inspected only if - * a suspending data source is used. - */ - -GLOBAL(boolean) -jpeg_finish_decompress (j_decompress_ptr cinfo) -{ - if ((cinfo->global_state == DSTATE_SCANNING || - cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) { - /* Terminate final pass of non-buffered mode */ - if (cinfo->output_scanline < cinfo->output_height) - ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); - (*cinfo->master->finish_output_pass) (cinfo); - cinfo->global_state = DSTATE_STOPPING; - } else if (cinfo->global_state == DSTATE_BUFIMAGE) { - /* Finishing after a buffered-image operation */ - cinfo->global_state = DSTATE_STOPPING; - } else if (cinfo->global_state != DSTATE_STOPPING) { - /* STOPPING = repeat call after a suspension, anything else is error */ - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - } - /* Read until EOI */ - while (! cinfo->inputctl->eoi_reached) { - if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) - return FALSE; /* Suspend, come back later */ - } - /* Do final cleanup */ - (*cinfo->src->term_source) (cinfo); - /* We can use jpeg_abort to release memory and reset global_state */ - jpeg_abort((j_common_ptr) cinfo); - return TRUE; -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jdapistd.c b/source/modules/juce_graphics/image_formats/jpglib/jdapistd.c deleted file mode 100644 index f6c7fffe1..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jdapistd.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * jdapistd.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains application interface code for the decompression half - * of the JPEG library. These are the "standard" API routines that are - * used in the normal full-decompression case. They are not used by a - * transcoding-only application. Note that if an application links in - * jpeg_start_decompress, it will end up linking in the entire decompressor. - * We thus must separate this file from jdapimin.c to avoid linking the - * whole decompression library into a transcoder. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Forward declarations */ -LOCAL(boolean) output_pass_setup JPP((j_decompress_ptr cinfo)); - - -/* - * Decompression initialization. - * jpeg_read_header must be completed before calling this. - * - * If a multipass operating mode was selected, this will do all but the - * last pass, and thus may take a great deal of time. - * - * Returns FALSE if suspended. The return value need be inspected only if - * a suspending data source is used. - */ - -GLOBAL(boolean) -jpeg_start_decompress (j_decompress_ptr cinfo) -{ - if (cinfo->global_state == DSTATE_READY) { - /* First call: initialize master control, select active modules */ - jinit_master_decompress(cinfo); - if (cinfo->buffered_image) { - /* No more work here; expecting jpeg_start_output next */ - cinfo->global_state = DSTATE_BUFIMAGE; - return TRUE; - } - cinfo->global_state = DSTATE_PRELOAD; - } - if (cinfo->global_state == DSTATE_PRELOAD) { - /* If file has multiple scans, absorb them all into the coef buffer */ - if (cinfo->inputctl->has_multiple_scans) { -#ifdef D_MULTISCAN_FILES_SUPPORTED - for (;;) { - int retcode; - /* Call progress monitor hook if present */ - if (cinfo->progress != NULL) - (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); - /* Absorb some more input */ - retcode = (*cinfo->inputctl->consume_input) (cinfo); - if (retcode == JPEG_SUSPENDED) - return FALSE; - if (retcode == JPEG_REACHED_EOI) - break; - /* Advance progress counter if appropriate */ - if (cinfo->progress != NULL && - (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { - if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { - /* jdmaster underestimated number of scans; ratchet up one scan */ - cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; - } - } - } -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif /* D_MULTISCAN_FILES_SUPPORTED */ - } - cinfo->output_scan_number = cinfo->input_scan_number; - } else if (cinfo->global_state != DSTATE_PRESCAN) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - /* Perform any dummy output passes, and set up for the final pass */ - return output_pass_setup(cinfo); -} - - -/* - * Set up for an output pass, and perform any dummy pass(es) needed. - * Common subroutine for jpeg_start_decompress and jpeg_start_output. - * Entry: global_state = DSTATE_PRESCAN only if previously suspended. - * Exit: If done, returns TRUE and sets global_state for proper output mode. - * If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN. - */ - -LOCAL(boolean) -output_pass_setup (j_decompress_ptr cinfo) -{ - if (cinfo->global_state != DSTATE_PRESCAN) { - /* First call: do pass setup */ - (*cinfo->master->prepare_for_output_pass) (cinfo); - cinfo->output_scanline = 0; - cinfo->global_state = DSTATE_PRESCAN; - } - /* Loop over any required dummy passes */ - while (cinfo->master->is_dummy_pass) { -#ifdef QUANT_2PASS_SUPPORTED - /* Crank through the dummy pass */ - while (cinfo->output_scanline < cinfo->output_height) { - JDIMENSION last_scanline; - /* Call progress monitor hook if present */ - if (cinfo->progress != NULL) { - cinfo->progress->pass_counter = (long) cinfo->output_scanline; - cinfo->progress->pass_limit = (long) cinfo->output_height; - (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); - } - /* Process some data */ - last_scanline = cinfo->output_scanline; - (*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL, - &cinfo->output_scanline, (JDIMENSION) 0); - if (cinfo->output_scanline == last_scanline) - return FALSE; /* No progress made, must suspend */ - } - /* Finish up dummy pass, and set up for another one */ - (*cinfo->master->finish_output_pass) (cinfo); - (*cinfo->master->prepare_for_output_pass) (cinfo); - cinfo->output_scanline = 0; -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif /* QUANT_2PASS_SUPPORTED */ - } - /* Ready for application to drive output pass through - * jpeg_read_scanlines or jpeg_read_raw_data. - */ - cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING; - return TRUE; -} - - -/* - * Read some scanlines of data from the JPEG decompressor. - * - * The return value will be the number of lines actually read. - * This may be less than the number requested in several cases, - * including bottom of image, data source suspension, and operating - * modes that emit multiple scanlines at a time. - * - * Note: we warn about excess calls to jpeg_read_scanlines() since - * this likely signals an application programmer error. However, - * an oversize buffer (max_lines > scanlines remaining) is not an error. - */ - -GLOBAL(JDIMENSION) -jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines, - JDIMENSION max_lines) -{ - JDIMENSION row_ctr; - - if (cinfo->global_state != DSTATE_SCANNING) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - if (cinfo->output_scanline >= cinfo->output_height) { - WARNMS(cinfo, JWRN_TOO_MUCH_DATA); - return 0; - } - - /* Call progress monitor hook if present */ - if (cinfo->progress != NULL) { - cinfo->progress->pass_counter = (long) cinfo->output_scanline; - cinfo->progress->pass_limit = (long) cinfo->output_height; - (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); - } - - /* Process some data */ - row_ctr = 0; - (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines); - cinfo->output_scanline += row_ctr; - return row_ctr; -} - - -/* - * Alternate entry point to read raw data. - * Processes exactly one iMCU row per call, unless suspended. - */ - -GLOBAL(JDIMENSION) -jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data, - JDIMENSION max_lines) -{ - JDIMENSION lines_per_iMCU_row; - - if (cinfo->global_state != DSTATE_RAW_OK) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - if (cinfo->output_scanline >= cinfo->output_height) { - WARNMS(cinfo, JWRN_TOO_MUCH_DATA); - return 0; - } - - /* Call progress monitor hook if present */ - if (cinfo->progress != NULL) { - cinfo->progress->pass_counter = (long) cinfo->output_scanline; - cinfo->progress->pass_limit = (long) cinfo->output_height; - (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); - } - - /* Verify that at least one iMCU row can be returned. */ - lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size; - if (max_lines < lines_per_iMCU_row) - ERREXIT(cinfo, JERR_BUFFER_SIZE); - - /* Decompress directly into user's buffer. */ - if (! (*cinfo->coef->decompress_data) (cinfo, data)) - return 0; /* suspension forced, can do nothing more */ - - /* OK, we processed one iMCU row. */ - cinfo->output_scanline += lines_per_iMCU_row; - return lines_per_iMCU_row; -} - - -/* Additional entry points for buffered-image mode. */ - -#ifdef D_MULTISCAN_FILES_SUPPORTED - -/* - * Initialize for an output pass in buffered-image mode. - */ - -GLOBAL(boolean) -jpeg_start_output (j_decompress_ptr cinfo, int scan_number) -{ - if (cinfo->global_state != DSTATE_BUFIMAGE && - cinfo->global_state != DSTATE_PRESCAN) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - /* Limit scan number to valid range */ - if (scan_number <= 0) - scan_number = 1; - if (cinfo->inputctl->eoi_reached && - scan_number > cinfo->input_scan_number) - scan_number = cinfo->input_scan_number; - cinfo->output_scan_number = scan_number; - /* Perform any dummy output passes, and set up for the real pass */ - return output_pass_setup(cinfo); -} - - -/* - * Finish up after an output pass in buffered-image mode. - * - * Returns FALSE if suspended. The return value need be inspected only if - * a suspending data source is used. - */ - -GLOBAL(boolean) -jpeg_finish_output (j_decompress_ptr cinfo) -{ - if ((cinfo->global_state == DSTATE_SCANNING || - cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) { - /* Terminate this pass. */ - /* We do not require the whole pass to have been completed. */ - (*cinfo->master->finish_output_pass) (cinfo); - cinfo->global_state = DSTATE_BUFPOST; - } else if (cinfo->global_state != DSTATE_BUFPOST) { - /* BUFPOST = repeat call after a suspension, anything else is error */ - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - } - /* Read markers looking for SOS or EOI */ - while (cinfo->input_scan_number <= cinfo->output_scan_number && - ! cinfo->inputctl->eoi_reached) { - if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) - return FALSE; /* Suspend, come back later */ - } - cinfo->global_state = DSTATE_BUFIMAGE; - return TRUE; -} - -#endif /* D_MULTISCAN_FILES_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jdatasrc.c b/source/modules/juce_graphics/image_formats/jpglib/jdatasrc.c deleted file mode 100644 index bd4770e0a..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jdatasrc.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * jdatasrc.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains decompression data source routines for the case of - * reading JPEG data from a file (or any stdio stream). While these routines - * are sufficient for most applications, some will want to use a different - * source manager. - * IMPORTANT: we assume that fread() will correctly transcribe an array of - * JOCTETs from 8-bit-wide elements on external storage. If char is wider - * than 8 bits on your machine, you may need to do some tweaking. - */ - -/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ -#include "jinclude.h" -#include "jpeglib.h" -#include "jerror.h" - - -/* Expanded data source object for stdio input */ - -typedef struct { - struct jpeg_source_mgr pub; /* public fields */ - - FILE * infile; /* source stream */ - JOCTET * buffer; /* start of buffer */ - boolean start_of_file; /* have we gotten any data yet? */ -} my_source_mgr; - -typedef my_source_mgr * my_src_ptr; - -#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ - - -/* - * Initialize source --- called by jpeg_read_header - * before any data is actually read. - */ - -METHODDEF(void) -init_source (j_decompress_ptr cinfo) -{ - my_src_ptr src = (my_src_ptr) cinfo->src; - - /* We reset the empty-input-file flag for each image, - * but we don't clear the input buffer. - * This is correct behavior for reading a series of images from one source. - */ - src->start_of_file = TRUE; -} - - -/* - * Fill the input buffer --- called whenever buffer is emptied. - * - * In typical applications, this should read fresh data into the buffer - * (ignoring the current state of next_input_byte & bytes_in_buffer), - * reset the pointer & count to the start of the buffer, and return TRUE - * indicating that the buffer has been reloaded. It is not necessary to - * fill the buffer entirely, only to obtain at least one more byte. - * - * There is no such thing as an EOF return. If the end of the file has been - * reached, the routine has a choice of ERREXIT() or inserting fake data into - * the buffer. In most cases, generating a warning message and inserting a - * fake EOI marker is the best course of action --- this will allow the - * decompressor to output however much of the image is there. However, - * the resulting error message is misleading if the real problem is an empty - * input file, so we handle that case specially. - * - * In applications that need to be able to suspend compression due to input - * not being available yet, a FALSE return indicates that no more data can be - * obtained right now, but more may be forthcoming later. In this situation, - * the decompressor will return to its caller (with an indication of the - * number of scanlines it has read, if any). The application should resume - * decompression after it has loaded more data into the input buffer. Note - * that there are substantial restrictions on the use of suspension --- see - * the documentation. - * - * When suspending, the decompressor will back up to a convenient restart point - * (typically the start of the current MCU). next_input_byte & bytes_in_buffer - * indicate where the restart point will be if the current call returns FALSE. - * Data beyond this point must be rescanned after resumption, so move it to - * the front of the buffer rather than discarding it. - */ - -METHODDEF(boolean) -fill_input_buffer (j_decompress_ptr cinfo) -{ - my_src_ptr src = (my_src_ptr) cinfo->src; - size_t nbytes; - - nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE); - - if (nbytes <= 0) { - if (src->start_of_file) /* Treat empty input file as fatal error */ - ERREXIT(cinfo, JERR_INPUT_EMPTY); - WARNMS(cinfo, JWRN_JPEG_EOF); - /* Insert a fake EOI marker */ - src->buffer[0] = (JOCTET) 0xFF; - src->buffer[1] = (JOCTET) JPEG_EOI; - nbytes = 2; - } - - src->pub.next_input_byte = src->buffer; - src->pub.bytes_in_buffer = nbytes; - src->start_of_file = FALSE; - - return TRUE; -} - - -/* - * Skip data --- used to skip over a potentially large amount of - * uninteresting data (such as an APPn marker). - * - * Writers of suspendable-input applications must note that skip_input_data - * is not granted the right to give a suspension return. If the skip extends - * beyond the data currently in the buffer, the buffer can be marked empty so - * that the next read will cause a fill_input_buffer call that can suspend. - * Arranging for additional bytes to be discarded before reloading the input - * buffer is the application writer's problem. - */ - -METHODDEF(void) -skip_input_data (j_decompress_ptr cinfo, long num_bytes) -{ - my_src_ptr src = (my_src_ptr) cinfo->src; - - /* Just a dumb implementation for now. Could use fseek() except - * it doesn't work on pipes. Not clear that being smart is worth - * any trouble anyway --- large skips are infrequent. - */ - if (num_bytes > 0) { - while (num_bytes > (long) src->pub.bytes_in_buffer) { - num_bytes -= (long) src->pub.bytes_in_buffer; - (void) fill_input_buffer(cinfo); - /* note we assume that fill_input_buffer will never return FALSE, - * so suspension need not be handled. - */ - } - src->pub.next_input_byte += (size_t) num_bytes; - src->pub.bytes_in_buffer -= (size_t) num_bytes; - } -} - - -/* - * An additional method that can be provided by data source modules is the - * resync_to_restart method for error recovery in the presence of RST markers. - * For the moment, this source module just uses the default resync method - * provided by the JPEG library. That method assumes that no backtracking - * is possible. - */ - - -/* - * Terminate source --- called by jpeg_finish_decompress - * after all data has been read. Often a no-op. - * - * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding - * application must deal with any cleanup that should happen even - * for error exit. - */ - -METHODDEF(void) -term_source (j_decompress_ptr) -{ - /* no work necessary here */ -} - - -/* - * Prepare for input from a stdio stream. - * The caller must have already opened the stream, and is responsible - * for closing it after finishing decompression. - */ - -GLOBAL(void) -jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile) -{ - my_src_ptr src; - - /* The source object and input buffer are made permanent so that a series - * of JPEG images can be read from the same file by calling jpeg_stdio_src - * only before the first one. (If we discarded the buffer at the end of - * one image, we'd likely lose the start of the next one.) - * This makes it unsafe to use this manager and a different source - * manager serially with the same JPEG object. Caveat programmer. - */ - if (cinfo->src == NULL) { /* first time for this JPEG object? */ - cinfo->src = (struct jpeg_source_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - SIZEOF(my_source_mgr)); - src = (my_src_ptr) cinfo->src; - src->buffer = (JOCTET *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - INPUT_BUF_SIZE * SIZEOF(JOCTET)); - } - - src = (my_src_ptr) cinfo->src; - src->pub.init_source = init_source; - src->pub.fill_input_buffer = fill_input_buffer; - src->pub.skip_input_data = skip_input_data; - src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ - src->pub.term_source = term_source; - src->infile = infile; - src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ - src->pub.next_input_byte = NULL; /* until buffer loaded */ -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jdcoefct.c b/source/modules/juce_graphics/image_formats/jpglib/jdcoefct.c deleted file mode 100644 index 4f15e631c..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jdcoefct.c +++ /dev/null @@ -1,736 +0,0 @@ -/* - * jdcoefct.c - * - * Copyright (C) 1994-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains the coefficient buffer controller for decompression. - * This controller is the top level of the JPEG decompressor proper. - * The coefficient buffer lies between entropy decoding and inverse-DCT steps. - * - * In buffered-image mode, this controller is the interface between - * input-oriented processing and output-oriented processing. - * Also, the input side (only) is used when reading a file for transcoding. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - -/* Block smoothing is only applicable for progressive JPEG, so: */ -#ifndef D_PROGRESSIVE_SUPPORTED -#undef BLOCK_SMOOTHING_SUPPORTED -#endif - -/* Private buffer controller object */ - -typedef struct { - struct jpeg_d_coef_controller pub; /* public fields */ - - /* These variables keep track of the current location of the input side. */ - /* cinfo->input_iMCU_row is also used for this. */ - JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ - int MCU_vert_offset; /* counts MCU rows within iMCU row */ - int MCU_rows_per_iMCU_row; /* number of such rows needed */ - - /* The output side's location is represented by cinfo->output_iMCU_row. */ - - /* In single-pass modes, it's sufficient to buffer just one MCU. - * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks, - * and let the entropy decoder write into that workspace each time. - * (On 80x86, the workspace is FAR even though it's not really very big; - * this is to keep the module interfaces unchanged when a large coefficient - * buffer is necessary.) - * In multi-pass modes, this array points to the current MCU's blocks - * within the virtual arrays; it is used only by the input side. - */ - JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU]; - -#ifdef D_MULTISCAN_FILES_SUPPORTED - /* In multi-pass modes, we need a virtual block array for each component. */ - jvirt_barray_ptr whole_image[MAX_COMPONENTS]; -#endif - -#ifdef BLOCK_SMOOTHING_SUPPORTED - /* When doing block smoothing, we latch coefficient Al values here */ - int * coef_bits_latch; -#define SAVED_COEFS 6 /* we save coef_bits[0..5] */ -#endif -} my_coef_controller3; - -typedef my_coef_controller3 * my_coef_ptr3; - -/* Forward declarations */ -METHODDEF(int) decompress_onepass - JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); -#ifdef D_MULTISCAN_FILES_SUPPORTED -METHODDEF(int) decompress_data - JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); -#endif -#ifdef BLOCK_SMOOTHING_SUPPORTED -LOCAL(boolean) smoothing_ok JPP((j_decompress_ptr cinfo)); -METHODDEF(int) decompress_smooth_data - JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); -#endif - - -LOCAL(void) -start_iMCU_row3 (j_decompress_ptr cinfo) -/* Reset within-iMCU-row counters for a new row (input side) */ -{ - my_coef_ptr3 coef = (my_coef_ptr3) cinfo->coef; - - /* In an interleaved scan, an MCU row is the same as an iMCU row. - * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. - * But at the bottom of the image, process only what's left. - */ - if (cinfo->comps_in_scan > 1) { - coef->MCU_rows_per_iMCU_row = 1; - } else { - if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1)) - coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; - else - coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; - } - - coef->MCU_ctr = 0; - coef->MCU_vert_offset = 0; -} - - -/* - * Initialize for an input processing pass. - */ - -METHODDEF(void) -start_input_pass (j_decompress_ptr cinfo) -{ - cinfo->input_iMCU_row = 0; - start_iMCU_row3(cinfo); -} - - -/* - * Initialize for an output processing pass. - */ - -METHODDEF(void) -start_output_pass (j_decompress_ptr cinfo) -{ -#ifdef BLOCK_SMOOTHING_SUPPORTED - my_coef_ptr3 coef = (my_coef_ptr3) cinfo->coef; - - /* If multipass, check to see whether to use block smoothing on this pass */ - if (coef->pub.coef_arrays != NULL) { - if (cinfo->do_block_smoothing && smoothing_ok(cinfo)) - coef->pub.decompress_data = decompress_smooth_data; - else - coef->pub.decompress_data = decompress_data; - } -#endif - cinfo->output_iMCU_row = 0; -} - - -/* - * Decompress and return some data in the single-pass case. - * Always attempts to emit one fully interleaved MCU row ("iMCU" row). - * Input and output must run in lockstep since we have only a one-MCU buffer. - * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. - * - * NB: output_buf contains a plane for each component in image, - * which we index according to the component's SOF position. - */ - -METHODDEF(int) -decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) -{ - my_coef_ptr3 coef = (my_coef_ptr3) cinfo->coef; - JDIMENSION MCU_col_num; /* index of current MCU within row */ - JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; - JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; - int blkn, ci, xindex, yindex, yoffset, useful_width; - JSAMPARRAY output_ptr; - JDIMENSION start_col, output_col; - jpeg_component_info *compptr; - inverse_DCT_method_ptr inverse_DCT; - - /* Loop to process as much as one whole iMCU row */ - for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; - yoffset++) { - for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col; - MCU_col_num++) { - /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */ - jzero_far((void FAR *) coef->MCU_buffer[0], - (size_t) (cinfo->blocks_in_MCU * SIZEOF(JBLOCK))); - if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { - /* Suspension forced; update state counters and exit */ - coef->MCU_vert_offset = yoffset; - coef->MCU_ctr = MCU_col_num; - return JPEG_SUSPENDED; - } - /* Determine where data should go in output_buf and do the IDCT thing. - * We skip dummy blocks at the right and bottom edges (but blkn gets - * incremented past them!). Note the inner loop relies on having - * allocated the MCU_buffer[] blocks sequentially. - */ - blkn = 0; /* index of current DCT block within MCU */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - /* Don't bother to IDCT an uninteresting component. */ - if (! compptr->component_needed) { - blkn += compptr->MCU_blocks; - continue; - } - inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index]; - useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width - : compptr->last_col_width; - output_ptr = output_buf[compptr->component_index] + - yoffset * compptr->DCT_scaled_size; - start_col = MCU_col_num * compptr->MCU_sample_width; - for (yindex = 0; yindex < compptr->MCU_height; yindex++) { - if (cinfo->input_iMCU_row < last_iMCU_row || - yoffset+yindex < compptr->last_row_height) { - output_col = start_col; - for (xindex = 0; xindex < useful_width; xindex++) { - (*inverse_DCT) (cinfo, compptr, - (JCOEFPTR) coef->MCU_buffer[blkn+xindex], - output_ptr, output_col); - output_col += compptr->DCT_scaled_size; - } - } - blkn += compptr->MCU_width; - output_ptr += compptr->DCT_scaled_size; - } - } - } - /* Completed an MCU row, but perhaps not an iMCU row */ - coef->MCU_ctr = 0; - } - /* Completed the iMCU row, advance counters for next one */ - cinfo->output_iMCU_row++; - if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { - start_iMCU_row3(cinfo); - return JPEG_ROW_COMPLETED; - } - /* Completed the scan */ - (*cinfo->inputctl->finish_input_pass) (cinfo); - return JPEG_SCAN_COMPLETED; -} - - -/* - * Dummy consume-input routine for single-pass operation. - */ - -METHODDEF(int) -dummy_consume_data (j_decompress_ptr) -{ - return JPEG_SUSPENDED; /* Always indicate nothing was done */ -} - - -#ifdef D_MULTISCAN_FILES_SUPPORTED - -/* - * Consume input data and store it in the full-image coefficient buffer. - * We read as much as one fully interleaved MCU row ("iMCU" row) per call, - * ie, v_samp_factor block rows for each component in the scan. - * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. - */ - -METHODDEF(int) -consume_data (j_decompress_ptr cinfo) -{ - my_coef_ptr3 coef = (my_coef_ptr3) cinfo->coef; - JDIMENSION MCU_col_num; /* index of current MCU within row */ - int blkn, ci, xindex, yindex, yoffset; - JDIMENSION start_col; - JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; - JBLOCKROW buffer_ptr; - jpeg_component_info *compptr; - - /* Align the virtual buffers for the components used in this scan. */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - buffer[ci] = (*cinfo->mem->access_virt_barray) - ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], - cinfo->input_iMCU_row * compptr->v_samp_factor, - (JDIMENSION) compptr->v_samp_factor, TRUE); - /* Note: entropy decoder expects buffer to be zeroed, - * but this is handled automatically by the memory manager - * because we requested a pre-zeroed array. - */ - } - - /* Loop to process one whole iMCU row */ - for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; - yoffset++) { - for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row; - MCU_col_num++) { - /* Construct list of pointers to DCT blocks belonging to this MCU */ - blkn = 0; /* index of current DCT block within MCU */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - start_col = MCU_col_num * compptr->MCU_width; - for (yindex = 0; yindex < compptr->MCU_height; yindex++) { - buffer_ptr = buffer[ci][yindex+yoffset] + start_col; - for (xindex = 0; xindex < compptr->MCU_width; xindex++) { - coef->MCU_buffer[blkn++] = buffer_ptr++; - } - } - } - /* Try to fetch the MCU. */ - if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { - /* Suspension forced; update state counters and exit */ - coef->MCU_vert_offset = yoffset; - coef->MCU_ctr = MCU_col_num; - return JPEG_SUSPENDED; - } - } - /* Completed an MCU row, but perhaps not an iMCU row */ - coef->MCU_ctr = 0; - } - /* Completed the iMCU row, advance counters for next one */ - if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { - start_iMCU_row3(cinfo); - return JPEG_ROW_COMPLETED; - } - /* Completed the scan */ - (*cinfo->inputctl->finish_input_pass) (cinfo); - return JPEG_SCAN_COMPLETED; -} - - -/* - * Decompress and return some data in the multi-pass case. - * Always attempts to emit one fully interleaved MCU row ("iMCU" row). - * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. - * - * NB: output_buf contains a plane for each component in image. - */ - -METHODDEF(int) -decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) -{ - my_coef_ptr3 coef = (my_coef_ptr3) cinfo->coef; - JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; - JDIMENSION block_num; - int ci, block_row, block_rows; - JBLOCKARRAY buffer; - JBLOCKROW buffer_ptr; - JSAMPARRAY output_ptr; - JDIMENSION output_col; - jpeg_component_info *compptr; - inverse_DCT_method_ptr inverse_DCT; - - /* Force some input to be done if we are getting ahead of the input. */ - while (cinfo->input_scan_number < cinfo->output_scan_number || - (cinfo->input_scan_number == cinfo->output_scan_number && - cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) { - if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) - return JPEG_SUSPENDED; - } - - /* OK, output from the virtual arrays. */ - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Don't bother to IDCT an uninteresting component. */ - if (! compptr->component_needed) - continue; - /* Align the virtual buffer for this component. */ - buffer = (*cinfo->mem->access_virt_barray) - ((j_common_ptr) cinfo, coef->whole_image[ci], - cinfo->output_iMCU_row * compptr->v_samp_factor, - (JDIMENSION) compptr->v_samp_factor, FALSE); - /* Count non-dummy DCT block rows in this iMCU row. */ - if (cinfo->output_iMCU_row < last_iMCU_row) - block_rows = compptr->v_samp_factor; - else { - /* NB: can't use last_row_height here; it is input-side-dependent! */ - block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); - if (block_rows == 0) block_rows = compptr->v_samp_factor; - } - inverse_DCT = cinfo->idct->inverse_DCT[ci]; - output_ptr = output_buf[ci]; - /* Loop over all DCT blocks to be processed. */ - for (block_row = 0; block_row < block_rows; block_row++) { - buffer_ptr = buffer[block_row]; - output_col = 0; - for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) { - (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr, - output_ptr, output_col); - buffer_ptr++; - output_col += compptr->DCT_scaled_size; - } - output_ptr += compptr->DCT_scaled_size; - } - } - - if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) - return JPEG_ROW_COMPLETED; - return JPEG_SCAN_COMPLETED; -} - -#endif /* D_MULTISCAN_FILES_SUPPORTED */ - - -#ifdef BLOCK_SMOOTHING_SUPPORTED - -/* - * This code applies interblock smoothing as described by section K.8 - * of the JPEG standard: the first 5 AC coefficients are estimated from - * the DC values of a DCT block and its 8 neighboring blocks. - * We apply smoothing only for progressive JPEG decoding, and only if - * the coefficients it can estimate are not yet known to full precision. - */ - -/* Natural-order array positions of the first 5 zigzag-order coefficients */ -#define Q01_POS 1 -#define Q10_POS 8 -#define Q20_POS 16 -#define Q11_POS 9 -#define Q02_POS 2 - -/* - * Determine whether block smoothing is applicable and safe. - * We also latch the current states of the coef_bits[] entries for the - * AC coefficients; otherwise, if the input side of the decompressor - * advances into a new scan, we might think the coefficients are known - * more accurately than they really are. - */ - -LOCAL(boolean) -smoothing_ok (j_decompress_ptr cinfo) -{ - my_coef_ptr3 coef = (my_coef_ptr3) cinfo->coef; - boolean smoothing_useful = FALSE; - int ci, coefi; - jpeg_component_info *compptr; - JQUANT_TBL * qtable; - int * coef_bits; - int * coef_bits_latch; - - if (! cinfo->progressive_mode || cinfo->coef_bits == NULL) - return FALSE; - - /* Allocate latch area if not already done */ - if (coef->coef_bits_latch == NULL) - coef->coef_bits_latch = (int *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - cinfo->num_components * - (SAVED_COEFS * SIZEOF(int))); - coef_bits_latch = coef->coef_bits_latch; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* All components' quantization values must already be latched. */ - if ((qtable = compptr->quant_table) == NULL) - return FALSE; - /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */ - if (qtable->quantval[0] == 0 || - qtable->quantval[Q01_POS] == 0 || - qtable->quantval[Q10_POS] == 0 || - qtable->quantval[Q20_POS] == 0 || - qtable->quantval[Q11_POS] == 0 || - qtable->quantval[Q02_POS] == 0) - return FALSE; - /* DC values must be at least partly known for all components. */ - coef_bits = cinfo->coef_bits[ci]; - if (coef_bits[0] < 0) - return FALSE; - /* Block smoothing is helpful if some AC coefficients remain inaccurate. */ - for (coefi = 1; coefi <= 5; coefi++) { - coef_bits_latch[coefi] = coef_bits[coefi]; - if (coef_bits[coefi] != 0) - smoothing_useful = TRUE; - } - coef_bits_latch += SAVED_COEFS; - } - - return smoothing_useful; -} - - -/* - * Variant of decompress_data for use when doing block smoothing. - */ - -METHODDEF(int) -decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) -{ - my_coef_ptr3 coef = (my_coef_ptr3) cinfo->coef; - JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; - JDIMENSION block_num, last_block_column; - int ci, block_row, block_rows, access_rows; - JBLOCKARRAY buffer; - JBLOCKROW buffer_ptr, prev_block_row, next_block_row; - JSAMPARRAY output_ptr; - JDIMENSION output_col; - jpeg_component_info *compptr; - inverse_DCT_method_ptr inverse_DCT; - boolean first_row, last_row; - JBLOCK workspace; - int *coef_bits; - JQUANT_TBL *quanttbl; - INT32 Q00,Q01,Q02,Q10,Q11,Q20, num; - int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9; - int Al, pred; - - /* Force some input to be done if we are getting ahead of the input. */ - while (cinfo->input_scan_number <= cinfo->output_scan_number && - ! cinfo->inputctl->eoi_reached) { - if (cinfo->input_scan_number == cinfo->output_scan_number) { - /* If input is working on current scan, we ordinarily want it to - * have completed the current row. But if input scan is DC, - * we want it to keep one row ahead so that next block row's DC - * values are up to date. - */ - JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0; - if (cinfo->input_iMCU_row > cinfo->output_iMCU_row+delta) - break; - } - if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) - return JPEG_SUSPENDED; - } - - /* OK, output from the virtual arrays. */ - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Don't bother to IDCT an uninteresting component. */ - if (! compptr->component_needed) - continue; - /* Count non-dummy DCT block rows in this iMCU row. */ - if (cinfo->output_iMCU_row < last_iMCU_row) { - block_rows = compptr->v_samp_factor; - access_rows = block_rows * 2; /* this and next iMCU row */ - last_row = FALSE; - } else { - /* NB: can't use last_row_height here; it is input-side-dependent! */ - block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); - if (block_rows == 0) block_rows = compptr->v_samp_factor; - access_rows = block_rows; /* this iMCU row only */ - last_row = TRUE; - } - /* Align the virtual buffer for this component. */ - if (cinfo->output_iMCU_row > 0) { - access_rows += compptr->v_samp_factor; /* prior iMCU row too */ - buffer = (*cinfo->mem->access_virt_barray) - ((j_common_ptr) cinfo, coef->whole_image[ci], - (cinfo->output_iMCU_row - 1) * compptr->v_samp_factor, - (JDIMENSION) access_rows, FALSE); - buffer += compptr->v_samp_factor; /* point to current iMCU row */ - first_row = FALSE; - } else { - buffer = (*cinfo->mem->access_virt_barray) - ((j_common_ptr) cinfo, coef->whole_image[ci], - (JDIMENSION) 0, (JDIMENSION) access_rows, FALSE); - first_row = TRUE; - } - /* Fetch component-dependent info */ - coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS); - quanttbl = compptr->quant_table; - Q00 = quanttbl->quantval[0]; - Q01 = quanttbl->quantval[Q01_POS]; - Q10 = quanttbl->quantval[Q10_POS]; - Q20 = quanttbl->quantval[Q20_POS]; - Q11 = quanttbl->quantval[Q11_POS]; - Q02 = quanttbl->quantval[Q02_POS]; - inverse_DCT = cinfo->idct->inverse_DCT[ci]; - output_ptr = output_buf[ci]; - /* Loop over all DCT blocks to be processed. */ - for (block_row = 0; block_row < block_rows; block_row++) { - buffer_ptr = buffer[block_row]; - if (first_row && block_row == 0) - prev_block_row = buffer_ptr; - else - prev_block_row = buffer[block_row-1]; - if (last_row && block_row == block_rows-1) - next_block_row = buffer_ptr; - else - next_block_row = buffer[block_row+1]; - /* We fetch the surrounding DC values using a sliding-register approach. - * Initialize all nine here so as to do the right thing on narrow pics. - */ - DC1 = DC2 = DC3 = (int) prev_block_row[0][0]; - DC4 = DC5 = DC6 = (int) buffer_ptr[0][0]; - DC7 = DC8 = DC9 = (int) next_block_row[0][0]; - output_col = 0; - last_block_column = compptr->width_in_blocks - 1; - for (block_num = 0; block_num <= last_block_column; block_num++) { - /* Fetch current DCT block into workspace so we can modify it. */ - jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1); - /* Update DC values */ - if (block_num < last_block_column) { - DC3 = (int) prev_block_row[1][0]; - DC6 = (int) buffer_ptr[1][0]; - DC9 = (int) next_block_row[1][0]; - } - /* Compute coefficient estimates per K.8. - * An estimate is applied only if coefficient is still zero, - * and is not known to be fully accurate. - */ - /* AC01 */ - if ((Al=coef_bits[1]) != 0 && workspace[1] == 0) { - num = 36 * Q00 * (DC4 - DC6); - if (num >= 0) { - pred = (int) (((Q01<<7) + num) / (Q01<<8)); - if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { - pred = (int) (((Q10<<7) + num) / (Q10<<8)); - if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { - pred = (int) (((Q20<<7) + num) / (Q20<<8)); - if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { - pred = (int) (((Q11<<7) + num) / (Q11<<8)); - if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { - pred = (int) (((Q02<<7) + num) / (Q02<<8)); - if (Al > 0 && pred >= (1< 0 && pred >= (1<DCT_scaled_size; - } - output_ptr += compptr->DCT_scaled_size; - } - } - - if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) - return JPEG_ROW_COMPLETED; - return JPEG_SCAN_COMPLETED; -} - -#endif /* BLOCK_SMOOTHING_SUPPORTED */ - - -/* - * Initialize coefficient buffer controller. - */ - -GLOBAL(void) -jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer) -{ - my_coef_ptr3 coef; - - coef = (my_coef_ptr3) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_coef_controller3)); - cinfo->coef = (struct jpeg_d_coef_controller *) coef; - coef->pub.start_input_pass = start_input_pass; - coef->pub.start_output_pass = start_output_pass; -#ifdef BLOCK_SMOOTHING_SUPPORTED - coef->coef_bits_latch = NULL; -#endif - - /* Create the coefficient buffer. */ - if (need_full_buffer) { -#ifdef D_MULTISCAN_FILES_SUPPORTED - /* Allocate a full-image virtual array for each component, */ - /* padded to a multiple of samp_factor DCT blocks in each direction. */ - /* Note we ask for a pre-zeroed array. */ - int ci, access_rows; - jpeg_component_info *compptr; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - access_rows = compptr->v_samp_factor; -#ifdef BLOCK_SMOOTHING_SUPPORTED - /* If block smoothing could be used, need a bigger window */ - if (cinfo->progressive_mode) - access_rows *= 3; -#endif - coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE, - (JDIMENSION) jround_up((long) compptr->width_in_blocks, - (long) compptr->h_samp_factor), - (JDIMENSION) jround_up((long) compptr->height_in_blocks, - (long) compptr->v_samp_factor), - (JDIMENSION) access_rows); - } - coef->pub.consume_data = consume_data; - coef->pub.decompress_data = decompress_data; - coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */ -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif - } else { - /* We only need a single-MCU buffer. */ - JBLOCKROW buffer; - int i; - - buffer = (JBLOCKROW) - (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, - D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); - for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) { - coef->MCU_buffer[i] = buffer + i; - } - coef->pub.consume_data = dummy_consume_data; - coef->pub.decompress_data = decompress_onepass; - coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */ - } -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jdcolor.c b/source/modules/juce_graphics/image_formats/jpglib/jdcolor.c deleted file mode 100644 index 30763e921..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jdcolor.c +++ /dev/null @@ -1,396 +0,0 @@ -/* - * jdcolor.c - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains output colorspace conversion routines. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Private subobject */ - -typedef struct { - struct jpeg_color_deconverter pub; /* public fields */ - - /* Private state for YCC->RGB conversion */ - int * Cr_r_tab; /* => table for Cr to R conversion */ - int * Cb_b_tab; /* => table for Cb to B conversion */ - INT32 * Cr_g_tab; /* => table for Cr to G conversion */ - INT32 * Cb_g_tab; /* => table for Cb to G conversion */ -} my_color_deconverter2; - -typedef my_color_deconverter2 * my_cconvert_ptr2; - - -/**************** YCbCr -> RGB conversion: most common case **************/ - -/* - * YCbCr is defined per CCIR 601-1, except that Cb and Cr are - * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. - * The conversion equations to be implemented are therefore - * R = Y + 1.40200 * Cr - * G = Y - 0.34414 * Cb - 0.71414 * Cr - * B = Y + 1.77200 * Cb - * where Cb and Cr represent the incoming values less CENTERJSAMPLE. - * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) - * - * To avoid floating-point arithmetic, we represent the fractional constants - * as integers scaled up by 2^16 (about 4 digits precision); we have to divide - * the products by 2^16, with appropriate rounding, to get the correct answer. - * Notice that Y, being an integral input, does not contribute any fraction - * so it need not participate in the rounding. - * - * For even more speed, we avoid doing any multiplications in the inner loop - * by precalculating the constants times Cb and Cr for all possible values. - * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); - * for 12-bit samples it is still acceptable. It's not very reasonable for - * 16-bit samples, but if you want lossless storage you shouldn't be changing - * colorspace anyway. - * The Cr=>R and Cb=>B values can be rounded to integers in advance; the - * values for the G calculation are left scaled up, since we must add them - * together before rounding. - */ - -#define SCALEBITS 16 /* speediest right-shift on some machines */ -#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) -#define FIX(x) ((INT32) ((x) * (1L<RGB colorspace conversion. - */ - -LOCAL(void) -build_ycc_rgb_table (j_decompress_ptr cinfo) -{ - my_cconvert_ptr2 cconvert = (my_cconvert_ptr2) cinfo->cconvert; - int i; - INT32 x; - SHIFT_TEMPS - - cconvert->Cr_r_tab = (int *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)); - cconvert->Cb_b_tab = (int *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)); - cconvert->Cr_g_tab = (INT32 *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)); - cconvert->Cb_g_tab = (INT32 *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)); - - for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { - /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ - /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ - /* Cr=>R value is nearest int to 1.40200 * x */ - cconvert->Cr_r_tab[i] = (int) - RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); - /* Cb=>B value is nearest int to 1.77200 * x */ - cconvert->Cb_b_tab[i] = (int) - RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); - /* Cr=>G value is scaled-up -0.71414 * x */ - cconvert->Cr_g_tab[i] = (- FIX(0.71414)) * x; - /* Cb=>G value is scaled-up -0.34414 * x */ - /* We also add in ONE_HALF so that need not do it in inner loop */ - cconvert->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF; - } -} - - -/* - * Convert some rows of samples to the output colorspace. - * - * Note that we change from noninterleaved, one-plane-per-component format - * to interleaved-pixel format. The output buffer is therefore three times - * as wide as the input buffer. - * A starting row offset is provided only for the input buffer. The caller - * can easily adjust the passed output_buf value to accommodate any row - * offset required on that side. - */ - -METHODDEF(void) -ycc_rgb_convert (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION input_row, - JSAMPARRAY output_buf, int num_rows) -{ - my_cconvert_ptr2 cconvert = (my_cconvert_ptr2) cinfo->cconvert; - int y, cb, cr; - JSAMPROW outptr; - JSAMPROW inptr0, inptr1, inptr2; - JDIMENSION col; - JDIMENSION num_cols = cinfo->output_width; - /* copy these pointers into registers if possible */ - JSAMPLE * range_limit = cinfo->sample_range_limit; - int * Crrtab = cconvert->Cr_r_tab; - int * Cbbtab = cconvert->Cb_b_tab; - INT32 * Crgtab = cconvert->Cr_g_tab; - INT32 * Cbgtab = cconvert->Cb_g_tab; - SHIFT_TEMPS - - while (--num_rows >= 0) { - inptr0 = input_buf[0][input_row]; - inptr1 = input_buf[1][input_row]; - inptr2 = input_buf[2][input_row]; - input_row++; - outptr = *output_buf++; - for (col = 0; col < num_cols; col++) { - y = GETJSAMPLE(inptr0[col]); - cb = GETJSAMPLE(inptr1[col]); - cr = GETJSAMPLE(inptr2[col]); - /* Range-limiting is essential due to noise introduced by DCT losses. */ - outptr[RGB_RED] = range_limit[y + Crrtab[cr]]; - outptr[RGB_GREEN] = range_limit[y + - ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], - SCALEBITS))]; - outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]]; - outptr += RGB_PIXELSIZE; - } - } -} - - -/**************** Cases other than YCbCr -> RGB **************/ - - -/* - * Color conversion for no colorspace change: just copy the data, - * converting from separate-planes to interleaved representation. - */ - -METHODDEF(void) -null_convert2 (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION input_row, - JSAMPARRAY output_buf, int num_rows) -{ - JSAMPROW inptr, outptr; - JDIMENSION count; - int num_components = cinfo->num_components; - JDIMENSION num_cols = cinfo->output_width; - int ci; - - while (--num_rows >= 0) { - for (ci = 0; ci < num_components; ci++) { - inptr = input_buf[ci][input_row]; - outptr = output_buf[0] + ci; - for (count = num_cols; count > 0; count--) { - *outptr = *inptr++; /* needn't bother with GETJSAMPLE() here */ - outptr += num_components; - } - } - input_row++; - output_buf++; - } -} - - -/* - * Color conversion for grayscale: just copy the data. - * This also works for YCbCr -> grayscale conversion, in which - * we just copy the Y (luminance) component and ignore chrominance. - */ - -METHODDEF(void) -grayscale_convert2 (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION input_row, - JSAMPARRAY output_buf, int num_rows) -{ - jcopy_sample_rows(input_buf[0], (int) input_row, output_buf, 0, - num_rows, cinfo->output_width); -} - - -/* - * Convert grayscale to RGB: just duplicate the graylevel three times. - * This is provided to support applications that don't want to cope - * with grayscale as a separate case. - */ - -METHODDEF(void) -gray_rgb_convert (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION input_row, - JSAMPARRAY output_buf, int num_rows) -{ - JSAMPROW inptr, outptr; - JDIMENSION col; - JDIMENSION num_cols = cinfo->output_width; - - while (--num_rows >= 0) { - inptr = input_buf[0][input_row++]; - outptr = *output_buf++; - for (col = 0; col < num_cols; col++) { - /* We can dispense with GETJSAMPLE() here */ - outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col]; - outptr += RGB_PIXELSIZE; - } - } -} - - -/* - * Adobe-style YCCK->CMYK conversion. - * We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same - * conversion as above, while passing K (black) unchanged. - * We assume build_ycc_rgb_table has been called. - */ - -METHODDEF(void) -ycck_cmyk_convert (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION input_row, - JSAMPARRAY output_buf, int num_rows) -{ - my_cconvert_ptr2 cconvert = (my_cconvert_ptr2) cinfo->cconvert; - int y, cb, cr; - JSAMPROW outptr; - JSAMPROW inptr0, inptr1, inptr2, inptr3; - JDIMENSION col; - JDIMENSION num_cols = cinfo->output_width; - /* copy these pointers into registers if possible */ - JSAMPLE * range_limit = cinfo->sample_range_limit; - int * Crrtab = cconvert->Cr_r_tab; - int * Cbbtab = cconvert->Cb_b_tab; - INT32 * Crgtab = cconvert->Cr_g_tab; - INT32 * Cbgtab = cconvert->Cb_g_tab; - SHIFT_TEMPS - - while (--num_rows >= 0) { - inptr0 = input_buf[0][input_row]; - inptr1 = input_buf[1][input_row]; - inptr2 = input_buf[2][input_row]; - inptr3 = input_buf[3][input_row]; - input_row++; - outptr = *output_buf++; - for (col = 0; col < num_cols; col++) { - y = GETJSAMPLE(inptr0[col]); - cb = GETJSAMPLE(inptr1[col]); - cr = GETJSAMPLE(inptr2[col]); - /* Range-limiting is essential due to noise introduced by DCT losses. */ - outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */ - outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */ - ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], - SCALEBITS)))]; - outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */ - /* K passes through unchanged */ - outptr[3] = inptr3[col]; /* don't need GETJSAMPLE here */ - outptr += 4; - } - } -} - - -/* - * Empty method for start_pass. - */ - -METHODDEF(void) -start_pass_dcolor (j_decompress_ptr) -{ - /* no work needed */ -} - - -/* - * Module initialization routine for output colorspace conversion. - */ - -GLOBAL(void) -jinit_color_deconverter (j_decompress_ptr cinfo) -{ - my_cconvert_ptr2 cconvert; - int ci; - - cconvert = (my_cconvert_ptr2) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_color_deconverter2)); - cinfo->cconvert = (struct jpeg_color_deconverter *) cconvert; - cconvert->pub.start_pass = start_pass_dcolor; - - /* Make sure num_components agrees with jpeg_color_space */ - switch (cinfo->jpeg_color_space) { - case JCS_GRAYSCALE: - if (cinfo->num_components != 1) - ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); - break; - - case JCS_RGB: - case JCS_YCbCr: - if (cinfo->num_components != 3) - ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); - break; - - case JCS_CMYK: - case JCS_YCCK: - if (cinfo->num_components != 4) - ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); - break; - - default: /* JCS_UNKNOWN can be anything */ - if (cinfo->num_components < 1) - ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); - break; - } - - /* Set out_color_components and conversion method based on requested space. - * Also clear the component_needed flags for any unused components, - * so that earlier pipeline stages can avoid useless computation. - */ - - switch (cinfo->out_color_space) { - case JCS_GRAYSCALE: - cinfo->out_color_components = 1; - if (cinfo->jpeg_color_space == JCS_GRAYSCALE || - cinfo->jpeg_color_space == JCS_YCbCr) { - cconvert->pub.color_convert = grayscale_convert2; - /* For color->grayscale conversion, only the Y (0) component is needed */ - for (ci = 1; ci < cinfo->num_components; ci++) - cinfo->comp_info[ci].component_needed = FALSE; - } else - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - break; - - case JCS_RGB: - cinfo->out_color_components = RGB_PIXELSIZE; - if (cinfo->jpeg_color_space == JCS_YCbCr) { - cconvert->pub.color_convert = ycc_rgb_convert; - build_ycc_rgb_table(cinfo); - } else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) { - cconvert->pub.color_convert = gray_rgb_convert; - } else if (cinfo->jpeg_color_space == JCS_RGB && RGB_PIXELSIZE == 3) { - cconvert->pub.color_convert = null_convert2; - } else - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - break; - - case JCS_CMYK: - cinfo->out_color_components = 4; - if (cinfo->jpeg_color_space == JCS_YCCK) { - cconvert->pub.color_convert = ycck_cmyk_convert; - build_ycc_rgb_table(cinfo); - } else if (cinfo->jpeg_color_space == JCS_CMYK) { - cconvert->pub.color_convert = null_convert2; - } else - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - break; - - default: - /* Permit null conversion to same output space */ - if (cinfo->out_color_space == cinfo->jpeg_color_space) { - cinfo->out_color_components = cinfo->num_components; - cconvert->pub.color_convert = null_convert2; - } else /* unsupported non-null conversion */ - ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); - break; - } - - if (cinfo->quantize_colors) - cinfo->output_components = 1; /* single colormapped output component */ - else - cinfo->output_components = cinfo->out_color_components; -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jdct.h b/source/modules/juce_graphics/image_formats/jpglib/jdct.h deleted file mode 100644 index d8df1b4c5..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jdct.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * jdct.h - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This include file contains common declarations for the forward and - * inverse DCT modules. These declarations are private to the DCT managers - * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms. - * The individual DCT algorithms are kept in separate files to ease - * machine-dependent tuning (e.g., assembly coding). - */ - - -/* - * A forward DCT routine is given a pointer to a work area of type DCTELEM[]; - * the DCT is to be performed in-place in that buffer. Type DCTELEM is int - * for 8-bit samples, INT32 for 12-bit samples. (NOTE: Floating-point DCT - * implementations use an array of type FAST_FLOAT, instead.) - * The DCT inputs are expected to be signed (range +-CENTERJSAMPLE). - * The DCT outputs are returned scaled up by a factor of 8; they therefore - * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This - * convention improves accuracy in integer implementations and saves some - * work in floating-point ones. - * Quantization of the output coefficients is done by jcdctmgr.c. - */ - -#ifndef __jdct_h__ -#define __jdct_h__ - -#if BITS_IN_JSAMPLE == 8 -typedef int DCTELEM; /* 16 or 32 bits is fine */ -#else -typedef INT32 DCTELEM; /* must have 32 bits */ -#endif - -typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data)); -typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data)); - - -/* - * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer - * to an output sample array. The routine must dequantize the input data as - * well as perform the IDCT; for dequantization, it uses the multiplier table - * pointed to by compptr->dct_table. The output data is to be placed into the - * sample array starting at a specified column. (Any row offset needed will - * be applied to the array pointer before it is passed to the IDCT code.) - * Note that the number of samples emitted by the IDCT routine is - * DCT_scaled_size * DCT_scaled_size. - */ - -/* typedef inverse_DCT_method_ptr is declared in jpegint.h */ - -/* - * Each IDCT routine has its own ideas about the best dct_table element type. - */ - -typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */ -#if BITS_IN_JSAMPLE == 8 -typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */ -#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */ -#else -typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */ -#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */ -#endif -typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */ - - -/* - * Each IDCT routine is responsible for range-limiting its results and - * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could - * be quite far out of range if the input data is corrupt, so a bulletproof - * range-limiting step is required. We use a mask-and-table-lookup method - * to do the combined operations quickly. See the comments with - * prepare_range_limit_table (in jdmaster.c) for more info. - */ - -#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE) - -#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */ - - -/* Short forms of external names for systems with brain-damaged linkers. */ - -#ifdef NEED_SHORT_EXTERNAL_NAMES -#define jpeg_fdct_islow jFDislow -#define jpeg_fdct_ifast jFDifast -#define jpeg_fdct_float jFDfloat -#define jpeg_idct_islow jRDislow -#define jpeg_idct_ifast jRDifast -#define jpeg_idct_float jRDfloat -#define jpeg_idct_4x4 jRD4x4 -#define jpeg_idct_2x2 jRD2x2 -#define jpeg_idct_1x1 jRD1x1 -#endif /* NEED_SHORT_EXTERNAL_NAMES */ - -/* Extern declarations for the forward and inverse DCT routines. */ - -EXTERN(void) jpeg_fdct_islow JPP((DCTELEM * data)); -EXTERN(void) jpeg_fdct_ifast JPP((DCTELEM * data)); -EXTERN(void) jpeg_fdct_float JPP((FAST_FLOAT * data)); - -EXTERN(void) jpeg_idct_islow - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_ifast - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_float - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_4x4 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_2x2 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); -EXTERN(void) jpeg_idct_1x1 - JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); - - -/* - * Macros for handling fixed-point arithmetic; these are used by many - * but not all of the DCT/IDCT modules. - * - * All values are expected to be of type INT32. - * Fractional constants are scaled left by CONST_BITS bits. - * CONST_BITS is defined within each module using these macros, - * and may differ from one module to the next. - */ - -#define ONE ((INT32) 1) -#define CONST_SCALE (ONE << CONST_BITS) - -/* Convert a positive real constant to an integer scaled by CONST_SCALE. - * Caution: some C compilers fail to reduce "FIX(constant)" at compile time, - * thus causing a lot of useless floating-point operations at run time. - */ - -#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5)) - -/* Descale and correctly round an INT32 value that's scaled by N bits. - * We assume RIGHT_SHIFT rounds towards minus infinity, so adding - * the fudge factor is correct for either sign of X. - */ - -#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n) - -/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. - * This macro is used only when the two inputs will actually be no more than - * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a - * full 32x32 multiply. This provides a useful speedup on many machines. - * Unfortunately there is no way to specify a 16x16->32 multiply portably - * in C, but some C compilers will do the right thing if you provide the - * correct combination of casts. - */ - -#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ -#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const))) -#endif -#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ -#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const))) -#endif - -#ifndef MULTIPLY16C16 /* default definition */ -#define MULTIPLY16C16(var,const) ((var) * (const)) -#endif - -/* Same except both inputs are variables. */ - -#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ -#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2))) -#endif - -#ifndef MULTIPLY16V16 /* default definition */ -#define MULTIPLY16V16(var1,var2) ((var1) * (var2)) -#endif - - -#endif diff --git a/source/modules/juce_graphics/image_formats/jpglib/jddctmgr.c b/source/modules/juce_graphics/image_formats/jpglib/jddctmgr.c deleted file mode 100644 index 0e44eb14a..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jddctmgr.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * jddctmgr.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains the inverse-DCT management logic. - * This code selects a particular IDCT implementation to be used, - * and it performs related housekeeping chores. No code in this file - * is executed per IDCT step, only during output pass setup. - * - * Note that the IDCT routines are responsible for performing coefficient - * dequantization as well as the IDCT proper. This module sets up the - * dequantization multiplier table needed by the IDCT routine. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jdct.h" /* Private declarations for DCT subsystem */ - - -/* - * The decompressor input side (jdinput.c) saves away the appropriate - * quantization table for each component at the start of the first scan - * involving that component. (This is necessary in order to correctly - * decode files that reuse Q-table slots.) - * When we are ready to make an output pass, the saved Q-table is converted - * to a multiplier table that will actually be used by the IDCT routine. - * The multiplier table contents are IDCT-method-dependent. To support - * application changes in IDCT method between scans, we can remake the - * multiplier tables if necessary. - * In buffered-image mode, the first output pass may occur before any data - * has been seen for some components, and thus before their Q-tables have - * been saved away. To handle this case, multiplier tables are preset - * to zeroes; the result of the IDCT will be a neutral gray level. - */ - - -/* Private subobject for this module */ - -typedef struct { - struct jpeg_inverse_dct pub; /* public fields */ - - /* This array contains the IDCT method code that each multiplier table - * is currently set up for, or -1 if it's not yet set up. - * The actual multiplier tables are pointed to by dct_table in the - * per-component comp_info structures. - */ - int cur_method[MAX_COMPONENTS]; -} my_idct_controller; - -typedef my_idct_controller * my_idct_ptr; - - -/* Allocated multiplier tables: big enough for any supported variant */ - -typedef union { - ISLOW_MULT_TYPE islow_array[DCTSIZE2]; -#ifdef DCT_IFAST_SUPPORTED - IFAST_MULT_TYPE ifast_array[DCTSIZE2]; -#endif -#ifdef DCT_FLOAT_SUPPORTED - FLOAT_MULT_TYPE float_array[DCTSIZE2]; -#endif -} multiplier_table; - - -/* The current scaled-IDCT routines require ISLOW-style multiplier tables, - * so be sure to compile that code if either ISLOW or SCALING is requested. - */ -#ifdef DCT_ISLOW_SUPPORTED -#define PROVIDE_ISLOW_TABLES -#else -#ifdef IDCT_SCALING_SUPPORTED -#define PROVIDE_ISLOW_TABLES -#endif -#endif - - -/* - * Prepare for an output pass. - * Here we select the proper IDCT routine for each component and build - * a matching multiplier table. - */ - -METHODDEF(void) -start_pass (j_decompress_ptr cinfo) -{ - my_idct_ptr idct = (my_idct_ptr) cinfo->idct; - int ci, i; - jpeg_component_info *compptr; - int method = 0; - inverse_DCT_method_ptr method_ptr = NULL; - JQUANT_TBL * qtbl; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Select the proper IDCT routine for this component's scaling */ - switch (compptr->DCT_scaled_size) { -#ifdef IDCT_SCALING_SUPPORTED - case 1: - method_ptr = jpeg_idct_1x1; - method = JDCT_ISLOW; /* jidctred uses islow-style table */ - break; - case 2: - method_ptr = jpeg_idct_2x2; - method = JDCT_ISLOW; /* jidctred uses islow-style table */ - break; - case 4: - method_ptr = jpeg_idct_4x4; - method = JDCT_ISLOW; /* jidctred uses islow-style table */ - break; -#endif - case DCTSIZE: - switch (cinfo->dct_method) { -#ifdef DCT_ISLOW_SUPPORTED - case JDCT_ISLOW: - method_ptr = jpeg_idct_islow; - method = JDCT_ISLOW; - break; -#endif -#ifdef DCT_IFAST_SUPPORTED - case JDCT_IFAST: - method_ptr = jpeg_idct_ifast; - method = JDCT_IFAST; - break; -#endif -#ifdef DCT_FLOAT_SUPPORTED - case JDCT_FLOAT: - method_ptr = jpeg_idct_float; - method = JDCT_FLOAT; - break; -#endif - default: - ERREXIT(cinfo, JERR_NOT_COMPILED); - break; - } - break; - default: - ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr->DCT_scaled_size); - break; - } - idct->pub.inverse_DCT[ci] = method_ptr; - /* Create multiplier table from quant table. - * However, we can skip this if the component is uninteresting - * or if we already built the table. Also, if no quant table - * has yet been saved for the component, we leave the - * multiplier table all-zero; we'll be reading zeroes from the - * coefficient controller's buffer anyway. - */ - if (! compptr->component_needed || idct->cur_method[ci] == method) - continue; - qtbl = compptr->quant_table; - if (qtbl == NULL) /* happens if no data yet for component */ - continue; - idct->cur_method[ci] = method; - switch (method) { -#ifdef PROVIDE_ISLOW_TABLES - case JDCT_ISLOW: - { - /* For LL&M IDCT method, multipliers are equal to raw quantization - * coefficients, but are stored as ints to ensure access efficiency. - */ - ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table; - for (i = 0; i < DCTSIZE2; i++) { - ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[i]; - } - } - break; -#endif -#ifdef DCT_IFAST_SUPPORTED - case JDCT_IFAST: - { - /* For AA&N IDCT method, multipliers are equal to quantization - * coefficients scaled by scalefactor[row]*scalefactor[col], where - * scalefactor[0] = 1 - * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 - * For integer operation, the multiplier table is to be scaled by - * IFAST_SCALE_BITS. - */ - IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table; -#define CONST_BITS 14 - static const INT16 aanscales[DCTSIZE2] = { - /* precomputed values scaled up by 14 bits */ - 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, - 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, - 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, - 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, - 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, - 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, - 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, - 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 - }; - SHIFT_TEMPS - - for (i = 0; i < DCTSIZE2; i++) { - ifmtbl[i] = (IFAST_MULT_TYPE) - DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i], - (INT32) aanscales[i]), - CONST_BITS-IFAST_SCALE_BITS); - } - } - break; -#endif -#ifdef DCT_FLOAT_SUPPORTED - case JDCT_FLOAT: - { - /* For float AA&N IDCT method, multipliers are equal to quantization - * coefficients scaled by scalefactor[row]*scalefactor[col], where - * scalefactor[0] = 1 - * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 - */ - FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table; - int row, col; - static const double aanscalefactor[DCTSIZE] = { - 1.0, 1.387039845, 1.306562965, 1.175875602, - 1.0, 0.785694958, 0.541196100, 0.275899379 - }; - - i = 0; - for (row = 0; row < DCTSIZE; row++) { - for (col = 0; col < DCTSIZE; col++) { - fmtbl[i] = (FLOAT_MULT_TYPE) - ((double) qtbl->quantval[i] * - aanscalefactor[row] * aanscalefactor[col]); - i++; - } - } - } - break; -#endif - default: - ERREXIT(cinfo, JERR_NOT_COMPILED); - break; - } - } -} - - -/* - * Initialize IDCT manager. - */ - -GLOBAL(void) -jinit_inverse_dct (j_decompress_ptr cinfo) -{ - my_idct_ptr idct; - int ci; - jpeg_component_info *compptr; - - idct = (my_idct_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_idct_controller)); - cinfo->idct = (struct jpeg_inverse_dct *) idct; - idct->pub.start_pass = start_pass; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Allocate and pre-zero a multiplier table for each component */ - compptr->dct_table = - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(multiplier_table)); - MEMZERO(compptr->dct_table, SIZEOF(multiplier_table)); - /* Mark multiplier table not yet set up for any method */ - idct->cur_method[ci] = -1; - } -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jdhuff.c b/source/modules/juce_graphics/image_formats/jpglib/jdhuff.c deleted file mode 100644 index e7e0ab73a..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jdhuff.c +++ /dev/null @@ -1,625 +0,0 @@ -/* - * jdhuff.c - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains Huffman entropy decoding routines. - * - * Much of the complexity here has to do with supporting input suspension. - * If the data source module demands suspension, we want to be able to back - * up to the start of the current MCU. To do this, we copy state variables - * into local working storage, and update them back to the permanent - * storage only upon successful completion of an MCU. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jdhuff.h" /* Declarations shared with jdphuff.c */ - - -/* - * Expanded entropy decoder object for Huffman decoding. - * - * The savable_state subrecord contains fields that change within an MCU, - * but must not be updated permanently until we complete the MCU. - */ - -typedef struct { - int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ -} savable_state2; - -/* This macro is to work around compilers with missing or broken - * structure assignment. You'll need to fix this code if you have - * such a compiler and you change MAX_COMPS_IN_SCAN. - */ - -#ifndef NO_STRUCT_ASSIGN -#define ASSIGN_STATE(dest,src) ((dest) = (src)) -#else -#if MAX_COMPS_IN_SCAN == 4 -#define ASSIGN_STATE(dest,src) \ - ((dest).last_dc_val[0] = (src).last_dc_val[0], \ - (dest).last_dc_val[1] = (src).last_dc_val[1], \ - (dest).last_dc_val[2] = (src).last_dc_val[2], \ - (dest).last_dc_val[3] = (src).last_dc_val[3]) -#endif -#endif - - -typedef struct { - struct jpeg_entropy_decoder pub; /* public fields */ - - /* These fields are loaded into local variables at start of each MCU. - * In case of suspension, we exit WITHOUT updating them. - */ - bitread_perm_state bitstate; /* Bit buffer at start of MCU */ - savable_state2 saved; /* Other state at start of MCU */ - - /* These fields are NOT loaded into local working state. */ - unsigned int restarts_to_go; /* MCUs left in this restart interval */ - - /* Pointers to derived tables (these workspaces have image lifespan) */ - d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; - d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; - - /* Precalculated info set up by start_pass for use in decode_mcu: */ - - /* Pointers to derived tables to be used for each block within an MCU */ - d_derived_tbl * dc_cur_tbls[D_MAX_BLOCKS_IN_MCU]; - d_derived_tbl * ac_cur_tbls[D_MAX_BLOCKS_IN_MCU]; - /* Whether we care about the DC and AC coefficient values for each block */ - boolean dc_needed[D_MAX_BLOCKS_IN_MCU]; - boolean ac_needed[D_MAX_BLOCKS_IN_MCU]; -} huff_entropy_decoder2; - -typedef huff_entropy_decoder2 * huff_entropy_ptr2; - - -/* - * Initialize for a Huffman-compressed scan. - */ - -METHODDEF(void) -start_pass_huff_decoder (j_decompress_ptr cinfo) -{ - huff_entropy_ptr2 entropy = (huff_entropy_ptr2) cinfo->entropy; - int ci, blkn, dctbl, actbl; - jpeg_component_info * compptr; - - /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. - * This ought to be an error condition, but we make it a warning because - * there are some baseline files out there with all zeroes in these bytes. - */ - if (cinfo->Ss != 0 || cinfo->Se != DCTSIZE2-1 || - cinfo->Ah != 0 || cinfo->Al != 0) - WARNMS(cinfo, JWRN_NOT_SEQUENTIAL); - - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - dctbl = compptr->dc_tbl_no; - actbl = compptr->ac_tbl_no; - /* Compute derived values for Huffman tables */ - /* We may do this more than once for a table, but it's not expensive */ - jpeg_make_d_derived_tbl(cinfo, TRUE, dctbl, - & entropy->dc_derived_tbls[dctbl]); - jpeg_make_d_derived_tbl(cinfo, FALSE, actbl, - & entropy->ac_derived_tbls[actbl]); - /* Initialize DC predictions to 0 */ - entropy->saved.last_dc_val[ci] = 0; - } - - /* Precalculate decoding info for each block in an MCU of this scan */ - for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - ci = cinfo->MCU_membership[blkn]; - compptr = cinfo->cur_comp_info[ci]; - /* Precalculate which table to use for each block */ - entropy->dc_cur_tbls[blkn] = entropy->dc_derived_tbls[compptr->dc_tbl_no]; - entropy->ac_cur_tbls[blkn] = entropy->ac_derived_tbls[compptr->ac_tbl_no]; - /* Decide whether we really care about the coefficient values */ - if (compptr->component_needed) { - entropy->dc_needed[blkn] = TRUE; - /* we don't need the ACs if producing a 1/8th-size image */ - entropy->ac_needed[blkn] = (compptr->DCT_scaled_size > 1); - } else { - entropy->dc_needed[blkn] = entropy->ac_needed[blkn] = FALSE; - } - } - - /* Initialize bitread state variables */ - entropy->bitstate.bits_left = 0; - entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ - entropy->pub.insufficient_data = FALSE; - - /* Initialize restart counter */ - entropy->restarts_to_go = cinfo->restart_interval; -} - - -/* - * Compute the derived values for a Huffman table. - * This routine also performs some validation checks on the table. - * - * Note this is also used by jdphuff.c. - */ - -GLOBAL(void) -jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno, - d_derived_tbl ** pdtbl) -{ - JHUFF_TBL *htbl; - d_derived_tbl *dtbl; - int p, i, l, si, numsymbols; - int lookbits, ctr; - char huffsize[257]; - unsigned int huffcode[257]; - unsigned int code; - - /* Note that huffsize[] and huffcode[] are filled in code-length order, - * paralleling the order of the symbols themselves in htbl->huffval[]. - */ - - /* Find the input Huffman table */ - if (tblno < 0 || tblno >= NUM_HUFF_TBLS) - ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); - htbl = - isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno]; - if (htbl == NULL) - ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); - - /* Allocate a workspace if we haven't already done so. */ - if (*pdtbl == NULL) - *pdtbl = (d_derived_tbl *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(d_derived_tbl)); - dtbl = *pdtbl; - dtbl->pub = htbl; /* fill in back link */ - - /* Figure C.1: make table of Huffman code length for each symbol */ - - p = 0; - for (l = 1; l <= 16; l++) { - i = (int) htbl->bits[l]; - if (i < 0 || p + i > 256) /* protect against table overrun */ - ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); - while (i--) - huffsize[p++] = (char) l; - } - huffsize[p] = 0; - numsymbols = p; - - /* Figure C.2: generate the codes themselves */ - /* We also validate that the counts represent a legal Huffman code tree. */ - - code = 0; - si = huffsize[0]; - p = 0; - while (huffsize[p]) { - while (((int) huffsize[p]) == si) { - huffcode[p++] = code; - code++; - } - /* code is now 1 more than the last code used for codelength si; but - * it must still fit in si bits, since no code is allowed to be all ones. - */ - if (((INT32) code) >= (((INT32) 1) << si)) - ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); - code <<= 1; - si++; - } - - /* Figure F.15: generate decoding tables for bit-sequential decoding */ - - p = 0; - for (l = 1; l <= 16; l++) { - if (htbl->bits[l]) { - /* valoffset[l] = huffval[] index of 1st symbol of code length l, - * minus the minimum code of length l - */ - dtbl->valoffset[l] = (INT32) p - (INT32) huffcode[p]; - p += htbl->bits[l]; - dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */ - } else { - dtbl->maxcode[l] = -1; /* -1 if no codes of this length */ - } - } - dtbl->maxcode[17] = 0xFFFFFL; /* ensures jpeg_huff_decode terminates */ - - /* Compute lookahead tables to speed up decoding. - * First we set all the table entries to 0, indicating "too long"; - * then we iterate through the Huffman codes that are short enough and - * fill in all the entries that correspond to bit sequences starting - * with that code. - */ - - MEMZERO(dtbl->look_nbits, SIZEOF(dtbl->look_nbits)); - - p = 0; - for (l = 1; l <= HUFF_LOOKAHEAD; l++) { - for (i = 1; i <= (int) htbl->bits[l]; i++, p++) { - /* l = current code's length, p = its index in huffcode[] & huffval[]. */ - /* Generate left-justified code followed by all possible bit sequences */ - lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l); - for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) { - dtbl->look_nbits[lookbits] = l; - dtbl->look_sym[lookbits] = htbl->huffval[p]; - lookbits++; - } - } - } - - /* Validate symbols as being reasonable. - * For AC tables, we make no check, but accept all byte values 0..255. - * For DC tables, we require the symbols to be in range 0..15. - * (Tighter bounds could be applied depending on the data depth and mode, - * but this is sufficient to ensure safe decoding.) - */ - if (isDC) { - for (i = 0; i < numsymbols; i++) { - int sym = htbl->huffval[i]; - if (sym < 0 || sym > 15) - ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); - } - } -} - - -/* - * Out-of-line code for bit fetching (shared with jdphuff.c). - * See jdhuff.h for info about usage. - * Note: current values of get_buffer and bits_left are passed as parameters, - * but are returned in the corresponding fields of the state struct. - * - * On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width - * of get_buffer to be used. (On machines with wider words, an even larger - * buffer could be used.) However, on some machines 32-bit shifts are - * quite slow and take time proportional to the number of places shifted. - * (This is true with most PC compilers, for instance.) In this case it may - * be a win to set MIN_GET_BITS to the minimum value of 15. This reduces the - * average shift distance at the cost of more calls to jpeg_fill_bit_buffer. - */ - -#ifdef SLOW_SHIFT_32 -#define MIN_GET_BITS 15 /* minimum allowable value */ -#else -#define MIN_GET_BITS (BIT_BUF_SIZE-7) -#endif - - -GLOBAL(boolean) -jpeg_fill_bit_buffer (bitread_working_state * state, - bit_buf_type get_buffer, int bits_left, - int nbits) -/* Load up the bit buffer to a depth of at least nbits */ -{ - /* Copy heavily used state fields into locals (hopefully registers) */ - const JOCTET * next_input_byte = state->next_input_byte; - size_t bytes_in_buffer = state->bytes_in_buffer; - j_decompress_ptr cinfo = state->cinfo; - - /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */ - /* (It is assumed that no request will be for more than that many bits.) */ - /* We fail to do so only if we hit a marker or are forced to suspend. */ - - if (cinfo->unread_marker == 0) { /* cannot advance past a marker */ - while (bits_left < MIN_GET_BITS) { - int c; - - /* Attempt to read a byte */ - if (bytes_in_buffer == 0) { - if (! (*cinfo->src->fill_input_buffer) (cinfo)) - return FALSE; - next_input_byte = cinfo->src->next_input_byte; - bytes_in_buffer = cinfo->src->bytes_in_buffer; - } - bytes_in_buffer--; - c = GETJOCTET(*next_input_byte++); - - /* If it's 0xFF, check and discard stuffed zero byte */ - if (c == 0xFF) { - /* Loop here to discard any padding FF's on terminating marker, - * so that we can save a valid unread_marker value. NOTE: we will - * accept multiple FF's followed by a 0 as meaning a single FF data - * byte. This data pattern is not valid according to the standard. - */ - do { - if (bytes_in_buffer == 0) { - if (! (*cinfo->src->fill_input_buffer) (cinfo)) - return FALSE; - next_input_byte = cinfo->src->next_input_byte; - bytes_in_buffer = cinfo->src->bytes_in_buffer; - } - bytes_in_buffer--; - c = GETJOCTET(*next_input_byte++); - } while (c == 0xFF); - - if (c == 0) { - /* Found FF/00, which represents an FF data byte */ - c = 0xFF; - } else { - /* Oops, it's actually a marker indicating end of compressed data. - * Save the marker code for later use. - * Fine point: it might appear that we should save the marker into - * bitread working state, not straight into permanent state. But - * once we have hit a marker, we cannot need to suspend within the - * current MCU, because we will read no more bytes from the data - * source. So it is OK to update permanent state right away. - */ - cinfo->unread_marker = c; - /* See if we need to insert some fake zero bits. */ - goto no_more_bytes; - } - } - - /* OK, load c into get_buffer */ - get_buffer = (get_buffer << 8) | c; - bits_left += 8; - } /* end while */ - } else { - no_more_bytes: - /* We get here if we've read the marker that terminates the compressed - * data segment. There should be enough bits in the buffer register - * to satisfy the request; if so, no problem. - */ - if (nbits > bits_left) { - /* Uh-oh. Report corrupted data to user and stuff zeroes into - * the data stream, so that we can produce some kind of image. - * We use a nonvolatile flag to ensure that only one warning message - * appears per data segment. - */ - if (! cinfo->entropy->insufficient_data) { - WARNMS(cinfo, JWRN_HIT_MARKER); - cinfo->entropy->insufficient_data = TRUE; - } - /* Fill the buffer with zero bits */ - get_buffer <<= MIN_GET_BITS - bits_left; - bits_left = MIN_GET_BITS; - } - } - - /* Unload the local registers */ - state->next_input_byte = next_input_byte; - state->bytes_in_buffer = bytes_in_buffer; - state->get_buffer = get_buffer; - state->bits_left = bits_left; - - return TRUE; -} - - -/* - * Out-of-line code for Huffman code decoding. - * See jdhuff.h for info about usage. - */ - -GLOBAL(int) -jpeg_huff_decode (bitread_working_state * state, - bit_buf_type get_buffer, int bits_left, - d_derived_tbl * htbl, int min_bits) -{ - int l = min_bits; - INT32 code; - - /* HUFF_DECODE has determined that the code is at least min_bits */ - /* bits long, so fetch that many bits in one swoop. */ - - CHECK_BIT_BUFFER(*state, l, return -1); - code = GET_BITS(l); - - /* Collect the rest of the Huffman code one bit at a time. */ - /* This is per Figure F.16 in the JPEG spec. */ - - while (code > htbl->maxcode[l]) { - code <<= 1; - CHECK_BIT_BUFFER(*state, 1, return -1); - code |= GET_BITS(1); - l++; - } - - /* Unload the local registers */ - state->get_buffer = get_buffer; - state->bits_left = bits_left; - - /* With garbage input we may reach the sentinel value l = 17. */ - - if (l > 16) { - WARNMS(state->cinfo, JWRN_HUFF_BAD_CODE); - return 0; /* fake a zero as the safest result */ - } - - return htbl->pub->huffval[ (int) (code + htbl->valoffset[l]) ]; -} - - -/* - * Check for a restart marker & resynchronize decoder. - * Returns FALSE if must suspend. - */ - -LOCAL(boolean) -process_restart (j_decompress_ptr cinfo) -{ - huff_entropy_ptr2 entropy = (huff_entropy_ptr2) cinfo->entropy; - int ci; - - /* Throw away any unused bits remaining in bit buffer; */ - /* include any full bytes in next_marker's count of discarded bytes */ - cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; - entropy->bitstate.bits_left = 0; - - /* Advance past the RSTn marker */ - if (! (*cinfo->marker->read_restart_marker) (cinfo)) - return FALSE; - - /* Re-initialize DC predictions to 0 */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) - entropy->saved.last_dc_val[ci] = 0; - - /* Reset restart counter */ - entropy->restarts_to_go = cinfo->restart_interval; - - /* Reset out-of-data flag, unless read_restart_marker left us smack up - * against a marker. In that case we will end up treating the next data - * segment as empty, and we can avoid producing bogus output pixels by - * leaving the flag set. - */ - if (cinfo->unread_marker == 0) - entropy->pub.insufficient_data = FALSE; - - return TRUE; -} - - -/* - * Decode and return one MCU's worth of Huffman-compressed coefficients. - * The coefficients are reordered from zigzag order into natural array order, - * but are not dequantized. - * - * The i'th block of the MCU is stored into the block pointed to by - * MCU_data[i]. WE ASSUME THIS AREA HAS BEEN ZEROED BY THE CALLER. - * (Wholesale zeroing is usually a little faster than retail...) - * - * Returns FALSE if data source requested suspension. In that case no - * changes have been made to permanent state. (Exception: some output - * coefficients may already have been assigned. This is harmless for - * this module, since we'll just re-assign them on the next call.) - */ - -METHODDEF(boolean) -decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) -{ - huff_entropy_ptr2 entropy = (huff_entropy_ptr2) cinfo->entropy; - int blkn; - BITREAD_STATE_VARS; - savable_state2 state; - - /* Process restart marker if needed; may have to suspend */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) - if (! process_restart(cinfo)) - return FALSE; - } - - /* If we've run out of data, just leave the MCU set to zeroes. - * This way, we return uniform gray for the remainder of the segment. - */ - if (! entropy->pub.insufficient_data) { - - /* Load up working state */ - BITREAD_LOAD_STATE(cinfo,entropy->bitstate); - ASSIGN_STATE(state, entropy->saved); - - /* Outer loop handles each block in the MCU */ - - for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - JBLOCKROW block = MCU_data[blkn]; - d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn]; - d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn]; - int s, k, r; - - /* Decode a single block's worth of coefficients */ - - /* Section F.2.2.1: decode the DC coefficient difference */ - HUFF_DECODE(s, br_state, dctbl, return FALSE, label1); - if (s) { - CHECK_BIT_BUFFER(br_state, s, return FALSE); - r = GET_BITS(s); - s = HUFF_EXTEND(r, s); - } - - if (entropy->dc_needed[blkn]) { - /* Convert DC difference to actual value, update last_dc_val */ - int ci = cinfo->MCU_membership[blkn]; - s += state.last_dc_val[ci]; - state.last_dc_val[ci] = s; - /* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */ - (*block)[0] = (JCOEF) s; - } - - if (entropy->ac_needed[blkn]) { - - /* Section F.2.2.2: decode the AC coefficients */ - /* Since zeroes are skipped, output area must be cleared beforehand */ - for (k = 1; k < DCTSIZE2; k++) { - HUFF_DECODE(s, br_state, actbl, return FALSE, label2); - - r = s >> 4; - s &= 15; - - if (s) { - k += r; - CHECK_BIT_BUFFER(br_state, s, return FALSE); - r = GET_BITS(s); - s = HUFF_EXTEND(r, s); - /* Output coefficient in natural (dezigzagged) order. - * Note: the extra entries in jpeg_natural_order[] will save us - * if k >= DCTSIZE2, which could happen if the data is corrupted. - */ - (*block)[jpeg_natural_order[k]] = (JCOEF) s; - } else { - if (r != 15) - break; - k += 15; - } - } - - } else { - - /* Section F.2.2.2: decode the AC coefficients */ - /* In this path we just discard the values */ - for (k = 1; k < DCTSIZE2; k++) { - HUFF_DECODE(s, br_state, actbl, return FALSE, label3); - - r = s >> 4; - s &= 15; - - if (s) { - k += r; - CHECK_BIT_BUFFER(br_state, s, return FALSE); - DROP_BITS(s); - } else { - if (r != 15) - break; - k += 15; - } - } - - } - } - - /* Completed MCU, so update state */ - BITREAD_SAVE_STATE(cinfo,entropy->bitstate); - ASSIGN_STATE(entropy->saved, state); - } - - /* Account for restart interval (no-op if not using restarts) */ - entropy->restarts_to_go--; - - return TRUE; -} - - -/* - * Module initialization routine for Huffman entropy decoding. - */ - -GLOBAL(void) -jinit_huff_decoder (j_decompress_ptr cinfo) -{ - huff_entropy_ptr2 entropy; - int i; - - entropy = (huff_entropy_ptr2) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(huff_entropy_decoder2)); - cinfo->entropy = (struct jpeg_entropy_decoder *) entropy; - entropy->pub.start_pass = start_pass_huff_decoder; - entropy->pub.decode_mcu = decode_mcu; - - /* Mark tables unallocated */ - for (i = 0; i < NUM_HUFF_TBLS; i++) { - entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; - } -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jdhuff.h b/source/modules/juce_graphics/image_formats/jpglib/jdhuff.h deleted file mode 100644 index 492a91257..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jdhuff.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * jdhuff.h - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains declarations for Huffman entropy decoding routines - * that are shared between the sequential decoder (jdhuff.c) and the - * progressive decoder (jdphuff.c). No other modules need to see these. - */ - -/* Short forms of external names for systems with brain-damaged linkers. */ - -#ifndef __jdhuff_h__ -#define __jdhuff_h__ - -#ifdef NEED_SHORT_EXTERNAL_NAMES -#define jpeg_make_d_derived_tbl jMkDDerived -#define jpeg_fill_bit_buffer jFilBitBuf -#define jpeg_huff_decode jHufDecode -#endif /* NEED_SHORT_EXTERNAL_NAMES */ - - -/* Derived data constructed for each Huffman table */ - -#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */ - -typedef struct { - /* Basic tables: (element [0] of each array is unused) */ - INT32 maxcode[18]; /* largest code of length k (-1 if none) */ - /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */ - INT32 valoffset[17]; /* huffval[] offset for codes of length k */ - /* valoffset[k] = huffval[] index of 1st symbol of code length k, less - * the smallest code of length k; so given a code of length k, the - * corresponding symbol is huffval[code + valoffset[k]] - */ - - /* Link to public Huffman table (needed only in jpeg_huff_decode) */ - JHUFF_TBL *pub; - - /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of - * the input data stream. If the next Huffman code is no more - * than HUFF_LOOKAHEAD bits long, we can obtain its length and - * the corresponding symbol directly from these tables. - */ - int look_nbits[1< 32 bits on your machine, and shifting/masking longs is - * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE - * appropriately should be a win. Unfortunately we can't define the size - * with something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8) - * because not all machines measure sizeof in 8-bit bytes. - */ - -typedef struct { /* Bitreading state saved across MCUs */ - bit_buf_type get_buffer; /* current bit-extraction buffer */ - int bits_left; /* # of unused bits in it */ -} bitread_perm_state; - -typedef struct { /* Bitreading working state within an MCU */ - /* Current data source location */ - /* We need a copy, rather than munging the original, in case of suspension */ - const JOCTET * next_input_byte; /* => next byte to read from source */ - size_t bytes_in_buffer; /* # of bytes remaining in source buffer */ - /* Bit input buffer --- note these values are kept in register variables, - * not in this struct, inside the inner loops. - */ - bit_buf_type get_buffer; /* current bit-extraction buffer */ - int bits_left; /* # of unused bits in it */ - /* Pointer needed by jpeg_fill_bit_buffer. */ - j_decompress_ptr cinfo; /* back link to decompress master record */ -} bitread_working_state; - -/* Macros to declare and load/save bitread local variables. */ -#define BITREAD_STATE_VARS \ - bit_buf_type get_buffer; \ - int bits_left; \ - bitread_working_state br_state - -#define BITREAD_LOAD_STATE(cinfop,permstate) \ - br_state.cinfo = cinfop; \ - br_state.next_input_byte = cinfop->src->next_input_byte; \ - br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \ - get_buffer = permstate.get_buffer; \ - bits_left = permstate.bits_left; - -#define BITREAD_SAVE_STATE(cinfop,permstate) \ - cinfop->src->next_input_byte = br_state.next_input_byte; \ - cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \ - permstate.get_buffer = get_buffer; \ - permstate.bits_left = bits_left - -/* - * These macros provide the in-line portion of bit fetching. - * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer - * before using GET_BITS, PEEK_BITS, or DROP_BITS. - * The variables get_buffer and bits_left are assumed to be locals, - * but the state struct might not be (jpeg_huff_decode needs this). - * CHECK_BIT_BUFFER(state,n,action); - * Ensure there are N bits in get_buffer; if suspend, take action. - * val = GET_BITS(n); - * Fetch next N bits. - * val = PEEK_BITS(n); - * Fetch next N bits without removing them from the buffer. - * DROP_BITS(n); - * Discard next N bits. - * The value N should be a simple variable, not an expression, because it - * is evaluated multiple times. - */ - -#define CHECK_BIT_BUFFER(state,nbits,action) \ - { if (bits_left < (nbits)) { \ - if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \ - { action; } \ - get_buffer = (state).get_buffer; bits_left = (state).bits_left; } } - -#define GET_BITS(nbits) \ - (((int) (get_buffer >> (bits_left -= (nbits)))) & ((1<<(nbits))-1)) - -#define PEEK_BITS(nbits) \ - (((int) (get_buffer >> (bits_left - (nbits)))) & ((1<<(nbits))-1)) - -#define DROP_BITS(nbits) \ - (bits_left -= (nbits)) - -/* Load up the bit buffer to a depth of at least nbits */ -EXTERN(boolean) jpeg_fill_bit_buffer - JPP((bitread_working_state * state, bit_buf_type get_buffer, - int bits_left, int nbits)); - - -/* - * Code for extracting next Huffman-coded symbol from input bit stream. - * Again, this is time-critical and we make the main paths be macros. - * - * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits - * without looping. Usually, more than 95% of the Huffman codes will be 8 - * or fewer bits long. The few overlength codes are handled with a loop, - * which need not be inline code. - * - * Notes about the HUFF_DECODE macro: - * 1. Near the end of the data segment, we may fail to get enough bits - * for a lookahead. In that case, we do it the hard way. - * 2. If the lookahead table contains no entry, the next code must be - * more than HUFF_LOOKAHEAD bits long. - * 3. jpeg_huff_decode returns -1 if forced to suspend. - */ - -#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \ -{ int nb, look; \ - if (bits_left < HUFF_LOOKAHEAD) { \ - if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \ - get_buffer = state.get_buffer; bits_left = state.bits_left; \ - if (bits_left < HUFF_LOOKAHEAD) { \ - nb = 1; goto slowlabel; \ - } \ - } \ - look = PEEK_BITS(HUFF_LOOKAHEAD); \ - if ((nb = htbl->look_nbits[look]) != 0) { \ - DROP_BITS(nb); \ - result = htbl->look_sym[look]; \ - } else { \ - nb = HUFF_LOOKAHEAD+1; \ -slowlabel: \ - if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \ - { failaction; } \ - get_buffer = state.get_buffer; bits_left = state.bits_left; \ - } \ -} - -/* Out-of-line case for Huffman code fetching */ -EXTERN(int) jpeg_huff_decode - JPP((bitread_working_state * state, bit_buf_type get_buffer, - int bits_left, d_derived_tbl * htbl, int min_bits)); - -#endif diff --git a/source/modules/juce_graphics/image_formats/jpglib/jdinput.c b/source/modules/juce_graphics/image_formats/jpglib/jdinput.c deleted file mode 100644 index 621b71462..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jdinput.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * jdinput.c - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains input control logic for the JPEG decompressor. - * These routines are concerned with controlling the decompressor's input - * processing (marker reading and coefficient decoding). The actual input - * reading is done in jdmarker.c, jdhuff.c, and jdphuff.c. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Private state */ - -typedef struct { - struct jpeg_input_controller pub; /* public fields */ - - boolean inheaders; /* TRUE until first SOS is reached */ -} my_input_controller; - -typedef my_input_controller * my_inputctl_ptr; - - -/* Forward declarations */ -METHODDEF(int) consume_markers JPP((j_decompress_ptr cinfo)); - - -/* - * Routines to calculate various quantities related to the size of the image. - */ - -LOCAL(void) -initial_setup2 (j_decompress_ptr cinfo) -/* Called once, when first SOS marker is reached */ -{ - int ci; - jpeg_component_info *compptr; - - /* Make sure image isn't bigger than I can handle */ - if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || - (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) - ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); - - /* For now, precision must match compiled-in value... */ - if (cinfo->data_precision != BITS_IN_JSAMPLE) - ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); - - /* Check that number of components won't exceed internal array sizes */ - if (cinfo->num_components > MAX_COMPONENTS) - ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, - MAX_COMPONENTS); - - /* Compute maximum sampling factors; check factor validity */ - cinfo->max_h_samp_factor = 1; - cinfo->max_v_samp_factor = 1; - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || - compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) - ERREXIT(cinfo, JERR_BAD_SAMPLING); - cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, - compptr->h_samp_factor); - cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, - compptr->v_samp_factor); - } - - /* We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE. - * In the full decompressor, this will be overridden by jdmaster.c; - * but in the transcoder, jdmaster.c is not used, so we must do it here. - */ - cinfo->min_DCT_scaled_size = DCTSIZE; - - /* Compute dimensions of components */ - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - compptr->DCT_scaled_size = DCTSIZE; - /* Size in DCT blocks */ - compptr->width_in_blocks = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, - (long) (cinfo->max_h_samp_factor * DCTSIZE)); - compptr->height_in_blocks = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, - (long) (cinfo->max_v_samp_factor * DCTSIZE)); - /* downsampled_width and downsampled_height will also be overridden by - * jdmaster.c if we are doing full decompression. The transcoder library - * doesn't use these values, but the calling application might. - */ - /* Size in samples */ - compptr->downsampled_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, - (long) cinfo->max_h_samp_factor); - compptr->downsampled_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, - (long) cinfo->max_v_samp_factor); - /* Mark component needed, until color conversion says otherwise */ - compptr->component_needed = TRUE; - /* Mark no quantization table yet saved for component */ - compptr->quant_table = NULL; - } - - /* Compute number of fully interleaved MCU rows. */ - cinfo->total_iMCU_rows = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height, - (long) (cinfo->max_v_samp_factor*DCTSIZE)); - - /* Decide whether file contains multiple scans */ - if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode) - cinfo->inputctl->has_multiple_scans = TRUE; - else - cinfo->inputctl->has_multiple_scans = FALSE; -} - - -LOCAL(void) -per_scan_setup2 (j_decompress_ptr cinfo) -/* Do computations that are needed before processing a JPEG scan */ -/* cinfo->comps_in_scan and cinfo->cur_comp_info[] were set from SOS marker */ -{ - int ci, mcublks, tmp; - jpeg_component_info *compptr; - - if (cinfo->comps_in_scan == 1) { - - /* Noninterleaved (single-component) scan */ - compptr = cinfo->cur_comp_info[0]; - - /* Overall image size in MCUs */ - cinfo->MCUs_per_row = compptr->width_in_blocks; - cinfo->MCU_rows_in_scan = compptr->height_in_blocks; - - /* For noninterleaved scan, always one block per MCU */ - compptr->MCU_width = 1; - compptr->MCU_height = 1; - compptr->MCU_blocks = 1; - compptr->MCU_sample_width = compptr->DCT_scaled_size; - compptr->last_col_width = 1; - /* For noninterleaved scans, it is convenient to define last_row_height - * as the number of block rows present in the last iMCU row. - */ - tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor); - if (tmp == 0) tmp = compptr->v_samp_factor; - compptr->last_row_height = tmp; - - /* Prepare array describing MCU composition */ - cinfo->blocks_in_MCU = 1; - cinfo->MCU_membership[0] = 0; - - } else { - - /* Interleaved (multi-component) scan */ - if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) - ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, - MAX_COMPS_IN_SCAN); - - /* Overall image size in MCUs */ - cinfo->MCUs_per_row = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width, - (long) (cinfo->max_h_samp_factor*DCTSIZE)); - cinfo->MCU_rows_in_scan = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height, - (long) (cinfo->max_v_samp_factor*DCTSIZE)); - - cinfo->blocks_in_MCU = 0; - - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - /* Sampling factors give # of blocks of component in each MCU */ - compptr->MCU_width = compptr->h_samp_factor; - compptr->MCU_height = compptr->v_samp_factor; - compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; - compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_scaled_size; - /* Figure number of non-dummy blocks in last MCU column & row */ - tmp = (int) (compptr->width_in_blocks % compptr->MCU_width); - if (tmp == 0) tmp = compptr->MCU_width; - compptr->last_col_width = tmp; - tmp = (int) (compptr->height_in_blocks % compptr->MCU_height); - if (tmp == 0) tmp = compptr->MCU_height; - compptr->last_row_height = tmp; - /* Prepare array describing MCU composition */ - mcublks = compptr->MCU_blocks; - if (cinfo->blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU) - ERREXIT(cinfo, JERR_BAD_MCU_SIZE); - while (mcublks-- > 0) { - cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; - } - } - - } -} - - -/* - * Save away a copy of the Q-table referenced by each component present - * in the current scan, unless already saved during a prior scan. - * - * In a multiple-scan JPEG file, the encoder could assign different components - * the same Q-table slot number, but change table definitions between scans - * so that each component uses a different Q-table. (The IJG encoder is not - * currently capable of doing this, but other encoders might.) Since we want - * to be able to dequantize all the components at the end of the file, this - * means that we have to save away the table actually used for each component. - * We do this by copying the table at the start of the first scan containing - * the component. - * The JPEG spec prohibits the encoder from changing the contents of a Q-table - * slot between scans of a component using that slot. If the encoder does so - * anyway, this decoder will simply use the Q-table values that were current - * at the start of the first scan for the component. - * - * The decompressor output side looks only at the saved quant tables, - * not at the current Q-table slots. - */ - -LOCAL(void) -latch_quant_tables (j_decompress_ptr cinfo) -{ - int ci, qtblno; - jpeg_component_info *compptr; - JQUANT_TBL * qtbl; - - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - /* No work if we already saved Q-table for this component */ - if (compptr->quant_table != NULL) - continue; - /* Make sure specified quantization table is present */ - qtblno = compptr->quant_tbl_no; - if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || - cinfo->quant_tbl_ptrs[qtblno] == NULL) - ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); - /* OK, save away the quantization table */ - qtbl = (JQUANT_TBL *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(JQUANT_TBL)); - MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL)); - compptr->quant_table = qtbl; - } -} - - -/* - * Initialize the input modules to read a scan of compressed data. - * The first call to this is done by jdmaster.c after initializing - * the entire decompressor (during jpeg_start_decompress). - * Subsequent calls come from consume_markers, below. - */ - -METHODDEF(void) -start_input_pass2 (j_decompress_ptr cinfo) -{ - per_scan_setup2(cinfo); - latch_quant_tables(cinfo); - (*cinfo->entropy->start_pass) (cinfo); - (*cinfo->coef->start_input_pass) (cinfo); - cinfo->inputctl->consume_input = cinfo->coef->consume_data; -} - - -/* - * Finish up after inputting a compressed-data scan. - * This is called by the coefficient controller after it's read all - * the expected data of the scan. - */ - -METHODDEF(void) -finish_input_pass (j_decompress_ptr cinfo) -{ - cinfo->inputctl->consume_input = consume_markers; -} - - -/* - * Read JPEG markers before, between, or after compressed-data scans. - * Change state as necessary when a new scan is reached. - * Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. - * - * The consume_input method pointer points either here or to the - * coefficient controller's consume_data routine, depending on whether - * we are reading a compressed data segment or inter-segment markers. - */ - -METHODDEF(int) -consume_markers (j_decompress_ptr cinfo) -{ - my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; - int val; - - if (inputctl->pub.eoi_reached) /* After hitting EOI, read no further */ - return JPEG_REACHED_EOI; - - val = (*cinfo->marker->read_markers) (cinfo); - - switch (val) { - case JPEG_REACHED_SOS: /* Found SOS */ - if (inputctl->inheaders) { /* 1st SOS */ - initial_setup2(cinfo); - inputctl->inheaders = FALSE; - /* Note: start_input_pass must be called by jdmaster.c - * before any more input can be consumed. jdapimin.c is - * responsible for enforcing this sequencing. - */ - } else { /* 2nd or later SOS marker */ - if (! inputctl->pub.has_multiple_scans) - ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */ - start_input_pass2(cinfo); - } - break; - case JPEG_REACHED_EOI: /* Found EOI */ - inputctl->pub.eoi_reached = TRUE; - if (inputctl->inheaders) { /* Tables-only datastream, apparently */ - if (cinfo->marker->saw_SOF) - ERREXIT(cinfo, JERR_SOF_NO_SOS); - } else { - /* Prevent infinite loop in coef ctlr's decompress_data routine - * if user set output_scan_number larger than number of scans. - */ - if (cinfo->output_scan_number > cinfo->input_scan_number) - cinfo->output_scan_number = cinfo->input_scan_number; - } - break; - case JPEG_SUSPENDED: - break; - } - - return val; -} - - -/* - * Reset state to begin a fresh datastream. - */ - -METHODDEF(void) -reset_input_controller (j_decompress_ptr cinfo) -{ - my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; - - inputctl->pub.consume_input = consume_markers; - inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ - inputctl->pub.eoi_reached = FALSE; - inputctl->inheaders = TRUE; - /* Reset other modules */ - (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); - (*cinfo->marker->reset_marker_reader) (cinfo); - /* Reset progression state -- would be cleaner if entropy decoder did this */ - cinfo->coef_bits = NULL; -} - - -/* - * Initialize the input controller module. - * This is called only once, when the decompression object is created. - */ - -GLOBAL(void) -jinit_input_controller (j_decompress_ptr cinfo) -{ - my_inputctl_ptr inputctl; - - /* Create subobject in permanent pool */ - inputctl = (my_inputctl_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - SIZEOF(my_input_controller)); - cinfo->inputctl = (struct jpeg_input_controller *) inputctl; - /* Initialize method pointers */ - inputctl->pub.consume_input = consume_markers; - inputctl->pub.reset_input_controller = reset_input_controller; - inputctl->pub.start_input_pass = start_input_pass2; - inputctl->pub.finish_input_pass = finish_input_pass; - /* Initialize state: can't use reset_input_controller since we don't - * want to try to reset other modules yet. - */ - inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ - inputctl->pub.eoi_reached = FALSE; - inputctl->inheaders = TRUE; -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jdmainct.c b/source/modules/juce_graphics/image_formats/jpglib/jdmainct.c deleted file mode 100644 index ee23fa822..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jdmainct.c +++ /dev/null @@ -1,512 +0,0 @@ -/* - * jdmainct.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains the main buffer controller for decompression. - * The main buffer lies between the JPEG decompressor proper and the - * post-processor; it holds downsampled data in the JPEG colorspace. - * - * Note that this code is bypassed in raw-data mode, since the application - * supplies the equivalent of the main buffer in that case. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* - * In the current system design, the main buffer need never be a full-image - * buffer; any full-height buffers will be found inside the coefficient or - * postprocessing controllers. Nonetheless, the main controller is not - * trivial. Its responsibility is to provide context rows for upsampling/ - * rescaling, and doing this in an efficient fashion is a bit tricky. - * - * Postprocessor input data is counted in "row groups". A row group - * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size) - * sample rows of each component. (We require DCT_scaled_size values to be - * chosen such that these numbers are integers. In practice DCT_scaled_size - * values will likely be powers of two, so we actually have the stronger - * condition that DCT_scaled_size / min_DCT_scaled_size is an integer.) - * Upsampling will typically produce max_v_samp_factor pixel rows from each - * row group (times any additional scale factor that the upsampler is - * applying). - * - * The coefficient controller will deliver data to us one iMCU row at a time; - * each iMCU row contains v_samp_factor * DCT_scaled_size sample rows, or - * exactly min_DCT_scaled_size row groups. (This amount of data corresponds - * to one row of MCUs when the image is fully interleaved.) Note that the - * number of sample rows varies across components, but the number of row - * groups does not. Some garbage sample rows may be included in the last iMCU - * row at the bottom of the image. - * - * Depending on the vertical scaling algorithm used, the upsampler may need - * access to the sample row(s) above and below its current input row group. - * The upsampler is required to set need_context_rows TRUE at global selection - * time if so. When need_context_rows is FALSE, this controller can simply - * obtain one iMCU row at a time from the coefficient controller and dole it - * out as row groups to the postprocessor. - * - * When need_context_rows is TRUE, this controller guarantees that the buffer - * passed to postprocessing contains at least one row group's worth of samples - * above and below the row group(s) being processed. Note that the context - * rows "above" the first passed row group appear at negative row offsets in - * the passed buffer. At the top and bottom of the image, the required - * context rows are manufactured by duplicating the first or last real sample - * row; this avoids having special cases in the upsampling inner loops. - * - * The amount of context is fixed at one row group just because that's a - * convenient number for this controller to work with. The existing - * upsamplers really only need one sample row of context. An upsampler - * supporting arbitrary output rescaling might wish for more than one row - * group of context when shrinking the image; tough, we don't handle that. - * (This is justified by the assumption that downsizing will be handled mostly - * by adjusting the DCT_scaled_size values, so that the actual scale factor at - * the upsample step needn't be much less than one.) - * - * To provide the desired context, we have to retain the last two row groups - * of one iMCU row while reading in the next iMCU row. (The last row group - * can't be processed until we have another row group for its below-context, - * and so we have to save the next-to-last group too for its above-context.) - * We could do this most simply by copying data around in our buffer, but - * that'd be very slow. We can avoid copying any data by creating a rather - * strange pointer structure. Here's how it works. We allocate a workspace - * consisting of M+2 row groups (where M = min_DCT_scaled_size is the number - * of row groups per iMCU row). We create two sets of redundant pointers to - * the workspace. Labeling the physical row groups 0 to M+1, the synthesized - * pointer lists look like this: - * M+1 M-1 - * master pointer --> 0 master pointer --> 0 - * 1 1 - * ... ... - * M-3 M-3 - * M-2 M - * M-1 M+1 - * M M-2 - * M+1 M-1 - * 0 0 - * We read alternate iMCU rows using each master pointer; thus the last two - * row groups of the previous iMCU row remain un-overwritten in the workspace. - * The pointer lists are set up so that the required context rows appear to - * be adjacent to the proper places when we pass the pointer lists to the - * upsampler. - * - * The above pictures describe the normal state of the pointer lists. - * At top and bottom of the image, we diddle the pointer lists to duplicate - * the first or last sample row as necessary (this is cheaper than copying - * sample rows around). - * - * This scheme breaks down if M < 2, ie, min_DCT_scaled_size is 1. In that - * situation each iMCU row provides only one row group so the buffering logic - * must be different (eg, we must read two iMCU rows before we can emit the - * first row group). For now, we simply do not support providing context - * rows when min_DCT_scaled_size is 1. That combination seems unlikely to - * be worth providing --- if someone wants a 1/8th-size preview, they probably - * want it quick and dirty, so a context-free upsampler is sufficient. - */ - - -/* Private buffer controller object */ - -typedef struct { - struct jpeg_d_main_controller pub; /* public fields */ - - /* Pointer to allocated workspace (M or M+2 row groups). */ - JSAMPARRAY buffer[MAX_COMPONENTS]; - - boolean buffer_full; /* Have we gotten an iMCU row from decoder? */ - JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */ - - /* Remaining fields are only used in the context case. */ - - /* These are the master pointers to the funny-order pointer lists. */ - JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */ - - int whichptr; /* indicates which pointer set is now in use */ - int context_state; /* process_data state machine status */ - JDIMENSION rowgroups_avail; /* row groups available to postprocessor */ - JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */ -} my_main_controller4; - -typedef my_main_controller4 * my_main_ptr4; - -/* context_state values: */ -#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */ -#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */ -#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */ - - -/* Forward declarations */ -METHODDEF(void) process_data_simple_main2 - JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, - JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); -METHODDEF(void) process_data_context_main - JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, - JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); -#ifdef QUANT_2PASS_SUPPORTED -METHODDEF(void) process_data_crank_post - JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, - JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); -#endif - - -LOCAL(void) -alloc_funny_pointers (j_decompress_ptr cinfo) -/* Allocate space for the funny pointer lists. - * This is done only once, not once per pass. - */ -{ - my_main_ptr4 main_ = (my_main_ptr4) cinfo->main; - int ci, rgroup; - int M = cinfo->min_DCT_scaled_size; - jpeg_component_info *compptr; - JSAMPARRAY xbuf; - - /* Get top-level space for component array pointers. - * We alloc both arrays with one call to save a few cycles. - */ - main_->xbuffer[0] = (JSAMPIMAGE) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - cinfo->num_components * 2 * SIZEOF(JSAMPARRAY)); - main_->xbuffer[1] = main_->xbuffer[0] + cinfo->num_components; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / - cinfo->min_DCT_scaled_size; /* height of a row group of component */ - /* Get space for pointer lists --- M+4 row groups in each list. - * We alloc both pointer lists with one call to save a few cycles. - */ - xbuf = (JSAMPARRAY) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW)); - xbuf += rgroup; /* want one row group at negative offsets */ - main_->xbuffer[0][ci] = xbuf; - xbuf += rgroup * (M + 4); - main_->xbuffer[1][ci] = xbuf; - } -} - - -LOCAL(void) -make_funny_pointers (j_decompress_ptr cinfo) -/* Create the funny pointer lists discussed in the comments above. - * The actual workspace is already allocated (in main->buffer), - * and the space for the pointer lists is allocated too. - * This routine just fills in the curiously ordered lists. - * This will be repeated at the beginning of each pass. - */ -{ - my_main_ptr4 main_ = (my_main_ptr4) cinfo->main; - int ci, i, rgroup; - int M = cinfo->min_DCT_scaled_size; - jpeg_component_info *compptr; - JSAMPARRAY buf, xbuf0, xbuf1; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / - cinfo->min_DCT_scaled_size; /* height of a row group of component */ - xbuf0 = main_->xbuffer[0][ci]; - xbuf1 = main_->xbuffer[1][ci]; - /* First copy the workspace pointers as-is */ - buf = main_->buffer[ci]; - for (i = 0; i < rgroup * (M + 2); i++) { - xbuf0[i] = xbuf1[i] = buf[i]; - } - /* In the second list, put the last four row groups in swapped order */ - for (i = 0; i < rgroup * 2; i++) { - xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i]; - xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i]; - } - /* The wraparound pointers at top and bottom will be filled later - * (see set_wraparound_pointers, below). Initially we want the "above" - * pointers to duplicate the first actual data line. This only needs - * to happen in xbuffer[0]. - */ - for (i = 0; i < rgroup; i++) { - xbuf0[i - rgroup] = xbuf0[0]; - } - } -} - - -LOCAL(void) -set_wraparound_pointers (j_decompress_ptr cinfo) -/* Set up the "wraparound" pointers at top and bottom of the pointer lists. - * This changes the pointer list state from top-of-image to the normal state. - */ -{ - my_main_ptr4 main_ = (my_main_ptr4) cinfo->main; - int ci, i, rgroup; - int M = cinfo->min_DCT_scaled_size; - jpeg_component_info *compptr; - JSAMPARRAY xbuf0, xbuf1; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / - cinfo->min_DCT_scaled_size; /* height of a row group of component */ - xbuf0 = main_->xbuffer[0][ci]; - xbuf1 = main_->xbuffer[1][ci]; - for (i = 0; i < rgroup; i++) { - xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i]; - xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i]; - xbuf0[rgroup*(M+2) + i] = xbuf0[i]; - xbuf1[rgroup*(M+2) + i] = xbuf1[i]; - } - } -} - - -LOCAL(void) -set_bottom_pointers (j_decompress_ptr cinfo) -/* Change the pointer lists to duplicate the last sample row at the bottom - * of the image. whichptr indicates which xbuffer holds the final iMCU row. - * Also sets rowgroups_avail to indicate number of nondummy row groups in row. - */ -{ - my_main_ptr4 main_ = (my_main_ptr4) cinfo->main; - int ci, i, rgroup, iMCUheight, rows_left; - jpeg_component_info *compptr; - JSAMPARRAY xbuf; - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Count sample rows in one iMCU row and in one row group */ - iMCUheight = compptr->v_samp_factor * compptr->DCT_scaled_size; - rgroup = iMCUheight / cinfo->min_DCT_scaled_size; - /* Count nondummy sample rows remaining for this component */ - rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight); - if (rows_left == 0) rows_left = iMCUheight; - /* Count nondummy row groups. Should get same answer for each component, - * so we need only do it once. - */ - if (ci == 0) { - main_->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1); - } - /* Duplicate the last real sample row rgroup*2 times; this pads out the - * last partial rowgroup and ensures at least one full rowgroup of context. - */ - xbuf = main_->xbuffer[main_->whichptr][ci]; - for (i = 0; i < rgroup * 2; i++) { - xbuf[rows_left + i] = xbuf[rows_left-1]; - } - } -} - - -/* - * Initialize for a processing pass. - */ - -METHODDEF(void) -start_pass_main2 (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) -{ - my_main_ptr4 main_ = (my_main_ptr4) cinfo->main; - - switch (pass_mode) { - case JBUF_PASS_THRU: - if (cinfo->upsample->need_context_rows) { - main_->pub.process_data = process_data_context_main; - make_funny_pointers(cinfo); /* Create the xbuffer[] lists */ - main_->whichptr = 0; /* Read first iMCU row into xbuffer[0] */ - main_->context_state = CTX_PREPARE_FOR_IMCU; - main_->iMCU_row_ctr = 0; - } else { - /* Simple case with no context needed */ - main_->pub.process_data = process_data_simple_main2; - } - main_->buffer_full = FALSE; /* Mark buffer empty */ - main_->rowgroup_ctr = 0; - break; -#ifdef QUANT_2PASS_SUPPORTED - case JBUF_CRANK_DEST: - /* For last pass of 2-pass quantization, just crank the postprocessor */ - main_->pub.process_data = process_data_crank_post; - break; -#endif - default: - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - break; - } -} - - -/* - * Process some data. - * This handles the simple case where no context is required. - */ - -METHODDEF(void) -process_data_simple_main2 (j_decompress_ptr cinfo, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail) -{ - my_main_ptr4 main_ = (my_main_ptr4) cinfo->main; - JDIMENSION rowgroups_avail; - - /* Read input data if we haven't filled the main buffer yet */ - if (! main_->buffer_full) { - if (! (*cinfo->coef->decompress_data) (cinfo, main_->buffer)) - return; /* suspension forced, can do nothing more */ - main_->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ - } - - /* There are always min_DCT_scaled_size row groups in an iMCU row. */ - rowgroups_avail = (JDIMENSION) cinfo->min_DCT_scaled_size; - /* Note: at the bottom of the image, we may pass extra garbage row groups - * to the postprocessor. The postprocessor has to check for bottom - * of image anyway (at row resolution), so no point in us doing it too. - */ - - /* Feed the postprocessor */ - (*cinfo->post->post_process_data) (cinfo, main_->buffer, - &main_->rowgroup_ctr, rowgroups_avail, - output_buf, out_row_ctr, out_rows_avail); - - /* Has postprocessor consumed all the data yet? If so, mark buffer empty */ - if (main_->rowgroup_ctr >= rowgroups_avail) { - main_->buffer_full = FALSE; - main_->rowgroup_ctr = 0; - } -} - - -/* - * Process some data. - * This handles the case where context rows must be provided. - */ - -METHODDEF(void) -process_data_context_main (j_decompress_ptr cinfo, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail) -{ - my_main_ptr4 main_ = (my_main_ptr4) cinfo->main; - - /* Read input data if we haven't filled the main buffer yet */ - if (! main_->buffer_full) { - if (! (*cinfo->coef->decompress_data) (cinfo, - main_->xbuffer[main_->whichptr])) - return; /* suspension forced, can do nothing more */ - main_->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ - main_->iMCU_row_ctr++; /* count rows received */ - } - - /* Postprocessor typically will not swallow all the input data it is handed - * in one call (due to filling the output buffer first). Must be prepared - * to exit and restart. This switch lets us keep track of how far we got. - * Note that each case falls through to the next on successful completion. - */ - switch (main_->context_state) { - case CTX_POSTPONED_ROW: - /* Call postprocessor using previously set pointers for postponed row */ - (*cinfo->post->post_process_data) (cinfo, main_->xbuffer[main_->whichptr], - &main_->rowgroup_ctr, main_->rowgroups_avail, - output_buf, out_row_ctr, out_rows_avail); - if (main_->rowgroup_ctr < main_->rowgroups_avail) - return; /* Need to suspend */ - main_->context_state = CTX_PREPARE_FOR_IMCU; - if (*out_row_ctr >= out_rows_avail) - return; /* Postprocessor exactly filled output buf */ - /*FALLTHROUGH*/ - case CTX_PREPARE_FOR_IMCU: - /* Prepare to process first M-1 row groups of this iMCU row */ - main_->rowgroup_ctr = 0; - main_->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size - 1); - /* Check for bottom of image: if so, tweak pointers to "duplicate" - * the last sample row, and adjust rowgroups_avail to ignore padding rows. - */ - if (main_->iMCU_row_ctr == cinfo->total_iMCU_rows) - set_bottom_pointers(cinfo); - main_->context_state = CTX_PROCESS_IMCU; - /*FALLTHROUGH*/ - case CTX_PROCESS_IMCU: - /* Call postprocessor using previously set pointers */ - (*cinfo->post->post_process_data) (cinfo, main_->xbuffer[main_->whichptr], - &main_->rowgroup_ctr, main_->rowgroups_avail, - output_buf, out_row_ctr, out_rows_avail); - if (main_->rowgroup_ctr < main_->rowgroups_avail) - return; /* Need to suspend */ - /* After the first iMCU, change wraparound pointers to normal state */ - if (main_->iMCU_row_ctr == 1) - set_wraparound_pointers(cinfo); - /* Prepare to load new iMCU row using other xbuffer list */ - main_->whichptr ^= 1; /* 0=>1 or 1=>0 */ - main_->buffer_full = FALSE; - /* Still need to process last row group of this iMCU row, */ - /* which is saved at index M+1 of the other xbuffer */ - main_->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_scaled_size + 1); - main_->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size + 2); - main_->context_state = CTX_POSTPONED_ROW; - } -} - - -/* - * Process some data. - * Final pass of two-pass quantization: just call the postprocessor. - * Source data will be the postprocessor controller's internal buffer. - */ - -#ifdef QUANT_2PASS_SUPPORTED - -METHODDEF(void) -process_data_crank_post (j_decompress_ptr cinfo, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail) -{ - (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL, - (JDIMENSION *) NULL, (JDIMENSION) 0, - output_buf, out_row_ctr, out_rows_avail); -} - -#endif /* QUANT_2PASS_SUPPORTED */ - - -/* - * Initialize main buffer controller. - */ - -GLOBAL(void) -jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer) -{ - my_main_ptr4 main_; - int ci, rgroup, ngroups; - jpeg_component_info *compptr; - - main_ = (my_main_ptr4) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_main_controller4)); - cinfo->main = (struct jpeg_d_main_controller *) main_; - main_->pub.start_pass = start_pass_main2; - - if (need_full_buffer) /* shouldn't happen */ - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - - /* Allocate the workspace. - * ngroups is the number of row groups we need. - */ - if (cinfo->upsample->need_context_rows) { - if (cinfo->min_DCT_scaled_size < 2) /* unsupported, see comments above */ - ERREXIT(cinfo, JERR_NOTIMPL); - alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */ - ngroups = cinfo->min_DCT_scaled_size + 2; - } else { - ngroups = cinfo->min_DCT_scaled_size; - } - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / - cinfo->min_DCT_scaled_size; /* height of a row group of component */ - main_->buffer[ci] = (*cinfo->mem->alloc_sarray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - compptr->width_in_blocks * compptr->DCT_scaled_size, - (JDIMENSION) (rgroup * ngroups)); - } -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jdmarker.c b/source/modules/juce_graphics/image_formats/jpglib/jdmarker.c deleted file mode 100644 index 0a57cca41..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jdmarker.c +++ /dev/null @@ -1,1292 +0,0 @@ -/* - * jdmarker.c - * - * Copyright (C) 1991-1998, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains routines to decode JPEG datastream markers. - * Most of the complexity arises from our desire to support input - * suspension: if not all of the data for a marker is available, - * we must exit back to the application. On resumption, we reprocess - * the marker. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Private state */ - -typedef struct { - struct jpeg_marker_reader pub; /* public fields */ - - /* Application-overridable marker processing methods */ - jpeg_marker_parser_method process_COM; - jpeg_marker_parser_method process_APPn[16]; - - /* Limit on marker data length to save for each marker type */ - unsigned int length_limit_COM; - unsigned int length_limit_APPn[16]; - - /* Status of COM/APPn marker saving */ - jpeg_saved_marker_ptr cur_marker; /* NULL if not processing a marker */ - unsigned int bytes_read; /* data bytes read so far in marker */ - /* Note: cur_marker is not linked into marker_list until it's all read. */ -} my_marker_reader; - -typedef my_marker_reader * my_marker_ptr2; - - -/* - * Macros for fetching data from the data source module. - * - * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect - * the current restart point; we update them only when we have reached a - * suitable place to restart if a suspension occurs. - */ - -/* Declare and initialize local copies of input pointer/count */ -#define INPUT_VARS(cinfo) \ - struct jpeg_source_mgr * datasrc = (cinfo)->src; \ - const JOCTET * next_input_byte = datasrc->next_input_byte; \ - size_t bytes_in_buffer = datasrc->bytes_in_buffer - -/* Unload the local copies --- do this only at a restart boundary */ -#define INPUT_SYNC(cinfo) \ - ( datasrc->next_input_byte = next_input_byte, \ - datasrc->bytes_in_buffer = bytes_in_buffer ) - -/* Reload the local copies --- used only in MAKE_BYTE_AVAIL */ -#define INPUT_RELOAD(cinfo) \ - ( next_input_byte = datasrc->next_input_byte, \ - bytes_in_buffer = datasrc->bytes_in_buffer ) - -/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available. - * Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - * but we must reload the local copies after a successful fill. - */ -#define MAKE_BYTE_AVAIL(cinfo,action) \ - if (bytes_in_buffer == 0) { \ - if (! (*datasrc->fill_input_buffer) (cinfo)) \ - { action; } \ - INPUT_RELOAD(cinfo); \ - } - -/* Read a byte into variable V. - * If must suspend, take the specified action (typically "return FALSE"). - */ -#define INPUT_BYTE(cinfo,V,action) \ - MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ - bytes_in_buffer--; \ - V = GETJOCTET(*next_input_byte++); ) - -/* As above, but read two bytes interpreted as an unsigned 16-bit integer. - * V should be declared unsigned int or perhaps INT32. - */ -#define INPUT_2BYTES(cinfo,V,action) \ - MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ - bytes_in_buffer--; \ - V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \ - MAKE_BYTE_AVAIL(cinfo,action); \ - bytes_in_buffer--; \ - V += GETJOCTET(*next_input_byte++); ) - - -/* - * Routines to process JPEG markers. - * - * Entry condition: JPEG marker itself has been read and its code saved - * in cinfo->unread_marker; input restart point is just after the marker. - * - * Exit: if return TRUE, have read and processed any parameters, and have - * updated the restart point to point after the parameters. - * If return FALSE, was forced to suspend before reaching end of - * marker parameters; restart point has not been moved. Same routine - * will be called again after application supplies more input data. - * - * This approach to suspension assumes that all of a marker's parameters - * can fit into a single input bufferload. This should hold for "normal" - * markers. Some COM/APPn markers might have large parameter segments - * that might not fit. If we are simply dropping such a marker, we use - * skip_input_data to get past it, and thereby put the problem on the - * source manager's shoulders. If we are saving the marker's contents - * into memory, we use a slightly different convention: when forced to - * suspend, the marker processor updates the restart point to the end of - * what it's consumed (ie, the end of the buffer) before returning FALSE. - * On resumption, cinfo->unread_marker still contains the marker code, - * but the data source will point to the next chunk of marker data. - * The marker processor must retain internal state to deal with this. - * - * Note that we don't bother to avoid duplicate trace messages if a - * suspension occurs within marker parameters. Other side effects - * require more care. - */ - - -LOCAL(boolean) -get_soi (j_decompress_ptr cinfo) -/* Process an SOI marker */ -{ - int i; - - TRACEMS(cinfo, 1, JTRC_SOI); - - if (cinfo->marker->saw_SOI) - ERREXIT(cinfo, JERR_SOI_DUPLICATE); - - /* Reset all parameters that are defined to be reset by SOI */ - - for (i = 0; i < NUM_ARITH_TBLS; i++) { - cinfo->arith_dc_L[i] = 0; - cinfo->arith_dc_U[i] = 1; - cinfo->arith_ac_K[i] = 5; - } - cinfo->restart_interval = 0; - - /* Set initial assumptions for colorspace etc */ - - cinfo->jpeg_color_space = JCS_UNKNOWN; - cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling??? */ - - cinfo->saw_JFIF_marker = FALSE; - cinfo->JFIF_major_version = 1; /* set default JFIF APP0 values */ - cinfo->JFIF_minor_version = 1; - cinfo->density_unit = 0; - cinfo->X_density = 1; - cinfo->Y_density = 1; - cinfo->saw_Adobe_marker = FALSE; - cinfo->Adobe_transform = 0; - - cinfo->marker->saw_SOI = TRUE; - - return TRUE; -} - - -LOCAL(boolean) -get_sof (j_decompress_ptr cinfo, boolean is_prog, boolean is_arith) -/* Process a SOFn marker */ -{ - INT32 length; - int c, ci; - jpeg_component_info * compptr; - INPUT_VARS(cinfo); - - cinfo->progressive_mode = is_prog; - cinfo->arith_code = is_arith; - - INPUT_2BYTES(cinfo, length, return FALSE); - - INPUT_BYTE(cinfo, cinfo->data_precision, return FALSE); - INPUT_2BYTES(cinfo, cinfo->image_height, return FALSE); - INPUT_2BYTES(cinfo, cinfo->image_width, return FALSE); - INPUT_BYTE(cinfo, cinfo->num_components, return FALSE); - - length -= 8; - - TRACEMS4(cinfo, 1, JTRC_SOF, cinfo->unread_marker, - (int) cinfo->image_width, (int) cinfo->image_height, - cinfo->num_components); - - if (cinfo->marker->saw_SOF) - ERREXIT(cinfo, JERR_SOF_DUPLICATE); - - /* We don't support files in which the image height is initially specified */ - /* as 0 and is later redefined by DNL. As long as we have to check that, */ - /* might as well have a general sanity check. */ - if (cinfo->image_height <= 0 || cinfo->image_width <= 0 - || cinfo->num_components <= 0) - ERREXIT(cinfo, JERR_EMPTY_IMAGE); - - if (length != (cinfo->num_components * 3)) - ERREXIT(cinfo, JERR_BAD_LENGTH); - - if (cinfo->comp_info == NULL) /* do only once, even if suspend */ - cinfo->comp_info = (jpeg_component_info *) (*cinfo->mem->alloc_small) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - cinfo->num_components * SIZEOF(jpeg_component_info)); - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - compptr->component_index = ci; - INPUT_BYTE(cinfo, compptr->component_id, return FALSE); - INPUT_BYTE(cinfo, c, return FALSE); - compptr->h_samp_factor = (c >> 4) & 15; - compptr->v_samp_factor = (c ) & 15; - INPUT_BYTE(cinfo, compptr->quant_tbl_no, return FALSE); - - TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT, - compptr->component_id, compptr->h_samp_factor, - compptr->v_samp_factor, compptr->quant_tbl_no); - } - - cinfo->marker->saw_SOF = TRUE; - - INPUT_SYNC(cinfo); - return TRUE; -} - - -LOCAL(boolean) -get_sos (j_decompress_ptr cinfo) -/* Process a SOS marker */ -{ - INT32 length; - int i, ci, n, c, cc; - jpeg_component_info * compptr; - INPUT_VARS(cinfo); - - if (! cinfo->marker->saw_SOF) - ERREXIT(cinfo, JERR_SOS_NO_SOF); - - INPUT_2BYTES(cinfo, length, return FALSE); - - INPUT_BYTE(cinfo, n, return FALSE); /* Number of components */ - - TRACEMS1(cinfo, 1, JTRC_SOS, n); - - if (length != (n * 2 + 6) || n < 1 || n > MAX_COMPS_IN_SCAN) - ERREXIT(cinfo, JERR_BAD_LENGTH); - - cinfo->comps_in_scan = n; - - /* Collect the component-spec parameters */ - - for (i = 0; i < n; i++) { - INPUT_BYTE(cinfo, cc, return FALSE); - INPUT_BYTE(cinfo, c, return FALSE); - - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - if (cc == compptr->component_id) - goto id_found; - } - - ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, cc); - - id_found: - - cinfo->cur_comp_info[i] = compptr; - compptr->dc_tbl_no = (c >> 4) & 15; - compptr->ac_tbl_no = (c ) & 15; - - TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, cc, - compptr->dc_tbl_no, compptr->ac_tbl_no); - } - - /* Collect the additional scan parameters Ss, Se, Ah/Al. */ - INPUT_BYTE(cinfo, c, return FALSE); - cinfo->Ss = c; - INPUT_BYTE(cinfo, c, return FALSE); - cinfo->Se = c; - INPUT_BYTE(cinfo, c, return FALSE); - cinfo->Ah = (c >> 4) & 15; - cinfo->Al = (c ) & 15; - - TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo->Ss, cinfo->Se, - cinfo->Ah, cinfo->Al); - - /* Prepare to scan data & restart markers */ - cinfo->marker->next_restart_num = 0; - - /* Count another SOS marker */ - cinfo->input_scan_number++; - - INPUT_SYNC(cinfo); - return TRUE; -} - - -#ifdef D_ARITH_CODING_SUPPORTED - -LOCAL(boolean) -get_dac (j_decompress_ptr cinfo) -/* Process a DAC marker */ -{ - INT32 length; - int index, val; - INPUT_VARS(cinfo); - - INPUT_2BYTES(cinfo, length, return FALSE); - length -= 2; - - while (length > 0) { - INPUT_BYTE(cinfo, index, return FALSE); - INPUT_BYTE(cinfo, val, return FALSE); - - length -= 2; - - TRACEMS2(cinfo, 1, JTRC_DAC, index, val); - - if (index < 0 || index >= (2*NUM_ARITH_TBLS)) - ERREXIT1(cinfo, JERR_DAC_INDEX, index); - - if (index >= NUM_ARITH_TBLS) { /* define AC table */ - cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = (UINT8) val; - } else { /* define DC table */ - cinfo->arith_dc_L[index] = (UINT8) (val & 0x0F); - cinfo->arith_dc_U[index] = (UINT8) (val >> 4); - if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index]) - ERREXIT1(cinfo, JERR_DAC_VALUE, val); - } - } - - if (length != 0) - ERREXIT(cinfo, JERR_BAD_LENGTH); - - INPUT_SYNC(cinfo); - return TRUE; -} - -#else /* ! D_ARITH_CODING_SUPPORTED */ - -#define get_dac(cinfo) skip_variable(cinfo) - -#endif /* D_ARITH_CODING_SUPPORTED */ - - -LOCAL(boolean) -get_dht (j_decompress_ptr cinfo) -/* Process a DHT marker */ -{ - INT32 length; - UINT8 bits[17]; - UINT8 huffval[256]; - int i, index, count; - JHUFF_TBL **htblptr; - INPUT_VARS(cinfo); - - INPUT_2BYTES(cinfo, length, return FALSE); - length -= 2; - - while (length > 16) { - INPUT_BYTE(cinfo, index, return FALSE); - - TRACEMS1(cinfo, 1, JTRC_DHT, index); - - bits[0] = 0; - count = 0; - for (i = 1; i <= 16; i++) { - INPUT_BYTE(cinfo, bits[i], return FALSE); - count += bits[i]; - } - - length -= 1 + 16; - - TRACEMS8(cinfo, 2, JTRC_HUFFBITS, - bits[1], bits[2], bits[3], bits[4], - bits[5], bits[6], bits[7], bits[8]); - TRACEMS8(cinfo, 2, JTRC_HUFFBITS, - bits[9], bits[10], bits[11], bits[12], - bits[13], bits[14], bits[15], bits[16]); - - /* Here we just do minimal validation of the counts to avoid walking - * off the end of our table space. jdhuff.c will check more carefully. - */ - if (count > 256 || ((INT32) count) > length) - ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); - - for (i = 0; i < count; i++) - INPUT_BYTE(cinfo, huffval[i], return FALSE); - - length -= count; - - if (index & 0x10) { /* AC table definition */ - index -= 0x10; - htblptr = &cinfo->ac_huff_tbl_ptrs[index]; - } else { /* DC table definition */ - htblptr = &cinfo->dc_huff_tbl_ptrs[index]; - } - - if (index < 0 || index >= NUM_HUFF_TBLS) - ERREXIT1(cinfo, JERR_DHT_INDEX, index); - - if (*htblptr == NULL) - *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); - - MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); - MEMCOPY((*htblptr)->huffval, huffval, SIZEOF((*htblptr)->huffval)); - } - - if (length != 0) - ERREXIT(cinfo, JERR_BAD_LENGTH); - - INPUT_SYNC(cinfo); - return TRUE; -} - - -LOCAL(boolean) -get_dqt (j_decompress_ptr cinfo) -/* Process a DQT marker */ -{ - INT32 length; - int n, i, prec; - unsigned int tmp; - JQUANT_TBL *quant_ptr; - INPUT_VARS(cinfo); - - INPUT_2BYTES(cinfo, length, return FALSE); - length -= 2; - - while (length > 0) { - INPUT_BYTE(cinfo, n, return FALSE); - prec = n >> 4; - n &= 0x0F; - - TRACEMS2(cinfo, 1, JTRC_DQT, n, prec); - - if (n >= NUM_QUANT_TBLS) - ERREXIT1(cinfo, JERR_DQT_INDEX, n); - - if (cinfo->quant_tbl_ptrs[n] == NULL) - cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) cinfo); - quant_ptr = cinfo->quant_tbl_ptrs[n]; - - for (i = 0; i < DCTSIZE2; i++) { - if (prec) - INPUT_2BYTES(cinfo, tmp, return FALSE); - else - INPUT_BYTE(cinfo, tmp, return FALSE); - /* We convert the zigzag-order table to natural array order. */ - quant_ptr->quantval[jpeg_natural_order[i]] = (UINT16) tmp; - } - - if (cinfo->err->trace_level >= 2) { - for (i = 0; i < DCTSIZE2; i += 8) { - TRACEMS8(cinfo, 2, JTRC_QUANTVALS, - quant_ptr->quantval[i], quant_ptr->quantval[i+1], - quant_ptr->quantval[i+2], quant_ptr->quantval[i+3], - quant_ptr->quantval[i+4], quant_ptr->quantval[i+5], - quant_ptr->quantval[i+6], quant_ptr->quantval[i+7]); - } - } - - length -= DCTSIZE2+1; - if (prec) length -= DCTSIZE2; - } - - if (length != 0) - ERREXIT(cinfo, JERR_BAD_LENGTH); - - INPUT_SYNC(cinfo); - return TRUE; -} - - -LOCAL(boolean) -get_dri (j_decompress_ptr cinfo) -/* Process a DRI marker */ -{ - INT32 length; - unsigned int tmp; - INPUT_VARS(cinfo); - - INPUT_2BYTES(cinfo, length, return FALSE); - - if (length != 4) - ERREXIT(cinfo, JERR_BAD_LENGTH); - - INPUT_2BYTES(cinfo, tmp, return FALSE); - - TRACEMS1(cinfo, 1, JTRC_DRI, tmp); - - cinfo->restart_interval = tmp; - - INPUT_SYNC(cinfo); - return TRUE; -} - - -/* - * Routines for processing APPn and COM markers. - * These are either saved in memory or discarded, per application request. - * APP0 and APP14 are specially checked to see if they are - * JFIF and Adobe markers, respectively. - */ - -#define APP0_DATA_LEN 14 /* Length of interesting data in APP0 */ -#define APP14_DATA_LEN 12 /* Length of interesting data in APP14 */ -#define APPN_DATA_LEN 14 /* Must be the largest of the above!! */ - - -LOCAL(void) -examine_app0 (j_decompress_ptr cinfo, JOCTET FAR * data, - unsigned int datalen, INT32 remaining) -/* Examine first few bytes from an APP0. - * Take appropriate action if it is a JFIF marker. - * datalen is # of bytes at data[], remaining is length of rest of marker data. - */ -{ - INT32 totallen = (INT32) datalen + remaining; - - if (datalen >= APP0_DATA_LEN && - GETJOCTET(data[0]) == 0x4A && - GETJOCTET(data[1]) == 0x46 && - GETJOCTET(data[2]) == 0x49 && - GETJOCTET(data[3]) == 0x46 && - GETJOCTET(data[4]) == 0) { - /* Found JFIF APP0 marker: save info */ - cinfo->saw_JFIF_marker = TRUE; - cinfo->JFIF_major_version = GETJOCTET(data[5]); - cinfo->JFIF_minor_version = GETJOCTET(data[6]); - cinfo->density_unit = GETJOCTET(data[7]); - cinfo->X_density = (GETJOCTET(data[8]) << 8) + GETJOCTET(data[9]); - cinfo->Y_density = (GETJOCTET(data[10]) << 8) + GETJOCTET(data[11]); - /* Check version. - * Major version must be 1, anything else signals an incompatible change. - * (We used to treat this as an error, but now it's a nonfatal warning, - * because some bozo at Hijaak couldn't read the spec.) - * Minor version should be 0..2, but process anyway if newer. - */ - if (cinfo->JFIF_major_version != 1) - WARNMS2(cinfo, JWRN_JFIF_MAJOR, - cinfo->JFIF_major_version, cinfo->JFIF_minor_version); - /* Generate trace messages */ - TRACEMS5(cinfo, 1, JTRC_JFIF, - cinfo->JFIF_major_version, cinfo->JFIF_minor_version, - cinfo->X_density, cinfo->Y_density, cinfo->density_unit); - /* Validate thumbnail dimensions and issue appropriate messages */ - if (GETJOCTET(data[12]) | GETJOCTET(data[13])) - TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL, - GETJOCTET(data[12]), GETJOCTET(data[13])); - totallen -= APP0_DATA_LEN; - if (totallen != - ((INT32)GETJOCTET(data[12]) * (INT32)GETJOCTET(data[13]) * (INT32) 3)) - TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) totallen); - } else if (datalen >= 6 && - GETJOCTET(data[0]) == 0x4A && - GETJOCTET(data[1]) == 0x46 && - GETJOCTET(data[2]) == 0x58 && - GETJOCTET(data[3]) == 0x58 && - GETJOCTET(data[4]) == 0) { - /* Found JFIF "JFXX" extension APP0 marker */ - /* The library doesn't actually do anything with these, - * but we try to produce a helpful trace message. - */ - switch (GETJOCTET(data[5])) { - case 0x10: - TRACEMS1(cinfo, 1, JTRC_THUMB_JPEG, (int) totallen); - break; - case 0x11: - TRACEMS1(cinfo, 1, JTRC_THUMB_PALETTE, (int) totallen); - break; - case 0x13: - TRACEMS1(cinfo, 1, JTRC_THUMB_RGB, (int) totallen); - break; - default: - TRACEMS2(cinfo, 1, JTRC_JFIF_EXTENSION, - GETJOCTET(data[5]), (int) totallen); - break; - } - } else { - /* Start of APP0 does not match "JFIF" or "JFXX", or too short */ - TRACEMS1(cinfo, 1, JTRC_APP0, (int) totallen); - } -} - - -LOCAL(void) -examine_app14 (j_decompress_ptr cinfo, JOCTET FAR * data, - unsigned int datalen, INT32 remaining) -/* Examine first few bytes from an APP14. - * Take appropriate action if it is an Adobe marker. - * datalen is # of bytes at data[], remaining is length of rest of marker data. - */ -{ - unsigned int version, flags0, flags1, transform; - - if (datalen >= APP14_DATA_LEN && - GETJOCTET(data[0]) == 0x41 && - GETJOCTET(data[1]) == 0x64 && - GETJOCTET(data[2]) == 0x6F && - GETJOCTET(data[3]) == 0x62 && - GETJOCTET(data[4]) == 0x65) { - /* Found Adobe APP14 marker */ - version = (GETJOCTET(data[5]) << 8) + GETJOCTET(data[6]); - flags0 = (GETJOCTET(data[7]) << 8) + GETJOCTET(data[8]); - flags1 = (GETJOCTET(data[9]) << 8) + GETJOCTET(data[10]); - transform = GETJOCTET(data[11]); - TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform); - cinfo->saw_Adobe_marker = TRUE; - cinfo->Adobe_transform = (UINT8) transform; - } else { - /* Start of APP14 does not match "Adobe", or too short */ - TRACEMS1(cinfo, 1, JTRC_APP14, (int) (datalen + remaining)); - } -} - - -METHODDEF(boolean) -get_interesting_appn (j_decompress_ptr cinfo) -/* Process an APP0 or APP14 marker without saving it */ -{ - INT32 length; - JOCTET b[APPN_DATA_LEN]; - unsigned int i, numtoread; - INPUT_VARS(cinfo); - - INPUT_2BYTES(cinfo, length, return FALSE); - length -= 2; - - /* get the interesting part of the marker data */ - if (length >= APPN_DATA_LEN) - numtoread = APPN_DATA_LEN; - else if (length > 0) - numtoread = (unsigned int) length; - else - numtoread = 0; - for (i = 0; i < numtoread; i++) - INPUT_BYTE(cinfo, b[i], return FALSE); - length -= numtoread; - - /* process it */ - switch (cinfo->unread_marker) { - case M_APP0: - examine_app0(cinfo, (JOCTET FAR *) b, numtoread, length); - break; - case M_APP14: - examine_app14(cinfo, (JOCTET FAR *) b, numtoread, length); - break; - default: - /* can't get here unless jpeg_save_markers chooses wrong processor */ - ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); - break; - } - - /* skip any remaining data -- could be lots */ - INPUT_SYNC(cinfo); - if (length > 0) - (*cinfo->src->skip_input_data) (cinfo, (long) length); - - return TRUE; -} - - -#ifdef SAVE_MARKERS_SUPPORTED - -METHODDEF(boolean) -save_marker (j_decompress_ptr cinfo) -/* Save an APPn or COM marker into the marker list */ -{ - my_marker_ptr2 marker = (my_marker_ptr2) cinfo->marker; - jpeg_saved_marker_ptr cur_marker = marker->cur_marker; - unsigned int bytes_read, data_length; - JOCTET FAR * data; - INT32 length = 0; - INPUT_VARS(cinfo); - - if (cur_marker == NULL) { - /* begin reading a marker */ - INPUT_2BYTES(cinfo, length, return FALSE); - length -= 2; - if (length >= 0) { /* watch out for bogus length word */ - /* figure out how much we want to save */ - unsigned int limit; - if (cinfo->unread_marker == (int) M_COM) - limit = marker->length_limit_COM; - else - limit = marker->length_limit_APPn[cinfo->unread_marker - (int) M_APP0]; - if ((unsigned int) length < limit) - limit = (unsigned int) length; - /* allocate and initialize the marker item */ - cur_marker = (jpeg_saved_marker_ptr) - (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(struct jpeg_marker_struct) + limit); - cur_marker->next = NULL; - cur_marker->marker = (UINT8) cinfo->unread_marker; - cur_marker->original_length = (unsigned int) length; - cur_marker->data_length = limit; - /* data area is just beyond the jpeg_marker_struct */ - data = cur_marker->data = (JOCTET FAR *) (cur_marker + 1); - marker->cur_marker = cur_marker; - marker->bytes_read = 0; - bytes_read = 0; - data_length = limit; - } else { - /* deal with bogus length word */ - bytes_read = data_length = 0; - data = NULL; - } - } else { - /* resume reading a marker */ - bytes_read = marker->bytes_read; - data_length = cur_marker->data_length; - data = cur_marker->data + bytes_read; - } - - while (bytes_read < data_length) { - INPUT_SYNC(cinfo); /* move the restart point to here */ - marker->bytes_read = bytes_read; - /* If there's not at least one byte in buffer, suspend */ - MAKE_BYTE_AVAIL(cinfo, return FALSE); - /* Copy bytes with reasonable rapidity */ - while (bytes_read < data_length && bytes_in_buffer > 0) { - *data++ = *next_input_byte++; - bytes_in_buffer--; - bytes_read++; - } - } - - /* Done reading what we want to read */ - if (cur_marker != NULL) { /* will be NULL if bogus length word */ - /* Add new marker to end of list */ - if (cinfo->marker_list == NULL) { - cinfo->marker_list = cur_marker; - } else { - jpeg_saved_marker_ptr prev = cinfo->marker_list; - while (prev->next != NULL) - prev = prev->next; - prev->next = cur_marker; - } - /* Reset pointer & calc remaining data length */ - data = cur_marker->data; - length = cur_marker->original_length - data_length; - } - /* Reset to initial state for next marker */ - marker->cur_marker = NULL; - - /* Process the marker if interesting; else just make a generic trace msg */ - switch (cinfo->unread_marker) { - case M_APP0: - examine_app0(cinfo, data, data_length, length); - break; - case M_APP14: - examine_app14(cinfo, data, data_length, length); - break; - default: - TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, - (int) (data_length + length)); - break; - } - - /* skip any remaining data -- could be lots */ - INPUT_SYNC(cinfo); /* do before skip_input_data */ - if (length > 0) - (*cinfo->src->skip_input_data) (cinfo, (long) length); - - return TRUE; -} - -#endif /* SAVE_MARKERS_SUPPORTED */ - - -METHODDEF(boolean) -skip_variable (j_decompress_ptr cinfo) -/* Skip over an unknown or uninteresting variable-length marker */ -{ - INT32 length; - INPUT_VARS(cinfo); - - INPUT_2BYTES(cinfo, length, return FALSE); - length -= 2; - - TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, (int) length); - - INPUT_SYNC(cinfo); /* do before skip_input_data */ - if (length > 0) - (*cinfo->src->skip_input_data) (cinfo, (long) length); - - return TRUE; -} - - -/* - * Find the next JPEG marker, save it in cinfo->unread_marker. - * Returns FALSE if had to suspend before reaching a marker; - * in that case cinfo->unread_marker is unchanged. - * - * Note that the result might not be a valid marker code, - * but it will never be 0 or FF. - */ - -LOCAL(boolean) -next_marker (j_decompress_ptr cinfo) -{ - int c; - INPUT_VARS(cinfo); - - for (;;) { - INPUT_BYTE(cinfo, c, return FALSE); - /* Skip any non-FF bytes. - * This may look a bit inefficient, but it will not occur in a valid file. - * We sync after each discarded byte so that a suspending data source - * can discard the byte from its buffer. - */ - while (c != 0xFF) { - cinfo->marker->discarded_bytes++; - INPUT_SYNC(cinfo); - INPUT_BYTE(cinfo, c, return FALSE); - } - /* This loop swallows any duplicate FF bytes. Extra FFs are legal as - * pad bytes, so don't count them in discarded_bytes. We assume there - * will not be so many consecutive FF bytes as to overflow a suspending - * data source's input buffer. - */ - do { - INPUT_BYTE(cinfo, c, return FALSE); - } while (c == 0xFF); - if (c != 0) - break; /* found a valid marker, exit loop */ - /* Reach here if we found a stuffed-zero data sequence (FF/00). - * Discard it and loop back to try again. - */ - cinfo->marker->discarded_bytes += 2; - INPUT_SYNC(cinfo); - } - - if (cinfo->marker->discarded_bytes != 0) { - WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo->marker->discarded_bytes, c); - cinfo->marker->discarded_bytes = 0; - } - - cinfo->unread_marker = c; - - INPUT_SYNC(cinfo); - return TRUE; -} - - -LOCAL(boolean) -first_marker (j_decompress_ptr cinfo) -/* Like next_marker, but used to obtain the initial SOI marker. */ -/* For this marker, we do not allow preceding garbage or fill; otherwise, - * we might well scan an entire input file before realizing it ain't JPEG. - * If an application wants to process non-JFIF files, it must seek to the - * SOI before calling the JPEG library. - */ -{ - int c, c2; - INPUT_VARS(cinfo); - - INPUT_BYTE(cinfo, c, return FALSE); - INPUT_BYTE(cinfo, c2, return FALSE); - if (c != 0xFF || c2 != (int) M_SOI) - ERREXIT2(cinfo, JERR_NO_SOI, c, c2); - - cinfo->unread_marker = c2; - - INPUT_SYNC(cinfo); - return TRUE; -} - - -/* - * Read markers until SOS or EOI. - * - * Returns same codes as are defined for jpeg_consume_input: - * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. - */ - -METHODDEF(int) -read_markers (j_decompress_ptr cinfo) -{ - /* Outer loop repeats once for each marker. */ - for (;;) { - /* Collect the marker proper, unless we already did. */ - /* NB: first_marker() enforces the requirement that SOI appear first. */ - if (cinfo->unread_marker == 0) { - if (! cinfo->marker->saw_SOI) { - if (! first_marker(cinfo)) - return JPEG_SUSPENDED; - } else { - if (! next_marker(cinfo)) - return JPEG_SUSPENDED; - } - } - /* At this point cinfo->unread_marker contains the marker code and the - * input point is just past the marker proper, but before any parameters. - * A suspension will cause us to return with this state still true. - */ - switch (cinfo->unread_marker) { - case M_SOI: - if (! get_soi(cinfo)) - return JPEG_SUSPENDED; - break; - - case M_SOF0: /* Baseline */ - case M_SOF1: /* Extended sequential, Huffman */ - if (! get_sof(cinfo, FALSE, FALSE)) - return JPEG_SUSPENDED; - break; - - case M_SOF2: /* Progressive, Huffman */ - if (! get_sof(cinfo, TRUE, FALSE)) - return JPEG_SUSPENDED; - break; - - case M_SOF9: /* Extended sequential, arithmetic */ - if (! get_sof(cinfo, FALSE, TRUE)) - return JPEG_SUSPENDED; - break; - - case M_SOF10: /* Progressive, arithmetic */ - if (! get_sof(cinfo, TRUE, TRUE)) - return JPEG_SUSPENDED; - break; - - /* Currently unsupported SOFn types */ - case M_SOF3: /* Lossless, Huffman */ - case M_SOF5: /* Differential sequential, Huffman */ - case M_SOF6: /* Differential progressive, Huffman */ - case M_SOF7: /* Differential lossless, Huffman */ - case M_JPG: /* Reserved for JPEG extensions */ - case M_SOF11: /* Lossless, arithmetic */ - case M_SOF13: /* Differential sequential, arithmetic */ - case M_SOF14: /* Differential progressive, arithmetic */ - case M_SOF15: /* Differential lossless, arithmetic */ - ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker); - break; - - case M_SOS: - if (! get_sos(cinfo)) - return JPEG_SUSPENDED; - cinfo->unread_marker = 0; /* processed the marker */ - return JPEG_REACHED_SOS; - - case M_EOI: - TRACEMS(cinfo, 1, JTRC_EOI); - cinfo->unread_marker = 0; /* processed the marker */ - return JPEG_REACHED_EOI; - - case M_DAC: - if (! get_dac(cinfo)) - return JPEG_SUSPENDED; - break; - - case M_DHT: - if (! get_dht(cinfo)) - return JPEG_SUSPENDED; - break; - - case M_DQT: - if (! get_dqt(cinfo)) - return JPEG_SUSPENDED; - break; - - case M_DRI: - if (! get_dri(cinfo)) - return JPEG_SUSPENDED; - break; - - case M_APP0: - case M_APP1: - case M_APP2: - case M_APP3: - case M_APP4: - case M_APP5: - case M_APP6: - case M_APP7: - case M_APP8: - case M_APP9: - case M_APP10: - case M_APP11: - case M_APP12: - case M_APP13: - case M_APP14: - case M_APP15: - if (! (*((my_marker_ptr2) cinfo->marker)->process_APPn[ - cinfo->unread_marker - (int) M_APP0]) (cinfo)) - return JPEG_SUSPENDED; - break; - - case M_COM: - if (! (*((my_marker_ptr2) cinfo->marker)->process_COM) (cinfo)) - return JPEG_SUSPENDED; - break; - - case M_RST0: /* these are all parameterless */ - case M_RST1: - case M_RST2: - case M_RST3: - case M_RST4: - case M_RST5: - case M_RST6: - case M_RST7: - case M_TEM: - TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker); - break; - - case M_DNL: /* Ignore DNL ... perhaps the wrong thing */ - if (! skip_variable(cinfo)) - return JPEG_SUSPENDED; - break; - - default: /* must be DHP, EXP, JPGn, or RESn */ - /* For now, we treat the reserved markers as fatal errors since they are - * likely to be used to signal incompatible JPEG Part 3 extensions. - * Once the JPEG 3 version-number marker is well defined, this code - * ought to change! - */ - ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); - break; - } - /* Successfully processed marker, so reset state variable */ - cinfo->unread_marker = 0; - } /* end loop */ -} - - -/* - * Read a restart marker, which is expected to appear next in the datastream; - * if the marker is not there, take appropriate recovery action. - * Returns FALSE if suspension is required. - * - * This is called by the entropy decoder after it has read an appropriate - * number of MCUs. cinfo->unread_marker may be nonzero if the entropy decoder - * has already read a marker from the data source. Under normal conditions - * cinfo->unread_marker will be reset to 0 before returning; if not reset, - * it holds a marker which the decoder will be unable to read past. - */ - -METHODDEF(boolean) -read_restart_marker (j_decompress_ptr cinfo) -{ - /* Obtain a marker unless we already did. */ - /* Note that next_marker will complain if it skips any data. */ - if (cinfo->unread_marker == 0) { - if (! next_marker(cinfo)) - return FALSE; - } - - if (cinfo->unread_marker == - ((int) M_RST0 + cinfo->marker->next_restart_num)) { - /* Normal case --- swallow the marker and let entropy decoder continue */ - TRACEMS1(cinfo, 3, JTRC_RST, cinfo->marker->next_restart_num); - cinfo->unread_marker = 0; - } else { - /* Uh-oh, the restart markers have been messed up. */ - /* Let the data source manager determine how to resync. */ - if (! (*cinfo->src->resync_to_restart) (cinfo, - cinfo->marker->next_restart_num)) - return FALSE; - } - - /* Update next-restart state */ - cinfo->marker->next_restart_num = (cinfo->marker->next_restart_num + 1) & 7; - - return TRUE; -} - - -/* - * This is the default resync_to_restart method for data source managers - * to use if they don't have any better approach. Some data source managers - * may be able to back up, or may have additional knowledge about the data - * which permits a more intelligent recovery strategy; such managers would - * presumably supply their own resync method. - * - * read_restart_marker calls resync_to_restart if it finds a marker other than - * the restart marker it was expecting. (This code is *not* used unless - * a nonzero restart interval has been declared.) cinfo->unread_marker is - * the marker code actually found (might be anything, except 0 or FF). - * The desired restart marker number (0..7) is passed as a parameter. - * This routine is supposed to apply whatever error recovery strategy seems - * appropriate in order to position the input stream to the next data segment. - * Note that cinfo->unread_marker is treated as a marker appearing before - * the current data-source input point; usually it should be reset to zero - * before returning. - * Returns FALSE if suspension is required. - * - * This implementation is substantially constrained by wanting to treat the - * input as a data stream; this means we can't back up. Therefore, we have - * only the following actions to work with: - * 1. Simply discard the marker and let the entropy decoder resume at next - * byte of file. - * 2. Read forward until we find another marker, discarding intervening - * data. (In theory we could look ahead within the current bufferload, - * without having to discard data if we don't find the desired marker. - * This idea is not implemented here, in part because it makes behavior - * dependent on buffer size and chance buffer-boundary positions.) - * 3. Leave the marker unread (by failing to zero cinfo->unread_marker). - * This will cause the entropy decoder to process an empty data segment, - * inserting dummy zeroes, and then we will reprocess the marker. - * - * #2 is appropriate if we think the desired marker lies ahead, while #3 is - * appropriate if the found marker is a future restart marker (indicating - * that we have missed the desired restart marker, probably because it got - * corrupted). - * We apply #2 or #3 if the found marker is a restart marker no more than - * two counts behind or ahead of the expected one. We also apply #2 if the - * found marker is not a legal JPEG marker code (it's certainly bogus data). - * If the found marker is a restart marker more than 2 counts away, we do #1 - * (too much risk that the marker is erroneous; with luck we will be able to - * resync at some future point). - * For any valid non-restart JPEG marker, we apply #3. This keeps us from - * overrunning the end of a scan. An implementation limited to single-scan - * files might find it better to apply #2 for markers other than EOI, since - * any other marker would have to be bogus data in that case. - */ - -GLOBAL(boolean) -jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired) -{ - int marker = cinfo->unread_marker; - int action = 1; - - /* Always put up a warning. */ - WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired); - - /* Outer loop handles repeated decision after scanning forward. */ - for (;;) { - if (marker < (int) M_SOF0) - action = 2; /* invalid marker */ - else if (marker < (int) M_RST0 || marker > (int) M_RST7) - action = 3; /* valid non-restart marker */ - else { - if (marker == ((int) M_RST0 + ((desired+1) & 7)) || - marker == ((int) M_RST0 + ((desired+2) & 7))) - action = 3; /* one of the next two expected restarts */ - else if (marker == ((int) M_RST0 + ((desired-1) & 7)) || - marker == ((int) M_RST0 + ((desired-2) & 7))) - action = 2; /* a prior restart, so advance */ - else - action = 1; /* desired restart or too far away */ - } - TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action); - switch (action) { - case 1: - /* Discard marker and let entropy decoder resume processing. */ - cinfo->unread_marker = 0; - return TRUE; - case 2: - /* Scan to the next marker, and repeat the decision loop. */ - if (! next_marker(cinfo)) - return FALSE; - marker = cinfo->unread_marker; - break; - case 3: - /* Return without advancing past this marker. */ - /* Entropy decoder will be forced to process an empty segment. */ - return TRUE; - } - } /* end loop */ -} - - -/* - * Reset marker processing state to begin a fresh datastream. - */ - -METHODDEF(void) -reset_marker_reader (j_decompress_ptr cinfo) -{ - my_marker_ptr2 marker = (my_marker_ptr2) cinfo->marker; - - cinfo->comp_info = NULL; /* until allocated by get_sof */ - cinfo->input_scan_number = 0; /* no SOS seen yet */ - cinfo->unread_marker = 0; /* no pending marker */ - marker->pub.saw_SOI = FALSE; /* set internal state too */ - marker->pub.saw_SOF = FALSE; - marker->pub.discarded_bytes = 0; - marker->cur_marker = NULL; -} - - -/* - * Initialize the marker reader module. - * This is called only once, when the decompression object is created. - */ - -GLOBAL(void) -jinit_marker_reader (j_decompress_ptr cinfo) -{ - my_marker_ptr2 marker; - int i; - - /* Create subobject in permanent pool */ - marker = (my_marker_ptr2) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - SIZEOF(my_marker_reader)); - cinfo->marker = (struct jpeg_marker_reader *) marker; - /* Initialize public method pointers */ - marker->pub.reset_marker_reader = reset_marker_reader; - marker->pub.read_markers = read_markers; - marker->pub.read_restart_marker = read_restart_marker; - /* Initialize COM/APPn processing. - * By default, we examine and then discard APP0 and APP14, - * but simply discard COM and all other APPn. - */ - marker->process_COM = skip_variable; - marker->length_limit_COM = 0; - for (i = 0; i < 16; i++) { - marker->process_APPn[i] = skip_variable; - marker->length_limit_APPn[i] = 0; - } - marker->process_APPn[0] = get_interesting_appn; - marker->process_APPn[14] = get_interesting_appn; - /* Reset marker processing state */ - reset_marker_reader(cinfo); -} - - -/* - * Control saving of COM and APPn markers into marker_list. - */ - -#ifdef SAVE_MARKERS_SUPPORTED - -GLOBAL(void) -jpeg_save_markers (j_decompress_ptr cinfo, int marker_code, - unsigned int length_limit) -{ - my_marker_ptr2 marker = (my_marker_ptr2) cinfo->marker; - long maxlength; - jpeg_marker_parser_method processor; - - /* Length limit mustn't be larger than what we can allocate - * (should only be a concern in a 16-bit environment). - */ - maxlength = cinfo->mem->max_alloc_chunk - SIZEOF(struct jpeg_marker_struct); - if (((long) length_limit) > maxlength) - length_limit = (unsigned int) maxlength; - - /* Choose processor routine to use. - * APP0/APP14 have special requirements. - */ - if (length_limit) { - processor = save_marker; - /* If saving APP0/APP14, save at least enough for our internal use. */ - if (marker_code == (int) M_APP0 && length_limit < APP0_DATA_LEN) - length_limit = APP0_DATA_LEN; - else if (marker_code == (int) M_APP14 && length_limit < APP14_DATA_LEN) - length_limit = APP14_DATA_LEN; - } else { - processor = skip_variable; - /* If discarding APP0/APP14, use our regular on-the-fly processor. */ - if (marker_code == (int) M_APP0 || marker_code == (int) M_APP14) - processor = get_interesting_appn; - } - - if (marker_code == (int) M_COM) { - marker->process_COM = processor; - marker->length_limit_COM = length_limit; - } else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) { - marker->process_APPn[marker_code - (int) M_APP0] = processor; - marker->length_limit_APPn[marker_code - (int) M_APP0] = length_limit; - } else - ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); -} - -#endif /* SAVE_MARKERS_SUPPORTED */ - - -/* - * Install a special processing method for COM or APPn markers. - */ - -GLOBAL(void) -jpeg_set_marker_processor (j_decompress_ptr cinfo, int marker_code, - jpeg_marker_parser_method routine) -{ - my_marker_ptr2 marker = (my_marker_ptr2) cinfo->marker; - - if (marker_code == (int) M_COM) - marker->process_COM = routine; - else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) - marker->process_APPn[marker_code - (int) M_APP0] = routine; - else - ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jdmaster.c b/source/modules/juce_graphics/image_formats/jpglib/jdmaster.c deleted file mode 100644 index 8c7ec43da..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jdmaster.c +++ /dev/null @@ -1,557 +0,0 @@ -/* - * jdmaster.c - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains master control logic for the JPEG decompressor. - * These routines are concerned with selecting the modules to be executed - * and with determining the number of passes and the work to be done in each - * pass. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Private state */ - -typedef struct { - struct jpeg_decomp_master pub; /* public fields */ - - int pass_number; /* # of passes completed */ - - boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */ - - /* Saved references to initialized quantizer modules, - * in case we need to switch modes. - */ - struct jpeg_color_quantizer * quantizer_1pass; - struct jpeg_color_quantizer * quantizer_2pass; -} my_decomp_master; - -typedef my_decomp_master * my_master_ptr6; - - -/* - * Determine whether merged upsample/color conversion should be used. - * CRUCIAL: this must match the actual capabilities of jdmerge.c! - */ - -LOCAL(boolean) -use_merged_upsample (j_decompress_ptr cinfo) -{ -#ifdef UPSAMPLE_MERGING_SUPPORTED - /* Merging is the equivalent of plain box-filter upsampling */ - if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling) - return FALSE; - /* jdmerge.c only supports YCC=>RGB color conversion */ - if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 || - cinfo->out_color_space != JCS_RGB || - cinfo->out_color_components != RGB_PIXELSIZE) - return FALSE; - /* and it only handles 2h1v or 2h2v sampling ratios */ - if (cinfo->comp_info[0].h_samp_factor != 2 || - cinfo->comp_info[1].h_samp_factor != 1 || - cinfo->comp_info[2].h_samp_factor != 1 || - cinfo->comp_info[0].v_samp_factor > 2 || - cinfo->comp_info[1].v_samp_factor != 1 || - cinfo->comp_info[2].v_samp_factor != 1) - return FALSE; - /* furthermore, it doesn't work if we've scaled the IDCTs differently */ - if (cinfo->comp_info[0].DCT_scaled_size != cinfo->min_DCT_scaled_size || - cinfo->comp_info[1].DCT_scaled_size != cinfo->min_DCT_scaled_size || - cinfo->comp_info[2].DCT_scaled_size != cinfo->min_DCT_scaled_size) - return FALSE; - /* ??? also need to test for upsample-time rescaling, when & if supported */ - return TRUE; /* by golly, it'll work... */ -#else - return FALSE; -#endif -} - - -/* - * Compute output image dimensions and related values. - * NOTE: this is exported for possible use by application. - * Hence it mustn't do anything that can't be done twice. - * Also note that it may be called before the master module is initialized! - */ - -GLOBAL(void) -jpeg_calc_output_dimensions (j_decompress_ptr cinfo) -/* Do computations that are needed before master selection phase */ -{ -#ifdef IDCT_SCALING_SUPPORTED - int ci; - jpeg_component_info *compptr; -#endif - - /* Prevent application from calling me at wrong times */ - if (cinfo->global_state != DSTATE_READY) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - -#ifdef IDCT_SCALING_SUPPORTED - - /* Compute actual output image dimensions and DCT scaling choices. */ - if (cinfo->scale_num * 8 <= cinfo->scale_denom) { - /* Provide 1/8 scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width, 8L); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height, 8L); - cinfo->min_DCT_scaled_size = 1; - } else if (cinfo->scale_num * 4 <= cinfo->scale_denom) { - /* Provide 1/4 scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width, 4L); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height, 4L); - cinfo->min_DCT_scaled_size = 2; - } else if (cinfo->scale_num * 2 <= cinfo->scale_denom) { - /* Provide 1/2 scaling */ - cinfo->output_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width, 2L); - cinfo->output_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height, 2L); - cinfo->min_DCT_scaled_size = 4; - } else { - /* Provide 1/1 scaling */ - cinfo->output_width = cinfo->image_width; - cinfo->output_height = cinfo->image_height; - cinfo->min_DCT_scaled_size = DCTSIZE; - } - /* In selecting the actual DCT scaling for each component, we try to - * scale up the chroma components via IDCT scaling rather than upsampling. - * This saves time if the upsampler gets to use 1:1 scaling. - * Note this code assumes that the supported DCT scalings are powers of 2. - */ - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - int ssize = cinfo->min_DCT_scaled_size; - while (ssize < DCTSIZE && - (compptr->h_samp_factor * ssize * 2 <= - cinfo->max_h_samp_factor * cinfo->min_DCT_scaled_size) && - (compptr->v_samp_factor * ssize * 2 <= - cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size)) { - ssize = ssize * 2; - } - compptr->DCT_scaled_size = ssize; - } - - /* Recompute downsampled dimensions of components; - * application needs to know these if using raw downsampled data. - */ - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Size in samples, after IDCT scaling */ - compptr->downsampled_width = (JDIMENSION) - jdiv_round_up((long) cinfo->image_width * - (long) (compptr->h_samp_factor * compptr->DCT_scaled_size), - (long) (cinfo->max_h_samp_factor * DCTSIZE)); - compptr->downsampled_height = (JDIMENSION) - jdiv_round_up((long) cinfo->image_height * - (long) (compptr->v_samp_factor * compptr->DCT_scaled_size), - (long) (cinfo->max_v_samp_factor * DCTSIZE)); - } - -#else /* !IDCT_SCALING_SUPPORTED */ - - /* Hardwire it to "no scaling" */ - cinfo->output_width = cinfo->image_width; - cinfo->output_height = cinfo->image_height; - /* jdinput.c has already initialized DCT_scaled_size to DCTSIZE, - * and has computed unscaled downsampled_width and downsampled_height. - */ - -#endif /* IDCT_SCALING_SUPPORTED */ - - /* Report number of components in selected colorspace. */ - /* Probably this should be in the color conversion module... */ - switch (cinfo->out_color_space) { - case JCS_GRAYSCALE: - cinfo->out_color_components = 1; - break; - case JCS_RGB: -#if RGB_PIXELSIZE != 3 - cinfo->out_color_components = RGB_PIXELSIZE; - break; -#endif /* else share code with YCbCr */ - case JCS_YCbCr: - cinfo->out_color_components = 3; - break; - case JCS_CMYK: - case JCS_YCCK: - cinfo->out_color_components = 4; - break; - default: /* else must be same colorspace as in file */ - cinfo->out_color_components = cinfo->num_components; - break; - } - cinfo->output_components = (cinfo->quantize_colors ? 1 : - cinfo->out_color_components); - - /* See if upsampler will want to emit more than one row at a time */ - if (use_merged_upsample(cinfo)) - cinfo->rec_outbuf_height = cinfo->max_v_samp_factor; - else - cinfo->rec_outbuf_height = 1; -} - - -/* - * Several decompression processes need to range-limit values to the range - * 0..MAXJSAMPLE; the input value may fall somewhat outside this range - * due to noise introduced by quantization, roundoff error, etc. These - * processes are inner loops and need to be as fast as possible. On most - * machines, particularly CPUs with pipelines or instruction prefetch, - * a (subscript-check-less) C table lookup - * x = sample_range_limit[x]; - * is faster than explicit tests - * if (x < 0) x = 0; - * else if (x > MAXJSAMPLE) x = MAXJSAMPLE; - * These processes all use a common table prepared by the routine below. - * - * For most steps we can mathematically guarantee that the initial value - * of x is within MAXJSAMPLE+1 of the legal range, so a table running from - * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial - * limiting step (just after the IDCT), a wildly out-of-range value is - * possible if the input data is corrupt. To avoid any chance of indexing - * off the end of memory and getting a bad-pointer trap, we perform the - * post-IDCT limiting thus: - * x = range_limit[x & MASK]; - * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit - * samples. Under normal circumstances this is more than enough range and - * a correct output will be generated; with bogus input data the mask will - * cause wraparound, and we will safely generate a bogus-but-in-range output. - * For the post-IDCT step, we want to convert the data from signed to unsigned - * representation by adding CENTERJSAMPLE at the same time that we limit it. - * So the post-IDCT limiting table ends up looking like this: - * CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE, - * MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), - * 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), - * 0,1,...,CENTERJSAMPLE-1 - * Negative inputs select values from the upper half of the table after - * masking. - * - * We can save some space by overlapping the start of the post-IDCT table - * with the simpler range limiting table. The post-IDCT table begins at - * sample_range_limit + CENTERJSAMPLE. - * - * Note that the table is allocated in near data space on PCs; it's small - * enough and used often enough to justify this. - */ - -LOCAL(void) -prepare_range_limit_table (j_decompress_ptr cinfo) -/* Allocate and fill in the sample_range_limit table */ -{ - JSAMPLE * table; - int i; - - table = (JSAMPLE *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE)); - table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */ - cinfo->sample_range_limit = table; - /* First segment of "simple" table: limit[x] = 0 for x < 0 */ - MEMZERO(table - (MAXJSAMPLE+1), (MAXJSAMPLE+1) * SIZEOF(JSAMPLE)); - /* Main part of "simple" table: limit[x] = x */ - for (i = 0; i <= MAXJSAMPLE; i++) - table[i] = (JSAMPLE) i; - table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */ - /* End of simple table, rest of first half of post-IDCT table */ - for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++) - table[i] = MAXJSAMPLE; - /* Second half of post-IDCT table */ - MEMZERO(table + (2 * (MAXJSAMPLE+1)), - (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE)); - MEMCOPY(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE), - cinfo->sample_range_limit, CENTERJSAMPLE * SIZEOF(JSAMPLE)); -} - - -/* - * Master selection of decompression modules. - * This is done once at jpeg_start_decompress time. We determine - * which modules will be used and give them appropriate initialization calls. - * We also initialize the decompressor input side to begin consuming data. - * - * Since jpeg_read_header has finished, we know what is in the SOF - * and (first) SOS markers. We also have all the application parameter - * settings. - */ - -LOCAL(void) -master_selection (j_decompress_ptr cinfo) -{ - my_master_ptr6 master = (my_master_ptr6) cinfo->master; - boolean use_c_buffer; - long samplesperrow; - JDIMENSION jd_samplesperrow; - - /* Initialize dimensions and other stuff */ - jpeg_calc_output_dimensions(cinfo); - prepare_range_limit_table(cinfo); - - /* Width of an output scanline must be representable as JDIMENSION. */ - samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components; - jd_samplesperrow = (JDIMENSION) samplesperrow; - if ((long) jd_samplesperrow != samplesperrow) - ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); - - /* Initialize my private state */ - master->pass_number = 0; - master->using_merged_upsample = use_merged_upsample(cinfo); - - /* Color quantizer selection */ - master->quantizer_1pass = NULL; - master->quantizer_2pass = NULL; - /* No mode changes if not using buffered-image mode. */ - if (! cinfo->quantize_colors || ! cinfo->buffered_image) { - cinfo->enable_1pass_quant = FALSE; - cinfo->enable_external_quant = FALSE; - cinfo->enable_2pass_quant = FALSE; - } - if (cinfo->quantize_colors) { - if (cinfo->raw_data_out) - ERREXIT(cinfo, JERR_NOTIMPL); - /* 2-pass quantizer only works in 3-component color space. */ - if (cinfo->out_color_components != 3) { - cinfo->enable_1pass_quant = TRUE; - cinfo->enable_external_quant = FALSE; - cinfo->enable_2pass_quant = FALSE; - cinfo->colormap = NULL; - } else if (cinfo->colormap != NULL) { - cinfo->enable_external_quant = TRUE; - } else if (cinfo->two_pass_quantize) { - cinfo->enable_2pass_quant = TRUE; - } else { - cinfo->enable_1pass_quant = TRUE; - } - - if (cinfo->enable_1pass_quant) { -#ifdef QUANT_1PASS_SUPPORTED - jinit_1pass_quantizer(cinfo); - master->quantizer_1pass = cinfo->cquantize; -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif - } - - /* We use the 2-pass code to map to external colormaps. */ - if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) { -#ifdef QUANT_2PASS_SUPPORTED - jinit_2pass_quantizer(cinfo); - master->quantizer_2pass = cinfo->cquantize; -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif - } - /* If both quantizers are initialized, the 2-pass one is left active; - * this is necessary for starting with quantization to an external map. - */ - } - - /* Post-processing: in particular, color conversion first */ - if (! cinfo->raw_data_out) { - if (master->using_merged_upsample) { -#ifdef UPSAMPLE_MERGING_SUPPORTED - jinit_merged_upsampler(cinfo); /* does color conversion too */ -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif - } else { - jinit_color_deconverter(cinfo); - jinit_upsampler(cinfo); - } - jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant); - } - /* Inverse DCT */ - jinit_inverse_dct(cinfo); - /* Entropy decoding: either Huffman or arithmetic coding. */ - if (cinfo->arith_code) { - ERREXIT(cinfo, JERR_ARITH_NOTIMPL); - } else { - if (cinfo->progressive_mode) { -#ifdef D_PROGRESSIVE_SUPPORTED - jinit_phuff_decoder(cinfo); -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif - } else - jinit_huff_decoder(cinfo); - } - - /* Initialize principal buffer controllers. */ - use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image; - jinit_d_coef_controller(cinfo, use_c_buffer); - - if (! cinfo->raw_data_out) - jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */); - - /* We can now tell the memory manager to allocate virtual arrays. */ - (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); - - /* Initialize input side of decompressor to consume first scan. */ - (*cinfo->inputctl->start_input_pass) (cinfo); - -#ifdef D_MULTISCAN_FILES_SUPPORTED - /* If jpeg_start_decompress will read the whole file, initialize - * progress monitoring appropriately. The input step is counted - * as one pass. - */ - if (cinfo->progress != NULL && ! cinfo->buffered_image && - cinfo->inputctl->has_multiple_scans) { - int nscans; - /* Estimate number of scans to set pass_limit. */ - if (cinfo->progressive_mode) { - /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ - nscans = 2 + 3 * cinfo->num_components; - } else { - /* For a nonprogressive multiscan file, estimate 1 scan per component. */ - nscans = cinfo->num_components; - } - cinfo->progress->pass_counter = 0L; - cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; - cinfo->progress->completed_passes = 0; - cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2); - /* Count the input pass as done */ - master->pass_number++; - } -#endif /* D_MULTISCAN_FILES_SUPPORTED */ -} - - -/* - * Per-pass setup. - * This is called at the beginning of each output pass. We determine which - * modules will be active during this pass and give them appropriate - * start_pass calls. We also set is_dummy_pass to indicate whether this - * is a "real" output pass or a dummy pass for color quantization. - * (In the latter case, jdapistd.c will crank the pass to completion.) - */ - -METHODDEF(void) -prepare_for_output_pass (j_decompress_ptr cinfo) -{ - my_master_ptr6 master = (my_master_ptr6) cinfo->master; - - if (master->pub.is_dummy_pass) { -#ifdef QUANT_2PASS_SUPPORTED - /* Final pass of 2-pass quantization */ - master->pub.is_dummy_pass = FALSE; - (*cinfo->cquantize->start_pass) (cinfo, FALSE); - (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST); - (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST); -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif /* QUANT_2PASS_SUPPORTED */ - } else { - if (cinfo->quantize_colors && cinfo->colormap == NULL) { - /* Select new quantization method */ - if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) { - cinfo->cquantize = master->quantizer_2pass; - master->pub.is_dummy_pass = TRUE; - } else if (cinfo->enable_1pass_quant) { - cinfo->cquantize = master->quantizer_1pass; - } else { - ERREXIT(cinfo, JERR_MODE_CHANGE); - } - } - (*cinfo->idct->start_pass) (cinfo); - (*cinfo->coef->start_output_pass) (cinfo); - if (! cinfo->raw_data_out) { - if (! master->using_merged_upsample) - (*cinfo->cconvert->start_pass) (cinfo); - (*cinfo->upsample->start_pass) (cinfo); - if (cinfo->quantize_colors) - (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass); - (*cinfo->post->start_pass) (cinfo, - (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); - (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); - } - } - - /* Set up progress monitor's pass info if present */ - if (cinfo->progress != NULL) { - cinfo->progress->completed_passes = master->pass_number; - cinfo->progress->total_passes = master->pass_number + - (master->pub.is_dummy_pass ? 2 : 1); - /* In buffered-image mode, we assume one more output pass if EOI not - * yet reached, but no more passes if EOI has been reached. - */ - if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) { - cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1); - } - } -} - - -/* - * Finish up at end of an output pass. - */ - -METHODDEF(void) -finish_output_pass (j_decompress_ptr cinfo) -{ - my_master_ptr6 master = (my_master_ptr6) cinfo->master; - - if (cinfo->quantize_colors) - (*cinfo->cquantize->finish_pass) (cinfo); - master->pass_number++; -} - - -#ifdef D_MULTISCAN_FILES_SUPPORTED - -/* - * Switch to a new external colormap between output passes. - */ - -GLOBAL(void) -jpeg_new_colormap (j_decompress_ptr cinfo) -{ - my_master_ptr6 master = (my_master_ptr6) cinfo->master; - - /* Prevent application from calling me at wrong times */ - if (cinfo->global_state != DSTATE_BUFIMAGE) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - - if (cinfo->quantize_colors && cinfo->enable_external_quant && - cinfo->colormap != NULL) { - /* Select 2-pass quantizer for external colormap use */ - cinfo->cquantize = master->quantizer_2pass; - /* Notify quantizer of colormap change */ - (*cinfo->cquantize->new_color_map) (cinfo); - master->pub.is_dummy_pass = FALSE; /* just in case */ - } else - ERREXIT(cinfo, JERR_MODE_CHANGE); -} - -#endif /* D_MULTISCAN_FILES_SUPPORTED */ - - -/* - * Initialize master decompression control and select active modules. - * This is performed at the start of jpeg_start_decompress. - */ - -GLOBAL(void) -jinit_master_decompress (j_decompress_ptr cinfo) -{ - my_master_ptr6 master; - - master = (my_master_ptr6) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_decomp_master)); - cinfo->master = (struct jpeg_decomp_master *) master; - master->pub.prepare_for_output_pass = prepare_for_output_pass; - master->pub.finish_output_pass = finish_output_pass; - - master->pub.is_dummy_pass = FALSE; - - master_selection(cinfo); -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jdmerge.c b/source/modules/juce_graphics/image_formats/jpglib/jdmerge.c deleted file mode 100644 index 1f483f622..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jdmerge.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * jdmerge.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains code for merged upsampling/color conversion. - * - * This file combines functions from jdsample.c and jdcolor.c; - * read those files first to understand what's going on. - * - * When the chroma components are to be upsampled by simple replication - * (ie, box filtering), we can save some work in color conversion by - * calculating all the output pixels corresponding to a pair of chroma - * samples at one time. In the conversion equations - * R = Y + K1 * Cr - * G = Y + K2 * Cb + K3 * Cr - * B = Y + K4 * Cb - * only the Y term varies among the group of pixels corresponding to a pair - * of chroma samples, so the rest of the terms can be calculated just once. - * At typical sampling ratios, this eliminates half or three-quarters of the - * multiplications needed for color conversion. - * - * This file currently provides implementations for the following cases: - * YCbCr => RGB color conversion only. - * Sampling ratios of 2h1v or 2h2v. - * No scaling needed at upsample time. - * Corner-aligned (non-CCIR601) sampling alignment. - * Other special cases could be added, but in most applications these are - * the only common cases. (For uncommon cases we fall back on the more - * general code in jdsample.c and jdcolor.c.) - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - -#ifdef UPSAMPLE_MERGING_SUPPORTED - - -/* Private subobject */ - -typedef struct { - struct jpeg_upsampler pub; /* public fields */ - - /* Pointer to routine to do actual upsampling/conversion of one row group */ - JMETHOD(void, upmethod, (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, - JSAMPARRAY output_buf)); - - /* Private state for YCC->RGB conversion */ - int * Cr_r_tab; /* => table for Cr to R conversion */ - int * Cb_b_tab; /* => table for Cb to B conversion */ - INT32 * Cr_g_tab; /* => table for Cr to G conversion */ - INT32 * Cb_g_tab; /* => table for Cb to G conversion */ - - /* For 2:1 vertical sampling, we produce two output rows at a time. - * We need a "spare" row buffer to hold the second output row if the - * application provides just a one-row buffer; we also use the spare - * to discard the dummy last row if the image height is odd. - */ - JSAMPROW spare_row; - boolean spare_full; /* T if spare buffer is occupied */ - - JDIMENSION out_row_width; /* samples per output row */ - JDIMENSION rows_to_go; /* counts rows remaining in image */ -} my_upsampler; - -typedef my_upsampler * my_upsample_ptr; - -#define SCALEBITS 16 /* speediest right-shift on some machines */ -#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) -#define FIX(x) ((INT32) ((x) * (1L<RGB colorspace conversion. - * This is taken directly from jdcolor.c; see that file for more info. - */ - -LOCAL(void) -build_ycc_rgb_table2 (j_decompress_ptr cinfo) -{ - my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; - int i; - INT32 x; - SHIFT_TEMPS - - upsample->Cr_r_tab = (int *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)); - upsample->Cb_b_tab = (int *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)); - upsample->Cr_g_tab = (INT32 *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)); - upsample->Cb_g_tab = (INT32 *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)); - - for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { - /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ - /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ - /* Cr=>R value is nearest int to 1.40200 * x */ - upsample->Cr_r_tab[i] = (int) - RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); - /* Cb=>B value is nearest int to 1.77200 * x */ - upsample->Cb_b_tab[i] = (int) - RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); - /* Cr=>G value is scaled-up -0.71414 * x */ - upsample->Cr_g_tab[i] = (- FIX(0.71414)) * x; - /* Cb=>G value is scaled-up -0.34414 * x */ - /* We also add in ONE_HALF so that need not do it in inner loop */ - upsample->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF; - } -} - - -/* - * Initialize for an upsampling pass. - */ - -METHODDEF(void) -start_pass_merged_upsample (j_decompress_ptr cinfo) -{ - my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; - - /* Mark the spare buffer empty */ - upsample->spare_full = FALSE; - /* Initialize total-height counter for detecting bottom of image */ - upsample->rows_to_go = cinfo->output_height; -} - - -/* - * Control routine to do upsampling (and color conversion). - * - * The control routine just handles the row buffering considerations. - */ - -METHODDEF(void) -merged_2v_upsample (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, - JDIMENSION, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail) -/* 2:1 vertical sampling case: may need a spare row. */ -{ - my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; - JSAMPROW work_ptrs[2]; - JDIMENSION num_rows; /* number of rows returned to caller */ - - if (upsample->spare_full) { - /* If we have a spare row saved from a previous cycle, just return it. */ - jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0, - 1, upsample->out_row_width); - num_rows = 1; - upsample->spare_full = FALSE; - } else { - /* Figure number of rows to return to caller. */ - num_rows = 2; - /* Not more than the distance to the end of the image. */ - if (num_rows > upsample->rows_to_go) - num_rows = upsample->rows_to_go; - /* And not more than what the client can accept: */ - out_rows_avail -= *out_row_ctr; - if (num_rows > out_rows_avail) - num_rows = out_rows_avail; - /* Create output pointer array for upsampler. */ - work_ptrs[0] = output_buf[*out_row_ctr]; - if (num_rows > 1) { - work_ptrs[1] = output_buf[*out_row_ctr + 1]; - } else { - work_ptrs[1] = upsample->spare_row; - upsample->spare_full = TRUE; - } - /* Now do the upsampling. */ - (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs); - } - - /* Adjust counts */ - *out_row_ctr += num_rows; - upsample->rows_to_go -= num_rows; - /* When the buffer is emptied, declare this input row group consumed */ - if (! upsample->spare_full) - (*in_row_group_ctr)++; -} - - -METHODDEF(void) -merged_1v_upsample (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, - JDIMENSION, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION) -/* 1:1 vertical sampling case: much easier, never need a spare row. */ -{ - my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; - - /* Just do the upsampling. */ - (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, - output_buf + *out_row_ctr); - /* Adjust counts */ - (*out_row_ctr)++; - (*in_row_group_ctr)++; -} - - -/* - * These are the routines invoked by the control routines to do - * the actual upsampling/conversion. One row group is processed per call. - * - * Note: since we may be writing directly into application-supplied buffers, - * we have to be honest about the output width; we can't assume the buffer - * has been rounded up to an even width. - */ - - -/* - * Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical. - */ - -METHODDEF(void) -h2v1_merged_upsample (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, - JSAMPARRAY output_buf) -{ - my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; - int y, cred, cgreen, cblue; - int cb, cr; - JSAMPROW outptr; - JSAMPROW inptr0, inptr1, inptr2; - JDIMENSION col; - /* copy these pointers into registers if possible */ - JSAMPLE * range_limit = cinfo->sample_range_limit; - int * Crrtab = upsample->Cr_r_tab; - int * Cbbtab = upsample->Cb_b_tab; - INT32 * Crgtab = upsample->Cr_g_tab; - INT32 * Cbgtab = upsample->Cb_g_tab; - SHIFT_TEMPS - - inptr0 = input_buf[0][in_row_group_ctr]; - inptr1 = input_buf[1][in_row_group_ctr]; - inptr2 = input_buf[2][in_row_group_ctr]; - outptr = output_buf[0]; - /* Loop for each pair of output pixels */ - for (col = cinfo->output_width >> 1; col > 0; col--) { - /* Do the chroma part of the calculation */ - cb = GETJSAMPLE(*inptr1++); - cr = GETJSAMPLE(*inptr2++); - cred = Crrtab[cr]; - cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); - cblue = Cbbtab[cb]; - /* Fetch 2 Y values and emit 2 pixels */ - y = GETJSAMPLE(*inptr0++); - outptr[RGB_RED] = range_limit[y + cred]; - outptr[RGB_GREEN] = range_limit[y + cgreen]; - outptr[RGB_BLUE] = range_limit[y + cblue]; - outptr += RGB_PIXELSIZE; - y = GETJSAMPLE(*inptr0++); - outptr[RGB_RED] = range_limit[y + cred]; - outptr[RGB_GREEN] = range_limit[y + cgreen]; - outptr[RGB_BLUE] = range_limit[y + cblue]; - outptr += RGB_PIXELSIZE; - } - /* If image width is odd, do the last output column separately */ - if (cinfo->output_width & 1) { - cb = GETJSAMPLE(*inptr1); - cr = GETJSAMPLE(*inptr2); - cred = Crrtab[cr]; - cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); - cblue = Cbbtab[cb]; - y = GETJSAMPLE(*inptr0); - outptr[RGB_RED] = range_limit[y + cred]; - outptr[RGB_GREEN] = range_limit[y + cgreen]; - outptr[RGB_BLUE] = range_limit[y + cblue]; - } -} - - -/* - * Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical. - */ - -METHODDEF(void) -h2v2_merged_upsample (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, - JSAMPARRAY output_buf) -{ - my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; - int y, cred, cgreen, cblue; - int cb, cr; - JSAMPROW outptr0, outptr1; - JSAMPROW inptr00, inptr01, inptr1, inptr2; - JDIMENSION col; - /* copy these pointers into registers if possible */ - JSAMPLE * range_limit = cinfo->sample_range_limit; - int * Crrtab = upsample->Cr_r_tab; - int * Cbbtab = upsample->Cb_b_tab; - INT32 * Crgtab = upsample->Cr_g_tab; - INT32 * Cbgtab = upsample->Cb_g_tab; - SHIFT_TEMPS - - inptr00 = input_buf[0][in_row_group_ctr*2]; - inptr01 = input_buf[0][in_row_group_ctr*2 + 1]; - inptr1 = input_buf[1][in_row_group_ctr]; - inptr2 = input_buf[2][in_row_group_ctr]; - outptr0 = output_buf[0]; - outptr1 = output_buf[1]; - /* Loop for each group of output pixels */ - for (col = cinfo->output_width >> 1; col > 0; col--) { - /* Do the chroma part of the calculation */ - cb = GETJSAMPLE(*inptr1++); - cr = GETJSAMPLE(*inptr2++); - cred = Crrtab[cr]; - cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); - cblue = Cbbtab[cb]; - /* Fetch 4 Y values and emit 4 pixels */ - y = GETJSAMPLE(*inptr00++); - outptr0[RGB_RED] = range_limit[y + cred]; - outptr0[RGB_GREEN] = range_limit[y + cgreen]; - outptr0[RGB_BLUE] = range_limit[y + cblue]; - outptr0 += RGB_PIXELSIZE; - y = GETJSAMPLE(*inptr00++); - outptr0[RGB_RED] = range_limit[y + cred]; - outptr0[RGB_GREEN] = range_limit[y + cgreen]; - outptr0[RGB_BLUE] = range_limit[y + cblue]; - outptr0 += RGB_PIXELSIZE; - y = GETJSAMPLE(*inptr01++); - outptr1[RGB_RED] = range_limit[y + cred]; - outptr1[RGB_GREEN] = range_limit[y + cgreen]; - outptr1[RGB_BLUE] = range_limit[y + cblue]; - outptr1 += RGB_PIXELSIZE; - y = GETJSAMPLE(*inptr01++); - outptr1[RGB_RED] = range_limit[y + cred]; - outptr1[RGB_GREEN] = range_limit[y + cgreen]; - outptr1[RGB_BLUE] = range_limit[y + cblue]; - outptr1 += RGB_PIXELSIZE; - } - /* If image width is odd, do the last output column separately */ - if (cinfo->output_width & 1) { - cb = GETJSAMPLE(*inptr1); - cr = GETJSAMPLE(*inptr2); - cred = Crrtab[cr]; - cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); - cblue = Cbbtab[cb]; - y = GETJSAMPLE(*inptr00); - outptr0[RGB_RED] = range_limit[y + cred]; - outptr0[RGB_GREEN] = range_limit[y + cgreen]; - outptr0[RGB_BLUE] = range_limit[y + cblue]; - y = GETJSAMPLE(*inptr01); - outptr1[RGB_RED] = range_limit[y + cred]; - outptr1[RGB_GREEN] = range_limit[y + cgreen]; - outptr1[RGB_BLUE] = range_limit[y + cblue]; - } -} - - -/* - * Module initialization routine for merged upsampling/color conversion. - * - * NB: this is called under the conditions determined by use_merged_upsample() - * in jdmaster.c. That routine MUST correspond to the actual capabilities - * of this module; no safety checks are made here. - */ - -GLOBAL(void) -jinit_merged_upsampler (j_decompress_ptr cinfo) -{ - my_upsample_ptr upsample; - - upsample = (my_upsample_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_upsampler)); - cinfo->upsample = (struct jpeg_upsampler *) upsample; - upsample->pub.start_pass = start_pass_merged_upsample; - upsample->pub.need_context_rows = FALSE; - - upsample->out_row_width = cinfo->output_width * cinfo->out_color_components; - - if (cinfo->max_v_samp_factor == 2) { - upsample->pub.upsample = merged_2v_upsample; - upsample->upmethod = h2v2_merged_upsample; - /* Allocate a spare row buffer */ - upsample->spare_row = (JSAMPROW) - (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, - (size_t) (upsample->out_row_width * SIZEOF(JSAMPLE))); - } else { - upsample->pub.upsample = merged_1v_upsample; - upsample->upmethod = h2v1_merged_upsample; - /* No spare row needed */ - upsample->spare_row = NULL; - } - - build_ycc_rgb_table2(cinfo); -} - -#endif /* UPSAMPLE_MERGING_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jdphuff.c b/source/modules/juce_graphics/image_formats/jpglib/jdphuff.c deleted file mode 100644 index 10e0a4636..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jdphuff.c +++ /dev/null @@ -1,642 +0,0 @@ -/* - * jdphuff.c - * - * Copyright (C) 1995-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains Huffman entropy decoding routines for progressive JPEG. - * - * Much of the complexity here has to do with supporting input suspension. - * If the data source module demands suspension, we want to be able to back - * up to the start of the current MCU. To do this, we copy state variables - * into local working storage, and update them back to the permanent - * storage only upon successful completion of an MCU. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jdhuff.h" /* Declarations shared with jdhuff.c */ - - -#ifdef D_PROGRESSIVE_SUPPORTED - -/* - * Expanded entropy decoder object for progressive Huffman decoding. - * - * The savable_state subrecord contains fields that change within an MCU, - * but must not be updated permanently until we complete the MCU. - */ - -typedef struct { - unsigned int EOBRUN; /* remaining EOBs in EOBRUN */ - int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ -} savable_state3; - -/* This macro is to work around compilers with missing or broken - * structure assignment. You'll need to fix this code if you have - * such a compiler and you change MAX_COMPS_IN_SCAN. - */ - -#ifndef NO_STRUCT_ASSIGN -#define ASSIGN_STATE(dest,src) ((dest) = (src)) -#else -#if MAX_COMPS_IN_SCAN == 4 -#define ASSIGN_STATE(dest,src) \ - ((dest).EOBRUN = (src).EOBRUN, \ - (dest).last_dc_val[0] = (src).last_dc_val[0], \ - (dest).last_dc_val[1] = (src).last_dc_val[1], \ - (dest).last_dc_val[2] = (src).last_dc_val[2], \ - (dest).last_dc_val[3] = (src).last_dc_val[3]) -#endif -#endif - - -typedef struct { - struct jpeg_entropy_decoder pub; /* public fields */ - - /* These fields are loaded into local variables at start of each MCU. - * In case of suspension, we exit WITHOUT updating them. - */ - bitread_perm_state bitstate; /* Bit buffer at start of MCU */ - savable_state3 saved; /* Other state at start of MCU */ - - /* These fields are NOT loaded into local working state. */ - unsigned int restarts_to_go; /* MCUs left in this restart interval */ - - /* Pointers to derived tables (these workspaces have image lifespan) */ - d_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; - - d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */ -} phuff_entropy_decoder; - -typedef phuff_entropy_decoder * phuff_entropy_ptr2; - -/* Forward declarations */ -METHODDEF(boolean) decode_mcu_DC_first JPP((j_decompress_ptr cinfo, - JBLOCKROW *MCU_data)); -METHODDEF(boolean) decode_mcu_AC_first JPP((j_decompress_ptr cinfo, - JBLOCKROW *MCU_data)); -METHODDEF(boolean) decode_mcu_DC_refine JPP((j_decompress_ptr cinfo, - JBLOCKROW *MCU_data)); -METHODDEF(boolean) decode_mcu_AC_refine JPP((j_decompress_ptr cinfo, - JBLOCKROW *MCU_data)); - - -/* - * Initialize for a Huffman-compressed scan. - */ - -METHODDEF(void) -start_pass_phuff_decoder (j_decompress_ptr cinfo) -{ - phuff_entropy_ptr2 entropy = (phuff_entropy_ptr2) cinfo->entropy; - boolean is_DC_band, bad; - int ci, coefi, tbl; - int *coef_bit_ptr; - jpeg_component_info * compptr; - - is_DC_band = (cinfo->Ss == 0); - - /* Validate scan parameters */ - bad = FALSE; - if (is_DC_band) { - if (cinfo->Se != 0) - bad = TRUE; - } else { - /* need not check Ss/Se < 0 since they came from unsigned bytes */ - if (cinfo->Ss > cinfo->Se || cinfo->Se >= DCTSIZE2) - bad = TRUE; - /* AC scans may have only one component */ - if (cinfo->comps_in_scan != 1) - bad = TRUE; - } - if (cinfo->Ah != 0) { - /* Successive approximation refinement scan: must have Al = Ah-1. */ - if (cinfo->Al != cinfo->Ah-1) - bad = TRUE; - } - if (cinfo->Al > 13) /* need not check for < 0 */ - bad = TRUE; - /* Arguably the maximum Al value should be less than 13 for 8-bit precision, - * but the spec doesn't say so, and we try to be liberal about what we - * accept. Note: large Al values could result in out-of-range DC - * coefficients during early scans, leading to bizarre displays due to - * overflows in the IDCT math. But we won't crash. - */ - if (bad) - ERREXIT4(cinfo, JERR_BAD_PROGRESSION, - cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); - /* Update progression status, and verify that scan order is legal. - * Note that inter-scan inconsistencies are treated as warnings - * not fatal errors ... not clear if this is right way to behave. - */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - int cindex = cinfo->cur_comp_info[ci]->component_index; - coef_bit_ptr = & cinfo->coef_bits[cindex][0]; - if (!is_DC_band && coef_bit_ptr[0] < 0) /* AC without prior DC scan */ - WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0); - for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) { - int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi]; - if (cinfo->Ah != expected) - WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi); - coef_bit_ptr[coefi] = cinfo->Al; - } - } - - /* Select MCU decoding routine */ - if (cinfo->Ah == 0) { - if (is_DC_band) - entropy->pub.decode_mcu = decode_mcu_DC_first; - else - entropy->pub.decode_mcu = decode_mcu_AC_first; - } else { - if (is_DC_band) - entropy->pub.decode_mcu = decode_mcu_DC_refine; - else - entropy->pub.decode_mcu = decode_mcu_AC_refine; - } - - for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - /* Make sure requested tables are present, and compute derived tables. - * We may build same derived table more than once, but it's not expensive. - */ - if (is_DC_band) { - if (cinfo->Ah == 0) { /* DC refinement needs no table */ - tbl = compptr->dc_tbl_no; - jpeg_make_d_derived_tbl(cinfo, TRUE, tbl, - & entropy->derived_tbls[tbl]); - } - } else { - tbl = compptr->ac_tbl_no; - jpeg_make_d_derived_tbl(cinfo, FALSE, tbl, - & entropy->derived_tbls[tbl]); - /* remember the single active table */ - entropy->ac_derived_tbl = entropy->derived_tbls[tbl]; - } - /* Initialize DC predictions to 0 */ - entropy->saved.last_dc_val[ci] = 0; - } - - /* Initialize bitread state variables */ - entropy->bitstate.bits_left = 0; - entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ - entropy->pub.insufficient_data = FALSE; - - /* Initialize private state variables */ - entropy->saved.EOBRUN = 0; - - /* Initialize restart counter */ - entropy->restarts_to_go = cinfo->restart_interval; -} - - -/* - * Check for a restart marker & resynchronize decoder. - * Returns FALSE if must suspend. - */ - -LOCAL(boolean) -process_restartp (j_decompress_ptr cinfo) -{ - phuff_entropy_ptr2 entropy = (phuff_entropy_ptr2) cinfo->entropy; - int ci; - - /* Throw away any unused bits remaining in bit buffer; */ - /* include any full bytes in next_marker's count of discarded bytes */ - cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; - entropy->bitstate.bits_left = 0; - - /* Advance past the RSTn marker */ - if (! (*cinfo->marker->read_restart_marker) (cinfo)) - return FALSE; - - /* Re-initialize DC predictions to 0 */ - for (ci = 0; ci < cinfo->comps_in_scan; ci++) - entropy->saved.last_dc_val[ci] = 0; - /* Re-init EOB run count, too */ - entropy->saved.EOBRUN = 0; - - /* Reset restart counter */ - entropy->restarts_to_go = cinfo->restart_interval; - - /* Reset out-of-data flag, unless read_restart_marker left us smack up - * against a marker. In that case we will end up treating the next data - * segment as empty, and we can avoid producing bogus output pixels by - * leaving the flag set. - */ - if (cinfo->unread_marker == 0) - entropy->pub.insufficient_data = FALSE; - - return TRUE; -} - - -/* - * Huffman MCU decoding. - * Each of these routines decodes and returns one MCU's worth of - * Huffman-compressed coefficients. - * The coefficients are reordered from zigzag order into natural array order, - * but are not dequantized. - * - * The i'th block of the MCU is stored into the block pointed to by - * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER. - * - * We return FALSE if data source requested suspension. In that case no - * changes have been made to permanent state. (Exception: some output - * coefficients may already have been assigned. This is harmless for - * spectral selection, since we'll just re-assign them on the next call. - * Successive approximation AC refinement has to be more careful, however.) - */ - -/* - * MCU decoding for DC initial scan (either spectral selection, - * or first pass of successive approximation). - */ - -METHODDEF(boolean) -decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) -{ - phuff_entropy_ptr2 entropy = (phuff_entropy_ptr2) cinfo->entropy; - int Al = cinfo->Al; - int s, r; - int blkn, ci; - JBLOCKROW block; - BITREAD_STATE_VARS; - savable_state3 state; - d_derived_tbl * tbl; - jpeg_component_info * compptr; - - /* Process restart marker if needed; may have to suspend */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) - if (! process_restartp(cinfo)) - return FALSE; - } - - /* If we've run out of data, just leave the MCU set to zeroes. - * This way, we return uniform gray for the remainder of the segment. - */ - if (! entropy->pub.insufficient_data) { - - /* Load up working state */ - BITREAD_LOAD_STATE(cinfo,entropy->bitstate); - ASSIGN_STATE(state, entropy->saved); - - /* Outer loop handles each block in the MCU */ - - for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - block = MCU_data[blkn]; - ci = cinfo->MCU_membership[blkn]; - compptr = cinfo->cur_comp_info[ci]; - tbl = entropy->derived_tbls[compptr->dc_tbl_no]; - - /* Decode a single block's worth of coefficients */ - - /* Section F.2.2.1: decode the DC coefficient difference */ - HUFF_DECODE(s, br_state, tbl, return FALSE, label1); - if (s) { - CHECK_BIT_BUFFER(br_state, s, return FALSE); - r = GET_BITS(s); - s = HUFF_EXTEND(r, s); - } - - /* Convert DC difference to actual value, update last_dc_val */ - s += state.last_dc_val[ci]; - state.last_dc_val[ci] = s; - /* Scale and output the coefficient (assumes jpeg_natural_order[0]=0) */ - (*block)[0] = (JCOEF) (s << Al); - } - - /* Completed MCU, so update state */ - BITREAD_SAVE_STATE(cinfo,entropy->bitstate); - ASSIGN_STATE(entropy->saved, state); - } - - /* Account for restart interval (no-op if not using restarts) */ - entropy->restarts_to_go--; - - return TRUE; -} - - -/* - * MCU decoding for AC initial scan (either spectral selection, - * or first pass of successive approximation). - */ - -METHODDEF(boolean) -decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) -{ - phuff_entropy_ptr2 entropy = (phuff_entropy_ptr2) cinfo->entropy; - int Se = cinfo->Se; - int Al = cinfo->Al; - int s, k, r; - unsigned int EOBRUN; - JBLOCKROW block; - BITREAD_STATE_VARS; - d_derived_tbl * tbl; - - /* Process restart marker if needed; may have to suspend */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) - if (! process_restartp(cinfo)) - return FALSE; - } - - /* If we've run out of data, just leave the MCU set to zeroes. - * This way, we return uniform gray for the remainder of the segment. - */ - if (! entropy->pub.insufficient_data) { - - /* Load up working state. - * We can avoid loading/saving bitread state if in an EOB run. - */ - EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */ - - /* There is always only one block per MCU */ - - if (EOBRUN > 0) /* if it's a band of zeroes... */ - EOBRUN--; /* ...process it now (we do nothing) */ - else { - BITREAD_LOAD_STATE(cinfo,entropy->bitstate); - block = MCU_data[0]; - tbl = entropy->ac_derived_tbl; - - for (k = cinfo->Ss; k <= Se; k++) { - HUFF_DECODE(s, br_state, tbl, return FALSE, label2); - r = s >> 4; - s &= 15; - if (s) { - k += r; - CHECK_BIT_BUFFER(br_state, s, return FALSE); - r = GET_BITS(s); - s = HUFF_EXTEND(r, s); - /* Scale and output coefficient in natural (dezigzagged) order */ - (*block)[jpeg_natural_order[k]] = (JCOEF) (s << Al); - } else { - if (r == 15) { /* ZRL */ - k += 15; /* skip 15 zeroes in band */ - } else { /* EOBr, run length is 2^r + appended bits */ - EOBRUN = 1 << r; - if (r) { /* EOBr, r > 0 */ - CHECK_BIT_BUFFER(br_state, r, return FALSE); - r = GET_BITS(r); - EOBRUN += r; - } - EOBRUN--; /* this band is processed at this moment */ - break; /* force end-of-band */ - } - } - } - - BITREAD_SAVE_STATE(cinfo,entropy->bitstate); - } - - /* Completed MCU, so update state */ - entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */ - } - - /* Account for restart interval (no-op if not using restarts) */ - entropy->restarts_to_go--; - - return TRUE; -} - - -/* - * MCU decoding for DC successive approximation refinement scan. - * Note: we assume such scans can be multi-component, although the spec - * is not very clear on the point. - */ - -METHODDEF(boolean) -decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) -{ - phuff_entropy_ptr2 entropy = (phuff_entropy_ptr2) cinfo->entropy; - int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ - int blkn; - JBLOCKROW block; - BITREAD_STATE_VARS; - - /* Process restart marker if needed; may have to suspend */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) - if (! process_restartp(cinfo)) - return FALSE; - } - - /* Not worth the cycles to check insufficient_data here, - * since we will not change the data anyway if we read zeroes. - */ - - /* Load up working state */ - BITREAD_LOAD_STATE(cinfo,entropy->bitstate); - - /* Outer loop handles each block in the MCU */ - - for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { - block = MCU_data[blkn]; - - /* Encoded data is simply the next bit of the two's-complement DC value */ - CHECK_BIT_BUFFER(br_state, 1, return FALSE); - if (GET_BITS(1)) - (*block)[0] |= p1; - /* Note: since we use |=, repeating the assignment later is safe */ - } - - /* Completed MCU, so update state */ - BITREAD_SAVE_STATE(cinfo,entropy->bitstate); - - /* Account for restart interval (no-op if not using restarts) */ - entropy->restarts_to_go--; - - return TRUE; -} - - -/* - * MCU decoding for AC successive approximation refinement scan. - */ - -METHODDEF(boolean) -decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) -{ - phuff_entropy_ptr2 entropy = (phuff_entropy_ptr2) cinfo->entropy; - int Se = cinfo->Se; - int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ - int m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */ - int s, k, r; - unsigned int EOBRUN; - JBLOCKROW block; - JCOEFPTR thiscoef; - BITREAD_STATE_VARS; - d_derived_tbl * tbl; - int num_newnz; - int newnz_pos[DCTSIZE2]; - - /* Process restart marker if needed; may have to suspend */ - if (cinfo->restart_interval) { - if (entropy->restarts_to_go == 0) - if (! process_restartp(cinfo)) - return FALSE; - } - - /* If we've run out of data, don't modify the MCU. - */ - if (! entropy->pub.insufficient_data) { - - /* Load up working state */ - BITREAD_LOAD_STATE(cinfo,entropy->bitstate); - EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */ - - /* There is always only one block per MCU */ - block = MCU_data[0]; - tbl = entropy->ac_derived_tbl; - - /* If we are forced to suspend, we must undo the assignments to any newly - * nonzero coefficients in the block, because otherwise we'd get confused - * next time about which coefficients were already nonzero. - * But we need not undo addition of bits to already-nonzero coefficients; - * instead, we can test the current bit to see if we already did it. - */ - num_newnz = 0; - - /* initialize coefficient loop counter to start of band */ - k = cinfo->Ss; - - if (EOBRUN == 0) { - for (; k <= Se; k++) { - HUFF_DECODE(s, br_state, tbl, goto undoit, label3); - r = s >> 4; - s &= 15; - if (s) { - if (s != 1) /* size of new coef should always be 1 */ - WARNMS(cinfo, JWRN_HUFF_BAD_CODE); - CHECK_BIT_BUFFER(br_state, 1, goto undoit); - if (GET_BITS(1)) - s = p1; /* newly nonzero coef is positive */ - else - s = m1; /* newly nonzero coef is negative */ - } else { - if (r != 15) { - EOBRUN = 1 << r; /* EOBr, run length is 2^r + appended bits */ - if (r) { - CHECK_BIT_BUFFER(br_state, r, goto undoit); - r = GET_BITS(r); - EOBRUN += r; - } - break; /* rest of block is handled by EOB logic */ - } - /* note s = 0 for processing ZRL */ - } - /* Advance over already-nonzero coefs and r still-zero coefs, - * appending correction bits to the nonzeroes. A correction bit is 1 - * if the absolute value of the coefficient must be increased. - */ - do { - thiscoef = *block + jpeg_natural_order[k]; - if (*thiscoef != 0) { - CHECK_BIT_BUFFER(br_state, 1, goto undoit); - if (GET_BITS(1)) { - if ((*thiscoef & p1) == 0) { /* do nothing if already set it */ - if (*thiscoef >= 0) - *thiscoef += p1; - else - *thiscoef += m1; - } - } - } else { - if (--r < 0) - break; /* reached target zero coefficient */ - } - k++; - } while (k <= Se); - if (s) { - int pos = jpeg_natural_order[k]; - /* Output newly nonzero coefficient */ - (*block)[pos] = (JCOEF) s; - /* Remember its position in case we have to suspend */ - newnz_pos[num_newnz++] = pos; - } - } - } - - if (EOBRUN > 0) { - /* Scan any remaining coefficient positions after the end-of-band - * (the last newly nonzero coefficient, if any). Append a correction - * bit to each already-nonzero coefficient. A correction bit is 1 - * if the absolute value of the coefficient must be increased. - */ - for (; k <= Se; k++) { - thiscoef = *block + jpeg_natural_order[k]; - if (*thiscoef != 0) { - CHECK_BIT_BUFFER(br_state, 1, goto undoit); - if (GET_BITS(1)) { - if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */ - if (*thiscoef >= 0) - *thiscoef += p1; - else - *thiscoef += m1; - } - } - } - } - /* Count one block completed in EOB run */ - EOBRUN--; - } - - /* Completed MCU, so update state */ - BITREAD_SAVE_STATE(cinfo,entropy->bitstate); - entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */ - } - - /* Account for restart interval (no-op if not using restarts) */ - entropy->restarts_to_go--; - - return TRUE; - -undoit: - /* Re-zero any output coefficients that we made newly nonzero */ - while (num_newnz > 0) - (*block)[newnz_pos[--num_newnz]] = 0; - - return FALSE; -} - - -/* - * Module initialization routine for progressive Huffman entropy decoding. - */ - -GLOBAL(void) -jinit_phuff_decoder (j_decompress_ptr cinfo) -{ - phuff_entropy_ptr2 entropy; - int *coef_bit_ptr; - int ci, i; - - entropy = (phuff_entropy_ptr2) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(phuff_entropy_decoder)); - cinfo->entropy = (struct jpeg_entropy_decoder *) entropy; - entropy->pub.start_pass = start_pass_phuff_decoder; - - /* Mark derived tables unallocated */ - for (i = 0; i < NUM_HUFF_TBLS; i++) { - entropy->derived_tbls[i] = NULL; - } - - /* Create progression status table */ - cinfo->coef_bits = (int (*)[DCTSIZE2]) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - cinfo->num_components*DCTSIZE2*SIZEOF(int)); - coef_bit_ptr = & cinfo->coef_bits[0][0]; - for (ci = 0; ci < cinfo->num_components; ci++) - for (i = 0; i < DCTSIZE2; i++) - *coef_bit_ptr++ = -1; -} - -#endif /* D_PROGRESSIVE_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jdpostct.c b/source/modules/juce_graphics/image_formats/jpglib/jdpostct.c deleted file mode 100644 index 2d93839ed..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jdpostct.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * jdpostct.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains the decompression postprocessing controller. - * This controller manages the upsampling, color conversion, and color - * quantization/reduction steps; specifically, it controls the buffering - * between upsample/color conversion and color quantization/reduction. - * - * If no color quantization/reduction is required, then this module has no - * work to do, and it just hands off to the upsample/color conversion code. - * An integrated upsample/convert/quantize process would replace this module - * entirely. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Private buffer controller object */ - -typedef struct { - struct jpeg_d_post_controller pub; /* public fields */ - - /* Color quantization source buffer: this holds output data from - * the upsample/color conversion step to be passed to the quantizer. - * For two-pass color quantization, we need a full-image buffer; - * for one-pass operation, a strip buffer is sufficient. - */ - jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */ - JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */ - JDIMENSION strip_height; /* buffer size in rows */ - /* for two-pass mode only: */ - JDIMENSION starting_row; /* row # of first row in current strip */ - JDIMENSION next_row; /* index of next row to fill/empty in strip */ -} my_post_controller; - -typedef my_post_controller * my_post_ptr; - - -/* Forward declarations */ -METHODDEF(void) post_process_1pass - JPP((j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail)); -#ifdef QUANT_2PASS_SUPPORTED -METHODDEF(void) post_process_prepass - JPP((j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail)); -METHODDEF(void) post_process_2pass - JPP((j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail)); -#endif - - -/* - * Initialize for a processing pass. - */ - -METHODDEF(void) -start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) -{ - my_post_ptr post = (my_post_ptr) cinfo->post; - - switch (pass_mode) { - case JBUF_PASS_THRU: - if (cinfo->quantize_colors) { - /* Single-pass processing with color quantization. */ - post->pub.post_process_data = post_process_1pass; - /* We could be doing buffered-image output before starting a 2-pass - * color quantization; in that case, jinit_d_post_controller did not - * allocate a strip buffer. Use the virtual-array buffer as workspace. - */ - if (post->buffer == NULL) { - post->buffer = (*cinfo->mem->access_virt_sarray) - ((j_common_ptr) cinfo, post->whole_image, - (JDIMENSION) 0, post->strip_height, TRUE); - } - } else { - /* For single-pass processing without color quantization, - * I have no work to do; just call the upsampler directly. - */ - post->pub.post_process_data = cinfo->upsample->upsample; - } - break; -#ifdef QUANT_2PASS_SUPPORTED - case JBUF_SAVE_AND_PASS: - /* First pass of 2-pass quantization */ - if (post->whole_image == NULL) - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - post->pub.post_process_data = post_process_prepass; - break; - case JBUF_CRANK_DEST: - /* Second pass of 2-pass quantization */ - if (post->whole_image == NULL) - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - post->pub.post_process_data = post_process_2pass; - break; -#endif /* QUANT_2PASS_SUPPORTED */ - default: - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); - break; - } - post->starting_row = post->next_row = 0; -} - - -/* - * Process some data in the one-pass (strip buffer) case. - * This is used for color precision reduction as well as one-pass quantization. - */ - -METHODDEF(void) -post_process_1pass (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail) -{ - my_post_ptr post = (my_post_ptr) cinfo->post; - JDIMENSION num_rows, max_rows; - - /* Fill the buffer, but not more than what we can dump out in one go. */ - /* Note we rely on the upsampler to detect bottom of image. */ - max_rows = out_rows_avail - *out_row_ctr; - if (max_rows > post->strip_height) - max_rows = post->strip_height; - num_rows = 0; - (*cinfo->upsample->upsample) (cinfo, - input_buf, in_row_group_ctr, in_row_groups_avail, - post->buffer, &num_rows, max_rows); - /* Quantize and emit data. */ - (*cinfo->cquantize->color_quantize) (cinfo, - post->buffer, output_buf + *out_row_ctr, (int) num_rows); - *out_row_ctr += num_rows; -} - - -#ifdef QUANT_2PASS_SUPPORTED - -/* - * Process some data in the first pass of 2-pass quantization. - */ - -METHODDEF(void) -post_process_prepass (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY, JDIMENSION *out_row_ctr, - JDIMENSION) -{ - my_post_ptr post = (my_post_ptr) cinfo->post; - JDIMENSION old_next_row, num_rows; - - /* Reposition virtual buffer if at start of strip. */ - if (post->next_row == 0) { - post->buffer = (*cinfo->mem->access_virt_sarray) - ((j_common_ptr) cinfo, post->whole_image, - post->starting_row, post->strip_height, TRUE); - } - - /* Upsample some data (up to a strip height's worth). */ - old_next_row = post->next_row; - (*cinfo->upsample->upsample) (cinfo, - input_buf, in_row_group_ctr, in_row_groups_avail, - post->buffer, &post->next_row, post->strip_height); - - /* Allow quantizer to scan new data. No data is emitted, */ - /* but we advance out_row_ctr so outer loop can tell when we're done. */ - if (post->next_row > old_next_row) { - num_rows = post->next_row - old_next_row; - (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row, - (JSAMPARRAY) NULL, (int) num_rows); - *out_row_ctr += num_rows; - } - - /* Advance if we filled the strip. */ - if (post->next_row >= post->strip_height) { - post->starting_row += post->strip_height; - post->next_row = 0; - } -} - - -/* - * Process some data in the second pass of 2-pass quantization. - */ - -METHODDEF(void) -post_process_2pass (j_decompress_ptr cinfo, - JSAMPIMAGE, JDIMENSION *, - JDIMENSION, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail) -{ - my_post_ptr post = (my_post_ptr) cinfo->post; - JDIMENSION num_rows, max_rows; - - /* Reposition virtual buffer if at start of strip. */ - if (post->next_row == 0) { - post->buffer = (*cinfo->mem->access_virt_sarray) - ((j_common_ptr) cinfo, post->whole_image, - post->starting_row, post->strip_height, FALSE); - } - - /* Determine number of rows to emit. */ - num_rows = post->strip_height - post->next_row; /* available in strip */ - max_rows = out_rows_avail - *out_row_ctr; /* available in output area */ - if (num_rows > max_rows) - num_rows = max_rows; - /* We have to check bottom of image here, can't depend on upsampler. */ - max_rows = cinfo->output_height - post->starting_row; - if (num_rows > max_rows) - num_rows = max_rows; - - /* Quantize and emit data. */ - (*cinfo->cquantize->color_quantize) (cinfo, - post->buffer + post->next_row, output_buf + *out_row_ctr, - (int) num_rows); - *out_row_ctr += num_rows; - - /* Advance if we filled the strip. */ - post->next_row += num_rows; - if (post->next_row >= post->strip_height) { - post->starting_row += post->strip_height; - post->next_row = 0; - } -} - -#endif /* QUANT_2PASS_SUPPORTED */ - - -/* - * Initialize postprocessing controller. - */ - -GLOBAL(void) -jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer) -{ - my_post_ptr post; - - post = (my_post_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_post_controller)); - cinfo->post = (struct jpeg_d_post_controller *) post; - post->pub.start_pass = start_pass_dpost; - post->whole_image = NULL; /* flag for no virtual arrays */ - post->buffer = NULL; /* flag for no strip buffer */ - - /* Create the quantization buffer, if needed */ - if (cinfo->quantize_colors) { - /* The buffer strip height is max_v_samp_factor, which is typically - * an efficient number of rows for upsampling to return. - * (In the presence of output rescaling, we might want to be smarter?) - */ - post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor; - if (need_full_buffer) { - /* Two-pass color quantization: need full-image storage. */ - /* We round up the number of rows to a multiple of the strip height. */ -#ifdef QUANT_2PASS_SUPPORTED - post->whole_image = (*cinfo->mem->request_virt_sarray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, - cinfo->output_width * cinfo->out_color_components, - (JDIMENSION) jround_up((long) cinfo->output_height, - (long) post->strip_height), - post->strip_height); -#else - ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); -#endif /* QUANT_2PASS_SUPPORTED */ - } else { - /* One-pass color quantization: just make a strip buffer. */ - post->buffer = (*cinfo->mem->alloc_sarray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - cinfo->output_width * cinfo->out_color_components, - post->strip_height); - } - } -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jdsample.c b/source/modules/juce_graphics/image_formats/jpglib/jdsample.c deleted file mode 100644 index ab2c01286..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jdsample.c +++ /dev/null @@ -1,478 +0,0 @@ -/* - * jdsample.c - * - * Copyright (C) 1991-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains upsampling routines. - * - * Upsampling input data is counted in "row groups". A row group - * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size) - * sample rows of each component. Upsampling will normally produce - * max_v_samp_factor pixel rows from each row group (but this could vary - * if the upsampler is applying a scale factor of its own). - * - * An excellent reference for image resampling is - * Digital Image Warping, George Wolberg, 1990. - * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Pointer to routine to upsample a single component */ -typedef JMETHOD(void, upsample1_ptr, - (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); - -/* Private subobject */ - -typedef struct { - struct jpeg_upsampler pub; /* public fields */ - - /* Color conversion buffer. When using separate upsampling and color - * conversion steps, this buffer holds one upsampled row group until it - * has been color converted and output. - * Note: we do not allocate any storage for component(s) which are full-size, - * ie do not need rescaling. The corresponding entry of color_buf[] is - * simply set to point to the input data array, thereby avoiding copying. - */ - JSAMPARRAY color_buf[MAX_COMPONENTS]; - - /* Per-component upsampling method pointers */ - upsample1_ptr methods[MAX_COMPONENTS]; - - int next_row_out; /* counts rows emitted from color_buf */ - JDIMENSION rows_to_go; /* counts rows remaining in image */ - - /* Height of an input row group for each component. */ - int rowgroup_height[MAX_COMPONENTS]; - - /* These arrays save pixel expansion factors so that int_expand need not - * recompute them each time. They are unused for other upsampling methods. - */ - UINT8 h_expand[MAX_COMPONENTS]; - UINT8 v_expand[MAX_COMPONENTS]; -} my_upsampler2; - -typedef my_upsampler2 * my_upsample_ptr2; - - -/* - * Initialize for an upsampling pass. - */ - -METHODDEF(void) -start_pass_upsample (j_decompress_ptr cinfo) -{ - my_upsample_ptr2 upsample = (my_upsample_ptr2) cinfo->upsample; - - /* Mark the conversion buffer empty */ - upsample->next_row_out = cinfo->max_v_samp_factor; - /* Initialize total-height counter for detecting bottom of image */ - upsample->rows_to_go = cinfo->output_height; -} - - -/* - * Control routine to do upsampling (and color conversion). - * - * In this version we upsample each component independently. - * We upsample one row group into the conversion buffer, then apply - * color conversion a row at a time. - */ - -METHODDEF(void) -sep_upsample (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, - JDIMENSION, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail) -{ - my_upsample_ptr2 upsample = (my_upsample_ptr2) cinfo->upsample; - int ci; - jpeg_component_info * compptr; - JDIMENSION num_rows; - - /* Fill the conversion buffer, if it's empty */ - if (upsample->next_row_out >= cinfo->max_v_samp_factor) { - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Invoke per-component upsample method. Notice we pass a POINTER - * to color_buf[ci], so that fullsize_upsample can change it. - */ - (*upsample->methods[ci]) (cinfo, compptr, - input_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]), - upsample->color_buf + ci); - } - upsample->next_row_out = 0; - } - - /* Color-convert and emit rows */ - - /* How many we have in the buffer: */ - num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out); - /* Not more than the distance to the end of the image. Need this test - * in case the image height is not a multiple of max_v_samp_factor: - */ - if (num_rows > upsample->rows_to_go) - num_rows = upsample->rows_to_go; - /* And not more than what the client can accept: */ - out_rows_avail -= *out_row_ctr; - if (num_rows > out_rows_avail) - num_rows = out_rows_avail; - - (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf, - (JDIMENSION) upsample->next_row_out, - output_buf + *out_row_ctr, - (int) num_rows); - - /* Adjust counts */ - *out_row_ctr += num_rows; - upsample->rows_to_go -= num_rows; - upsample->next_row_out += num_rows; - /* When the buffer is emptied, declare this input row group consumed */ - if (upsample->next_row_out >= cinfo->max_v_samp_factor) - (*in_row_group_ctr)++; -} - - -/* - * These are the routines invoked by sep_upsample to upsample pixel values - * of a single component. One row group is processed per call. - */ - - -/* - * For full-size components, we just make color_buf[ci] point at the - * input buffer, and thus avoid copying any data. Note that this is - * safe only because sep_upsample doesn't declare the input row group - * "consumed" until we are done color converting and emitting it. - */ - -METHODDEF(void) -fullsize_upsample (j_decompress_ptr, jpeg_component_info *, - JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) -{ - *output_data_ptr = input_data; -} - - -/* - * This is a no-op version used for "uninteresting" components. - * These components will not be referenced by color conversion. - */ - -METHODDEF(void) -noop_upsample (j_decompress_ptr, jpeg_component_info *, - JSAMPARRAY, JSAMPARRAY * output_data_ptr) -{ - *output_data_ptr = NULL; /* safety check */ -} - - -/* - * This version handles any integral sampling ratios. - * This is not used for typical JPEG files, so it need not be fast. - * Nor, for that matter, is it particularly accurate: the algorithm is - * simple replication of the input pixel onto the corresponding output - * pixels. The hi-falutin sampling literature refers to this as a - * "box filter". A box filter tends to introduce visible artifacts, - * so if you are actually going to use 3:1 or 4:1 sampling ratios - * you would be well advised to improve this code. - */ - -METHODDEF(void) -int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) -{ - my_upsample_ptr2 upsample = (my_upsample_ptr2) cinfo->upsample; - JSAMPARRAY output_data = *output_data_ptr; - JSAMPROW inptr, outptr; - JSAMPLE invalue; - int h; - JSAMPROW outend; - int h_expand, v_expand; - int inrow, outrow; - - h_expand = upsample->h_expand[compptr->component_index]; - v_expand = upsample->v_expand[compptr->component_index]; - - inrow = outrow = 0; - while (outrow < cinfo->max_v_samp_factor) { - /* Generate one output row with proper horizontal expansion */ - inptr = input_data[inrow]; - outptr = output_data[outrow]; - outend = outptr + cinfo->output_width; - while (outptr < outend) { - invalue = *inptr++; /* don't need GETJSAMPLE() here */ - for (h = h_expand; h > 0; h--) { - *outptr++ = invalue; - } - } - /* Generate any additional output rows by duplicating the first one */ - if (v_expand > 1) { - jcopy_sample_rows(output_data, outrow, output_data, outrow+1, - v_expand-1, cinfo->output_width); - } - inrow++; - outrow += v_expand; - } -} - - -/* - * Fast processing for the common case of 2:1 horizontal and 1:1 vertical. - * It's still a box filter. - */ - -METHODDEF(void) -h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info *, - JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) -{ - JSAMPARRAY output_data = *output_data_ptr; - JSAMPROW inptr, outptr; - JSAMPLE invalue; - JSAMPROW outend; - int inrow; - - for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { - inptr = input_data[inrow]; - outptr = output_data[inrow]; - outend = outptr + cinfo->output_width; - while (outptr < outend) { - invalue = *inptr++; /* don't need GETJSAMPLE() here */ - *outptr++ = invalue; - *outptr++ = invalue; - } - } -} - - -/* - * Fast processing for the common case of 2:1 horizontal and 2:1 vertical. - * It's still a box filter. - */ - -METHODDEF(void) -h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info *, - JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) -{ - JSAMPARRAY output_data = *output_data_ptr; - JSAMPROW inptr, outptr; - JSAMPLE invalue; - JSAMPROW outend; - int inrow, outrow; - - inrow = outrow = 0; - while (outrow < cinfo->max_v_samp_factor) { - inptr = input_data[inrow]; - outptr = output_data[outrow]; - outend = outptr + cinfo->output_width; - while (outptr < outend) { - invalue = *inptr++; /* don't need GETJSAMPLE() here */ - *outptr++ = invalue; - *outptr++ = invalue; - } - jcopy_sample_rows(output_data, outrow, output_data, outrow+1, - 1, cinfo->output_width); - inrow++; - outrow += 2; - } -} - - -/* - * Fancy processing for the common case of 2:1 horizontal and 1:1 vertical. - * - * The upsampling algorithm is linear interpolation between pixel centers, - * also known as a "triangle filter". This is a good compromise between - * speed and visual quality. The centers of the output pixels are 1/4 and 3/4 - * of the way between input pixel centers. - * - * A note about the "bias" calculations: when rounding fractional values to - * integer, we do not want to always round 0.5 up to the next integer. - * If we did that, we'd introduce a noticeable bias towards larger values. - * Instead, this code is arranged so that 0.5 will be rounded up or down at - * alternate pixel locations (a simple ordered dither pattern). - */ - -METHODDEF(void) -h2v1_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) -{ - JSAMPARRAY output_data = *output_data_ptr; - JSAMPROW inptr, outptr; - int invalue; - JDIMENSION colctr; - int inrow; - - for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { - inptr = input_data[inrow]; - outptr = output_data[inrow]; - /* Special case for first column */ - invalue = GETJSAMPLE(*inptr++); - *outptr++ = (JSAMPLE) invalue; - *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(*inptr) + 2) >> 2); - - for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { - /* General case: 3/4 * nearer pixel + 1/4 * further pixel */ - invalue = GETJSAMPLE(*inptr++) * 3; - *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(inptr[-2]) + 1) >> 2); - *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(*inptr) + 2) >> 2); - } - - /* Special case for last column */ - invalue = GETJSAMPLE(*inptr); - *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(inptr[-1]) + 1) >> 2); - *outptr++ = (JSAMPLE) invalue; - } -} - - -/* - * Fancy processing for the common case of 2:1 horizontal and 2:1 vertical. - * Again a triangle filter; see comments for h2v1 case, above. - * - * It is OK for us to reference the adjacent input rows because we demanded - * context from the main buffer controller (see initialization code). - */ - -METHODDEF(void) -h2v2_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) -{ - JSAMPARRAY output_data = *output_data_ptr; - JSAMPROW inptr0, inptr1, outptr; -#if BITS_IN_JSAMPLE == 8 - int thiscolsum, lastcolsum, nextcolsum; -#else - INT32 thiscolsum, lastcolsum, nextcolsum; -#endif - JDIMENSION colctr; - int inrow, outrow, v; - - inrow = outrow = 0; - while (outrow < cinfo->max_v_samp_factor) { - for (v = 0; v < 2; v++) { - /* inptr0 points to nearest input row, inptr1 points to next nearest */ - inptr0 = input_data[inrow]; - if (v == 0) /* next nearest is row above */ - inptr1 = input_data[inrow-1]; - else /* next nearest is row below */ - inptr1 = input_data[inrow+1]; - outptr = output_data[outrow++]; - - /* Special case for first column */ - thiscolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); - nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); - *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 8) >> 4); - *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4); - lastcolsum = thiscolsum; thiscolsum = nextcolsum; - - for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { - /* General case: 3/4 * nearer pixel + 1/4 * further pixel in each */ - /* dimension, thus 9/16, 3/16, 3/16, 1/16 overall */ - nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); - *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4); - *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4); - lastcolsum = thiscolsum; thiscolsum = nextcolsum; - } - - /* Special case for last column */ - *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4); - *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 7) >> 4); - } - inrow++; - } -} - - -/* - * Module initialization routine for upsampling. - */ - -GLOBAL(void) -jinit_upsampler (j_decompress_ptr cinfo) -{ - my_upsample_ptr2 upsample; - int ci; - jpeg_component_info * compptr; - boolean need_buffer, do_fancy; - int h_in_group, v_in_group, h_out_group, v_out_group; - - upsample = (my_upsample_ptr2) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_upsampler2)); - cinfo->upsample = (struct jpeg_upsampler *) upsample; - upsample->pub.start_pass = start_pass_upsample; - upsample->pub.upsample = sep_upsample; - upsample->pub.need_context_rows = FALSE; /* until we find out differently */ - - if (cinfo->CCIR601_sampling) /* this isn't supported */ - ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); - - /* jdmainct.c doesn't support context rows when min_DCT_scaled_size = 1, - * so don't ask for it. - */ - do_fancy = cinfo->do_fancy_upsampling && cinfo->min_DCT_scaled_size > 1; - - /* Verify we can handle the sampling factors, select per-component methods, - * and create storage as needed. - */ - for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; - ci++, compptr++) { - /* Compute size of an "input group" after IDCT scaling. This many samples - * are to be converted to max_h_samp_factor * max_v_samp_factor pixels. - */ - h_in_group = (compptr->h_samp_factor * compptr->DCT_scaled_size) / - cinfo->min_DCT_scaled_size; - v_in_group = (compptr->v_samp_factor * compptr->DCT_scaled_size) / - cinfo->min_DCT_scaled_size; - h_out_group = cinfo->max_h_samp_factor; - v_out_group = cinfo->max_v_samp_factor; - upsample->rowgroup_height[ci] = v_in_group; /* save for use later */ - need_buffer = TRUE; - if (! compptr->component_needed) { - /* Don't bother to upsample an uninteresting component. */ - upsample->methods[ci] = noop_upsample; - need_buffer = FALSE; - } else if (h_in_group == h_out_group && v_in_group == v_out_group) { - /* Fullsize components can be processed without any work. */ - upsample->methods[ci] = fullsize_upsample; - need_buffer = FALSE; - } else if (h_in_group * 2 == h_out_group && - v_in_group == v_out_group) { - /* Special cases for 2h1v upsampling */ - if (do_fancy && compptr->downsampled_width > 2) - upsample->methods[ci] = h2v1_fancy_upsample; - else - upsample->methods[ci] = h2v1_upsample; - } else if (h_in_group * 2 == h_out_group && - v_in_group * 2 == v_out_group) { - /* Special cases for 2h2v upsampling */ - if (do_fancy && compptr->downsampled_width > 2) { - upsample->methods[ci] = h2v2_fancy_upsample; - upsample->pub.need_context_rows = TRUE; - } else - upsample->methods[ci] = h2v2_upsample; - } else if ((h_out_group % h_in_group) == 0 && - (v_out_group % v_in_group) == 0) { - /* Generic integral-factors upsampling method */ - upsample->methods[ci] = int_upsample; - upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group); - upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group); - } else - ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); - if (need_buffer) { - upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - (JDIMENSION) jround_up((long) cinfo->output_width, - (long) cinfo->max_h_samp_factor), - (JDIMENSION) cinfo->max_v_samp_factor); - } - } -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jdtrans.c b/source/modules/juce_graphics/image_formats/jpglib/jdtrans.c deleted file mode 100644 index 12c193c88..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jdtrans.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * jdtrans.c - * - * Copyright (C) 1995-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains library routines for transcoding decompression, - * that is, reading raw DCT coefficient arrays from an input JPEG file. - * The routines in jdapimin.c will also be needed by a transcoder. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* Forward declarations */ -LOCAL(void) transdecode_master_selection JPP((j_decompress_ptr cinfo)); - - -/* - * Read the coefficient arrays from a JPEG file. - * jpeg_read_header must be completed before calling this. - * - * The entire image is read into a set of virtual coefficient-block arrays, - * one per component. The return value is a pointer to the array of - * virtual-array descriptors. These can be manipulated directly via the - * JPEG memory manager, or handed off to jpeg_write_coefficients(). - * To release the memory occupied by the virtual arrays, call - * jpeg_finish_decompress() when done with the data. - * - * An alternative usage is to simply obtain access to the coefficient arrays - * during a buffered-image-mode decompression operation. This is allowed - * after any jpeg_finish_output() call. The arrays can be accessed until - * jpeg_finish_decompress() is called. (Note that any call to the library - * may reposition the arrays, so don't rely on access_virt_barray() results - * to stay valid across library calls.) - * - * Returns NULL if suspended. This case need be checked only if - * a suspending data source is used. - */ - -GLOBAL(jvirt_barray_ptr *) -jpeg_read_coefficients (j_decompress_ptr cinfo) -{ - if (cinfo->global_state == DSTATE_READY) { - /* First call: initialize active modules */ - transdecode_master_selection(cinfo); - cinfo->global_state = DSTATE_RDCOEFS; - } - if (cinfo->global_state == DSTATE_RDCOEFS) { - /* Absorb whole file into the coef buffer */ - for (;;) { - int retcode; - /* Call progress monitor hook if present */ - if (cinfo->progress != NULL) - (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); - /* Absorb some more input */ - retcode = (*cinfo->inputctl->consume_input) (cinfo); - if (retcode == JPEG_SUSPENDED) - return NULL; - if (retcode == JPEG_REACHED_EOI) - break; - /* Advance progress counter if appropriate */ - if (cinfo->progress != NULL && - (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { - if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { - /* startup underestimated number of scans; ratchet up one scan */ - cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; - } - } - } - /* Set state so that jpeg_finish_decompress does the right thing */ - cinfo->global_state = DSTATE_STOPPING; - } - /* At this point we should be in state DSTATE_STOPPING if being used - * standalone, or in state DSTATE_BUFIMAGE if being invoked to get access - * to the coefficients during a full buffered-image-mode decompression. - */ - if ((cinfo->global_state == DSTATE_STOPPING || - cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) { - return cinfo->coef->coef_arrays; - } - /* Oops, improper usage */ - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); - return NULL; /* keep compiler happy */ -} - - -/* - * Master selection of decompression modules for transcoding. - * This substitutes for jdmaster.c's initialization of the full decompressor. - */ - -LOCAL(void) -transdecode_master_selection (j_decompress_ptr cinfo) -{ - /* This is effectively a buffered-image operation. */ - cinfo->buffered_image = TRUE; - - /* Entropy decoding: either Huffman or arithmetic coding. */ - if (cinfo->arith_code) { - ERREXIT(cinfo, JERR_ARITH_NOTIMPL); - } else { - if (cinfo->progressive_mode) { -#ifdef D_PROGRESSIVE_SUPPORTED - jinit_phuff_decoder(cinfo); -#else - ERREXIT(cinfo, JERR_NOT_COMPILED); -#endif - } else - jinit_huff_decoder(cinfo); - } - - /* Always get a full-image coefficient buffer. */ - jinit_d_coef_controller(cinfo, TRUE); - - /* We can now tell the memory manager to allocate virtual arrays. */ - (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); - - /* Initialize input side of decompressor to consume first scan. */ - (*cinfo->inputctl->start_input_pass) (cinfo); - - /* Initialize progress monitoring. */ - if (cinfo->progress != NULL) { - int nscans; - /* Estimate number of scans to set pass_limit. */ - if (cinfo->progressive_mode) { - /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ - nscans = 2 + 3 * cinfo->num_components; - } else if (cinfo->inputctl->has_multiple_scans) { - /* For a nonprogressive multiscan file, estimate 1 scan per component. */ - nscans = cinfo->num_components; - } else { - nscans = 1; - } - cinfo->progress->pass_counter = 0L; - cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; - cinfo->progress->completed_passes = 0; - cinfo->progress->total_passes = 1; - } -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jerror.c b/source/modules/juce_graphics/image_formats/jpglib/jerror.c deleted file mode 100644 index c98aed76e..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jerror.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * jerror.c - * - * Copyright (C) 1991-1998, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains simple error-reporting and trace-message routines. - * These are suitable for Unix-like systems and others where writing to - * stderr is the right thing to do. Many applications will want to replace - * some or all of these routines. - * - * If you define USE_WINDOWS_MESSAGEBOX in jconfig.h or in the makefile, - * you get a Windows-specific hack to display error messages in a dialog box. - * It ain't much, but it beats dropping error messages into the bit bucket, - * which is what happens to output to stderr under most Windows C compilers. - * - * These routines are used by both the compression and decompression code. - */ - -/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ -#include "jinclude.h" -#include "jpeglib.h" -#include "jversion.h" -#include "jerror.h" - -#ifdef USE_WINDOWS_MESSAGEBOX -#include -#endif - -#ifndef EXIT_FAILURE /* define exit() codes if not provided */ -#define EXIT_FAILURE 1 -#endif - - -/* - * Create the message string table. - * We do this from the master message list in jerror.h by re-reading - * jerror.h with a suitable definition for macro JMESSAGE. - * The message table is made an external symbol just in case any applications - * want to refer to it directly. - */ - -#ifdef NEED_SHORT_EXTERNAL_NAMES -#define jpeg_std_message_table jMsgTable -#endif - -#define JMESSAGE(code,string) string , - -const char * const jpeg_std_message_table[] = { -#include "jerror.h" - NULL -}; - - -/* - * Error exit handler: must not return to caller. - * - * Applications may override this if they want to get control back after - * an error. Typically one would longjmp somewhere instead of exiting. - * The setjmp buffer can be made a private field within an expanded error - * handler object. Note that the info needed to generate an error message - * is stored in the error object, so you can generate the message now or - * later, at your convenience. - * You should make sure that the JPEG object is cleaned up (with jpeg_abort - * or jpeg_destroy) at some point. - */ - -METHODDEF(void) -error_exit (j_common_ptr cinfo) -{ - /* Always display the message */ - (*cinfo->err->output_message) (cinfo); - - /* Let the memory manager delete any temp files before we die */ - jpeg_destroy(cinfo); - - exit(EXIT_FAILURE); -} - - -/* - * Actual output of an error or trace message. - * Applications may override this method to send JPEG messages somewhere - * other than stderr. - * - * On Windows, printing to stderr is generally completely useless, - * so we provide optional code to produce an error-dialog popup. - * Most Windows applications will still prefer to override this routine, - * but if they don't, it'll do something at least marginally useful. - * - * NOTE: to use the library in an environment that doesn't support the - * C stdio library, you may have to delete the call to fprintf() entirely, - * not just not use this routine. - */ - -METHODDEF(void) -output_message (j_common_ptr cinfo) -{ - char buffer[JMSG_LENGTH_MAX]; - - /* Create the message */ - (*cinfo->err->format_message) (cinfo, buffer); - -#ifdef USE_WINDOWS_MESSAGEBOX - /* Display it in a message dialog box */ - MessageBox(GetActiveWindow(), buffer, "JPEG Library Error", - MB_OK | MB_ICONERROR); -#else - /* Send it to stderr, adding a newline */ - fprintf(stderr, "%s\n", buffer); -#endif -} - - -/* - * Decide whether to emit a trace or warning message. - * msg_level is one of: - * -1: recoverable corrupt-data warning, may want to abort. - * 0: important advisory messages (always display to user). - * 1: first level of tracing detail. - * 2,3,...: successively more detailed tracing messages. - * An application might override this method if it wanted to abort on warnings - * or change the policy about which messages to display. - */ - -METHODDEF(void) -emit_message (j_common_ptr cinfo, int msg_level) -{ - struct jpeg_error_mgr * err = cinfo->err; - - if (msg_level < 0) { - /* It's a warning message. Since corrupt files may generate many warnings, - * the policy implemented here is to show only the first warning, - * unless trace_level >= 3. - */ - if (err->num_warnings == 0 || err->trace_level >= 3) - (*err->output_message) (cinfo); - /* Always count warnings in num_warnings. */ - err->num_warnings++; - } else { - /* It's a trace message. Show it if trace_level >= msg_level. */ - if (err->trace_level >= msg_level) - (*err->output_message) (cinfo); - } -} - - -/* - * Format a message string for the most recent JPEG error or message. - * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX - * characters. Note that no '\n' character is added to the string. - * Few applications should need to override this method. - */ - -METHODDEF(void) -format_message (j_common_ptr cinfo, char * buffer) -{ - struct jpeg_error_mgr * err = cinfo->err; - int msg_code = err->msg_code; - const char * msgtext = NULL; - const char * msgptr; - char ch; - boolean isstring; - - /* Look up message string in proper table */ - if (msg_code > 0 && msg_code <= err->last_jpeg_message) { - msgtext = err->jpeg_message_table[msg_code]; - } else if (err->addon_message_table != NULL && - msg_code >= err->first_addon_message && - msg_code <= err->last_addon_message) { - msgtext = err->addon_message_table[msg_code - err->first_addon_message]; - } - - /* Defend against bogus message number */ - if (msgtext == NULL) { - err->msg_parm.i[0] = msg_code; - msgtext = err->jpeg_message_table[0]; - } - - /* Check for string parameter, as indicated by %s in the message text */ - isstring = FALSE; - msgptr = msgtext; - while ((ch = *msgptr++) != '\0') { - if (ch == '%') { - if (*msgptr == 's') isstring = TRUE; - break; - } - } - - /* Format the message into the passed buffer */ - if (isstring) - sprintf(buffer, msgtext, err->msg_parm.s); - else - sprintf(buffer, msgtext, - err->msg_parm.i[0], err->msg_parm.i[1], - err->msg_parm.i[2], err->msg_parm.i[3], - err->msg_parm.i[4], err->msg_parm.i[5], - err->msg_parm.i[6], err->msg_parm.i[7]); -} - - -/* - * Reset error state variables at start of a new image. - * This is called during compression startup to reset trace/error - * processing to default state, without losing any application-specific - * method pointers. An application might possibly want to override - * this method if it has additional error processing state. - */ - -METHODDEF(void) -reset_error_mgr (j_common_ptr cinfo) -{ - cinfo->err->num_warnings = 0; - /* trace_level is not reset since it is an application-supplied parameter */ - cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */ -} - - -/* - * Fill in the standard error-handling methods in a jpeg_error_mgr object. - * Typical call is: - * struct jpeg_compress_struct cinfo; - * struct jpeg_error_mgr err; - * - * cinfo.err = jpeg_std_error(&err); - * after which the application may override some of the methods. - */ - -GLOBAL(struct jpeg_error_mgr *) -jpeg_std_error (struct jpeg_error_mgr * err) -{ - err->error_exit = error_exit; - err->emit_message = emit_message; - err->output_message = output_message; - err->format_message = format_message; - err->reset_error_mgr = reset_error_mgr; - - err->trace_level = 0; /* default = no tracing */ - err->num_warnings = 0; /* no warnings emitted yet */ - err->msg_code = 0; /* may be useful as a flag for "no error" */ - - /* Initialize message table pointers */ - err->jpeg_message_table = jpeg_std_message_table; - err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1; - - err->addon_message_table = NULL; - err->first_addon_message = 0; /* for safety */ - err->last_addon_message = 0; - - return err; -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jerror.h b/source/modules/juce_graphics/image_formats/jpglib/jerror.h deleted file mode 100644 index 79084f2e0..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jerror.h +++ /dev/null @@ -1,291 +0,0 @@ -/* - * jerror.h - * - * Copyright (C) 1994-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file defines the error and message codes for the JPEG library. - * Edit this file to add new codes, or to translate the message strings to - * some other language. - * A set of error-reporting macros are defined too. Some applications using - * the JPEG library may wish to include this file to get the error codes - * and/or the macros. - */ - -/* - * To define the enum list of message codes, include this file without - * defining macro JMESSAGE. To create a message string table, include it - * again with a suitable JMESSAGE definition (see jerror.c for an example). - */ -#ifndef JMESSAGE -#ifndef JERROR_H -/* First time through, define the enum list */ -#define JMAKE_ENUM_LIST -#else -/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ -#define JMESSAGE(code,string) -#endif /* JERROR_H */ -#endif /* JMESSAGE */ - -#ifdef JMAKE_ENUM_LIST - -typedef enum { - -#define JMESSAGE(code,string) code , - -#endif /* JMAKE_ENUM_LIST */ - -JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */ - -/* For maintenance convenience, list is alphabetical by message code name */ -JMESSAGE(JERR_ARITH_NOTIMPL, - "Sorry, there are legal restrictions on arithmetic coding") -JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix") -JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") -JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") -JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") -JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range") -JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") -JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") -JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") -JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") -JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") -JMESSAGE(JERR_BAD_LIB_VERSION, - "Wrong JPEG library version: library is %d, caller expects %d") -JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") -JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") -JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") -JMESSAGE(JERR_BAD_PROGRESSION, - "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d") -JMESSAGE(JERR_BAD_PROG_SCRIPT, - "Invalid progressive parameters at scan script entry %d") -JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") -JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") -JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") -JMESSAGE(JERR_BAD_STRUCT_SIZE, - "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u") -JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") -JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") -JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") -JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") -JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") -JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") -JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d") -JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x") -JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d") -JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d") -JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)") -JMESSAGE(JERR_EMS_READ, "Read from EMS failed") -JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed") -JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan") -JMESSAGE(JERR_FILE_READ, "Input file read error") -JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?") -JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet") -JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow") -JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry") -JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels") -JMESSAGE(JERR_INPUT_EMPTY, "Empty input file") -JMESSAGE(JERR_INPUT_EOF, "Premature end of input file") -JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, - "Cannot transcode due to multiple use of quantization table %d") -JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") -JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") -JMESSAGE(JERR_NOTIMPL, "Not implemented yet") -JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") -JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") -JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") -JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") -JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") -JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") -JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") -JMESSAGE(JERR_QUANT_COMPONENTS, - "Cannot quantize more than %d color components") -JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") -JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") -JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") -JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") -JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") -JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") -JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF") -JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") -JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") -JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") -JMESSAGE(JERR_TFILE_WRITE, - "Write failed on temporary file --- out of disk space?") -JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines") -JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x") -JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up") -JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation") -JMESSAGE(JERR_XMS_READ, "Read from XMS failed") -JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed") -JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT) -JMESSAGE(JMSG_VERSION, JVERSION) -JMESSAGE(JTRC_16BIT_TABLES, - "Caution: quantization tables are too coarse for baseline JPEG") -JMESSAGE(JTRC_ADOBE, - "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d") -JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u") -JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u") -JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x") -JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x") -JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d") -JMESSAGE(JTRC_DRI, "Define Restart Interval %u") -JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u") -JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u") -JMESSAGE(JTRC_EOI, "End Of Image") -JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d") -JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d") -JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, - "Warning: thumbnail image size does not match data length %u") -JMESSAGE(JTRC_JFIF_EXTENSION, - "JFIF extension marker: type 0x%02x, length %u") -JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image") -JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u") -JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x") -JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u") -JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors") -JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors") -JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization") -JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d") -JMESSAGE(JTRC_RST, "RST%d") -JMESSAGE(JTRC_SMOOTH_NOTIMPL, - "Smoothing not supported with nonstandard sampling ratios") -JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d") -JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d") -JMESSAGE(JTRC_SOI, "Start of Image") -JMESSAGE(JTRC_SOS, "Start Of Scan: %d components") -JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d") -JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d") -JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s") -JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s") -JMESSAGE(JTRC_THUMB_JPEG, - "JFIF extension marker: JPEG-compressed thumbnail image, length %u") -JMESSAGE(JTRC_THUMB_PALETTE, - "JFIF extension marker: palette thumbnail image, length %u") -JMESSAGE(JTRC_THUMB_RGB, - "JFIF extension marker: RGB thumbnail image, length %u") -JMESSAGE(JTRC_UNKNOWN_IDS, - "Unrecognized component IDs %d %d %d, assuming YCbCr") -JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") -JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") -JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") -JMESSAGE(JWRN_BOGUS_PROGRESSION, - "Inconsistent progression sequence for component %d coefficient %d") -JMESSAGE(JWRN_EXTRANEOUS_DATA, - "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x") -JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment") -JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") -JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") -JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") -JMESSAGE(JWRN_MUST_RESYNC, - "Corrupt JPEG data: found marker 0x%02x instead of RST%d") -JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") -JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") - -#ifdef JMAKE_ENUM_LIST - - JMSG_LASTMSGCODE -} J_MESSAGE_CODE; - -#undef JMAKE_ENUM_LIST -#endif /* JMAKE_ENUM_LIST */ - -/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ -#undef JMESSAGE - - -#ifndef JERROR_H -#define JERROR_H - -/* Macros to simplify using the error and trace message stuff */ -/* The first parameter is either type of cinfo pointer */ - -/* Fatal errors (print message and exit) */ -#define ERREXIT(cinfo,code) \ - ((cinfo)->err->msg_code = (code), \ - (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) -#define ERREXIT1(cinfo,code,p1) \ - ((cinfo)->err->msg_code = (code), \ - (cinfo)->err->msg_parm.i[0] = (p1), \ - (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) -#define ERREXIT2(cinfo,code,p1,p2) \ - ((cinfo)->err->msg_code = (code), \ - (cinfo)->err->msg_parm.i[0] = (p1), \ - (cinfo)->err->msg_parm.i[1] = (p2), \ - (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) -#define ERREXIT3(cinfo,code,p1,p2,p3) \ - ((cinfo)->err->msg_code = (code), \ - (cinfo)->err->msg_parm.i[0] = (p1), \ - (cinfo)->err->msg_parm.i[1] = (p2), \ - (cinfo)->err->msg_parm.i[2] = (p3), \ - (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) -#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \ - ((cinfo)->err->msg_code = (code), \ - (cinfo)->err->msg_parm.i[0] = (p1), \ - (cinfo)->err->msg_parm.i[1] = (p2), \ - (cinfo)->err->msg_parm.i[2] = (p3), \ - (cinfo)->err->msg_parm.i[3] = (p4), \ - (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) -#define ERREXITS(cinfo,code,str) \ - ((cinfo)->err->msg_code = (code), \ - strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ - (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) - -#define MAKESTMT(stuff) do { stuff } while (0) - -/* Nonfatal errors (we can keep going, but the data is probably corrupt) */ -#define WARNMS(cinfo,code) \ - ((cinfo)->err->msg_code = (code), \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) -#define WARNMS1(cinfo,code,p1) \ - ((cinfo)->err->msg_code = (code), \ - (cinfo)->err->msg_parm.i[0] = (p1), \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) -#define WARNMS2(cinfo,code,p1,p2) \ - ((cinfo)->err->msg_code = (code), \ - (cinfo)->err->msg_parm.i[0] = (p1), \ - (cinfo)->err->msg_parm.i[1] = (p2), \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) - -/* Informational/debugging messages */ -#define TRACEMS(cinfo,lvl,code) \ - ((cinfo)->err->msg_code = (code), \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) -#define TRACEMS1(cinfo,lvl,code,p1) \ - ((cinfo)->err->msg_code = (code), \ - (cinfo)->err->msg_parm.i[0] = (p1), \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) -#define TRACEMS2(cinfo,lvl,code,p1,p2) \ - ((cinfo)->err->msg_code = (code), \ - (cinfo)->err->msg_parm.i[0] = (p1), \ - (cinfo)->err->msg_parm.i[1] = (p2), \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) -#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \ - MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ - _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \ - (cinfo)->err->msg_code = (code); \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) -#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \ - MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ - _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ - (cinfo)->err->msg_code = (code); \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) -#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \ - MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ - _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ - _mp[4] = (p5); \ - (cinfo)->err->msg_code = (code); \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) -#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \ - MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ - _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ - _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \ - (cinfo)->err->msg_code = (code); \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) -#define TRACEMSS(cinfo,lvl,code,str) \ - ((cinfo)->err->msg_code = (code), \ - strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ - (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) - -#endif /* JERROR_H */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jfdctflt.c b/source/modules/juce_graphics/image_formats/jpglib/jfdctflt.c deleted file mode 100644 index 102f7d5ad..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jfdctflt.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * jfdctflt.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains a floating-point implementation of the - * forward DCT (Discrete Cosine Transform). - * - * This implementation should be more accurate than either of the integer - * DCT implementations. However, it may not give the same results on all - * machines because of differences in roundoff behavior. Speed will depend - * on the hardware's floating point capacity. - * - * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT - * on each column. Direct algorithms are also available, but they are - * much more complex and seem not to be any faster when reduced to code. - * - * This implementation is based on Arai, Agui, and Nakajima's algorithm for - * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in - * Japanese, but the algorithm is described in the Pennebaker & Mitchell - * JPEG textbook (see REFERENCES section in file README). The following code - * is based directly on figure 4-8 in P&M. - * While an 8-point DCT cannot be done in less than 11 multiplies, it is - * possible to arrange the computation so that many of the multiplies are - * simple scalings of the final outputs. These multiplies can then be - * folded into the multiplications or divisions by the JPEG quantization - * table entries. The AA&N method leaves only 5 multiplies and 29 adds - * to be done in the DCT itself. - * The primary disadvantage of this method is that with a fixed-point - * implementation, accuracy is lost due to imprecise representation of the - * scaled quantization values. However, that problem does not arise if - * we use floating point arithmetic. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jdct.h" /* Private declarations for DCT subsystem */ - -#ifdef DCT_FLOAT_SUPPORTED - - -/* - * This module is specialized to the case DCTSIZE = 8. - */ - -#if DCTSIZE != 8 - Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ -#endif - - -/* - * Perform the forward DCT on one block of samples. - */ - -GLOBAL(void) -jpeg_fdct_float (FAST_FLOAT * data) -{ - FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; - FAST_FLOAT tmp10, tmp11, tmp12, tmp13; - FAST_FLOAT z1, z2, z3, z4, z5, z11, z13; - FAST_FLOAT *dataptr; - int ctr; - - /* Pass 1: process rows. */ - - dataptr = data; - for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { - tmp0 = dataptr[0] + dataptr[7]; - tmp7 = dataptr[0] - dataptr[7]; - tmp1 = dataptr[1] + dataptr[6]; - tmp6 = dataptr[1] - dataptr[6]; - tmp2 = dataptr[2] + dataptr[5]; - tmp5 = dataptr[2] - dataptr[5]; - tmp3 = dataptr[3] + dataptr[4]; - tmp4 = dataptr[3] - dataptr[4]; - - /* Even part */ - - tmp10 = tmp0 + tmp3; /* phase 2 */ - tmp13 = tmp0 - tmp3; - tmp11 = tmp1 + tmp2; - tmp12 = tmp1 - tmp2; - - dataptr[0] = tmp10 + tmp11; /* phase 3 */ - dataptr[4] = tmp10 - tmp11; - - z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ - dataptr[2] = tmp13 + z1; /* phase 5 */ - dataptr[6] = tmp13 - z1; - - /* Odd part */ - - tmp10 = tmp4 + tmp5; /* phase 2 */ - tmp11 = tmp5 + tmp6; - tmp12 = tmp6 + tmp7; - - /* The rotator is modified from fig 4-8 to avoid extra negations. */ - z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ - z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ - z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ - z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ - - z11 = tmp7 + z3; /* phase 5 */ - z13 = tmp7 - z3; - - dataptr[5] = z13 + z2; /* phase 6 */ - dataptr[3] = z13 - z2; - dataptr[1] = z11 + z4; - dataptr[7] = z11 - z4; - - dataptr += DCTSIZE; /* advance pointer to next row */ - } - - /* Pass 2: process columns. */ - - dataptr = data; - for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { - tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; - tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; - tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; - tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; - tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; - tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; - tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; - tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; - - /* Even part */ - - tmp10 = tmp0 + tmp3; /* phase 2 */ - tmp13 = tmp0 - tmp3; - tmp11 = tmp1 + tmp2; - tmp12 = tmp1 - tmp2; - - dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ - dataptr[DCTSIZE*4] = tmp10 - tmp11; - - z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ - dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ - dataptr[DCTSIZE*6] = tmp13 - z1; - - /* Odd part */ - - tmp10 = tmp4 + tmp5; /* phase 2 */ - tmp11 = tmp5 + tmp6; - tmp12 = tmp6 + tmp7; - - /* The rotator is modified from fig 4-8 to avoid extra negations. */ - z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ - z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ - z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ - z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ - - z11 = tmp7 + z3; /* phase 5 */ - z13 = tmp7 - z3; - - dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ - dataptr[DCTSIZE*3] = z13 - z2; - dataptr[DCTSIZE*1] = z11 + z4; - dataptr[DCTSIZE*7] = z11 - z4; - - dataptr++; /* advance pointer to next column */ - } -} - -#endif /* DCT_FLOAT_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jfdctfst.c b/source/modules/juce_graphics/image_formats/jpglib/jfdctfst.c deleted file mode 100644 index f26221def..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jfdctfst.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * jfdctfst.c - * - * Copyright (C) 1994-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains a fast, not so accurate integer implementation of the - * forward DCT (Discrete Cosine Transform). - * - * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT - * on each column. Direct algorithms are also available, but they are - * much more complex and seem not to be any faster when reduced to code. - * - * This implementation is based on Arai, Agui, and Nakajima's algorithm for - * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in - * Japanese, but the algorithm is described in the Pennebaker & Mitchell - * JPEG textbook (see REFERENCES section in file README). The following code - * is based directly on figure 4-8 in P&M. - * While an 8-point DCT cannot be done in less than 11 multiplies, it is - * possible to arrange the computation so that many of the multiplies are - * simple scalings of the final outputs. These multiplies can then be - * folded into the multiplications or divisions by the JPEG quantization - * table entries. The AA&N method leaves only 5 multiplies and 29 adds - * to be done in the DCT itself. - * The primary disadvantage of this method is that with fixed-point math, - * accuracy is lost due to imprecise representation of the scaled - * quantization values. The smaller the quantization table entry, the less - * precise the scaled value, so this implementation does worse with high- - * quality-setting files than with low-quality ones. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jdct.h" /* Private declarations for DCT subsystem */ - -#ifdef DCT_IFAST_SUPPORTED - - -/* - * This module is specialized to the case DCTSIZE = 8. - */ - -#if DCTSIZE != 8 - Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ -#endif - - -/* Scaling decisions are generally the same as in the LL&M algorithm; - * see jfdctint.c for more details. However, we choose to descale - * (right shift) multiplication products as soon as they are formed, - * rather than carrying additional fractional bits into subsequent additions. - * This compromises accuracy slightly, but it lets us save a few shifts. - * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) - * everywhere except in the multiplications proper; this saves a good deal - * of work on 16-bit-int machines. - * - * Again to save a few shifts, the intermediate results between pass 1 and - * pass 2 are not upscaled, but are represented only to integral precision. - * - * A final compromise is to represent the multiplicative constants to only - * 8 fractional bits, rather than 13. This saves some shifting work on some - * machines, and may also reduce the cost of multiplication (since there - * are fewer one-bits in the constants). - */ - -#define CONST_BITS 8 - - -/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus - * causing a lot of useless floating-point operations at run time. - * To get around this we use the following pre-calculated constants. - * If you change CONST_BITS you may want to add appropriate values. - * (With a reasonable C compiler, you can just rely on the FIX() macro...) - */ - -#if CONST_BITS == 8 -#define FIX_0_382683433 ((INT32) 98) /* FIX(0.382683433) */ -#define FIX_0_541196100 ((INT32) 139) /* FIX(0.541196100) */ -#define FIX_0_707106781 ((INT32) 181) /* FIX(0.707106781) */ -#define FIX_1_306562965 ((INT32) 334) /* FIX(1.306562965) */ -#else -#define FIX_0_382683433 FIX(0.382683433) -#define FIX_0_541196100 FIX(0.541196100) -#define FIX_0_707106781 FIX(0.707106781) -#define FIX_1_306562965 FIX(1.306562965) -#endif - - -/* We can gain a little more speed, with a further compromise in accuracy, - * by omitting the addition in a descaling shift. This yields an incorrectly - * rounded result half the time... - */ - -#ifndef USE_ACCURATE_ROUNDING -#undef DESCALE -#define DESCALE(x,n) RIGHT_SHIFT(x, n) -#endif - - -/* Multiply a DCTELEM variable by an INT32 constant, and immediately - * descale to yield a DCTELEM result. - */ - -#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS)) - - -/* - * Perform the forward DCT on one block of samples. - */ - -GLOBAL(void) -jpeg_fdct_ifast (DCTELEM * data) -{ - DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; - DCTELEM tmp10, tmp11, tmp12, tmp13; - DCTELEM z1, z2, z3, z4, z5, z11, z13; - DCTELEM *dataptr; - int ctr; - SHIFT_TEMPS - - /* Pass 1: process rows. */ - - dataptr = data; - for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { - tmp0 = dataptr[0] + dataptr[7]; - tmp7 = dataptr[0] - dataptr[7]; - tmp1 = dataptr[1] + dataptr[6]; - tmp6 = dataptr[1] - dataptr[6]; - tmp2 = dataptr[2] + dataptr[5]; - tmp5 = dataptr[2] - dataptr[5]; - tmp3 = dataptr[3] + dataptr[4]; - tmp4 = dataptr[3] - dataptr[4]; - - /* Even part */ - - tmp10 = tmp0 + tmp3; /* phase 2 */ - tmp13 = tmp0 - tmp3; - tmp11 = tmp1 + tmp2; - tmp12 = tmp1 - tmp2; - - dataptr[0] = tmp10 + tmp11; /* phase 3 */ - dataptr[4] = tmp10 - tmp11; - - z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */ - dataptr[2] = tmp13 + z1; /* phase 5 */ - dataptr[6] = tmp13 - z1; - - /* Odd part */ - - tmp10 = tmp4 + tmp5; /* phase 2 */ - tmp11 = tmp5 + tmp6; - tmp12 = tmp6 + tmp7; - - /* The rotator is modified from fig 4-8 to avoid extra negations. */ - z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */ - z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */ - z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */ - z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */ - - z11 = tmp7 + z3; /* phase 5 */ - z13 = tmp7 - z3; - - dataptr[5] = z13 + z2; /* phase 6 */ - dataptr[3] = z13 - z2; - dataptr[1] = z11 + z4; - dataptr[7] = z11 - z4; - - dataptr += DCTSIZE; /* advance pointer to next row */ - } - - /* Pass 2: process columns. */ - - dataptr = data; - for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { - tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; - tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; - tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; - tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; - tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; - tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; - tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; - tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; - - /* Even part */ - - tmp10 = tmp0 + tmp3; /* phase 2 */ - tmp13 = tmp0 - tmp3; - tmp11 = tmp1 + tmp2; - tmp12 = tmp1 - tmp2; - - dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ - dataptr[DCTSIZE*4] = tmp10 - tmp11; - - z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */ - dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ - dataptr[DCTSIZE*6] = tmp13 - z1; - - /* Odd part */ - - tmp10 = tmp4 + tmp5; /* phase 2 */ - tmp11 = tmp5 + tmp6; - tmp12 = tmp6 + tmp7; - - /* The rotator is modified from fig 4-8 to avoid extra negations. */ - z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */ - z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */ - z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */ - z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */ - - z11 = tmp7 + z3; /* phase 5 */ - z13 = tmp7 - z3; - - dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ - dataptr[DCTSIZE*3] = z13 - z2; - dataptr[DCTSIZE*1] = z11 + z4; - dataptr[DCTSIZE*7] = z11 - z4; - - dataptr++; /* advance pointer to next column */ - } -} - -#endif /* DCT_IFAST_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jfdctint.c b/source/modules/juce_graphics/image_formats/jpglib/jfdctint.c deleted file mode 100644 index a9058494d..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jfdctint.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * jfdctint.c - * - * Copyright (C) 1991-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains a slow-but-accurate integer implementation of the - * forward DCT (Discrete Cosine Transform). - * - * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT - * on each column. Direct algorithms are also available, but they are - * much more complex and seem not to be any faster when reduced to code. - * - * This implementation is based on an algorithm described in - * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT - * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, - * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. - * The primary algorithm described there uses 11 multiplies and 29 adds. - * We use their alternate method with 12 multiplies and 32 adds. - * The advantage of this method is that no data path contains more than one - * multiplication; this allows a very simple and accurate implementation in - * scaled fixed-point arithmetic, with a minimal number of shifts. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jdct.h" /* Private declarations for DCT subsystem */ - -#ifdef DCT_ISLOW_SUPPORTED - - -/* - * This module is specialized to the case DCTSIZE = 8. - */ - -#if DCTSIZE != 8 - Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ -#endif - - -/* - * The poop on this scaling stuff is as follows: - * - * Each 1-D DCT step produces outputs which are a factor of sqrt(N) - * larger than the true DCT outputs. The final outputs are therefore - * a factor of N larger than desired; since N=8 this can be cured by - * a simple right shift at the end of the algorithm. The advantage of - * this arrangement is that we save two multiplications per 1-D DCT, - * because the y0 and y4 outputs need not be divided by sqrt(N). - * In the IJG code, this factor of 8 is removed by the quantization step - * (in jcdctmgr.c), NOT in this module. - * - * We have to do addition and subtraction of the integer inputs, which - * is no problem, and multiplication by fractional constants, which is - * a problem to do in integer arithmetic. We multiply all the constants - * by CONST_SCALE and convert them to integer constants (thus retaining - * CONST_BITS bits of precision in the constants). After doing a - * multiplication we have to divide the product by CONST_SCALE, with proper - * rounding, to produce the correct output. This division can be done - * cheaply as a right shift of CONST_BITS bits. We postpone shifting - * as long as possible so that partial sums can be added together with - * full fractional precision. - * - * The outputs of the first pass are scaled up by PASS1_BITS bits so that - * they are represented to better-than-integral precision. These outputs - * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word - * with the recommended scaling. (For 12-bit sample data, the intermediate - * array is INT32 anyway.) - * - * To avoid overflow of the 32-bit intermediate results in pass 2, we must - * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis - * shows that the values given below are the most effective. - */ - -#if BITS_IN_JSAMPLE == 8 -#define CONST_BITS 13 -#define PASS1_BITS 2 -#else -#define CONST_BITS 13 -#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ -#endif - -/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus - * causing a lot of useless floating-point operations at run time. - * To get around this we use the following pre-calculated constants. - * If you change CONST_BITS you may want to add appropriate values. - * (With a reasonable C compiler, you can just rely on the FIX() macro...) - */ - -#if CONST_BITS == 13 -#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */ -#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */ -#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */ -#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ -#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ -#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */ -#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */ -#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ -#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */ -#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */ -#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ -#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */ -#else -#define FIX_0_298631336 FIX(0.298631336) -#define FIX_0_390180644 FIX(0.390180644) -#define FIX_0_541196100 FIX(0.541196100) -#define FIX_0_765366865 FIX(0.765366865) -#define FIX_0_899976223 FIX(0.899976223) -#define FIX_1_175875602 FIX(1.175875602) -#define FIX_1_501321110 FIX(1.501321110) -#define FIX_1_847759065 FIX(1.847759065) -#define FIX_1_961570560 FIX(1.961570560) -#define FIX_2_053119869 FIX(2.053119869) -#define FIX_2_562915447 FIX(2.562915447) -#define FIX_3_072711026 FIX(3.072711026) -#endif - - -/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. - * For 8-bit samples with the recommended scaling, all the variable - * and constant values involved are no more than 16 bits wide, so a - * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. - * For 12-bit samples, a full 32-bit multiplication will be needed. - */ - -#if BITS_IN_JSAMPLE == 8 -#define MULTIPLY(var,const) MULTIPLY16C16(var,const) -#else -#define MULTIPLY(var,const) ((var) * (const)) -#endif - - -/* - * Perform the forward DCT on one block of samples. - */ - -GLOBAL(void) -jpeg_fdct_islow (DCTELEM * data) -{ - INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; - INT32 tmp10, tmp11, tmp12, tmp13; - INT32 z1, z2, z3, z4, z5; - DCTELEM *dataptr; - int ctr; - SHIFT_TEMPS - - /* Pass 1: process rows. */ - /* Note results are scaled up by sqrt(8) compared to a true DCT; */ - /* furthermore, we scale the results by 2**PASS1_BITS. */ - - dataptr = data; - for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { - tmp0 = dataptr[0] + dataptr[7]; - tmp7 = dataptr[0] - dataptr[7]; - tmp1 = dataptr[1] + dataptr[6]; - tmp6 = dataptr[1] - dataptr[6]; - tmp2 = dataptr[2] + dataptr[5]; - tmp5 = dataptr[2] - dataptr[5]; - tmp3 = dataptr[3] + dataptr[4]; - tmp4 = dataptr[3] - dataptr[4]; - - /* Even part per LL&M figure 1 --- note that published figure is faulty; - * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". - */ - - tmp10 = tmp0 + tmp3; - tmp13 = tmp0 - tmp3; - tmp11 = tmp1 + tmp2; - tmp12 = tmp1 - tmp2; - - dataptr[0] = (DCTELEM) ((tmp10 + tmp11) << PASS1_BITS); - dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS); - - z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); - dataptr[2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865), - CONST_BITS-PASS1_BITS); - dataptr[6] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065), - CONST_BITS-PASS1_BITS); - - /* Odd part per figure 8 --- note paper omits factor of sqrt(2). - * cK represents cos(K*pi/16). - * i0..i3 in the paper are tmp4..tmp7 here. - */ - - z1 = tmp4 + tmp7; - z2 = tmp5 + tmp6; - z3 = tmp4 + tmp6; - z4 = tmp5 + tmp7; - z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ - - tmp4 = MULTIPLY(tmp4, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ - tmp5 = MULTIPLY(tmp5, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ - tmp6 = MULTIPLY(tmp6, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ - tmp7 = MULTIPLY(tmp7, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ - z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ - z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ - z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ - z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ - - z3 += z5; - z4 += z5; - - dataptr[7] = (DCTELEM) DESCALE(tmp4 + z1 + z3, CONST_BITS-PASS1_BITS); - dataptr[5] = (DCTELEM) DESCALE(tmp5 + z2 + z4, CONST_BITS-PASS1_BITS); - dataptr[3] = (DCTELEM) DESCALE(tmp6 + z2 + z3, CONST_BITS-PASS1_BITS); - dataptr[1] = (DCTELEM) DESCALE(tmp7 + z1 + z4, CONST_BITS-PASS1_BITS); - - dataptr += DCTSIZE; /* advance pointer to next row */ - } - - /* Pass 2: process columns. - * We remove the PASS1_BITS scaling, but leave the results scaled up - * by an overall factor of 8. - */ - - dataptr = data; - for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { - tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; - tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; - tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; - tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; - tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; - tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; - tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; - tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; - - /* Even part per LL&M figure 1 --- note that published figure is faulty; - * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". - */ - - tmp10 = tmp0 + tmp3; - tmp13 = tmp0 - tmp3; - tmp11 = tmp1 + tmp2; - tmp12 = tmp1 - tmp2; - - dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp11, PASS1_BITS); - dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp10 - tmp11, PASS1_BITS); - - z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); - dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865), - CONST_BITS+PASS1_BITS); - dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065), - CONST_BITS+PASS1_BITS); - - /* Odd part per figure 8 --- note paper omits factor of sqrt(2). - * cK represents cos(K*pi/16). - * i0..i3 in the paper are tmp4..tmp7 here. - */ - - z1 = tmp4 + tmp7; - z2 = tmp5 + tmp6; - z3 = tmp4 + tmp6; - z4 = tmp5 + tmp7; - z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ - - tmp4 = MULTIPLY(tmp4, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ - tmp5 = MULTIPLY(tmp5, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ - tmp6 = MULTIPLY(tmp6, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ - tmp7 = MULTIPLY(tmp7, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ - z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ - z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ - z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ - z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ - - z3 += z5; - z4 += z5; - - dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp4 + z1 + z3, - CONST_BITS+PASS1_BITS); - dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp5 + z2 + z4, - CONST_BITS+PASS1_BITS); - dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp6 + z2 + z3, - CONST_BITS+PASS1_BITS); - dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp7 + z1 + z4, - CONST_BITS+PASS1_BITS); - - dataptr++; /* advance pointer to next column */ - } -} - -#endif /* DCT_ISLOW_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jidctflt.c b/source/modules/juce_graphics/image_formats/jpglib/jidctflt.c deleted file mode 100644 index 4a89578dc..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jidctflt.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * jidctflt.c - * - * Copyright (C) 1994-1998, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains a floating-point implementation of the - * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine - * must also perform dequantization of the input coefficients. - * - * This implementation should be more accurate than either of the integer - * IDCT implementations. However, it may not give the same results on all - * machines because of differences in roundoff behavior. Speed will depend - * on the hardware's floating point capacity. - * - * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT - * on each row (or vice versa, but it's more convenient to emit a row at - * a time). Direct algorithms are also available, but they are much more - * complex and seem not to be any faster when reduced to code. - * - * This implementation is based on Arai, Agui, and Nakajima's algorithm for - * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in - * Japanese, but the algorithm is described in the Pennebaker & Mitchell - * JPEG textbook (see REFERENCES section in file README). The following code - * is based directly on figure 4-8 in P&M. - * While an 8-point DCT cannot be done in less than 11 multiplies, it is - * possible to arrange the computation so that many of the multiplies are - * simple scalings of the final outputs. These multiplies can then be - * folded into the multiplications or divisions by the JPEG quantization - * table entries. The AA&N method leaves only 5 multiplies and 29 adds - * to be done in the DCT itself. - * The primary disadvantage of this method is that with a fixed-point - * implementation, accuracy is lost due to imprecise representation of the - * scaled quantization values. However, that problem does not arise if - * we use floating point arithmetic. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jdct.h" /* Private declarations for DCT subsystem */ - -#ifdef DCT_FLOAT_SUPPORTED - - -/* - * This module is specialized to the case DCTSIZE = 8. - */ - -#if DCTSIZE != 8 - Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ -#endif - - -/* Dequantize a coefficient by multiplying it by the multiplier-table - * entry; produce a float result. - */ - -#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval)) - - -/* - * Perform dequantization and inverse DCT on one block of coefficients. - */ - -GLOBAL(void) -jpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; - FAST_FLOAT tmp10, tmp11, tmp12, tmp13; - FAST_FLOAT z5, z10, z11, z12, z13; - JCOEFPTR inptr; - FLOAT_MULT_TYPE * quantptr; - FAST_FLOAT * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = DCTSIZE; ctr > 0; ctr--) { - /* Due to quantization, we will usually find that many of the input - * coefficients are zero, especially the AC terms. We can exploit this - * by short-circuiting the IDCT calculation for any column in which all - * the AC terms are zero. In that case each output is equal to the - * DC coefficient (with scale factor as needed). - * With typical images and quantization tables, half or more of the - * column DCT calculations can be simplified this way. - */ - - if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && - inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && - inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && - inptr[DCTSIZE*7] == 0) { - /* AC terms all zero */ - FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - - wsptr[DCTSIZE*0] = dcval; - wsptr[DCTSIZE*1] = dcval; - wsptr[DCTSIZE*2] = dcval; - wsptr[DCTSIZE*3] = dcval; - wsptr[DCTSIZE*4] = dcval; - wsptr[DCTSIZE*5] = dcval; - wsptr[DCTSIZE*6] = dcval; - wsptr[DCTSIZE*7] = dcval; - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - continue; - } - - /* Even part */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - tmp10 = tmp0 + tmp2; /* phase 3 */ - tmp11 = tmp0 - tmp2; - - tmp13 = tmp1 + tmp3; /* phases 5-3 */ - tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */ - - tmp0 = tmp10 + tmp13; /* phase 2 */ - tmp3 = tmp10 - tmp13; - tmp1 = tmp11 + tmp12; - tmp2 = tmp11 - tmp12; - - /* Odd part */ - - tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - - z13 = tmp6 + tmp5; /* phase 6 */ - z10 = tmp6 - tmp5; - z11 = tmp4 + tmp7; - z12 = tmp4 - tmp7; - - tmp7 = z11 + z13; /* phase 5 */ - tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */ - - z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ - tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ - tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ - - tmp6 = tmp12 - tmp7; /* phase 2 */ - tmp5 = tmp11 - tmp6; - tmp4 = tmp10 + tmp5; - - wsptr[DCTSIZE*0] = tmp0 + tmp7; - wsptr[DCTSIZE*7] = tmp0 - tmp7; - wsptr[DCTSIZE*1] = tmp1 + tmp6; - wsptr[DCTSIZE*6] = tmp1 - tmp6; - wsptr[DCTSIZE*2] = tmp2 + tmp5; - wsptr[DCTSIZE*5] = tmp2 - tmp5; - wsptr[DCTSIZE*4] = tmp3 + tmp4; - wsptr[DCTSIZE*3] = tmp3 - tmp4; - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - } - - /* Pass 2: process rows from work array, store into output array. */ - /* Note that we must descale the results by a factor of 8 == 2**3. */ - - wsptr = workspace; - for (ctr = 0; ctr < DCTSIZE; ctr++) { - outptr = output_buf[ctr] + output_col; - /* Rows of zeroes can be exploited in the same way as we did with columns. - * However, the column calculation has created many nonzero AC terms, so - * the simplification applies less often (typically 5% to 10% of the time). - * And testing floats for zero is relatively expensive, so we don't bother. - */ - - /* Even part */ - - tmp10 = wsptr[0] + wsptr[4]; - tmp11 = wsptr[0] - wsptr[4]; - - tmp13 = wsptr[2] + wsptr[6]; - tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13; - - tmp0 = tmp10 + tmp13; - tmp3 = tmp10 - tmp13; - tmp1 = tmp11 + tmp12; - tmp2 = tmp11 - tmp12; - - /* Odd part */ - - z13 = wsptr[5] + wsptr[3]; - z10 = wsptr[5] - wsptr[3]; - z11 = wsptr[1] + wsptr[7]; - z12 = wsptr[1] - wsptr[7]; - - tmp7 = z11 + z13; - tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); - - z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ - tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ - tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ - - tmp6 = tmp12 - tmp7; - tmp5 = tmp11 - tmp6; - tmp4 = tmp10 + tmp5; - - /* Final output stage: scale down by a factor of 8 and range-limit */ - - outptr[0] = range_limit[(int) DESCALE((INT32) (tmp0 + tmp7), 3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) DESCALE((INT32) (tmp0 - tmp7), 3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) DESCALE((INT32) (tmp1 + tmp6), 3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) DESCALE((INT32) (tmp1 - tmp6), 3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) DESCALE((INT32) (tmp2 + tmp5), 3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) DESCALE((INT32) (tmp2 - tmp5), 3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) DESCALE((INT32) (tmp3 + tmp4), 3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) DESCALE((INT32) (tmp3 - tmp4), 3) - & RANGE_MASK]; - - wsptr += DCTSIZE; /* advance pointer to next row */ - } -} - -#endif /* DCT_FLOAT_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jidctfst.c b/source/modules/juce_graphics/image_formats/jpglib/jidctfst.c deleted file mode 100644 index 41790ea8c..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jidctfst.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - * jidctfst.c - * - * Copyright (C) 1994-1998, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains a fast, not so accurate integer implementation of the - * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine - * must also perform dequantization of the input coefficients. - * - * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT - * on each row (or vice versa, but it's more convenient to emit a row at - * a time). Direct algorithms are also available, but they are much more - * complex and seem not to be any faster when reduced to code. - * - * This implementation is based on Arai, Agui, and Nakajima's algorithm for - * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in - * Japanese, but the algorithm is described in the Pennebaker & Mitchell - * JPEG textbook (see REFERENCES section in file README). The following code - * is based directly on figure 4-8 in P&M. - * While an 8-point DCT cannot be done in less than 11 multiplies, it is - * possible to arrange the computation so that many of the multiplies are - * simple scalings of the final outputs. These multiplies can then be - * folded into the multiplications or divisions by the JPEG quantization - * table entries. The AA&N method leaves only 5 multiplies and 29 adds - * to be done in the DCT itself. - * The primary disadvantage of this method is that with fixed-point math, - * accuracy is lost due to imprecise representation of the scaled - * quantization values. The smaller the quantization table entry, the less - * precise the scaled value, so this implementation does worse with high- - * quality-setting files than with low-quality ones. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jdct.h" /* Private declarations for DCT subsystem */ - -#ifdef DCT_IFAST_SUPPORTED - - -/* - * This module is specialized to the case DCTSIZE = 8. - */ - -#if DCTSIZE != 8 - Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ -#endif - - -/* Scaling decisions are generally the same as in the LL&M algorithm; - * see jidctint.c for more details. However, we choose to descale - * (right shift) multiplication products as soon as they are formed, - * rather than carrying additional fractional bits into subsequent additions. - * This compromises accuracy slightly, but it lets us save a few shifts. - * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) - * everywhere except in the multiplications proper; this saves a good deal - * of work on 16-bit-int machines. - * - * The dequantized coefficients are not integers because the AA&N scaling - * factors have been incorporated. We represent them scaled up by PASS1_BITS, - * so that the first and second IDCT rounds have the same input scaling. - * For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to - * avoid a descaling shift; this compromises accuracy rather drastically - * for small quantization table entries, but it saves a lot of shifts. - * For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway, - * so we use a much larger scaling factor to preserve accuracy. - * - * A final compromise is to represent the multiplicative constants to only - * 8 fractional bits, rather than 13. This saves some shifting work on some - * machines, and may also reduce the cost of multiplication (since there - * are fewer one-bits in the constants). - */ - -#if BITS_IN_JSAMPLE == 8 -#define CONST_BITS 8 -#define PASS1_BITS 2 -#else -#define CONST_BITS 8 -#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ -#endif - -/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus - * causing a lot of useless floating-point operations at run time. - * To get around this we use the following pre-calculated constants. - * If you change CONST_BITS you may want to add appropriate values. - * (With a reasonable C compiler, you can just rely on the FIX() macro...) - */ - -#if CONST_BITS == 8 -#define FIX_1_082392200 ((INT32) 277) /* FIX(1.082392200) */ -#define FIX_1_414213562 ((INT32) 362) /* FIX(1.414213562) */ -#define FIX_1_847759065 ((INT32) 473) /* FIX(1.847759065) */ -#define FIX_2_613125930 ((INT32) 669) /* FIX(2.613125930) */ -#else -#define FIX_1_082392200 FIX(1.082392200) -#define FIX_1_414213562 FIX(1.414213562) -#define FIX_1_847759065 FIX(1.847759065) -#define FIX_2_613125930 FIX(2.613125930) -#endif - - -/* We can gain a little more speed, with a further compromise in accuracy, - * by omitting the addition in a descaling shift. This yields an incorrectly - * rounded result half the time... - */ - -#ifndef USE_ACCURATE_ROUNDING -#undef DESCALE -#define DESCALE(x,n) RIGHT_SHIFT(x, n) -#endif - - -/* Multiply a DCTELEM variable by an INT32 constant, and immediately - * descale to yield a DCTELEM result. - */ - -#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS)) - - -/* Dequantize a coefficient by multiplying it by the multiplier-table - * entry; produce a DCTELEM result. For 8-bit data a 16x16->16 - * multiplication will do. For 12-bit data, the multiplier table is - * declared INT32, so a 32-bit multiply will be used. - */ - -#if BITS_IN_JSAMPLE == 8 -#define DEQUANTIZE(coef,quantval) (((IFAST_MULT_TYPE) (coef)) * (quantval)) -#else -#define DEQUANTIZE(coef,quantval) \ - DESCALE((coef)*(quantval), IFAST_SCALE_BITS-PASS1_BITS) -#endif - - -/* Like DESCALE, but applies to a DCTELEM and produces an int. - * We assume that int right shift is unsigned if INT32 right shift is. - */ - -#ifdef RIGHT_SHIFT_IS_UNSIGNED -#define ISHIFT_TEMPS DCTELEM ishift_temp; -#if BITS_IN_JSAMPLE == 8 -#define DCTELEMBITS 16 /* DCTELEM may be 16 or 32 bits */ -#else -#define DCTELEMBITS 32 /* DCTELEM must be 32 bits */ -#endif -#define IRIGHT_SHIFT(x,shft) \ - ((ishift_temp = (x)) < 0 ? \ - (ishift_temp >> (shft)) | ((~((DCTELEM) 0)) << (DCTELEMBITS-(shft))) : \ - (ishift_temp >> (shft))) -#else -#define ISHIFT_TEMPS -#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) -#endif - -#ifdef USE_ACCURATE_ROUNDING -#define IDESCALE(x,n) ((int) IRIGHT_SHIFT((x) + (1 << ((n)-1)), n)) -#else -#define IDESCALE(x,n) ((int) IRIGHT_SHIFT(x, n)) -#endif - - -/* - * Perform dequantization and inverse DCT on one block of coefficients. - */ - -GLOBAL(void) -jpeg_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; - DCTELEM tmp10, tmp11, tmp12, tmp13; - DCTELEM z5, z10, z11, z12, z13; - JCOEFPTR inptr; - IFAST_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[DCTSIZE2]; /* buffers data between passes */ - SHIFT_TEMPS /* for DESCALE */ - ISHIFT_TEMPS /* for IDESCALE */ - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (IFAST_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = DCTSIZE; ctr > 0; ctr--) { - /* Due to quantization, we will usually find that many of the input - * coefficients are zero, especially the AC terms. We can exploit this - * by short-circuiting the IDCT calculation for any column in which all - * the AC terms are zero. In that case each output is equal to the - * DC coefficient (with scale factor as needed). - * With typical images and quantization tables, half or more of the - * column DCT calculations can be simplified this way. - */ - - if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && - inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && - inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && - inptr[DCTSIZE*7] == 0) { - /* AC terms all zero */ - int dcval = (int) DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - - wsptr[DCTSIZE*0] = dcval; - wsptr[DCTSIZE*1] = dcval; - wsptr[DCTSIZE*2] = dcval; - wsptr[DCTSIZE*3] = dcval; - wsptr[DCTSIZE*4] = dcval; - wsptr[DCTSIZE*5] = dcval; - wsptr[DCTSIZE*6] = dcval; - wsptr[DCTSIZE*7] = dcval; - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - continue; - } - - /* Even part */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - tmp10 = tmp0 + tmp2; /* phase 3 */ - tmp11 = tmp0 - tmp2; - - tmp13 = tmp1 + tmp3; /* phases 5-3 */ - tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */ - - tmp0 = tmp10 + tmp13; /* phase 2 */ - tmp3 = tmp10 - tmp13; - tmp1 = tmp11 + tmp12; - tmp2 = tmp11 - tmp12; - - /* Odd part */ - - tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - - z13 = tmp6 + tmp5; /* phase 6 */ - z10 = tmp6 - tmp5; - z11 = tmp4 + tmp7; - z12 = tmp4 - tmp7; - - tmp7 = z11 + z13; /* phase 5 */ - tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ - - z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ - tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ - tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */ - - tmp6 = tmp12 - tmp7; /* phase 2 */ - tmp5 = tmp11 - tmp6; - tmp4 = tmp10 + tmp5; - - wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7); - wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7); - wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6); - wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6); - wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5); - wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5); - wsptr[DCTSIZE*4] = (int) (tmp3 + tmp4); - wsptr[DCTSIZE*3] = (int) (tmp3 - tmp4); - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - } - - /* Pass 2: process rows from work array, store into output array. */ - /* Note that we must descale the results by a factor of 8 == 2**3, */ - /* and also undo the PASS1_BITS scaling. */ - - wsptr = workspace; - for (ctr = 0; ctr < DCTSIZE; ctr++) { - outptr = output_buf[ctr] + output_col; - /* Rows of zeroes can be exploited in the same way as we did with columns. - * However, the column calculation has created many nonzero AC terms, so - * the simplification applies less often (typically 5% to 10% of the time). - * On machines with very fast multiplication, it's possible that the - * test takes more time than it's worth. In that case this section - * may be commented out. - */ - -#ifndef NO_ZERO_ROW_TEST - if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 && - wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { - /* AC terms all zero */ - JSAMPLE dcval = range_limit[IDESCALE(wsptr[0], PASS1_BITS+3) - & RANGE_MASK]; - - outptr[0] = dcval; - outptr[1] = dcval; - outptr[2] = dcval; - outptr[3] = dcval; - outptr[4] = dcval; - outptr[5] = dcval; - outptr[6] = dcval; - outptr[7] = dcval; - - wsptr += DCTSIZE; /* advance pointer to next row */ - continue; - } -#endif - - /* Even part */ - - tmp10 = ((DCTELEM) wsptr[0] + (DCTELEM) wsptr[4]); - tmp11 = ((DCTELEM) wsptr[0] - (DCTELEM) wsptr[4]); - - tmp13 = ((DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]); - tmp12 = MULTIPLY((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6], FIX_1_414213562) - - tmp13; - - tmp0 = tmp10 + tmp13; - tmp3 = tmp10 - tmp13; - tmp1 = tmp11 + tmp12; - tmp2 = tmp11 - tmp12; - - /* Odd part */ - - z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3]; - z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3]; - z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7]; - z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7]; - - tmp7 = z11 + z13; /* phase 5 */ - tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ - - z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ - tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ - tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */ - - tmp6 = tmp12 - tmp7; /* phase 2 */ - tmp5 = tmp11 - tmp6; - tmp4 = tmp10 + tmp5; - - /* Final output stage: scale down by a factor of 8 and range-limit */ - - outptr[0] = range_limit[IDESCALE(tmp0 + tmp7, PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[IDESCALE(tmp0 - tmp7, PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[IDESCALE(tmp1 + tmp6, PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[IDESCALE(tmp1 - tmp6, PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[IDESCALE(tmp2 + tmp5, PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[IDESCALE(tmp2 - tmp5, PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[IDESCALE(tmp3 + tmp4, PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[IDESCALE(tmp3 - tmp4, PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += DCTSIZE; /* advance pointer to next row */ - } -} - -#endif /* DCT_IFAST_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jidctint.c b/source/modules/juce_graphics/image_formats/jpglib/jidctint.c deleted file mode 100644 index 63ad6d370..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jidctint.c +++ /dev/null @@ -1,389 +0,0 @@ -/* - * jidctint.c - * - * Copyright (C) 1991-1998, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains a slow-but-accurate integer implementation of the - * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine - * must also perform dequantization of the input coefficients. - * - * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT - * on each row (or vice versa, but it's more convenient to emit a row at - * a time). Direct algorithms are also available, but they are much more - * complex and seem not to be any faster when reduced to code. - * - * This implementation is based on an algorithm described in - * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT - * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, - * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. - * The primary algorithm described there uses 11 multiplies and 29 adds. - * We use their alternate method with 12 multiplies and 32 adds. - * The advantage of this method is that no data path contains more than one - * multiplication; this allows a very simple and accurate implementation in - * scaled fixed-point arithmetic, with a minimal number of shifts. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jdct.h" /* Private declarations for DCT subsystem */ - -#ifdef DCT_ISLOW_SUPPORTED - - -/* - * This module is specialized to the case DCTSIZE = 8. - */ - -#if DCTSIZE != 8 - Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ -#endif - - -/* - * The poop on this scaling stuff is as follows: - * - * Each 1-D IDCT step produces outputs which are a factor of sqrt(N) - * larger than the true IDCT outputs. The final outputs are therefore - * a factor of N larger than desired; since N=8 this can be cured by - * a simple right shift at the end of the algorithm. The advantage of - * this arrangement is that we save two multiplications per 1-D IDCT, - * because the y0 and y4 inputs need not be divided by sqrt(N). - * - * We have to do addition and subtraction of the integer inputs, which - * is no problem, and multiplication by fractional constants, which is - * a problem to do in integer arithmetic. We multiply all the constants - * by CONST_SCALE and convert them to integer constants (thus retaining - * CONST_BITS bits of precision in the constants). After doing a - * multiplication we have to divide the product by CONST_SCALE, with proper - * rounding, to produce the correct output. This division can be done - * cheaply as a right shift of CONST_BITS bits. We postpone shifting - * as long as possible so that partial sums can be added together with - * full fractional precision. - * - * The outputs of the first pass are scaled up by PASS1_BITS bits so that - * they are represented to better-than-integral precision. These outputs - * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word - * with the recommended scaling. (To scale up 12-bit sample data further, an - * intermediate INT32 array would be needed.) - * - * To avoid overflow of the 32-bit intermediate results in pass 2, we must - * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis - * shows that the values given below are the most effective. - */ - -#if BITS_IN_JSAMPLE == 8 -#define CONST_BITS 13 -#define PASS1_BITS 2 -#else -#define CONST_BITS 13 -#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ -#endif - -/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus - * causing a lot of useless floating-point operations at run time. - * To get around this we use the following pre-calculated constants. - * If you change CONST_BITS you may want to add appropriate values. - * (With a reasonable C compiler, you can just rely on the FIX() macro...) - */ - -#if CONST_BITS == 13 -#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */ -#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */ -#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */ -#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ -#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ -#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */ -#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */ -#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ -#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */ -#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */ -#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ -#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */ -#else -#define FIX_0_298631336 FIX(0.298631336) -#define FIX_0_390180644 FIX(0.390180644) -#define FIX_0_541196100 FIX(0.541196100) -#define FIX_0_765366865 FIX(0.765366865) -#define FIX_0_899976223 FIX(0.899976223) -#define FIX_1_175875602 FIX(1.175875602) -#define FIX_1_501321110 FIX(1.501321110) -#define FIX_1_847759065 FIX(1.847759065) -#define FIX_1_961570560 FIX(1.961570560) -#define FIX_2_053119869 FIX(2.053119869) -#define FIX_2_562915447 FIX(2.562915447) -#define FIX_3_072711026 FIX(3.072711026) -#endif - - -/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. - * For 8-bit samples with the recommended scaling, all the variable - * and constant values involved are no more than 16 bits wide, so a - * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. - * For 12-bit samples, a full 32-bit multiplication will be needed. - */ - -#if BITS_IN_JSAMPLE == 8 -#define MULTIPLY(var,const) MULTIPLY16C16(var,const) -#else -#define MULTIPLY(var,const) ((var) * (const)) -#endif - - -/* Dequantize a coefficient by multiplying it by the multiplier-table - * entry; produce an int result. In this module, both inputs and result - * are 16 bits or less, so either int or short multiply will work. - */ - -#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval)) - - -/* - * Perform dequantization and inverse DCT on one block of coefficients. - */ - -GLOBAL(void) -jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp1, tmp2, tmp3; - INT32 tmp10, tmp11, tmp12, tmp13; - INT32 z1, z2, z3, z4, z5; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[DCTSIZE2]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ - /* furthermore, we scale the results by 2**PASS1_BITS. */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = DCTSIZE; ctr > 0; ctr--) { - /* Due to quantization, we will usually find that many of the input - * coefficients are zero, especially the AC terms. We can exploit this - * by short-circuiting the IDCT calculation for any column in which all - * the AC terms are zero. In that case each output is equal to the - * DC coefficient (with scale factor as needed). - * With typical images and quantization tables, half or more of the - * column DCT calculations can be simplified this way. - */ - - if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && - inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && - inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && - inptr[DCTSIZE*7] == 0) { - /* AC terms all zero */ - int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; - - wsptr[DCTSIZE*0] = dcval; - wsptr[DCTSIZE*1] = dcval; - wsptr[DCTSIZE*2] = dcval; - wsptr[DCTSIZE*3] = dcval; - wsptr[DCTSIZE*4] = dcval; - wsptr[DCTSIZE*5] = dcval; - wsptr[DCTSIZE*6] = dcval; - wsptr[DCTSIZE*7] = dcval; - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - continue; - } - - /* Even part: reverse the even part of the forward DCT. */ - /* The rotator is sqrt(2)*c(-6). */ - - z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - z1 = MULTIPLY(z2 + z3, FIX_0_541196100); - tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); - tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); - - z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - - tmp0 = (z2 + z3) << CONST_BITS; - tmp1 = (z2 - z3) << CONST_BITS; - - tmp10 = tmp0 + tmp3; - tmp13 = tmp0 - tmp3; - tmp11 = tmp1 + tmp2; - tmp12 = tmp1 - tmp2; - - /* Odd part per figure 8; the matrix is unitary and hence its - * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. - */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - - z1 = tmp0 + tmp3; - z2 = tmp1 + tmp2; - z3 = tmp0 + tmp2; - z4 = tmp1 + tmp3; - z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ - - tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ - tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ - tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ - tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ - z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ - z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ - z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ - z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ - - z3 += z5; - z4 += z5; - - tmp0 += z1 + z3; - tmp1 += z2 + z4; - tmp2 += z2 + z3; - tmp3 += z1 + z4; - - /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ - - wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*7] = (int) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*1] = (int) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*6] = (int) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*5] = (int) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*3] = (int) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS); - wsptr[DCTSIZE*4] = (int) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS); - - inptr++; /* advance pointers to next column */ - quantptr++; - wsptr++; - } - - /* Pass 2: process rows from work array, store into output array. */ - /* Note that we must descale the results by a factor of 8 == 2**3, */ - /* and also undo the PASS1_BITS scaling. */ - - wsptr = workspace; - for (ctr = 0; ctr < DCTSIZE; ctr++) { - outptr = output_buf[ctr] + output_col; - /* Rows of zeroes can be exploited in the same way as we did with columns. - * However, the column calculation has created many nonzero AC terms, so - * the simplification applies less often (typically 5% to 10% of the time). - * On machines with very fast multiplication, it's possible that the - * test takes more time than it's worth. In that case this section - * may be commented out. - */ - -#ifndef NO_ZERO_ROW_TEST - if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 && - wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { - /* AC terms all zero */ - JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) - & RANGE_MASK]; - - outptr[0] = dcval; - outptr[1] = dcval; - outptr[2] = dcval; - outptr[3] = dcval; - outptr[4] = dcval; - outptr[5] = dcval; - outptr[6] = dcval; - outptr[7] = dcval; - - wsptr += DCTSIZE; /* advance pointer to next row */ - continue; - } -#endif - - /* Even part: reverse the even part of the forward DCT. */ - /* The rotator is sqrt(2)*c(-6). */ - - z2 = (INT32) wsptr[2]; - z3 = (INT32) wsptr[6]; - - z1 = MULTIPLY(z2 + z3, FIX_0_541196100); - tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); - tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); - - tmp0 = ((INT32) wsptr[0] + (INT32) wsptr[4]) << CONST_BITS; - tmp1 = ((INT32) wsptr[0] - (INT32) wsptr[4]) << CONST_BITS; - - tmp10 = tmp0 + tmp3; - tmp13 = tmp0 - tmp3; - tmp11 = tmp1 + tmp2; - tmp12 = tmp1 - tmp2; - - /* Odd part per figure 8; the matrix is unitary and hence its - * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. - */ - - tmp0 = (INT32) wsptr[7]; - tmp1 = (INT32) wsptr[5]; - tmp2 = (INT32) wsptr[3]; - tmp3 = (INT32) wsptr[1]; - - z1 = tmp0 + tmp3; - z2 = tmp1 + tmp2; - z3 = tmp0 + tmp2; - z4 = tmp1 + tmp3; - z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ - - tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ - tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ - tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ - tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ - z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ - z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ - z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ - z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ - - z3 += z5; - z4 += z5; - - tmp0 += z1 + z3; - tmp1 += z2 + z4; - tmp2 += z2 + z3; - tmp3 += z1 + z4; - - /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ - - outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp3, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[7] = range_limit[(int) DESCALE(tmp10 - tmp3, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[1] = range_limit[(int) DESCALE(tmp11 + tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[6] = range_limit[(int) DESCALE(tmp11 - tmp2, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[2] = range_limit[(int) DESCALE(tmp12 + tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[5] = range_limit[(int) DESCALE(tmp12 - tmp1, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[3] = range_limit[(int) DESCALE(tmp13 + tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - outptr[4] = range_limit[(int) DESCALE(tmp13 - tmp0, - CONST_BITS+PASS1_BITS+3) - & RANGE_MASK]; - - wsptr += DCTSIZE; /* advance pointer to next row */ - } -} - -#endif /* DCT_ISLOW_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jidctred.c b/source/modules/juce_graphics/image_formats/jpglib/jidctred.c deleted file mode 100644 index 6a923f455..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jidctred.c +++ /dev/null @@ -1,398 +0,0 @@ -/* - * jidctred.c - * - * Copyright (C) 1994-1998, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains inverse-DCT routines that produce reduced-size output: - * either 4x4, 2x2, or 1x1 pixels from an 8x8 DCT block. - * - * The implementation is based on the Loeffler, Ligtenberg and Moschytz (LL&M) - * algorithm used in jidctint.c. We simply replace each 8-to-8 1-D IDCT step - * with an 8-to-4 step that produces the four averages of two adjacent outputs - * (or an 8-to-2 step producing two averages of four outputs, for 2x2 output). - * These steps were derived by computing the corresponding values at the end - * of the normal LL&M code, then simplifying as much as possible. - * - * 1x1 is trivial: just take the DC coefficient divided by 8. - * - * See jidctint.c for additional comments. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jdct.h" /* Private declarations for DCT subsystem */ - -#ifdef IDCT_SCALING_SUPPORTED - - -/* - * This module is specialized to the case DCTSIZE = 8. - */ - -#if DCTSIZE != 8 - Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ -#endif - - -/* Scaling is the same as in jidctint.c. */ - -#if BITS_IN_JSAMPLE == 8 -#define CONST_BITS 13 -#define PASS1_BITS 2 -#else -#define CONST_BITS 13 -#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ -#endif - -/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus - * causing a lot of useless floating-point operations at run time. - * To get around this we use the following pre-calculated constants. - * If you change CONST_BITS you may want to add appropriate values. - * (With a reasonable C compiler, you can just rely on the FIX() macro...) - */ - -#if CONST_BITS == 13 -#define FIX_0_211164243 ((INT32) 1730) /* FIX(0.211164243) */ -#define FIX_0_509795579 ((INT32) 4176) /* FIX(0.509795579) */ -#define FIX_0_601344887 ((INT32) 4926) /* FIX(0.601344887) */ -#define FIX_0_720959822 ((INT32) 5906) /* FIX(0.720959822) */ -#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ -#define FIX_0_850430095 ((INT32) 6967) /* FIX(0.850430095) */ -#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ -#define FIX_1_061594337 ((INT32) 8697) /* FIX(1.061594337) */ -#define FIX_1_272758580 ((INT32) 10426) /* FIX(1.272758580) */ -#define FIX_1_451774981 ((INT32) 11893) /* FIX(1.451774981) */ -#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ -#define FIX_2_172734803 ((INT32) 17799) /* FIX(2.172734803) */ -#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ -#define FIX_3_624509785 ((INT32) 29692) /* FIX(3.624509785) */ -#else -#define FIX_0_211164243 FIX(0.211164243) -#define FIX_0_509795579 FIX(0.509795579) -#define FIX_0_601344887 FIX(0.601344887) -#define FIX_0_720959822 FIX(0.720959822) -#define FIX_0_765366865 FIX(0.765366865) -#define FIX_0_850430095 FIX(0.850430095) -#define FIX_0_899976223 FIX(0.899976223) -#define FIX_1_061594337 FIX(1.061594337) -#define FIX_1_272758580 FIX(1.272758580) -#define FIX_1_451774981 FIX(1.451774981) -#define FIX_1_847759065 FIX(1.847759065) -#define FIX_2_172734803 FIX(2.172734803) -#define FIX_2_562915447 FIX(2.562915447) -#define FIX_3_624509785 FIX(3.624509785) -#endif - - -/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. - * For 8-bit samples with the recommended scaling, all the variable - * and constant values involved are no more than 16 bits wide, so a - * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. - * For 12-bit samples, a full 32-bit multiplication will be needed. - */ - -#if BITS_IN_JSAMPLE == 8 -#define MULTIPLY(var,const) MULTIPLY16C16(var,const) -#else -#define MULTIPLY(var,const) ((var) * (const)) -#endif - - -/* Dequantize a coefficient by multiplying it by the multiplier-table - * entry; produce an int result. In this module, both inputs and result - * are 16 bits or less, so either int or short multiply will work. - */ - -#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval)) - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a reduced-size 4x4 output block. - */ - -GLOBAL(void) -jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp2, tmp10, tmp12; - INT32 z1, z2, z3, z4; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[DCTSIZE*4]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) { - /* Don't bother to process column 4, because second pass won't use it */ - if (ctr == DCTSIZE-4) - continue; - if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && - inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*5] == 0 && - inptr[DCTSIZE*6] == 0 && inptr[DCTSIZE*7] == 0) { - /* AC terms all zero; we need not examine term 4 for 4x4 output */ - int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; - - wsptr[DCTSIZE*0] = dcval; - wsptr[DCTSIZE*1] = dcval; - wsptr[DCTSIZE*2] = dcval; - wsptr[DCTSIZE*3] = dcval; - - continue; - } - - /* Even part */ - - tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp0 <<= (CONST_BITS+1); - - z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); - z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - - tmp2 = MULTIPLY(z2, FIX_1_847759065) + MULTIPLY(z3, - FIX_0_765366865); - - tmp10 = tmp0 + tmp2; - tmp12 = tmp0 - tmp2; - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - z2 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - z4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - - tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */ - + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */ - + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */ - + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */ - - tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */ - + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */ - + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */ - + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */ - - /* Final output stage */ - - wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp2, CONST_BITS-PASS1_BITS+1); - wsptr[DCTSIZE*3] = (int) DESCALE(tmp10 - tmp2, CONST_BITS-PASS1_BITS+1); - wsptr[DCTSIZE*1] = (int) DESCALE(tmp12 + tmp0, CONST_BITS-PASS1_BITS+1); - wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 - tmp0, CONST_BITS-PASS1_BITS+1); - } - - /* Pass 2: process 4 rows from work array, store into output array. */ - - wsptr = workspace; - for (ctr = 0; ctr < 4; ctr++) { - outptr = output_buf[ctr] + output_col; - /* It's not clear whether a zero row test is worthwhile here ... */ - -#ifndef NO_ZERO_ROW_TEST - if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && - wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { - /* AC terms all zero */ - JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) - & RANGE_MASK]; - - outptr[0] = dcval; - outptr[1] = dcval; - outptr[2] = dcval; - outptr[3] = dcval; - - wsptr += DCTSIZE; /* advance pointer to next row */ - continue; - } -#endif - - /* Even part */ - - tmp0 = ((INT32) wsptr[0]) << (CONST_BITS+1); - - tmp2 = MULTIPLY((INT32) wsptr[2], FIX_1_847759065) - + MULTIPLY((INT32) wsptr[6], - FIX_0_765366865); - - tmp10 = tmp0 + tmp2; - tmp12 = tmp0 - tmp2; - - /* Odd part */ - - z1 = (INT32) wsptr[7]; - z2 = (INT32) wsptr[5]; - z3 = (INT32) wsptr[3]; - z4 = (INT32) wsptr[1]; - - tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */ - + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */ - + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */ - + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */ - - tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */ - + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */ - + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */ - + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp2, - CONST_BITS+PASS1_BITS+3+1) - & RANGE_MASK]; - outptr[3] = range_limit[(int) DESCALE(tmp10 - tmp2, - CONST_BITS+PASS1_BITS+3+1) - & RANGE_MASK]; - outptr[1] = range_limit[(int) DESCALE(tmp12 + tmp0, - CONST_BITS+PASS1_BITS+3+1) - & RANGE_MASK]; - outptr[2] = range_limit[(int) DESCALE(tmp12 - tmp0, - CONST_BITS+PASS1_BITS+3+1) - & RANGE_MASK]; - - wsptr += DCTSIZE; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a reduced-size 2x2 output block. - */ - -GLOBAL(void) -jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - INT32 tmp0, tmp10, z1; - JCOEFPTR inptr; - ISLOW_MULT_TYPE * quantptr; - int * wsptr; - JSAMPROW outptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - int ctr; - int workspace[DCTSIZE*2]; /* buffers data between passes */ - SHIFT_TEMPS - - /* Pass 1: process columns from input, store into work array. */ - - inptr = coef_block; - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - wsptr = workspace; - for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) { - /* Don't bother to process columns 2,4,6 */ - if (ctr == DCTSIZE-2 || ctr == DCTSIZE-4 || ctr == DCTSIZE-6) - continue; - if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*3] == 0 && - inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*7] == 0) { - /* AC terms all zero; we need not examine terms 2,4,6 for 2x2 output */ - int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; - - wsptr[DCTSIZE*0] = dcval; - wsptr[DCTSIZE*1] = dcval; - - continue; - } - - /* Even part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp10 = z1 << (CONST_BITS+2); - - /* Odd part */ - - z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - tmp0 = MULTIPLY(z1, - FIX_0_720959822); /* sqrt(2) * (c7-c5+c3-c1) */ - z1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); - tmp0 += MULTIPLY(z1, FIX_0_850430095); /* sqrt(2) * (-c1+c3+c5+c7) */ - z1 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); - tmp0 += MULTIPLY(z1, - FIX_1_272758580); /* sqrt(2) * (-c1+c3-c5-c7) */ - z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); - tmp0 += MULTIPLY(z1, FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */ - - /* Final output stage */ - - wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp0, CONST_BITS-PASS1_BITS+2); - wsptr[DCTSIZE*1] = (int) DESCALE(tmp10 - tmp0, CONST_BITS-PASS1_BITS+2); - } - - /* Pass 2: process 2 rows from work array, store into output array. */ - - wsptr = workspace; - for (ctr = 0; ctr < 2; ctr++) { - outptr = output_buf[ctr] + output_col; - /* It's not clear whether a zero row test is worthwhile here ... */ - -#ifndef NO_ZERO_ROW_TEST - if (wsptr[1] == 0 && wsptr[3] == 0 && wsptr[5] == 0 && wsptr[7] == 0) { - /* AC terms all zero */ - JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) - & RANGE_MASK]; - - outptr[0] = dcval; - outptr[1] = dcval; - - wsptr += DCTSIZE; /* advance pointer to next row */ - continue; - } -#endif - - /* Even part */ - - tmp10 = ((INT32) wsptr[0]) << (CONST_BITS+2); - - /* Odd part */ - - tmp0 = MULTIPLY((INT32) wsptr[7], - FIX_0_720959822) /* sqrt(2) * (c7-c5+c3-c1) */ - + MULTIPLY((INT32) wsptr[5], FIX_0_850430095) /* sqrt(2) * (-c1+c3+c5+c7) */ - + MULTIPLY((INT32) wsptr[3], - FIX_1_272758580) /* sqrt(2) * (-c1+c3-c5-c7) */ - + MULTIPLY((INT32) wsptr[1], FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */ - - /* Final output stage */ - - outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp0, - CONST_BITS+PASS1_BITS+3+2) - & RANGE_MASK]; - outptr[1] = range_limit[(int) DESCALE(tmp10 - tmp0, - CONST_BITS+PASS1_BITS+3+2) - & RANGE_MASK]; - - wsptr += DCTSIZE; /* advance pointer to next row */ - } -} - - -/* - * Perform dequantization and inverse DCT on one block of coefficients, - * producing a reduced-size 1x1 output block. - */ - -GLOBAL(void) -jpeg_idct_1x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col) -{ - int dcval; - ISLOW_MULT_TYPE * quantptr; - JSAMPLE *range_limit = IDCT_range_limit(cinfo); - SHIFT_TEMPS - - /* We hardly need an inverse DCT routine for this: just take the - * average pixel value, which is one-eighth of the DC coefficient. - */ - quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; - dcval = DEQUANTIZE(coef_block[0], quantptr[0]); - dcval = (int) DESCALE((INT32) dcval, 3); - - output_buf[0][output_col] = range_limit[dcval & RANGE_MASK]; -} - -#endif /* IDCT_SCALING_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jinclude.h b/source/modules/juce_graphics/image_formats/jpglib/jinclude.h deleted file mode 100644 index bccfd5442..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jinclude.h +++ /dev/null @@ -1,197 +0,0 @@ -/* - * jinclude.h - * - * Copyright (C) 1991-1994, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file exists to provide a single place to fix any problems with - * including the wrong system include files. (Common problems are taken - * care of by the standard jconfig symbols, but on really weird systems - * you may have to edit this file.) - * - * NOTE: this file is NOT intended to be included by applications using the - * JPEG library. Most applications need only include jpeglib.h. - */ - - -/* Include auto-config file to find out which system include files we need. */ - -#ifndef __jinclude_h__ -#define __jinclude_h__ - -#include "jconfig.h" /* auto configuration options */ -#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ - -/* - * We need the NULL macro and size_t typedef. - * On an ANSI-conforming system it is sufficient to include . - * Otherwise, we get them from or ; we may have to - * pull in as well. - * Note that the core JPEG library does not require ; - * only the default error handler and data source/destination modules do. - * But we must pull it in because of the references to FILE in jpeglib.h. - * You can remove those references if you want to compile without . - */ - -#ifdef HAVE_STDDEF_H -#include -#endif - -#ifdef HAVE_STDLIB_H -#include -#endif - -#ifdef NEED_SYS_TYPES_H -#include -#endif - -#include - -/* - * We need memory copying and zeroing functions, plus strncpy(). - * ANSI and System V implementations declare these in . - * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). - * Some systems may declare memset and memcpy in . - * - * NOTE: we assume the size parameters to these functions are of type size_t. - * Change the casts in these macros if not! - */ - -#ifdef NEED_BSD_STRINGS - -#include -#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) -#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) - -#else /* not BSD, assume ANSI/SysV string lib */ - -#include -#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) -#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) - -#endif - -/* - * In ANSI C, and indeed any rational implementation, size_t is also the - * type returned by sizeof(). However, it seems there are some irrational - * implementations out there, in which sizeof() returns an int even though - * size_t is defined as long or unsigned long. To ensure consistent results - * we always use this SIZEOF() macro in place of using sizeof() directly. - */ - -#define SIZEOF(object) ((size_t) sizeof(object)) - -/* - * The modules that use fread() and fwrite() always invoke them through - * these macros. On some systems you may need to twiddle the argument casts. - * CAUTION: argument order is different from underlying functions! - */ - -#define JFREAD(file,buf,sizeofbuf) \ - ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) -#define JFWRITE(file,buf,sizeofbuf) \ - ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) - - - -typedef enum { /* JPEG marker codes */ - M_SOF0 = 0xc0, - M_SOF1 = 0xc1, - M_SOF2 = 0xc2, - M_SOF3 = 0xc3, - - M_SOF5 = 0xc5, - M_SOF6 = 0xc6, - M_SOF7 = 0xc7, - - M_JPG = 0xc8, - M_SOF9 = 0xc9, - M_SOF10 = 0xca, - M_SOF11 = 0xcb, - - M_SOF13 = 0xcd, - M_SOF14 = 0xce, - M_SOF15 = 0xcf, - - M_DHT = 0xc4, - - M_DAC = 0xcc, - - M_RST0 = 0xd0, - M_RST1 = 0xd1, - M_RST2 = 0xd2, - M_RST3 = 0xd3, - M_RST4 = 0xd4, - M_RST5 = 0xd5, - M_RST6 = 0xd6, - M_RST7 = 0xd7, - - M_SOI = 0xd8, - M_EOI = 0xd9, - M_SOS = 0xda, - M_DQT = 0xdb, - M_DNL = 0xdc, - M_DRI = 0xdd, - M_DHP = 0xde, - M_EXP = 0xdf, - - M_APP0 = 0xe0, - M_APP1 = 0xe1, - M_APP2 = 0xe2, - M_APP3 = 0xe3, - M_APP4 = 0xe4, - M_APP5 = 0xe5, - M_APP6 = 0xe6, - M_APP7 = 0xe7, - M_APP8 = 0xe8, - M_APP9 = 0xe9, - M_APP10 = 0xea, - M_APP11 = 0xeb, - M_APP12 = 0xec, - M_APP13 = 0xed, - M_APP14 = 0xee, - M_APP15 = 0xef, - - M_JPG0 = 0xf0, - M_JPG13 = 0xfd, - M_COM = 0xfe, - - M_TEM = 0x01, - - M_ERROR = 0x100 -} JPEG_MARKER; - - -/* - * Figure F.12: extend sign bit. - * On some machines, a shift and add will be faster than a table lookup. - */ - -#ifdef AVOID_TABLES - -#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x)) - -#else - -#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) - -static const int extend_test[16] = /* entry n is 2**(n-1) */ - { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, - 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; - -#define SHIFTED_BITS_PLUS_ONE(n) (int) (((unsigned int) -1) << n) + 1 - -static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ - { 0, - SHIFTED_BITS_PLUS_ONE (1), SHIFTED_BITS_PLUS_ONE (2), SHIFTED_BITS_PLUS_ONE (3), SHIFTED_BITS_PLUS_ONE (4), - SHIFTED_BITS_PLUS_ONE (5), SHIFTED_BITS_PLUS_ONE (6), SHIFTED_BITS_PLUS_ONE (7), SHIFTED_BITS_PLUS_ONE (8), - SHIFTED_BITS_PLUS_ONE (9), SHIFTED_BITS_PLUS_ONE (10), SHIFTED_BITS_PLUS_ONE (11), SHIFTED_BITS_PLUS_ONE (12), - SHIFTED_BITS_PLUS_ONE (13), SHIFTED_BITS_PLUS_ONE (14), SHIFTED_BITS_PLUS_ONE (15) }; - -#undef SHIFTED_BITS_PLUS_ONE - -#endif /* AVOID_TABLES */ - - -#endif diff --git a/source/modules/juce_graphics/image_formats/jpglib/jmemmgr.c b/source/modules/juce_graphics/image_formats/jpglib/jmemmgr.c deleted file mode 100644 index d7dca35d2..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jmemmgr.c +++ /dev/null @@ -1,1118 +0,0 @@ -/* - * jmemmgr.c - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains the JPEG system-independent memory management - * routines. This code is usable across a wide variety of machines; most - * of the system dependencies have been isolated in a separate file. - * The major functions provided here are: - * * pool-based allocation and freeing of memory; - * * policy decisions about how to divide available memory among the - * virtual arrays; - * * control logic for swapping virtual arrays between main memory and - * backing storage. - * The separate system-dependent file provides the actual backing-storage - * access code, and it contains the policy decision about how much total - * main memory to use. - * This file is system-dependent in the sense that some of its functions - * are unnecessary in some systems. For example, if there is enough virtual - * memory so that backing storage will never be used, much of the virtual - * array control logic could be removed. (Of course, if you have that much - * memory then you shouldn't care about a little bit of unused code...) - */ - -#define JPEG_INTERNALS -#define AM_MEMORY_MANAGER /* we define jvirt_Xarray_control structs */ -#include "jinclude.h" -#include "jpeglib.h" -#include "jmemsys.h" /* import the system-dependent declarations */ - -#ifndef NO_GETENV -#ifndef HAVE_STDLIB_H /* should declare getenv() */ -extern char * getenv JPP((const char * name)); -#endif -#endif - - -/* - * Some important notes: - * The allocation routines provided here must never return NULL. - * They should exit to error_exit if unsuccessful. - * - * It's not a good idea to try to merge the sarray and barray routines, - * even though they are textually almost the same, because samples are - * usually stored as bytes while coefficients are shorts or ints. Thus, - * in machines where byte pointers have a different representation from - * word pointers, the resulting machine code could not be the same. - */ - - -/* - * Many machines require storage alignment: longs must start on 4-byte - * boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc() - * always returns pointers that are multiples of the worst-case alignment - * requirement, and we had better do so too. - * There isn't any really portable way to determine the worst-case alignment - * requirement. This module assumes that the alignment requirement is - * multiples of sizeof(ALIGN_TYPE). - * By default, we define ALIGN_TYPE as double. This is necessary on some - * workstations (where doubles really do need 8-byte alignment) and will work - * fine on nearly everything. If your machine has lesser alignment needs, - * you can save a few bytes by making ALIGN_TYPE smaller. - * The only place I know of where this will NOT work is certain Macintosh - * 680x0 compilers that define double as a 10-byte IEEE extended float. - * Doing 10-byte alignment is counterproductive because longwords won't be - * aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have - * such a compiler. - */ - -#ifndef ALIGN_TYPE /* so can override from jconfig.h */ -#define ALIGN_TYPE double -#endif - - -/* - * We allocate objects from "pools", where each pool is gotten with a single - * request to jpeg_get_small() or jpeg_get_large(). There is no per-object - * overhead within a pool, except for alignment padding. Each pool has a - * header with a link to the next pool of the same class. - * Small and large pool headers are identical except that the latter's - * link pointer must be FAR on 80x86 machines. - * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE - * field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple - * of the alignment requirement of ALIGN_TYPE. - */ - -typedef union small_pool_struct * small_pool_ptr; - -typedef union small_pool_struct { - struct { - small_pool_ptr next; /* next in list of pools */ - size_t bytes_used; /* how many bytes already used within pool */ - size_t bytes_left; /* bytes still available in this pool */ - } hdr; - ALIGN_TYPE dummy; /* included in union to ensure alignment */ -} small_pool_hdr; - -typedef union large_pool_struct FAR * large_pool_ptr; - -typedef union large_pool_struct { - struct { - large_pool_ptr next; /* next in list of pools */ - size_t bytes_used; /* how many bytes already used within pool */ - size_t bytes_left; /* bytes still available in this pool */ - } hdr; - ALIGN_TYPE dummy; /* included in union to ensure alignment */ -} large_pool_hdr; - - -/* - * Here is the full definition of a memory manager object. - */ - -typedef struct { - struct jpeg_memory_mgr pub; /* public fields */ - - /* Each pool identifier (lifetime class) names a linked list of pools. */ - small_pool_ptr small_list[JPOOL_NUMPOOLS]; - large_pool_ptr large_list[JPOOL_NUMPOOLS]; - - /* Since we only have one lifetime class of virtual arrays, only one - * linked list is necessary (for each datatype). Note that the virtual - * array control blocks being linked together are actually stored somewhere - * in the small-pool list. - */ - jvirt_sarray_ptr virt_sarray_list; - jvirt_barray_ptr virt_barray_list; - - /* This counts total space obtained from jpeg_get_small/large */ - long total_space_allocated; - - /* alloc_sarray and alloc_barray set this value for use by virtual - * array routines. - */ - JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */ -} my_memory_mgr; - -typedef my_memory_mgr * my_mem_ptr; - - -/* - * The control blocks for virtual arrays. - * Note that these blocks are allocated in the "small" pool area. - * System-dependent info for the associated backing store (if any) is hidden - * inside the backing_store_info struct. - */ - -struct jvirt_sarray_control { - JSAMPARRAY mem_buffer; /* => the in-memory buffer */ - JDIMENSION rows_in_array; /* total virtual array height */ - JDIMENSION samplesperrow; /* width of array (and of memory buffer) */ - JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */ - JDIMENSION rows_in_mem; /* height of memory buffer */ - JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ - JDIMENSION cur_start_row; /* first logical row # in the buffer */ - JDIMENSION first_undef_row; /* row # of first uninitialized row */ - boolean pre_zero; /* pre-zero mode requested? */ - boolean dirty; /* do current buffer contents need written? */ - boolean b_s_open; /* is backing-store data valid? */ - jvirt_sarray_ptr next; /* link to next virtual sarray control block */ - backing_store_info b_s_info; /* System-dependent control info */ -}; - -struct jvirt_barray_control { - JBLOCKARRAY mem_buffer; /* => the in-memory buffer */ - JDIMENSION rows_in_array; /* total virtual array height */ - JDIMENSION blocksperrow; /* width of array (and of memory buffer) */ - JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */ - JDIMENSION rows_in_mem; /* height of memory buffer */ - JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ - JDIMENSION cur_start_row; /* first logical row # in the buffer */ - JDIMENSION first_undef_row; /* row # of first uninitialized row */ - boolean pre_zero; /* pre-zero mode requested? */ - boolean dirty; /* do current buffer contents need written? */ - boolean b_s_open; /* is backing-store data valid? */ - jvirt_barray_ptr next; /* link to next virtual barray control block */ - backing_store_info b_s_info; /* System-dependent control info */ -}; - - -#ifdef MEM_STATS /* optional extra stuff for statistics */ - -LOCAL(void) -print_mem_stats (j_common_ptr cinfo, int pool_id) -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - small_pool_ptr shdr_ptr; - large_pool_ptr lhdr_ptr; - - /* Since this is only a debugging stub, we can cheat a little by using - * fprintf directly rather than going through the trace message code. - * This is helpful because message parm array can't handle longs. - */ - fprintf(stderr, "Freeing pool %d, total space = %ld\n", - pool_id, mem->total_space_allocated); - - for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL; - lhdr_ptr = lhdr_ptr->hdr.next) { - fprintf(stderr, " Large chunk used %ld\n", - (long) lhdr_ptr->hdr.bytes_used); - } - - for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL; - shdr_ptr = shdr_ptr->hdr.next) { - fprintf(stderr, " Small chunk used %ld free %ld\n", - (long) shdr_ptr->hdr.bytes_used, - (long) shdr_ptr->hdr.bytes_left); - } -} - -#endif /* MEM_STATS */ - - -LOCAL(void) -out_of_memory (j_common_ptr cinfo, int which) -/* Report an out-of-memory error and stop execution */ -/* If we compiled MEM_STATS support, report alloc requests before dying */ -{ -#ifdef MEM_STATS - cinfo->err->trace_level = 2; /* force self_destruct to report stats */ -#endif - ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which); -} - - -/* - * Allocation of "small" objects. - * - * For these, we use pooled storage. When a new pool must be created, - * we try to get enough space for the current request plus a "slop" factor, - * where the slop will be the amount of leftover space in the new pool. - * The speed vs. space tradeoff is largely determined by the slop values. - * A different slop value is provided for each pool class (lifetime), - * and we also distinguish the first pool of a class from later ones. - * NOTE: the values given work fairly well on both 16- and 32-bit-int - * machines, but may be too small if longs are 64 bits or more. - */ - -static const size_t first_pool_slop[JPOOL_NUMPOOLS] = -{ - 1600, /* first PERMANENT pool */ - 16000 /* first IMAGE pool */ -}; - -static const size_t extra_pool_slop[JPOOL_NUMPOOLS] = -{ - 0, /* additional PERMANENT pools */ - 5000 /* additional IMAGE pools */ -}; - -#define MIN_SLOP 50 /* greater than 0 to avoid futile looping */ - - -METHODDEF(void *) -alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject) -/* Allocate a "small" object */ -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - small_pool_ptr hdr_ptr, prev_hdr_ptr; - char * data_ptr; - size_t odd_bytes, min_request, slop; - - /* Check for unsatisfiable request (do now to ensure no overflow below) */ - if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr))) - out_of_memory(cinfo, 1); /* request exceeds malloc's ability */ - - /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ - odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); - if (odd_bytes > 0) - sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; - - /* See if space is available in any existing pool */ - if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) - ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ - prev_hdr_ptr = NULL; - hdr_ptr = mem->small_list[pool_id]; - while (hdr_ptr != NULL) { - if (hdr_ptr->hdr.bytes_left >= sizeofobject) - break; /* found pool with enough space */ - prev_hdr_ptr = hdr_ptr; - hdr_ptr = hdr_ptr->hdr.next; - } - - /* Time to make a new pool? */ - if (hdr_ptr == NULL) { - /* min_request is what we need now, slop is what will be leftover */ - min_request = sizeofobject + SIZEOF(small_pool_hdr); - if (prev_hdr_ptr == NULL) /* first pool in class? */ - slop = first_pool_slop[pool_id]; - else - slop = extra_pool_slop[pool_id]; - /* Don't ask for more than MAX_ALLOC_CHUNK */ - if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request)) - slop = (size_t) (MAX_ALLOC_CHUNK-min_request); - /* Try to get space, if fail reduce slop and try again */ - for (;;) { - hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop); - if (hdr_ptr != NULL) - break; - slop /= 2; - if (slop < MIN_SLOP) /* give up when it gets real small */ - out_of_memory(cinfo, 2); /* jpeg_get_small failed */ - } - mem->total_space_allocated += min_request + slop; - /* Success, initialize the new pool header and add to end of list */ - hdr_ptr->hdr.next = NULL; - hdr_ptr->hdr.bytes_used = 0; - hdr_ptr->hdr.bytes_left = sizeofobject + slop; - if (prev_hdr_ptr == NULL) /* first pool in class? */ - mem->small_list[pool_id] = hdr_ptr; - else - prev_hdr_ptr->hdr.next = hdr_ptr; - } - - /* OK, allocate the object from the current pool */ - data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */ - data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */ - hdr_ptr->hdr.bytes_used += sizeofobject; - hdr_ptr->hdr.bytes_left -= sizeofobject; - - return (void *) data_ptr; -} - - -/* - * Allocation of "large" objects. - * - * The external semantics of these are the same as "small" objects, - * except that FAR pointers are used on 80x86. However the pool - * management heuristics are quite different. We assume that each - * request is large enough that it may as well be passed directly to - * jpeg_get_large; the pool management just links everything together - * so that we can free it all on demand. - * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY - * structures. The routines that create these structures (see below) - * deliberately bunch rows together to ensure a large request size. - */ - -METHODDEF(void FAR *) -alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject) -/* Allocate a "large" object */ -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - large_pool_ptr hdr_ptr; - size_t odd_bytes; - - /* Check for unsatisfiable request (do now to ensure no overflow below) */ - if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr))) - out_of_memory(cinfo, 3); /* request exceeds malloc's ability */ - - /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ - odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); - if (odd_bytes > 0) - sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; - - /* Always make a new pool */ - if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) - ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ - - hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject + - SIZEOF(large_pool_hdr)); - if (hdr_ptr == NULL) - out_of_memory(cinfo, 4); /* jpeg_get_large failed */ - mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr); - - /* Success, initialize the new pool header and add to list */ - hdr_ptr->hdr.next = mem->large_list[pool_id]; - /* We maintain space counts in each pool header for statistical purposes, - * even though they are not needed for allocation. - */ - hdr_ptr->hdr.bytes_used = sizeofobject; - hdr_ptr->hdr.bytes_left = 0; - mem->large_list[pool_id] = hdr_ptr; - - return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */ -} - - -/* - * Creation of 2-D sample arrays. - * The pointers are in near heap, the samples themselves in FAR heap. - * - * To minimize allocation overhead and to allow I/O of large contiguous - * blocks, we allocate the sample rows in groups of as many rows as possible - * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request. - * NB: the virtual array control routines, later in this file, know about - * this chunking of rows. The rowsperchunk value is left in the mem manager - * object so that it can be saved away if this sarray is the workspace for - * a virtual array. - */ - -METHODDEF(JSAMPARRAY) -alloc_sarray (j_common_ptr cinfo, int pool_id, - JDIMENSION samplesperrow, JDIMENSION numrows) -/* Allocate a 2-D sample array */ -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - JSAMPARRAY result; - JSAMPROW workspace; - JDIMENSION rowsperchunk, currow, i; - long ltemp; - - /* Calculate max # of rows allowed in one allocation chunk */ - ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / - ((long) samplesperrow * SIZEOF(JSAMPLE)); - if (ltemp <= 0) - ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); - if (ltemp < (long) numrows) - rowsperchunk = (JDIMENSION) ltemp; - else - rowsperchunk = numrows; - mem->last_rowsperchunk = rowsperchunk; - - /* Get space for row pointers (small object) */ - result = (JSAMPARRAY) alloc_small(cinfo, pool_id, - (size_t) (numrows * SIZEOF(JSAMPROW))); - - /* Get the rows themselves (large objects) */ - currow = 0; - while (currow < numrows) { - rowsperchunk = MIN(rowsperchunk, numrows - currow); - workspace = (JSAMPROW) alloc_large(cinfo, pool_id, - (size_t) ((size_t) rowsperchunk * (size_t) samplesperrow - * SIZEOF(JSAMPLE))); - for (i = rowsperchunk; i > 0; i--) { - result[currow++] = workspace; - workspace += samplesperrow; - } - } - - return result; -} - - -/* - * Creation of 2-D coefficient-block arrays. - * This is essentially the same as the code for sample arrays, above. - */ - -METHODDEF(JBLOCKARRAY) -alloc_barray (j_common_ptr cinfo, int pool_id, - JDIMENSION blocksperrow, JDIMENSION numrows) -/* Allocate a 2-D coefficient-block array */ -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - JBLOCKARRAY result; - JBLOCKROW workspace; - JDIMENSION rowsperchunk, currow, i; - long ltemp; - - /* Calculate max # of rows allowed in one allocation chunk */ - ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / - ((long) blocksperrow * SIZEOF(JBLOCK)); - if (ltemp <= 0) - ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); - if (ltemp < (long) numrows) - rowsperchunk = (JDIMENSION) ltemp; - else - rowsperchunk = numrows; - mem->last_rowsperchunk = rowsperchunk; - - /* Get space for row pointers (small object) */ - result = (JBLOCKARRAY) alloc_small(cinfo, pool_id, - (size_t) (numrows * SIZEOF(JBLOCKROW))); - - /* Get the rows themselves (large objects) */ - currow = 0; - while (currow < numrows) { - rowsperchunk = MIN(rowsperchunk, numrows - currow); - workspace = (JBLOCKROW) alloc_large(cinfo, pool_id, - (size_t) ((size_t) rowsperchunk * (size_t) blocksperrow - * SIZEOF(JBLOCK))); - for (i = rowsperchunk; i > 0; i--) { - result[currow++] = workspace; - workspace += blocksperrow; - } - } - - return result; -} - - -/* - * About virtual array management: - * - * The above "normal" array routines are only used to allocate strip buffers - * (as wide as the image, but just a few rows high). Full-image-sized buffers - * are handled as "virtual" arrays. The array is still accessed a strip at a - * time, but the memory manager must save the whole array for repeated - * accesses. The intended implementation is that there is a strip buffer in - * memory (as high as is possible given the desired memory limit), plus a - * backing file that holds the rest of the array. - * - * The request_virt_array routines are told the total size of the image and - * the maximum number of rows that will be accessed at once. The in-memory - * buffer must be at least as large as the maxaccess value. - * - * The request routines create control blocks but not the in-memory buffers. - * That is postponed until realize_virt_arrays is called. At that time the - * total amount of space needed is known (approximately, anyway), so free - * memory can be divided up fairly. - * - * The access_virt_array routines are responsible for making a specific strip - * area accessible (after reading or writing the backing file, if necessary). - * Note that the access routines are told whether the caller intends to modify - * the accessed strip; during a read-only pass this saves having to rewrite - * data to disk. The access routines are also responsible for pre-zeroing - * any newly accessed rows, if pre-zeroing was requested. - * - * In current usage, the access requests are usually for nonoverlapping - * strips; that is, successive access start_row numbers differ by exactly - * num_rows = maxaccess. This means we can get good performance with simple - * buffer dump/reload logic, by making the in-memory buffer be a multiple - * of the access height; then there will never be accesses across bufferload - * boundaries. The code will still work with overlapping access requests, - * but it doesn't handle bufferload overlaps very efficiently. - */ - - -METHODDEF(jvirt_sarray_ptr) -request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero, - JDIMENSION samplesperrow, JDIMENSION numrows, - JDIMENSION maxaccess) -/* Request a virtual 2-D sample array */ -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - jvirt_sarray_ptr result; - - /* Only IMAGE-lifetime virtual arrays are currently supported */ - if (pool_id != JPOOL_IMAGE) - ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ - - /* get control block */ - result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id, - SIZEOF(struct jvirt_sarray_control)); - - result->mem_buffer = NULL; /* marks array not yet realized */ - result->rows_in_array = numrows; - result->samplesperrow = samplesperrow; - result->maxaccess = maxaccess; - result->pre_zero = pre_zero; - result->b_s_open = FALSE; /* no associated backing-store object */ - result->next = mem->virt_sarray_list; /* add to list of virtual arrays */ - mem->virt_sarray_list = result; - - return result; -} - - -METHODDEF(jvirt_barray_ptr) -request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero, - JDIMENSION blocksperrow, JDIMENSION numrows, - JDIMENSION maxaccess) -/* Request a virtual 2-D coefficient-block array */ -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - jvirt_barray_ptr result; - - /* Only IMAGE-lifetime virtual arrays are currently supported */ - if (pool_id != JPOOL_IMAGE) - ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ - - /* get control block */ - result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id, - SIZEOF(struct jvirt_barray_control)); - - result->mem_buffer = NULL; /* marks array not yet realized */ - result->rows_in_array = numrows; - result->blocksperrow = blocksperrow; - result->maxaccess = maxaccess; - result->pre_zero = pre_zero; - result->b_s_open = FALSE; /* no associated backing-store object */ - result->next = mem->virt_barray_list; /* add to list of virtual arrays */ - mem->virt_barray_list = result; - - return result; -} - - -METHODDEF(void) -realize_virt_arrays (j_common_ptr cinfo) -/* Allocate the in-memory buffers for any unrealized virtual arrays */ -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - long space_per_minheight, maximum_space, avail_mem; - long minheights, max_minheights; - jvirt_sarray_ptr sptr; - jvirt_barray_ptr bptr; - - /* Compute the minimum space needed (maxaccess rows in each buffer) - * and the maximum space needed (full image height in each buffer). - * These may be of use to the system-dependent jpeg_mem_available routine. - */ - space_per_minheight = 0; - maximum_space = 0; - for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { - if (sptr->mem_buffer == NULL) { /* if not realized yet */ - space_per_minheight += (long) sptr->maxaccess * - (long) sptr->samplesperrow * SIZEOF(JSAMPLE); - maximum_space += (long) sptr->rows_in_array * - (long) sptr->samplesperrow * SIZEOF(JSAMPLE); - } - } - for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { - if (bptr->mem_buffer == NULL) { /* if not realized yet */ - space_per_minheight += (long) bptr->maxaccess * - (long) bptr->blocksperrow * SIZEOF(JBLOCK); - maximum_space += (long) bptr->rows_in_array * - (long) bptr->blocksperrow * SIZEOF(JBLOCK); - } - } - - if (space_per_minheight <= 0) - return; /* no unrealized arrays, no work */ - - /* Determine amount of memory to actually use; this is system-dependent. */ - avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space, - mem->total_space_allocated); - - /* If the maximum space needed is available, make all the buffers full - * height; otherwise parcel it out with the same number of minheights - * in each buffer. - */ - if (avail_mem >= maximum_space) - max_minheights = 1000000000L; - else { - max_minheights = avail_mem / space_per_minheight; - /* If there doesn't seem to be enough space, try to get the minimum - * anyway. This allows a "stub" implementation of jpeg_mem_available(). - */ - if (max_minheights <= 0) - max_minheights = 1; - } - - /* Allocate the in-memory buffers and initialize backing store as needed. */ - - for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { - if (sptr->mem_buffer == NULL) { /* if not realized yet */ - minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L; - if (minheights <= max_minheights) { - /* This buffer fits in memory */ - sptr->rows_in_mem = sptr->rows_in_array; - } else { - /* It doesn't fit in memory, create backing store. */ - sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess); - jpeg_open_backing_store(cinfo, & sptr->b_s_info, - (long) sptr->rows_in_array * - (long) sptr->samplesperrow * - (long) SIZEOF(JSAMPLE)); - sptr->b_s_open = TRUE; - } - sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE, - sptr->samplesperrow, sptr->rows_in_mem); - sptr->rowsperchunk = mem->last_rowsperchunk; - sptr->cur_start_row = 0; - sptr->first_undef_row = 0; - sptr->dirty = FALSE; - } - } - - for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { - if (bptr->mem_buffer == NULL) { /* if not realized yet */ - minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L; - if (minheights <= max_minheights) { - /* This buffer fits in memory */ - bptr->rows_in_mem = bptr->rows_in_array; - } else { - /* It doesn't fit in memory, create backing store. */ - bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess); - jpeg_open_backing_store(cinfo, & bptr->b_s_info, - (long) bptr->rows_in_array * - (long) bptr->blocksperrow * - (long) SIZEOF(JBLOCK)); - bptr->b_s_open = TRUE; - } - bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE, - bptr->blocksperrow, bptr->rows_in_mem); - bptr->rowsperchunk = mem->last_rowsperchunk; - bptr->cur_start_row = 0; - bptr->first_undef_row = 0; - bptr->dirty = FALSE; - } - } -} - - -LOCAL(void) -do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing) -/* Do backing store read or write of a virtual sample array */ -{ - long bytesperrow, file_offset, byte_count, rows, thisrow, i; - - bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE); - file_offset = ptr->cur_start_row * bytesperrow; - /* Loop to read or write each allocation chunk in mem_buffer */ - for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { - /* One chunk, but check for short chunk at end of buffer */ - rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); - /* Transfer no more than is currently defined */ - thisrow = (long) ptr->cur_start_row + i; - rows = MIN(rows, (long) ptr->first_undef_row - thisrow); - /* Transfer no more than fits in file */ - rows = MIN(rows, (long) ptr->rows_in_array - thisrow); - if (rows <= 0) /* this chunk might be past end of file! */ - break; - byte_count = rows * bytesperrow; - if (writing) - (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, - (void FAR *) ptr->mem_buffer[i], - file_offset, byte_count); - else - (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, - (void FAR *) ptr->mem_buffer[i], - file_offset, byte_count); - file_offset += byte_count; - } -} - - -LOCAL(void) -do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing) -/* Do backing store read or write of a virtual coefficient-block array */ -{ - long bytesperrow, file_offset, byte_count, rows, thisrow, i; - - bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK); - file_offset = ptr->cur_start_row * bytesperrow; - /* Loop to read or write each allocation chunk in mem_buffer */ - for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { - /* One chunk, but check for short chunk at end of buffer */ - rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); - /* Transfer no more than is currently defined */ - thisrow = (long) ptr->cur_start_row + i; - rows = MIN(rows, (long) ptr->first_undef_row - thisrow); - /* Transfer no more than fits in file */ - rows = MIN(rows, (long) ptr->rows_in_array - thisrow); - if (rows <= 0) /* this chunk might be past end of file! */ - break; - byte_count = rows * bytesperrow; - if (writing) - (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, - (void FAR *) ptr->mem_buffer[i], - file_offset, byte_count); - else - (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, - (void FAR *) ptr->mem_buffer[i], - file_offset, byte_count); - file_offset += byte_count; - } -} - - -METHODDEF(JSAMPARRAY) -access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr, - JDIMENSION start_row, JDIMENSION num_rows, - boolean writable) -/* Access the part of a virtual sample array starting at start_row */ -/* and extending for num_rows rows. writable is true if */ -/* caller intends to modify the accessed area. */ -{ - JDIMENSION end_row = start_row + num_rows; - JDIMENSION undef_row; - - /* debugging check */ - if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || - ptr->mem_buffer == NULL) - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - - /* Make the desired part of the virtual array accessible */ - if (start_row < ptr->cur_start_row || - end_row > ptr->cur_start_row+ptr->rows_in_mem) { - if (! ptr->b_s_open) - ERREXIT(cinfo, JERR_VIRTUAL_BUG); - /* Flush old buffer contents if necessary */ - if (ptr->dirty) { - do_sarray_io(cinfo, ptr, TRUE); - ptr->dirty = FALSE; - } - /* Decide what part of virtual array to access. - * Algorithm: if target address > current window, assume forward scan, - * load starting at target address. If target address < current window, - * assume backward scan, load so that target area is top of window. - * Note that when switching from forward write to forward read, will have - * start_row = 0, so the limiting case applies and we load from 0 anyway. - */ - if (start_row > ptr->cur_start_row) { - ptr->cur_start_row = start_row; - } else { - /* use long arithmetic here to avoid overflow & unsigned problems */ - long ltemp; - - ltemp = (long) end_row - (long) ptr->rows_in_mem; - if (ltemp < 0) - ltemp = 0; /* don't fall off front end of file */ - ptr->cur_start_row = (JDIMENSION) ltemp; - } - /* Read in the selected part of the array. - * During the initial write pass, we will do no actual read - * because the selected part is all undefined. - */ - do_sarray_io(cinfo, ptr, FALSE); - } - /* Ensure the accessed part of the array is defined; prezero if needed. - * To improve locality of access, we only prezero the part of the array - * that the caller is about to access, not the entire in-memory array. - */ - if (ptr->first_undef_row < end_row) { - if (ptr->first_undef_row < start_row) { - if (writable) /* writer skipped over a section of array */ - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - undef_row = start_row; /* but reader is allowed to read ahead */ - } else { - undef_row = ptr->first_undef_row; - } - if (writable) - ptr->first_undef_row = end_row; - if (ptr->pre_zero) { - size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE); - undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ - end_row -= ptr->cur_start_row; - while (undef_row < end_row) { - jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); - undef_row++; - } - } else { - if (! writable) /* reader looking at undefined data */ - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - } - } - /* Flag the buffer dirty if caller will write in it */ - if (writable) - ptr->dirty = TRUE; - /* Return address of proper part of the buffer */ - return ptr->mem_buffer + (start_row - ptr->cur_start_row); -} - - -METHODDEF(JBLOCKARRAY) -access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr, - JDIMENSION start_row, JDIMENSION num_rows, - boolean writable) -/* Access the part of a virtual block array starting at start_row */ -/* and extending for num_rows rows. writable is true if */ -/* caller intends to modify the accessed area. */ -{ - JDIMENSION end_row = start_row + num_rows; - JDIMENSION undef_row; - - /* debugging check */ - if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || - ptr->mem_buffer == NULL) - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - - /* Make the desired part of the virtual array accessible */ - if (start_row < ptr->cur_start_row || - end_row > ptr->cur_start_row+ptr->rows_in_mem) { - if (! ptr->b_s_open) - ERREXIT(cinfo, JERR_VIRTUAL_BUG); - /* Flush old buffer contents if necessary */ - if (ptr->dirty) { - do_barray_io(cinfo, ptr, TRUE); - ptr->dirty = FALSE; - } - /* Decide what part of virtual array to access. - * Algorithm: if target address > current window, assume forward scan, - * load starting at target address. If target address < current window, - * assume backward scan, load so that target area is top of window. - * Note that when switching from forward write to forward read, will have - * start_row = 0, so the limiting case applies and we load from 0 anyway. - */ - if (start_row > ptr->cur_start_row) { - ptr->cur_start_row = start_row; - } else { - /* use long arithmetic here to avoid overflow & unsigned problems */ - long ltemp; - - ltemp = (long) end_row - (long) ptr->rows_in_mem; - if (ltemp < 0) - ltemp = 0; /* don't fall off front end of file */ - ptr->cur_start_row = (JDIMENSION) ltemp; - } - /* Read in the selected part of the array. - * During the initial write pass, we will do no actual read - * because the selected part is all undefined. - */ - do_barray_io(cinfo, ptr, FALSE); - } - /* Ensure the accessed part of the array is defined; prezero if needed. - * To improve locality of access, we only prezero the part of the array - * that the caller is about to access, not the entire in-memory array. - */ - if (ptr->first_undef_row < end_row) { - if (ptr->first_undef_row < start_row) { - if (writable) /* writer skipped over a section of array */ - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - undef_row = start_row; /* but reader is allowed to read ahead */ - } else { - undef_row = ptr->first_undef_row; - } - if (writable) - ptr->first_undef_row = end_row; - if (ptr->pre_zero) { - size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK); - undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ - end_row -= ptr->cur_start_row; - while (undef_row < end_row) { - jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); - undef_row++; - } - } else { - if (! writable) /* reader looking at undefined data */ - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - } - } - /* Flag the buffer dirty if caller will write in it */ - if (writable) - ptr->dirty = TRUE; - /* Return address of proper part of the buffer */ - return ptr->mem_buffer + (start_row - ptr->cur_start_row); -} - - -/* - * Release all objects belonging to a specified pool. - */ - -METHODDEF(void) -free_pool (j_common_ptr cinfo, int pool_id) -{ - my_mem_ptr mem = (my_mem_ptr) cinfo->mem; - small_pool_ptr shdr_ptr; - large_pool_ptr lhdr_ptr; - size_t space_freed; - - if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) - ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ - -#ifdef MEM_STATS - if (cinfo->err->trace_level > 1) - print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */ -#endif - - /* If freeing IMAGE pool, close any virtual arrays first */ - if (pool_id == JPOOL_IMAGE) { - jvirt_sarray_ptr sptr; - jvirt_barray_ptr bptr; - - for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { - if (sptr->b_s_open) { /* there may be no backing store */ - sptr->b_s_open = FALSE; /* prevent recursive close if error */ - (*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info); - } - } - mem->virt_sarray_list = NULL; - for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { - if (bptr->b_s_open) { /* there may be no backing store */ - bptr->b_s_open = FALSE; /* prevent recursive close if error */ - (*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info); - } - } - mem->virt_barray_list = NULL; - } - - /* Release large objects */ - lhdr_ptr = mem->large_list[pool_id]; - mem->large_list[pool_id] = NULL; - - while (lhdr_ptr != NULL) { - large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next; - space_freed = lhdr_ptr->hdr.bytes_used + - lhdr_ptr->hdr.bytes_left + - SIZEOF(large_pool_hdr); - jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed); - mem->total_space_allocated -= space_freed; - lhdr_ptr = next_lhdr_ptr; - } - - /* Release small objects */ - shdr_ptr = mem->small_list[pool_id]; - mem->small_list[pool_id] = NULL; - - while (shdr_ptr != NULL) { - small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next; - space_freed = shdr_ptr->hdr.bytes_used + - shdr_ptr->hdr.bytes_left + - SIZEOF(small_pool_hdr); - jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed); - mem->total_space_allocated -= space_freed; - shdr_ptr = next_shdr_ptr; - } -} - - -/* - * Close up shop entirely. - * Note that this cannot be called unless cinfo->mem is non-NULL. - */ - -METHODDEF(void) -self_destruct (j_common_ptr cinfo) -{ - int pool; - - /* Close all backing store, release all memory. - * Releasing pools in reverse order might help avoid fragmentation - * with some (brain-damaged) malloc libraries. - */ - for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { - free_pool(cinfo, pool); - } - - /* Release the memory manager control block too. */ - jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr)); - cinfo->mem = NULL; /* ensures I will be called only once */ - - jpeg_mem_term(cinfo); /* system-dependent cleanup */ -} - - -/* - * Memory manager initialization. - * When this is called, only the error manager pointer is valid in cinfo! - */ - -GLOBAL(void) -jinit_memory_mgr (j_common_ptr cinfo) -{ - my_mem_ptr mem; - long max_to_use; - int pool; -// size_t test_mac; - - cinfo->mem = NULL; /* for safety if init fails */ - - /* Check for configuration errors. - * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably - * doesn't reflect any real hardware alignment requirement. - * The test is a little tricky: for X>0, X and X-1 have no one-bits - * in common if and only if X is a power of 2, ie has only one one-bit. - * Some compilers may give an "unreachable code" warning here; ignore it. - */ - if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0) - ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE); - /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be - * a multiple of SIZEOF(ALIGN_TYPE). - * Again, an "unreachable code" warning may be ignored here. - * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK. - */ -// test_mac = (size_t) MAX_ALLOC_CHUNK; -// if ((long) test_mac != MAX_ALLOC_CHUNK || -// (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0) -// ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); - - max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */ - - /* Attempt to allocate memory manager's control block */ - mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr)); - - if (mem == NULL) { - jpeg_mem_term(cinfo); /* system-dependent cleanup */ - ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0); - } - - /* OK, fill in the method pointers */ - mem->pub.alloc_small = alloc_small; - mem->pub.alloc_large = alloc_large; - mem->pub.alloc_sarray = alloc_sarray; - mem->pub.alloc_barray = alloc_barray; - mem->pub.request_virt_sarray = request_virt_sarray; - mem->pub.request_virt_barray = request_virt_barray; - mem->pub.realize_virt_arrays = realize_virt_arrays; - mem->pub.access_virt_sarray = access_virt_sarray; - mem->pub.access_virt_barray = access_virt_barray; - mem->pub.free_pool = free_pool; - mem->pub.self_destruct = self_destruct; - - /* Make MAX_ALLOC_CHUNK accessible to other modules */ - mem->pub.max_alloc_chunk = MAX_ALLOC_CHUNK; - - /* Initialize working state */ - mem->pub.max_memory_to_use = max_to_use; - - for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { - mem->small_list[pool] = NULL; - mem->large_list[pool] = NULL; - } - mem->virt_sarray_list = NULL; - mem->virt_barray_list = NULL; - - mem->total_space_allocated = SIZEOF(my_memory_mgr); - - /* Declare ourselves open for business */ - cinfo->mem = & mem->pub; - - /* Check for an environment variable JPEGMEM; if found, override the - * default max_memory setting from jpeg_mem_init. Note that the - * surrounding application may again override this value. - * If your system doesn't support getenv(), define NO_GETENV to disable - * this feature. - */ -#ifndef NO_GETENV - { char * memenv; - - if ((memenv = getenv("JPEGMEM")) != NULL) { - char ch = 'x'; - - if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) { - if (ch == 'm' || ch == 'M') - max_to_use *= 1000L; - mem->pub.max_memory_to_use = max_to_use * 1000L; - } - } - } -#endif - -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jmemnobs.c b/source/modules/juce_graphics/image_formats/jpglib/jmemnobs.c deleted file mode 100644 index e74edbcbf..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jmemnobs.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * jmemnobs.c - * - * Copyright (C) 1992-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file provides a really simple implementation of the system- - * dependent portion of the JPEG memory manager. This implementation - * assumes that no backing-store files are needed: all required space - * can be obtained from malloc(). - * This is very portable in the sense that it'll compile on almost anything, - * but you'd better have lots of main memory (or virtual memory) if you want - * to process big images. - * Note that the max_memory_to_use option is ignored by this implementation. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" -#include "jmemsys.h" /* import the system-dependent declarations */ - -#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ -extern void * malloc JPP((size_t size)); -extern void free JPP((void *ptr)); -#endif - - -/* - * Memory allocation and freeing are controlled by the regular library - * routines malloc() and free(). - */ - -GLOBAL(void *) -jpeg_get_small (j_common_ptr , size_t sizeofobject) -{ - return (void *) malloc(sizeofobject); -} - -GLOBAL(void) -jpeg_free_small (j_common_ptr , void * object, size_t) -{ - free(object); -} - - -/* - * "Large" objects are treated the same as "small" ones. - * NB: although we include FAR keywords in the routine declarations, - * this file won't actually work in 80x86 small/medium model; at least, - * you probably won't be able to process useful-size images in only 64KB. - */ - -GLOBAL(void FAR *) -jpeg_get_large (j_common_ptr, size_t sizeofobject) -{ - return (void FAR *) malloc(sizeofobject); -} - -GLOBAL(void) -jpeg_free_large (j_common_ptr, void FAR * object, size_t) -{ - free(object); -} - - -/* - * This routine computes the total memory space available for allocation. - * Here we always say, "we got all you want bud!" - */ - -GLOBAL(long) -jpeg_mem_available (j_common_ptr, long, - long max_bytes_needed, long) -{ - return max_bytes_needed; -} - - -/* - * Backing store (temporary file) management. - * Since jpeg_mem_available always promised the moon, - * this should never be called and we can just error out. - */ - -GLOBAL(void) -jpeg_open_backing_store (j_common_ptr cinfo, struct backing_store_struct *, - long ) -{ - ERREXIT(cinfo, JERR_NO_BACKING_STORE); -} - - -/* - * These routines take care of any system-dependent initialization and - * cleanup required. Here, there isn't any. - */ - -GLOBAL(long) -jpeg_mem_init (j_common_ptr) -{ - return 0; /* just set max_memory_to_use to 0 */ -} - -GLOBAL(void) -jpeg_mem_term (j_common_ptr) -{ - /* no work */ -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jmemsys.h b/source/modules/juce_graphics/image_formats/jpglib/jmemsys.h deleted file mode 100644 index d834ea4fe..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jmemsys.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * jmemsys.h - * - * Copyright (C) 1992-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This include file defines the interface between the system-independent - * and system-dependent portions of the JPEG memory manager. No other - * modules need include it. (The system-independent portion is jmemmgr.c; - * there are several different versions of the system-dependent portion.) - * - * This file works as-is for the system-dependent memory managers supplied - * in the IJG distribution. You may need to modify it if you write a - * custom memory manager. If system-dependent changes are needed in - * this file, the best method is to #ifdef them based on a configuration - * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR - * and USE_MAC_MEMMGR. - */ - -#ifndef __jmemsys_h__ -#define __jmemsys_h__ - -/* Short forms of external names for systems with brain-damaged linkers. */ - -#ifdef NEED_SHORT_EXTERNAL_NAMES -#define jpeg_get_small jGetSmall -#define jpeg_free_small jFreeSmall -#define jpeg_get_large jGetLarge -#define jpeg_free_large jFreeLarge -#define jpeg_mem_available jMemAvail -#define jpeg_open_backing_store jOpenBackStore -#define jpeg_mem_init jMemInit -#define jpeg_mem_term jMemTerm -#endif /* NEED_SHORT_EXTERNAL_NAMES */ - - -/* - * These two functions are used to allocate and release small chunks of - * memory. (Typically the total amount requested through jpeg_get_small is - * no more than 20K or so; this will be requested in chunks of a few K each.) - * Behavior should be the same as for the standard library functions malloc - * and free; in particular, jpeg_get_small must return NULL on failure. - * On most systems, these ARE malloc and free. jpeg_free_small is passed the - * size of the object being freed, just in case it's needed. - * On an 80x86 machine using small-data memory model, these manage near heap. - */ - -EXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject)); -EXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object, - size_t sizeofobject)); - -/* - * These two functions are used to allocate and release large chunks of - * memory (up to the total free space designated by jpeg_mem_available). - * The interface is the same as above, except that on an 80x86 machine, - * far pointers are used. On most other machines these are identical to - * the jpeg_get/free_small routines; but we keep them separate anyway, - * in case a different allocation strategy is desirable for large chunks. - */ - -EXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo, - size_t sizeofobject)); -EXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object, - size_t sizeofobject)); - -/* - * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may - * be requested in a single call to jpeg_get_large (and jpeg_get_small for that - * matter, but that case should never come into play). This macro is needed - * to model the 64Kb-segment-size limit of far addressing on 80x86 machines. - * On those machines, we expect that jconfig.h will provide a proper value. - * On machines with 32-bit flat address spaces, any large constant may be used. - * - * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type - * size_t and will be a multiple of sizeof(align_type). - */ - -#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */ -#define MAX_ALLOC_CHUNK 1000000000L -#endif - -/* - * This routine computes the total space still available for allocation by - * jpeg_get_large. If more space than this is needed, backing store will be - * used. NOTE: any memory already allocated must not be counted. - * - * There is a minimum space requirement, corresponding to the minimum - * feasible buffer sizes; jmemmgr.c will request that much space even if - * jpeg_mem_available returns zero. The maximum space needed, enough to hold - * all working storage in memory, is also passed in case it is useful. - * Finally, the total space already allocated is passed. If no better - * method is available, cinfo->mem->max_memory_to_use - already_allocated - * is often a suitable calculation. - * - * It is OK for jpeg_mem_available to underestimate the space available - * (that'll just lead to more backing-store access than is really necessary). - * However, an overestimate will lead to failure. Hence it's wise to subtract - * a slop factor from the true available space. 5% should be enough. - * - * On machines with lots of virtual memory, any large constant may be returned. - * Conversely, zero may be returned to always use the minimum amount of memory. - */ - -EXTERN(long) jpeg_mem_available JPP((j_common_ptr cinfo, - long min_bytes_needed, - long max_bytes_needed, - long already_allocated)); - - -/* - * This structure holds whatever state is needed to access a single - * backing-store object. The read/write/close method pointers are called - * by jmemmgr.c to manipulate the backing-store object; all other fields - * are private to the system-dependent backing store routines. - */ - -#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */ - - -#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */ - -typedef unsigned short XMSH; /* type of extended-memory handles */ -typedef unsigned short EMSH; /* type of expanded-memory handles */ - -typedef union { - short file_handle; /* DOS file handle if it's a temp file */ - XMSH xms_handle; /* handle if it's a chunk of XMS */ - EMSH ems_handle; /* handle if it's a chunk of EMS */ -} handle_union; - -#endif /* USE_MSDOS_MEMMGR */ - -#ifdef USE_MAC_MEMMGR /* Mac-specific junk */ -#include -#endif /* USE_MAC_MEMMGR */ - - -//typedef struct backing_store_struct * backing_store_ptr; - -typedef struct backing_store_struct { - /* Methods for reading/writing/closing this backing-store object */ - JMETHOD(void, read_backing_store, (j_common_ptr cinfo, - struct backing_store_struct *info, - void FAR * buffer_address, - long file_offset, long byte_count)); - JMETHOD(void, write_backing_store, (j_common_ptr cinfo, - struct backing_store_struct *info, - void FAR * buffer_address, - long file_offset, long byte_count)); - JMETHOD(void, close_backing_store, (j_common_ptr cinfo, - struct backing_store_struct *info)); - - /* Private fields for system-dependent backing-store management */ -#ifdef USE_MSDOS_MEMMGR - /* For the MS-DOS manager (jmemdos.c), we need: */ - handle_union handle; /* reference to backing-store storage object */ - char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ -#else -#ifdef USE_MAC_MEMMGR - /* For the Mac manager (jmemmac.c), we need: */ - short temp_file; /* file reference number to temp file */ - FSSpec tempSpec; /* the FSSpec for the temp file */ - char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ -#else - /* For a typical implementation with temp files, we need: */ - FILE * temp_file; /* stdio reference to temp file */ - char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */ -#endif -#endif -} backing_store_info; - - -/* - * Initial opening of a backing-store object. This must fill in the - * read/write/close pointers in the object. The read/write routines - * may take an error exit if the specified maximum file size is exceeded. - * (If jpeg_mem_available always returns a large value, this routine can - * just take an error exit.) - */ - -EXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo, - struct backing_store_struct *info, - long total_bytes_needed)); - - -/* - * These routines take care of any system-dependent initialization and - * cleanup required. jpeg_mem_init will be called before anything is - * allocated (and, therefore, nothing in cinfo is of use except the error - * manager pointer). It should return a suitable default value for - * max_memory_to_use; this may subsequently be overridden by the surrounding - * application. (Note that max_memory_to_use is only important if - * jpeg_mem_available chooses to consult it ... no one else will.) - * jpeg_mem_term may assume that all requested memory has been freed and that - * all opened backing-store objects have been closed. - */ - -EXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo)); -EXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo)); - - -#endif diff --git a/source/modules/juce_graphics/image_formats/jpglib/jmorecfg.h b/source/modules/juce_graphics/image_formats/jpglib/jmorecfg.h deleted file mode 100644 index c856e2260..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jmorecfg.h +++ /dev/null @@ -1,363 +0,0 @@ -/* - * jmorecfg.h - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains additional configuration options that customize the - * JPEG software for special applications or support machine-dependent - * optimizations. Most users will not need to touch this file. - */ - - -/* - * Define BITS_IN_JSAMPLE as either - * 8 for 8-bit sample values (the usual setting) - * 12 for 12-bit sample values - * Only 8 and 12 are legal data precisions for lossy JPEG according to the - * JPEG standard, and the IJG code does not support anything else! - * We do not support run-time selection of data precision, sorry. - */ - -#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ - - -/* - * Maximum number of components (color channels) allowed in JPEG image. - * To meet the letter of the JPEG spec, set this to 255. However, darn - * few applications need more than 4 channels (maybe 5 for CMYK + alpha - * mask). We recommend 10 as a reasonable compromise; use 4 if you are - * really short on memory. (Each allowed component costs a hundred or so - * bytes of storage, whether actually used in an image or not.) - */ - -#define MAX_COMPONENTS 10 /* maximum number of image components */ - - -/* - * Basic data types. - * You may need to change these if you have a machine with unusual data - * type sizes; for example, "char" not 8 bits, "short" not 16 bits, - * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, - * but it had better be at least 16. - */ - -/* Representation of a single sample (pixel element value). - * We frequently allocate large arrays of these, so it's important to keep - * them small. But if you have memory to burn and access to char or short - * arrays is very slow on your hardware, you might want to change these. - */ - -#if BITS_IN_JSAMPLE == 8 -/* JSAMPLE should be the smallest type that will hold the values 0..255. - * You can use a signed char by having GETJSAMPLE mask it with 0xFF. - */ - -#ifdef HAVE_UNSIGNED_CHAR - -typedef unsigned char JSAMPLE; -#define GETJSAMPLE(value) ((int) (value)) - -#else /* not HAVE_UNSIGNED_CHAR */ - -typedef char JSAMPLE; -#ifdef CHAR_IS_UNSIGNED -#define GETJSAMPLE(value) ((int) (value)) -#else -#define GETJSAMPLE(value) ((int) (value) & 0xFF) -#endif /* CHAR_IS_UNSIGNED */ - -#endif /* HAVE_UNSIGNED_CHAR */ - -#define MAXJSAMPLE 255 -#define CENTERJSAMPLE 128 - -#endif /* BITS_IN_JSAMPLE == 8 */ - - -#if BITS_IN_JSAMPLE == 12 -/* JSAMPLE should be the smallest type that will hold the values 0..4095. - * On nearly all machines "short" will do nicely. - */ - -typedef short JSAMPLE; -#define GETJSAMPLE(value) ((int) (value)) - -#define MAXJSAMPLE 4095 -#define CENTERJSAMPLE 2048 - -#endif /* BITS_IN_JSAMPLE == 12 */ - - -/* Representation of a DCT frequency coefficient. - * This should be a signed value of at least 16 bits; "short" is usually OK. - * Again, we allocate large arrays of these, but you can change to int - * if you have memory to burn and "short" is really slow. - */ - -typedef short JCOEF; - - -/* Compressed datastreams are represented as arrays of JOCTET. - * These must be EXACTLY 8 bits wide, at least once they are written to - * external storage. Note that when using the stdio data source/destination - * managers, this is also the data type passed to fread/fwrite. - */ - -#ifdef HAVE_UNSIGNED_CHAR - -typedef unsigned char JOCTET; -#define GETJOCTET(value) (value) - -#else /* not HAVE_UNSIGNED_CHAR */ - -typedef char JOCTET; -#ifdef CHAR_IS_UNSIGNED -#define GETJOCTET(value) (value) -#else -#define GETJOCTET(value) ((value) & 0xFF) -#endif /* CHAR_IS_UNSIGNED */ - -#endif /* HAVE_UNSIGNED_CHAR */ - - -/* These typedefs are used for various table entries and so forth. - * They must be at least as wide as specified; but making them too big - * won't cost a huge amount of memory, so we don't provide special - * extraction code like we did for JSAMPLE. (In other words, these - * typedefs live at a different point on the speed/space tradeoff curve.) - */ - -/* UINT8 must hold at least the values 0..255. */ - -#ifdef HAVE_UNSIGNED_CHAR -typedef unsigned char UINT8; -#else /* not HAVE_UNSIGNED_CHAR */ -#ifdef CHAR_IS_UNSIGNED -typedef char UINT8; -#else /* not CHAR_IS_UNSIGNED */ -typedef short UINT8; -#endif /* CHAR_IS_UNSIGNED */ -#endif /* HAVE_UNSIGNED_CHAR */ - -/* UINT16 must hold at least the values 0..65535. */ - -#ifdef HAVE_UNSIGNED_SHORT -typedef unsigned short UINT16; -#else /* not HAVE_UNSIGNED_SHORT */ -typedef unsigned int UINT16; -#endif /* HAVE_UNSIGNED_SHORT */ - -/* INT16 must hold at least the values -32768..32767. */ - -#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ -typedef short INT16; -#endif - -/* INT32 must hold at least signed 32-bit values. */ - -#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ -typedef long INT32; -#endif - -/* Datatype used for image dimensions. The JPEG standard only supports - * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore - * "unsigned int" is sufficient on all machines. However, if you need to - * handle larger images and you don't mind deviating from the spec, you - * can change this datatype. - */ - -typedef unsigned int JDIMENSION; - -#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ - - -/* These macros are used in all function definitions and extern declarations. - * You could modify them if you need to change function linkage conventions; - * in particular, you'll need to do that to make the library a Windows DLL. - * Another application is to make all functions global for use with debuggers - * or code profilers that require it. - */ - -/* a function called through method pointers: */ -#define METHODDEF(type) static type -/* a function used only in its module: */ -#define LOCAL(type) static type -/* a function referenced thru EXTERNs: */ -#define GLOBAL(type) type -/* a reference to a GLOBAL function: */ -#define EXTERN(type) extern type - - -/* This macro is used to declare a "method", that is, a function pointer. - * We want to supply prototype parameters if the compiler can cope. - * Note that the arglist parameter must be parenthesized! - * Again, you can customize this if you need special linkage keywords. - */ - -#ifdef HAVE_PROTOTYPES -#define JMETHOD(type,methodname,arglist) type (*methodname) arglist -#else -#define JMETHOD(type,methodname,arglist) type (*methodname) () -#endif - - -/* Here is the pseudo-keyword for declaring pointers that must be "far" - * on 80x86 machines. Most of the specialized coding for 80x86 is handled - * by just saying "FAR *" where such a pointer is needed. In a few places - * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. - */ - -#ifdef NEED_FAR_POINTERS -#define FAR far -#else -#define FAR -#endif - - -/* - * On a few systems, type boolean and/or its values FALSE, TRUE may appear - * in standard header files. Or you may have conflicts with application- - * specific header files that you want to include together with these files. - * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. - */ - -#ifndef HAVE_BOOLEAN -typedef int boolean; -#endif -#ifndef FALSE /* in case these macros already exist */ -#define FALSE 0 /* values of boolean */ -#endif -#ifndef TRUE -#define TRUE 1 -#endif - - -/* - * The remaining options affect code selection within the JPEG library, - * but they don't need to be visible to most applications using the library. - * To minimize application namespace pollution, the symbols won't be - * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. - */ - -#ifdef JPEG_INTERNALS -#define JPEG_INTERNAL_OPTIONS -#endif - -#ifdef JPEG_INTERNAL_OPTIONS - - -/* - * These defines indicate whether to include various optional functions. - * Undefining some of these symbols will produce a smaller but less capable - * library. Note that you can leave certain source files out of the - * compilation/linking process if you've #undef'd the corresponding symbols. - * (You may HAVE to do that if your compiler doesn't like null source files.) - */ - -/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */ - -/* Capability options common to encoder and decoder: */ - -#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ -#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ -#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ - -/* Encoder capability options: */ - -#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ -#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ -#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ -#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ -/* Note: if you selected 12-bit data precision, it is dangerous to turn off - * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit - * precision, so jchuff.c normally uses entropy optimization to compute - * usable tables for higher precision. If you don't want to do optimization, - * you'll have to supply different default Huffman tables. - * The exact same statements apply for progressive JPEG: the default tables - * don't work for progressive mode. (This may get fixed, however.) - */ -#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ - -/* Decoder capability options: */ - -#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ -#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ -#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ -#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ -#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ -#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ -#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ -#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ -#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ -#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ - -/* more capability options later, no doubt */ - - -/* - * Ordering of RGB data in scanlines passed to or from the application. - * If your application wants to deal with data in the order B,G,R, just - * change these macros. You can also deal with formats such as R,G,B,X - * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing - * the offsets will also change the order in which colormap data is organized. - * RESTRICTIONS: - * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. - * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not - * useful if you are using JPEG color spaces other than YCbCr or grayscale. - * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE - * is not 3 (they don't understand about dummy color components!). So you - * can't use color quantization if you change that value. - */ - -#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ -#define RGB_GREEN 1 /* Offset of Green */ -#define RGB_BLUE 2 /* Offset of Blue */ -#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ - - -/* Definitions for speed-related optimizations. */ - - -/* If your compiler supports inline functions, define INLINE - * as the inline keyword; otherwise define it as empty. - */ - -#ifndef INLINE -#ifdef __GNUC__ /* for instance, GNU C knows about inline */ -#define INLINE __inline__ -#endif -#ifndef INLINE -#define INLINE /* default is to define it as empty */ -#endif -#endif - - -/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying - * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER - * as short on such a machine. MULTIPLIER must be at least 16 bits wide. - */ - -#ifndef MULTIPLIER -#define MULTIPLIER int /* type for fastest integer multiply */ -#endif - - -/* FAST_FLOAT should be either float or double, whichever is done faster - * by your compiler. (Note that this type is only used in the floating point - * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) - * Typically, float is faster in ANSI C compilers, while double is faster in - * pre-ANSI compilers (because they insist on converting to double anyway). - * The code below therefore chooses float if we have ANSI-style prototypes. - */ - -#ifndef FAST_FLOAT -#ifdef HAVE_PROTOTYPES -#define FAST_FLOAT float -#else -#define FAST_FLOAT double -#endif -#endif - -#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jpegint.h b/source/modules/juce_graphics/image_formats/jpglib/jpegint.h deleted file mode 100644 index 685a3610b..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jpegint.h +++ /dev/null @@ -1,392 +0,0 @@ -/* - * jpegint.h - * - * Copyright (C) 1991-1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file provides common declarations for the various JPEG modules. - * These declarations are considered internal to the JPEG library; most - * applications using the library shouldn't need to include this file. - */ - - -/* Declarations for both compression & decompression */ - -typedef enum { /* Operating modes for buffer controllers */ - JBUF_PASS_THRU, /* Plain stripwise operation */ - /* Remaining modes require a full-image buffer to have been created */ - JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ - JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ - JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ -} J_BUF_MODE; - -/* Values of global_state field (jdapi.c has some dependencies on ordering!) */ -#define CSTATE_START 100 /* after create_compress */ -#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ -#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ -#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ -#define DSTATE_START 200 /* after create_decompress */ -#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ -#define DSTATE_READY 202 /* found SOS, ready for start_decompress */ -#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ -#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ -#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ -#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ -#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ -#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ -#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ -#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ - - -/* Declarations for compression modules */ - -/* Master control module */ -struct jpeg_comp_master { - JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); - JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); - JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); - - /* State variables made visible to other modules */ - boolean call_pass_startup; /* True if pass_startup must be called */ - boolean is_last_pass; /* True during last pass */ -}; - -/* Main buffer control (downsampled-data buffer) */ -struct jpeg_c_main_controller { - JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); - JMETHOD(void, process_data, (j_compress_ptr cinfo, - JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, - JDIMENSION in_rows_avail)); -}; - -/* Compression preprocessing (downsampling input buffer control) */ -struct jpeg_c_prep_controller { - JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); - JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, - JSAMPARRAY input_buf, - JDIMENSION *in_row_ctr, - JDIMENSION in_rows_avail, - JSAMPIMAGE output_buf, - JDIMENSION *out_row_group_ctr, - JDIMENSION out_row_groups_avail)); -}; - -/* Coefficient buffer control */ -struct jpeg_c_coef_controller { - JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); - JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, - JSAMPIMAGE input_buf)); -}; - -/* Colorspace conversion */ -struct jpeg_color_converter { - JMETHOD(void, start_pass, (j_compress_ptr cinfo)); - JMETHOD(void, color_convert, (j_compress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPIMAGE output_buf, - JDIMENSION output_row, int num_rows)); -}; - -/* Downsampling */ -struct jpeg_downsampler { - JMETHOD(void, start_pass, (j_compress_ptr cinfo)); - JMETHOD(void, downsample, (j_compress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION in_row_index, - JSAMPIMAGE output_buf, - JDIMENSION out_row_group_index)); - - boolean need_context_rows; /* TRUE if need rows above & below */ -}; - -/* Forward DCT (also controls coefficient quantization) */ -struct jpeg_forward_dct { - JMETHOD(void, start_pass, (j_compress_ptr cinfo)); - /* perhaps this should be an array??? */ - JMETHOD(void, forward_DCT, (j_compress_ptr cinfo, - jpeg_component_info * compptr, - JSAMPARRAY sample_data, JBLOCKROW coef_blocks, - JDIMENSION start_row, JDIMENSION start_col, - JDIMENSION num_blocks)); -}; - -/* Entropy encoding */ -struct jpeg_entropy_encoder { - JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics)); - JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data)); - JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); -}; - -/* Marker writing */ -struct jpeg_marker_writer { - JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); - JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); - JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); - JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); - JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); - /* These routines are exported to allow insertion of extra markers */ - /* Probably only COM and APPn markers should be written this way */ - JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker, - unsigned int datalen)); - JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val)); -}; - - -/* Declarations for decompression modules */ - -/* Master control module */ -struct jpeg_decomp_master { - JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); - JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); - - /* State variables made visible to other modules */ - boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ -}; - -/* Input control module */ -struct jpeg_input_controller { - JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); - JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); - JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); - JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); - - /* State variables made visible to other modules */ - boolean has_multiple_scans; /* True if file has multiple scans */ - boolean eoi_reached; /* True when EOI has been consumed */ -}; - -/* Main buffer control (downsampled-data buffer) */ -struct jpeg_d_main_controller { - JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); - JMETHOD(void, process_data, (j_decompress_ptr cinfo, - JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail)); -}; - -/* Coefficient buffer control */ -struct jpeg_d_coef_controller { - JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); - JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); - JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); - JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, - JSAMPIMAGE output_buf)); - /* Pointer to array of coefficient virtual arrays, or NULL if none */ - jvirt_barray_ptr *coef_arrays; -}; - -/* Decompression postprocessing (color quantization buffer control) */ -struct jpeg_d_post_controller { - JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); - JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, - JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY output_buf, - JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail)); -}; - -/* Marker reading & parsing */ -struct jpeg_marker_reader { - JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); - /* Read markers until SOS or EOI. - * Returns same codes as are defined for jpeg_consume_input: - * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. - */ - JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); - /* Read a restart marker --- exported for use by entropy decoder only */ - jpeg_marker_parser_method read_restart_marker; - - /* State of marker reader --- nominally internal, but applications - * supplying COM or APPn handlers might like to know the state. - */ - boolean saw_SOI; /* found SOI? */ - boolean saw_SOF; /* found SOF? */ - int next_restart_num; /* next restart number expected (0-7) */ - unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ -}; - -/* Entropy decoding */ -struct jpeg_entropy_decoder { - JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); - JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, - JBLOCKROW *MCU_data)); - - /* This is here to share code between baseline and progressive decoders; */ - /* other modules probably should not use it */ - boolean insufficient_data; /* set TRUE after emitting warning */ -}; - -/* Inverse DCT (also performs dequantization) */ -typedef JMETHOD(void, inverse_DCT_method_ptr, - (j_decompress_ptr cinfo, jpeg_component_info * compptr, - JCOEFPTR coef_block, - JSAMPARRAY output_buf, JDIMENSION output_col)); - -struct jpeg_inverse_dct { - JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); - /* It is useful to allow each component to have a separate IDCT method. */ - inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; -}; - -/* Upsampling (note that upsampler must also call color converter) */ -struct jpeg_upsampler { - JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); - JMETHOD(void, upsample, (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, - JDIMENSION *in_row_group_ctr, - JDIMENSION in_row_groups_avail, - JSAMPARRAY output_buf, - JDIMENSION *out_row_ctr, - JDIMENSION out_rows_avail)); - - boolean need_context_rows; /* TRUE if need rows above & below */ -}; - -/* Colorspace conversion */ -struct jpeg_color_deconverter { - JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); - JMETHOD(void, color_convert, (j_decompress_ptr cinfo, - JSAMPIMAGE input_buf, JDIMENSION input_row, - JSAMPARRAY output_buf, int num_rows)); -}; - -/* Color quantization or color precision reduction */ -struct jpeg_color_quantizer { - JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); - JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPARRAY output_buf, - int num_rows)); - JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); - JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); -}; - - -/* Miscellaneous useful macros */ - -#undef MAX -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#undef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - - -/* We assume that right shift corresponds to signed division by 2 with - * rounding towards minus infinity. This is correct for typical "arithmetic - * shift" instructions that shift in copies of the sign bit. But some - * C compilers implement >> with an unsigned shift. For these machines you - * must define RIGHT_SHIFT_IS_UNSIGNED. - * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. - * It is only applied with constant shift counts. SHIFT_TEMPS must be - * included in the variables of any routine using RIGHT_SHIFT. - */ - -#ifdef RIGHT_SHIFT_IS_UNSIGNED -#define SHIFT_TEMPS INT32 shift_temp; -#define RIGHT_SHIFT(x,shft) \ - ((shift_temp = (x)) < 0 ? \ - (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ - (shift_temp >> (shft))) -#else -#define SHIFT_TEMPS -#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) -#endif - - -/* Short forms of external names for systems with brain-damaged linkers. */ - -#ifdef NEED_SHORT_EXTERNAL_NAMES -#define jinit_compress_master jICompress -#define jinit_c_master_control jICMaster -#define jinit_c_main_controller jICMainC -#define jinit_c_prep_controller jICPrepC -#define jinit_c_coef_controller jICCoefC -#define jinit_color_converter jICColor -#define jinit_downsampler jIDownsampler -#define jinit_forward_dct jIFDCT -#define jinit_huff_encoder jIHEncoder -#define jinit_phuff_encoder jIPHEncoder -#define jinit_marker_writer jIMWriter -#define jinit_master_decompress jIDMaster -#define jinit_d_main_controller jIDMainC -#define jinit_d_coef_controller jIDCoefC -#define jinit_d_post_controller jIDPostC -#define jinit_input_controller jIInCtlr -#define jinit_marker_reader jIMReader -#define jinit_huff_decoder jIHDecoder -#define jinit_phuff_decoder jIPHDecoder -#define jinit_inverse_dct jIIDCT -#define jinit_upsampler jIUpsampler -#define jinit_color_deconverter jIDColor -#define jinit_1pass_quantizer jI1Quant -#define jinit_2pass_quantizer jI2Quant -#define jinit_merged_upsampler jIMUpsampler -#define jinit_memory_mgr jIMemMgr -#define jdiv_round_up jDivRound -#define jround_up jRound -#define jcopy_sample_rows jCopySamples -#define jcopy_block_row jCopyBlocks -#define jzero_far jZeroFar -#define jpeg_zigzag_order jZIGTable -#define jpeg_natural_order jZAGTable -#endif /* NEED_SHORT_EXTERNAL_NAMES */ - - -/* Compression module initialization routines */ -EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); -EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, - boolean transcode_only)); -EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, - boolean need_full_buffer)); -EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, - boolean need_full_buffer)); -EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, - boolean need_full_buffer)); -EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); -EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); -EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo)); -EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo)); -EXTERN(void) jinit_phuff_encoder JPP((j_compress_ptr cinfo)); -EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); -/* Decompression module initialization routines */ -EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, - boolean need_full_buffer)); -EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, - boolean need_full_buffer)); -EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, - boolean need_full_buffer)); -EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); -EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); -/* Memory manager initialization */ -EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); - -/* Utility routines in jutils.c */ -EXTERN(long) jdiv_round_up JPP((long a, long b)); -EXTERN(long) jround_up JPP((long a, long b)); -EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, - JSAMPARRAY output_array, int dest_row, - int num_rows, JDIMENSION num_cols)); -EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, - JDIMENSION num_blocks)); -EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); -/* Constant tables in jutils.c */ -#if 0 /* This table is not actually needed in v6a */ -extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ -#endif -extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ - -/* Suppress undefined-structure complaints if necessary. */ - -#ifdef INCOMPLETE_TYPES_BROKEN -#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ -struct jvirt_sarray_control { long dummy; }; -struct jvirt_barray_control { long dummy; }; -#endif -#endif /* INCOMPLETE_TYPES_BROKEN */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jpeglib.h b/source/modules/juce_graphics/image_formats/jpglib/jpeglib.h deleted file mode 100644 index bf6ce08a4..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jpeglib.h +++ /dev/null @@ -1,1096 +0,0 @@ -/* - * jpeglib.h - * - * Copyright (C) 1991-1998, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file defines the application interface for the JPEG library. - * Most applications using the library need only include this file, - * and perhaps jerror.h if they want to know the exact error codes. - */ - -#ifndef JPEGLIB_H -#define JPEGLIB_H - -/* - * First we include the configuration files that record how this - * installation of the JPEG library is set up. jconfig.h can be - * generated automatically for many systems. jmorecfg.h contains - * manual configuration options that most people need not worry about. - */ - -#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ -#include "jconfig.h" /* widely used configuration options */ -#endif -#include "jmorecfg.h" /* seldom changed options */ - - -/* Version ID for the JPEG library. - * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". - */ - -#define JPEG_LIB_VERSION 62 /* Version 6b */ - - -/* Various constants determining the sizes of things. - * All of these are specified by the JPEG standard, so don't change them - * if you want to be compatible. - */ - -#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ -#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ -#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ -#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ -#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ -#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ -#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ -/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; - * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. - * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU - * to handle it. We even let you do this from the jconfig.h file. However, - * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe - * sometimes emits noncompliant files doesn't mean you should too. - */ -#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ -#ifndef D_MAX_BLOCKS_IN_MCU -#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ -#endif - - -/* Data structures for images (arrays of samples and of DCT coefficients). - * On 80x86 machines, the image arrays are too big for near pointers, - * but the pointer arrays can fit in near memory. - */ - -typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ -typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ -typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ - -typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ -typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ -typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ -typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ - -typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ - - -/* Types for JPEG compression parameters and working tables. */ - - -/* DCT coefficient quantization tables. */ - -typedef struct { - /* This array gives the coefficient quantizers in natural array order - * (not the zigzag order in which they are stored in a JPEG DQT marker). - * CAUTION: IJG versions prior to v6a kept this array in zigzag order. - */ - UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ - /* This field is used only during compression. It's initialized FALSE when - * the table is created, and set TRUE when it's been output to the file. - * You could suppress output of a table by setting this to TRUE. - * (See jpeg_suppress_tables for an example.) - */ - boolean sent_table; /* TRUE when table has been output */ -} JQUANT_TBL; - - -/* Huffman coding tables. */ - -typedef struct { - /* These two fields directly represent the contents of a JPEG DHT marker */ - UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ - /* length k bits; bits[0] is unused */ - UINT8 huffval[256]; /* The symbols, in order of incr code length */ - /* This field is used only during compression. It's initialized FALSE when - * the table is created, and set TRUE when it's been output to the file. - * You could suppress output of a table by setting this to TRUE. - * (See jpeg_suppress_tables for an example.) - */ - boolean sent_table; /* TRUE when table has been output */ -} JHUFF_TBL; - - -/* Basic info about one component (color channel). */ - -typedef struct { - /* These values are fixed over the whole image. */ - /* For compression, they must be supplied by parameter setup; */ - /* for decompression, they are read from the SOF marker. */ - int component_id; /* identifier for this component (0..255) */ - int component_index; /* its index in SOF or cinfo->comp_info[] */ - int h_samp_factor; /* horizontal sampling factor (1..4) */ - int v_samp_factor; /* vertical sampling factor (1..4) */ - int quant_tbl_no; /* quantization table selector (0..3) */ - /* These values may vary between scans. */ - /* For compression, they must be supplied by parameter setup; */ - /* for decompression, they are read from the SOS marker. */ - /* The decompressor output side may not use these variables. */ - int dc_tbl_no; /* DC entropy table selector (0..3) */ - int ac_tbl_no; /* AC entropy table selector (0..3) */ - - /* Remaining fields should be treated as private by applications. */ - - /* These values are computed during compression or decompression startup: */ - /* Component's size in DCT blocks. - * Any dummy blocks added to complete an MCU are not counted; therefore - * these values do not depend on whether a scan is interleaved or not. - */ - JDIMENSION width_in_blocks; - JDIMENSION height_in_blocks; - /* Size of a DCT block in samples. Always DCTSIZE for compression. - * For decompression this is the size of the output from one DCT block, - * reflecting any scaling we choose to apply during the IDCT step. - * Values of 1,2,4,8 are likely to be supported. Note that different - * components may receive different IDCT scalings. - */ - int DCT_scaled_size; - /* The downsampled dimensions are the component's actual, unpadded number - * of samples at the main buffer (preprocessing/compression interface), thus - * downsampled_width = ceil(image_width * Hi/Hmax) - * and similarly for height. For decompression, IDCT scaling is included, so - * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE) - */ - JDIMENSION downsampled_width; /* actual width in samples */ - JDIMENSION downsampled_height; /* actual height in samples */ - /* This flag is used only for decompression. In cases where some of the - * components will be ignored (eg grayscale output from YCbCr image), - * we can skip most computations for the unused components. - */ - boolean component_needed; /* do we need the value of this component? */ - - /* These values are computed before starting a scan of the component. */ - /* The decompressor output side may not use these variables. */ - int MCU_width; /* number of blocks per MCU, horizontally */ - int MCU_height; /* number of blocks per MCU, vertically */ - int MCU_blocks; /* MCU_width * MCU_height */ - int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */ - int last_col_width; /* # of non-dummy blocks across in last MCU */ - int last_row_height; /* # of non-dummy blocks down in last MCU */ - - /* Saved quantization table for component; NULL if none yet saved. - * See jdinput.c comments about the need for this information. - * This field is currently used only for decompression. - */ - JQUANT_TBL * quant_table; - - /* Private per-component storage for DCT or IDCT subsystem. */ - void * dct_table; -} jpeg_component_info; - - -/* The script for encoding a multiple-scan file is an array of these: */ - -typedef struct { - int comps_in_scan; /* number of components encoded in this scan */ - int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ - int Ss, Se; /* progressive JPEG spectral selection parms */ - int Ah, Al; /* progressive JPEG successive approx. parms */ -} jpeg_scan_info; - -/* The decompressor can save APPn and COM markers in a list of these: */ - -typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; - -struct jpeg_marker_struct { - jpeg_saved_marker_ptr next; /* next in list, or NULL */ - UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ - unsigned int original_length; /* # bytes of data in the file */ - unsigned int data_length; /* # bytes of data saved at data[] */ - JOCTET FAR * data; /* the data contained in the marker */ - /* the marker length word is not counted in data_length or original_length */ -}; - -/* Known color spaces. */ - -typedef enum { - JCS_UNKNOWN, /* error/unspecified */ - JCS_GRAYSCALE, /* monochrome */ - JCS_RGB, /* red/green/blue */ - JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ - JCS_CMYK, /* C/M/Y/K */ - JCS_YCCK /* Y/Cb/Cr/K */ -} J_COLOR_SPACE; - -/* DCT/IDCT algorithm options. */ - -typedef enum { - JDCT_ISLOW, /* slow but accurate integer algorithm */ - JDCT_IFAST, /* faster, less accurate integer method */ - JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ -} J_DCT_METHOD; - -#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ -#define JDCT_DEFAULT JDCT_ISLOW -#endif -#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ -#define JDCT_FASTEST JDCT_IFAST -#endif - -/* Dithering options for decompression. */ - -typedef enum { - JDITHER_NONE, /* no dithering */ - JDITHER_ORDERED, /* simple ordered dither */ - JDITHER_FS /* Floyd-Steinberg error diffusion dither */ -} J_DITHER_MODE; - - -/* Common fields between JPEG compression and decompression master structs. */ - -#define jpeg_common_fields \ - struct jpeg_error_mgr * err; /* Error handler module */\ - struct jpeg_memory_mgr * mem; /* Memory manager module */\ - struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ - void * client_data; /* Available for use by application */\ - boolean is_decompressor; /* So common code can tell which is which */\ - int global_state /* For checking call sequence validity */ - -/* Routines that are to be used by both halves of the library are declared - * to receive a pointer to this structure. There are no actual instances of - * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. - */ -struct jpeg_common_struct { - jpeg_common_fields; /* Fields common to both master struct types */ - /* Additional fields follow in an actual jpeg_compress_struct or - * jpeg_decompress_struct. All three structs must agree on these - * initial fields! (This would be a lot cleaner in C++.) - */ -}; - -typedef struct jpeg_common_struct * j_common_ptr; -typedef struct jpeg_compress_struct * j_compress_ptr; -typedef struct jpeg_decompress_struct * j_decompress_ptr; - - -/* Master record for a compression instance */ - -struct jpeg_compress_struct { - jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ - - /* Destination for compressed data */ - struct jpeg_destination_mgr * dest; - - /* Description of source image --- these fields must be filled in by - * outer application before starting compression. in_color_space must - * be correct before you can even call jpeg_set_defaults(). - */ - - JDIMENSION image_width; /* input image width */ - JDIMENSION image_height; /* input image height */ - int input_components; /* # of color components in input image */ - J_COLOR_SPACE in_color_space; /* colorspace of input image */ - - double input_gamma; /* image gamma of input image */ - - /* Compression parameters --- these fields must be set before calling - * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to - * initialize everything to reasonable defaults, then changing anything - * the application specifically wants to change. That way you won't get - * burnt when new parameters are added. Also note that there are several - * helper routines to simplify changing parameters. - */ - - int data_precision; /* bits of precision in image data */ - - int num_components; /* # of color components in JPEG image */ - J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ - - jpeg_component_info * comp_info; - /* comp_info[i] describes component that appears i'th in SOF */ - - JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; - /* ptrs to coefficient quantization tables, or NULL if not defined */ - - JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; - JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; - /* ptrs to Huffman coding tables, or NULL if not defined */ - - UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ - UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ - UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ - - int num_scans; /* # of entries in scan_info array */ - const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ - /* The default value of scan_info is NULL, which causes a single-scan - * sequential JPEG file to be emitted. To create a multi-scan file, - * set num_scans and scan_info to point to an array of scan definitions. - */ - - boolean raw_data_in; /* TRUE=caller supplies downsampled data */ - boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ - boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ - boolean CCIR601_sampling; /* TRUE=first samples are cosited */ - int smoothing_factor; /* 1..100, or 0 for no input smoothing */ - J_DCT_METHOD dct_method; /* DCT algorithm selector */ - - /* The restart interval can be specified in absolute MCUs by setting - * restart_interval, or in MCU rows by setting restart_in_rows - * (in which case the correct restart_interval will be figured - * for each scan). - */ - unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ - int restart_in_rows; /* if > 0, MCU rows per restart interval */ - - /* Parameters controlling emission of special markers. */ - - boolean write_JFIF_header; /* should a JFIF marker be written? */ - UINT8 JFIF_major_version; /* What to write for the JFIF version number */ - UINT8 JFIF_minor_version; - /* These three values are not used by the JPEG code, merely copied */ - /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ - /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ - /* ratio is defined by X_density/Y_density even when density_unit=0. */ - UINT8 density_unit; /* JFIF code for pixel size units */ - UINT16 X_density; /* Horizontal pixel density */ - UINT16 Y_density; /* Vertical pixel density */ - boolean write_Adobe_marker; /* should an Adobe marker be written? */ - - /* State variable: index of next scanline to be written to - * jpeg_write_scanlines(). Application may use this to control its - * processing loop, e.g., "while (next_scanline < image_height)". - */ - - JDIMENSION next_scanline; /* 0 .. image_height-1 */ - - /* Remaining fields are known throughout compressor, but generally - * should not be touched by a surrounding application. - */ - - /* - * These fields are computed during compression startup - */ - boolean progressive_mode; /* TRUE if scan script uses progressive mode */ - int max_h_samp_factor; /* largest h_samp_factor */ - int max_v_samp_factor; /* largest v_samp_factor */ - - JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ - /* The coefficient controller receives data in units of MCU rows as defined - * for fully interleaved scans (whether the JPEG file is interleaved or not). - * There are v_samp_factor * DCTSIZE sample rows of each component in an - * "iMCU" (interleaved MCU) row. - */ - - /* - * These fields are valid during any one scan. - * They describe the components and MCUs actually appearing in the scan. - */ - int comps_in_scan; /* # of JPEG components in this scan */ - jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; - /* *cur_comp_info[i] describes component that appears i'th in SOS */ - - JDIMENSION MCUs_per_row; /* # of MCUs across the image */ - JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ - - int blocks_in_MCU; /* # of DCT blocks per MCU */ - int MCU_membership[C_MAX_BLOCKS_IN_MCU]; - /* MCU_membership[i] is index in cur_comp_info of component owning */ - /* i'th block in an MCU */ - - int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ - - /* - * Links to compression subobjects (methods and private variables of modules) - */ - struct jpeg_comp_master * master; - struct jpeg_c_main_controller * main; - struct jpeg_c_prep_controller * prep; - struct jpeg_c_coef_controller * coef; - struct jpeg_marker_writer * marker; - struct jpeg_color_converter * cconvert; - struct jpeg_downsampler * downsample; - struct jpeg_forward_dct * fdct; - struct jpeg_entropy_encoder * entropy; - jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ - int script_space_size; -}; - - -/* Master record for a decompression instance */ - -struct jpeg_decompress_struct { - jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ - - /* Source of compressed data */ - struct jpeg_source_mgr * src; - - /* Basic description of image --- filled in by jpeg_read_header(). */ - /* Application may inspect these values to decide how to process image. */ - - JDIMENSION image_width; /* nominal image width (from SOF marker) */ - JDIMENSION image_height; /* nominal image height */ - int num_components; /* # of color components in JPEG image */ - J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ - - /* Decompression processing parameters --- these fields must be set before - * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes - * them to default values. - */ - - J_COLOR_SPACE out_color_space; /* colorspace for output */ - - unsigned int scale_num, scale_denom; /* fraction by which to scale image */ - - double output_gamma; /* image gamma wanted in output */ - - boolean buffered_image; /* TRUE=multiple output passes */ - boolean raw_data_out; /* TRUE=downsampled data wanted */ - - J_DCT_METHOD dct_method; /* IDCT algorithm selector */ - boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ - boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ - - boolean quantize_colors; /* TRUE=colormapped output wanted */ - /* the following are ignored if not quantize_colors: */ - J_DITHER_MODE dither_mode; /* type of color dithering to use */ - boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ - int desired_number_of_colors; /* max # colors to use in created colormap */ - /* these are significant only in buffered-image mode: */ - boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ - boolean enable_external_quant;/* enable future use of external colormap */ - boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ - - /* Description of actual output image that will be returned to application. - * These fields are computed by jpeg_start_decompress(). - * You can also use jpeg_calc_output_dimensions() to determine these values - * in advance of calling jpeg_start_decompress(). - */ - - JDIMENSION output_width; /* scaled image width */ - JDIMENSION output_height; /* scaled image height */ - int out_color_components; /* # of color components in out_color_space */ - int output_components; /* # of color components returned */ - /* output_components is 1 (a colormap index) when quantizing colors; - * otherwise it equals out_color_components. - */ - int rec_outbuf_height; /* min recommended height of scanline buffer */ - /* If the buffer passed to jpeg_read_scanlines() is less than this many rows - * high, space and time will be wasted due to unnecessary data copying. - * Usually rec_outbuf_height will be 1 or 2, at most 4. - */ - - /* When quantizing colors, the output colormap is described by these fields. - * The application can supply a colormap by setting colormap non-NULL before - * calling jpeg_start_decompress; otherwise a colormap is created during - * jpeg_start_decompress or jpeg_start_output. - * The map has out_color_components rows and actual_number_of_colors columns. - */ - int actual_number_of_colors; /* number of entries in use */ - JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ - - /* State variables: these variables indicate the progress of decompression. - * The application may examine these but must not modify them. - */ - - /* Row index of next scanline to be read from jpeg_read_scanlines(). - * Application may use this to control its processing loop, e.g., - * "while (output_scanline < output_height)". - */ - JDIMENSION output_scanline; /* 0 .. output_height-1 */ - - /* Current input scan number and number of iMCU rows completed in scan. - * These indicate the progress of the decompressor input side. - */ - int input_scan_number; /* Number of SOS markers seen so far */ - JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ - - /* The "output scan number" is the notional scan being displayed by the - * output side. The decompressor will not allow output scan/row number - * to get ahead of input scan/row, but it can fall arbitrarily far behind. - */ - int output_scan_number; /* Nominal scan number being displayed */ - JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ - - /* Current progression status. coef_bits[c][i] indicates the precision - * with which component c's DCT coefficient i (in zigzag order) is known. - * It is -1 when no data has yet been received, otherwise it is the point - * transform (shift) value for the most recent scan of the coefficient - * (thus, 0 at completion of the progression). - * This pointer is NULL when reading a non-progressive file. - */ - int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ - - /* Internal JPEG parameters --- the application usually need not look at - * these fields. Note that the decompressor output side may not use - * any parameters that can change between scans. - */ - - /* Quantization and Huffman tables are carried forward across input - * datastreams when processing abbreviated JPEG datastreams. - */ - - JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; - /* ptrs to coefficient quantization tables, or NULL if not defined */ - - JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; - JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; - /* ptrs to Huffman coding tables, or NULL if not defined */ - - /* These parameters are never carried across datastreams, since they - * are given in SOF/SOS markers or defined to be reset by SOI. - */ - - int data_precision; /* bits of precision in image data */ - - jpeg_component_info * comp_info; - /* comp_info[i] describes component that appears i'th in SOF */ - - boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ - boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ - - UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ - UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ - UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ - - unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ - - /* These fields record data obtained from optional markers recognized by - * the JPEG library. - */ - boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ - /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ - UINT8 JFIF_major_version; /* JFIF version number */ - UINT8 JFIF_minor_version; - UINT8 density_unit; /* JFIF code for pixel size units */ - UINT16 X_density; /* Horizontal pixel density */ - UINT16 Y_density; /* Vertical pixel density */ - boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ - UINT8 Adobe_transform; /* Color transform code from Adobe marker */ - - boolean CCIR601_sampling; /* TRUE=first samples are cosited */ - - /* Aside from the specific data retained from APPn markers known to the - * library, the uninterpreted contents of any or all APPn and COM markers - * can be saved in a list for examination by the application. - */ - jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ - - /* Remaining fields are known throughout decompressor, but generally - * should not be touched by a surrounding application. - */ - - /* - * These fields are computed during decompression startup - */ - int max_h_samp_factor; /* largest h_samp_factor */ - int max_v_samp_factor; /* largest v_samp_factor */ - - int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */ - - JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ - /* The coefficient controller's input and output progress is measured in - * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows - * in fully interleaved JPEG scans, but are used whether the scan is - * interleaved or not. We define an iMCU row as v_samp_factor DCT block - * rows of each component. Therefore, the IDCT output contains - * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row. - */ - - JSAMPLE * sample_range_limit; /* table for fast range-limiting */ - - /* - * These fields are valid during any one scan. - * They describe the components and MCUs actually appearing in the scan. - * Note that the decompressor output side must not use these fields. - */ - int comps_in_scan; /* # of JPEG components in this scan */ - jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; - /* *cur_comp_info[i] describes component that appears i'th in SOS */ - - JDIMENSION MCUs_per_row; /* # of MCUs across the image */ - JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ - - int blocks_in_MCU; /* # of DCT blocks per MCU */ - int MCU_membership[D_MAX_BLOCKS_IN_MCU]; - /* MCU_membership[i] is index in cur_comp_info of component owning */ - /* i'th block in an MCU */ - - int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ - - /* This field is shared between entropy decoder and marker parser. - * It is either zero or the code of a JPEG marker that has been - * read from the data source, but has not yet been processed. - */ - int unread_marker; - - /* - * Links to decompression subobjects (methods, private variables of modules) - */ - struct jpeg_decomp_master * master; - struct jpeg_d_main_controller * main; - struct jpeg_d_coef_controller * coef; - struct jpeg_d_post_controller * post; - struct jpeg_input_controller * inputctl; - struct jpeg_marker_reader * marker; - struct jpeg_entropy_decoder * entropy; - struct jpeg_inverse_dct * idct; - struct jpeg_upsampler * upsample; - struct jpeg_color_deconverter * cconvert; - struct jpeg_color_quantizer * cquantize; -}; - - -/* "Object" declarations for JPEG modules that may be supplied or called - * directly by the surrounding application. - * As with all objects in the JPEG library, these structs only define the - * publicly visible methods and state variables of a module. Additional - * private fields may exist after the public ones. - */ - - -/* Error handler object */ - -struct jpeg_error_mgr { - /* Error exit handler: does not return to caller */ - JMETHOD(void, error_exit, (j_common_ptr cinfo)); - /* Conditionally emit a trace or warning message */ - JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); - /* Routine that actually outputs a trace or error message */ - JMETHOD(void, output_message, (j_common_ptr cinfo)); - /* Format a message string for the most recent JPEG error or message */ - JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); -#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ - /* Reset error state variables at start of a new image */ - JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); - - /* The message ID code and any parameters are saved here. - * A message can have one string parameter or up to 8 int parameters. - */ - int msg_code; -#define JMSG_STR_PARM_MAX 80 - union { - int i[8]; - char s[JMSG_STR_PARM_MAX]; - } msg_parm; - - /* Standard state variables for error facility */ - - int trace_level; /* max msg_level that will be displayed */ - - /* For recoverable corrupt-data errors, we emit a warning message, - * but keep going unless emit_message chooses to abort. emit_message - * should count warnings in num_warnings. The surrounding application - * can check for bad data by seeing if num_warnings is nonzero at the - * end of processing. - */ - long num_warnings; /* number of corrupt-data warnings */ - - /* These fields point to the table(s) of error message strings. - * An application can change the table pointer to switch to a different - * message list (typically, to change the language in which errors are - * reported). Some applications may wish to add additional error codes - * that will be handled by the JPEG library error mechanism; the second - * table pointer is used for this purpose. - * - * First table includes all errors generated by JPEG library itself. - * Error code 0 is reserved for a "no such error string" message. - */ - const char * const * jpeg_message_table; /* Library errors */ - int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ - /* Second table can be added by application (see cjpeg/djpeg for example). - * It contains strings numbered first_addon_message..last_addon_message. - */ - const char * const * addon_message_table; /* Non-library errors */ - int first_addon_message; /* code for first string in addon table */ - int last_addon_message; /* code for last string in addon table */ -}; - - -/* Progress monitor object */ - -struct jpeg_progress_mgr { - JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); - - long pass_counter; /* work units completed in this pass */ - long pass_limit; /* total number of work units in this pass */ - int completed_passes; /* passes completed so far */ - int total_passes; /* total number of passes expected */ -}; - - -/* Data destination object for compression */ - -struct jpeg_destination_mgr { - JOCTET * next_output_byte; /* => next byte to write in buffer */ - size_t free_in_buffer; /* # of byte spaces remaining in buffer */ - - JMETHOD(void, init_destination, (j_compress_ptr cinfo)); - JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); - JMETHOD(void, term_destination, (j_compress_ptr cinfo)); -}; - - -/* Data source object for decompression */ - -struct jpeg_source_mgr { - const JOCTET * next_input_byte; /* => next byte to read from buffer */ - size_t bytes_in_buffer; /* # of bytes remaining in buffer */ - - JMETHOD(void, init_source, (j_decompress_ptr cinfo)); - JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); - JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); - JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); - JMETHOD(void, term_source, (j_decompress_ptr cinfo)); -}; - - -/* Memory manager object. - * Allocates "small" objects (a few K total), "large" objects (tens of K), - * and "really big" objects (virtual arrays with backing store if needed). - * The memory manager does not allow individual objects to be freed; rather, - * each created object is assigned to a pool, and whole pools can be freed - * at once. This is faster and more convenient than remembering exactly what - * to free, especially where malloc()/free() are not too speedy. - * NB: alloc routines never return NULL. They exit to error_exit if not - * successful. - */ - -#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ -#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ -#define JPOOL_NUMPOOLS 2 - -typedef struct jvirt_sarray_control * jvirt_sarray_ptr; -typedef struct jvirt_barray_control * jvirt_barray_ptr; - - -struct jpeg_memory_mgr { - /* Method pointers */ - JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, - size_t sizeofobject)); - JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, - size_t sizeofobject)); - JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, - JDIMENSION samplesperrow, - JDIMENSION numrows)); - JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, - JDIMENSION blocksperrow, - JDIMENSION numrows)); - JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, - int pool_id, - boolean pre_zero, - JDIMENSION samplesperrow, - JDIMENSION numrows, - JDIMENSION maxaccess)); - JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, - int pool_id, - boolean pre_zero, - JDIMENSION blocksperrow, - JDIMENSION numrows, - JDIMENSION maxaccess)); - JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); - JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, - jvirt_sarray_ptr ptr, - JDIMENSION start_row, - JDIMENSION num_rows, - boolean writable)); - JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, - jvirt_barray_ptr ptr, - JDIMENSION start_row, - JDIMENSION num_rows, - boolean writable)); - JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); - JMETHOD(void, self_destruct, (j_common_ptr cinfo)); - - /* Limit on memory allocation for this JPEG object. (Note that this is - * merely advisory, not a guaranteed maximum; it only affects the space - * used for virtual-array buffers.) May be changed by outer application - * after creating the JPEG object. - */ - long max_memory_to_use; - - /* Maximum allocation request accepted by alloc_large. */ - long max_alloc_chunk; -}; - - -/* Routine signature for application-supplied marker processing methods. - * Need not pass marker code since it is stored in cinfo->unread_marker. - */ -typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); - - -/* Declarations for routines called by application. - * The JPP macro hides prototype parameters from compilers that can't cope. - * Note JPP requires double parentheses. - */ - -#ifdef HAVE_PROTOTYPES -#define JPP(arglist) arglist -#else -#define JPP(arglist) () -#endif - - -/* Short forms of external names for systems with brain-damaged linkers. - * We shorten external names to be unique in the first six letters, which - * is good enough for all known systems. - * (If your compiler itself needs names to be unique in less than 15 - * characters, you are out of luck. Get a better compiler.) - */ - -#ifdef NEED_SHORT_EXTERNAL_NAMES -#define jpeg_std_error jStdError -#define jpeg_CreateCompress jCreaCompress -#define jpeg_CreateDecompress jCreaDecompress -#define jpeg_destroy_compress jDestCompress -#define jpeg_destroy_decompress jDestDecompress -#define jpeg_stdio_dest jStdDest -#define jpeg_stdio_src jStdSrc -#define jpeg_set_defaults jSetDefaults -#define jpeg_set_colorspace jSetColorspace -#define jpeg_default_colorspace jDefColorspace -#define jpeg_set_quality jSetQuality -#define jpeg_set_linear_quality jSetLQuality -#define jpeg_add_quant_table jAddQuantTable -#define jpeg_quality_scaling jQualityScaling -#define jpeg_simple_progression jSimProgress -#define jpeg_suppress_tables jSuppressTables -#define jpeg_alloc_quant_table jAlcQTable -#define jpeg_alloc_huff_table jAlcHTable -#define jpeg_start_compress jStrtCompress -#define jpeg_write_scanlines jWrtScanlines -#define jpeg_finish_compress jFinCompress -#define jpeg_write_raw_data jWrtRawData -#define jpeg_write_marker jWrtMarker -#define jpeg_write_m_header jWrtMHeader -#define jpeg_write_m_byte jWrtMByte -#define jpeg_write_tables jWrtTables -#define jpeg_read_header jReadHeader -#define jpeg_start_decompress jStrtDecompress -#define jpeg_read_scanlines jReadScanlines -#define jpeg_finish_decompress jFinDecompress -#define jpeg_read_raw_data jReadRawData -#define jpeg_has_multiple_scans jHasMultScn -#define jpeg_start_output jStrtOutput -#define jpeg_finish_output jFinOutput -#define jpeg_input_complete jInComplete -#define jpeg_new_colormap jNewCMap -#define jpeg_consume_input jConsumeInput -#define jpeg_calc_output_dimensions jCalcDimensions -#define jpeg_save_markers jSaveMarkers -#define jpeg_set_marker_processor jSetMarker -#define jpeg_read_coefficients jReadCoefs -#define jpeg_write_coefficients jWrtCoefs -#define jpeg_copy_critical_parameters jCopyCrit -#define jpeg_abort_compress jAbrtCompress -#define jpeg_abort_decompress jAbrtDecompress -#define jpeg_abort jAbort -#define jpeg_destroy jDestroy -#define jpeg_resync_to_restart jResyncRestart -#endif /* NEED_SHORT_EXTERNAL_NAMES */ - - -/* Default error-management setup */ -EXTERN(struct jpeg_error_mgr *) jpeg_std_error - JPP((struct jpeg_error_mgr * err)); - -/* Initialization of JPEG compression objects. - * jpeg_create_compress() and jpeg_create_decompress() are the exported - * names that applications should call. These expand to calls on - * jpeg_CreateCompress and jpeg_CreateDecompress with additional information - * passed for version mismatch checking. - * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. - */ -#define jpeg_create_compress(cinfo) \ - jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ - (size_t) sizeof(struct jpeg_compress_struct)) -#define jpeg_create_decompress(cinfo) \ - jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ - (size_t) sizeof(struct jpeg_decompress_struct)) -EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, - int version, size_t structsize)); -EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, - int version, size_t structsize)); -/* Destruction of JPEG compression objects */ -EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); -EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); - -/* Standard data source and destination managers: stdio streams. */ -/* Caller is responsible for opening the file before and closing after. */ -EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); -EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); - -/* Default parameter setup for compression */ -EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); -/* Compression parameter setup aids */ -EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, - J_COLOR_SPACE colorspace)); -EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); -EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, - boolean force_baseline)); -EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, - int scale_factor, - boolean force_baseline)); -EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, - const unsigned int *basic_table, - int scale_factor, - boolean force_baseline)); -EXTERN(int) jpeg_quality_scaling JPP((int quality)); -EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); -EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, - boolean suppress)); -EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); -EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); - -/* Main entry points for compression */ -EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, - boolean write_all_tables)); -EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, - JSAMPARRAY scanlines, - JDIMENSION num_lines)); -EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); - -/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ -EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, - JSAMPIMAGE data, - JDIMENSION num_lines)); - -/* Write a special marker. See libjpeg.doc concerning safe usage. */ -EXTERN(void) jpeg_write_marker - JPP((j_compress_ptr cinfo, int marker, - const JOCTET * dataptr, unsigned int datalen)); -/* Same, but piecemeal. */ -EXTERN(void) jpeg_write_m_header - JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); -EXTERN(void) jpeg_write_m_byte - JPP((j_compress_ptr cinfo, int val)); - -/* Alternate compression function: just write an abbreviated table file */ -EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); - -/* Decompression startup: read start of JPEG datastream to see what's there */ -EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, - boolean require_image)); -/* Return value is one of: */ -#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ -#define JPEG_HEADER_OK 1 /* Found valid image datastream */ -#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ -/* If you pass require_image = TRUE (normal case), you need not check for - * a TABLES_ONLY return code; an abbreviated file will cause an error exit. - * JPEG_SUSPENDED is only possible if you use a data source module that can - * give a suspension return (the stdio source module doesn't). - */ - -/* Main entry points for decompression */ -EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); -EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, - JSAMPARRAY scanlines, - JDIMENSION max_lines)); -EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); - -/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ -EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, - JSAMPIMAGE data, - JDIMENSION max_lines)); - -/* Additional entry points for buffered-image mode. */ -EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); -EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, - int scan_number)); -EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); -EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); -EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); -EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); -/* Return value is one of: */ -/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ -#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ -#define JPEG_REACHED_EOI 2 /* Reached end of image */ -#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ -#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ - -/* Precalculate output dimensions for current decompression parameters. */ -EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); - -/* Control saving of COM and APPn markers into marker_list. */ -EXTERN(void) jpeg_save_markers - JPP((j_decompress_ptr cinfo, int marker_code, - unsigned int length_limit)); - -/* Install a special processing method for COM or APPn markers. */ -EXTERN(void) jpeg_set_marker_processor - JPP((j_decompress_ptr cinfo, int marker_code, - jpeg_marker_parser_method routine)); - -/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ -EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); -EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, - jvirt_barray_ptr * coef_arrays)); -EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, - j_compress_ptr dstinfo)); - -/* If you choose to abort compression or decompression before completing - * jpeg_finish_(de)compress, then you need to clean up to release memory, - * temporary files, etc. You can just call jpeg_destroy_(de)compress - * if you're done with the JPEG object, but if you want to clean it up and - * reuse it, call this: - */ -EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); -EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); - -/* Generic versions of jpeg_abort and jpeg_destroy that work on either - * flavor of JPEG object. These may be more convenient in some places. - */ -EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); -EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); - -/* Default restart-marker-resync procedure for use by data source modules */ -EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, - int desired)); - - -/* These marker codes are exported since applications and data source modules - * are likely to want to use them. - */ - -#define JPEG_RST0 0xD0 /* RST0 marker code */ -#define JPEG_EOI 0xD9 /* EOI marker code */ -#define JPEG_APP0 0xE0 /* APP0 marker code */ -#define JPEG_COM 0xFE /* COM marker code */ - - -/* If we have a brain-damaged compiler that emits warnings (or worse, errors) - * for structure definitions that are never filled in, keep it quiet by - * supplying dummy definitions for the various substructures. - */ - -#ifdef INCOMPLETE_TYPES_BROKEN -#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ -struct jvirt_sarray_control { long dummy; }; -struct jvirt_barray_control { long dummy; }; -struct jpeg_comp_master { long dummy; }; -struct jpeg_c_main_controller { long dummy; }; -struct jpeg_c_prep_controller { long dummy; }; -struct jpeg_c_coef_controller { long dummy; }; -struct jpeg_marker_writer { long dummy; }; -struct jpeg_color_converter { long dummy; }; -struct jpeg_downsampler { long dummy; }; -struct jpeg_forward_dct { long dummy; }; -struct jpeg_entropy_encoder { long dummy; }; -struct jpeg_decomp_master { long dummy; }; -struct jpeg_d_main_controller { long dummy; }; -struct jpeg_d_coef_controller { long dummy; }; -struct jpeg_d_post_controller { long dummy; }; -struct jpeg_input_controller { long dummy; }; -struct jpeg_marker_reader { long dummy; }; -struct jpeg_entropy_decoder { long dummy; }; -struct jpeg_inverse_dct { long dummy; }; -struct jpeg_upsampler { long dummy; }; -struct jpeg_color_deconverter { long dummy; }; -struct jpeg_color_quantizer { long dummy; }; -#endif /* JPEG_INTERNALS */ -#endif /* INCOMPLETE_TYPES_BROKEN */ - - -/* - * The JPEG library modules define JPEG_INTERNALS before including this file. - * The internal structure declarations are read only when that is true. - * Applications using the library should not include jpegint.h, but may wish - * to include jerror.h. - */ - -#ifdef JPEG_INTERNALS -#include "jpegint.h" /* fetch private declarations */ -#include "jerror.h" /* fetch error codes too */ -#endif - -#endif /* JPEGLIB_H */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jquant1.c b/source/modules/juce_graphics/image_formats/jpglib/jquant1.c deleted file mode 100644 index 65f488237..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jquant1.c +++ /dev/null @@ -1,856 +0,0 @@ -/* - * jquant1.c - * - * Copyright (C) 1991-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains 1-pass color quantization (color mapping) routines. - * These routines provide mapping to a fixed color map using equally spaced - * color values. Optional Floyd-Steinberg or ordered dithering is available. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - -#ifdef QUANT_1PASS_SUPPORTED - - -/* - * The main purpose of 1-pass quantization is to provide a fast, if not very - * high quality, colormapped output capability. A 2-pass quantizer usually - * gives better visual quality; however, for quantized grayscale output this - * quantizer is perfectly adequate. Dithering is highly recommended with this - * quantizer, though you can turn it off if you really want to. - * - * In 1-pass quantization the colormap must be chosen in advance of seeing the - * image. We use a map consisting of all combinations of Ncolors[i] color - * values for the i'th component. The Ncolors[] values are chosen so that - * their product, the total number of colors, is no more than that requested. - * (In most cases, the product will be somewhat less.) - * - * Since the colormap is orthogonal, the representative value for each color - * component can be determined without considering the other components; - * then these indexes can be combined into a colormap index by a standard - * N-dimensional-array-subscript calculation. Most of the arithmetic involved - * can be precalculated and stored in the lookup table colorindex[]. - * colorindex[i][j] maps pixel value j in component i to the nearest - * representative value (grid plane) for that component; this index is - * multiplied by the array stride for component i, so that the - * index of the colormap entry closest to a given pixel value is just - * sum( colorindex[component-number][pixel-component-value] ) - * Aside from being fast, this scheme allows for variable spacing between - * representative values with no additional lookup cost. - * - * If gamma correction has been applied in color conversion, it might be wise - * to adjust the color grid spacing so that the representative colors are - * equidistant in linear space. At this writing, gamma correction is not - * implemented by jdcolor, so nothing is done here. - */ - - -/* Declarations for ordered dithering. - * - * We use a standard 16x16 ordered dither array. The basic concept of ordered - * dithering is described in many references, for instance Dale Schumacher's - * chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991). - * In place of Schumacher's comparisons against a "threshold" value, we add a - * "dither" value to the input pixel and then round the result to the nearest - * output value. The dither value is equivalent to (0.5 - threshold) times - * the distance between output values. For ordered dithering, we assume that - * the output colors are equally spaced; if not, results will probably be - * worse, since the dither may be too much or too little at a given point. - * - * The normal calculation would be to form pixel value + dither, range-limit - * this to 0..MAXJSAMPLE, and then index into the colorindex table as usual. - * We can skip the separate range-limiting step by extending the colorindex - * table in both directions. - */ - -#define ODITHER_SIZE 16 /* dimension of dither matrix */ -/* NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break */ -#define ODITHER_CELLS (ODITHER_SIZE*ODITHER_SIZE) /* # cells in matrix */ -#define ODITHER_MASK (ODITHER_SIZE-1) /* mask for wrapping around counters */ - -typedef int ODITHER_MATRIX[ODITHER_SIZE][ODITHER_SIZE]; -typedef int (*ODITHER_MATRIX_PTR)[ODITHER_SIZE]; - -static const UINT8 base_dither_matrix[ODITHER_SIZE][ODITHER_SIZE] = { - /* Bayer's order-4 dither array. Generated by the code given in - * Stephen Hawley's article "Ordered Dithering" in Graphics Gems I. - * The values in this array must range from 0 to ODITHER_CELLS-1. - */ - { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, - { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, - { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, - { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 }, - { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 }, - { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 }, - { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 }, - { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 }, - { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 }, - { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 }, - { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 }, - { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 }, - { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 }, - { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 }, - { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 }, - { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 } -}; - - -/* Declarations for Floyd-Steinberg dithering. - * - * Errors are accumulated into the array fserrors[], at a resolution of - * 1/16th of a pixel count. The error at a given pixel is propagated - * to its not-yet-processed neighbors using the standard F-S fractions, - * ... (here) 7/16 - * 3/16 5/16 1/16 - * We work left-to-right on even rows, right-to-left on odd rows. - * - * We can get away with a single array (holding one row's worth of errors) - * by using it to store the current row's errors at pixel columns not yet - * processed, but the next row's errors at columns already processed. We - * need only a few extra variables to hold the errors immediately around the - * current column. (If we are lucky, those variables are in registers, but - * even if not, they're probably cheaper to access than array elements are.) - * - * The fserrors[] array is indexed [component#][position]. - * We provide (#columns + 2) entries per component; the extra entry at each - * end saves us from special-casing the first and last pixels. - * - * Note: on a wide image, we might not have enough room in a PC's near data - * segment to hold the error array; so it is allocated with alloc_large. - */ - -#if BITS_IN_JSAMPLE == 8 -typedef INT16 FSERROR; /* 16 bits should be enough */ -typedef int LOCFSERROR; /* use 'int' for calculation temps */ -#else -typedef INT32 FSERROR; /* may need more than 16 bits */ -typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */ -#endif - -typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */ - - -/* Private subobject */ - -#define MAX_Q_COMPS 4 /* max components I can handle */ - -typedef struct { - struct jpeg_color_quantizer pub; /* public fields */ - - /* Initially allocated colormap is saved here */ - JSAMPARRAY sv_colormap; /* The color map as a 2-D pixel array */ - int sv_actual; /* number of entries in use */ - - JSAMPARRAY colorindex; /* Precomputed mapping for speed */ - /* colorindex[i][j] = index of color closest to pixel value j in component i, - * premultiplied as described above. Since colormap indexes must fit into - * JSAMPLEs, the entries of this array will too. - */ - boolean is_padded; /* is the colorindex padded for odither? */ - - int Ncolors[MAX_Q_COMPS]; /* # of values alloced to each component */ - - /* Variables for ordered dithering */ - int row_index; /* cur row's vertical index in dither matrix */ - ODITHER_MATRIX_PTR odither[MAX_Q_COMPS]; /* one dither array per component */ - - /* Variables for Floyd-Steinberg dithering */ - FSERRPTR fserrors[MAX_Q_COMPS]; /* accumulated errors */ - boolean on_odd_row; /* flag to remember which row we are on */ -} my_cquantizer; - -typedef my_cquantizer * my_cquantize_ptr; - - -/* - * Policy-making subroutines for create_colormap and create_colorindex. - * These routines determine the colormap to be used. The rest of the module - * only assumes that the colormap is orthogonal. - * - * * select_ncolors decides how to divvy up the available colors - * among the components. - * * output_value defines the set of representative values for a component. - * * largest_input_value defines the mapping from input values to - * representative values for a component. - * Note that the latter two routines may impose different policies for - * different components, though this is not currently done. - */ - - -LOCAL(int) -select_ncolors (j_decompress_ptr cinfo, int Ncolors[]) -/* Determine allocation of desired colors to components, */ -/* and fill in Ncolors[] array to indicate choice. */ -/* Return value is total number of colors (product of Ncolors[] values). */ -{ - int nc = cinfo->out_color_components; /* number of color components */ - int max_colors = cinfo->desired_number_of_colors; - int total_colors, iroot, i, j; - boolean changed; - long temp; - static const int RGB_order[3] = { RGB_GREEN, RGB_RED, RGB_BLUE }; - - /* We can allocate at least the nc'th root of max_colors per component. */ - /* Compute floor(nc'th root of max_colors). */ - iroot = 1; - do { - iroot++; - temp = iroot; /* set temp = iroot ** nc */ - for (i = 1; i < nc; i++) - temp *= iroot; - } while (temp <= (long) max_colors); /* repeat till iroot exceeds root */ - iroot--; /* now iroot = floor(root) */ - - /* Must have at least 2 color values per component */ - if (iroot < 2) - ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, (int) temp); - - /* Initialize to iroot color values for each component */ - total_colors = 1; - for (i = 0; i < nc; i++) { - Ncolors[i] = iroot; - total_colors *= iroot; - } - /* We may be able to increment the count for one or more components without - * exceeding max_colors, though we know not all can be incremented. - * Sometimes, the first component can be incremented more than once! - * (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.) - * In RGB colorspace, try to increment G first, then R, then B. - */ - do { - changed = FALSE; - for (i = 0; i < nc; i++) { - j = (cinfo->out_color_space == JCS_RGB ? RGB_order[i] : i); - /* calculate new total_colors if Ncolors[j] is incremented */ - temp = total_colors / Ncolors[j]; - temp *= Ncolors[j]+1; /* done in long arith to avoid oflo */ - if (temp > (long) max_colors) - break; /* won't fit, done with this pass */ - Ncolors[j]++; /* OK, apply the increment */ - total_colors = (int) temp; - changed = TRUE; - } - } while (changed); - - return total_colors; -} - - -LOCAL(int) -output_value (j_decompress_ptr, int, int j, int maxj) -/* Return j'th output value, where j will range from 0 to maxj */ -/* The output values must fall in 0..MAXJSAMPLE in increasing order */ -{ - /* We always provide values 0 and MAXJSAMPLE for each component; - * any additional values are equally spaced between these limits. - * (Forcing the upper and lower values to the limits ensures that - * dithering can't produce a color outside the selected gamut.) - */ - return (int) (((INT32) j * MAXJSAMPLE + maxj/2) / maxj); -} - - -LOCAL(int) -largest_input_value (j_decompress_ptr, int, int j, int maxj) -/* Return largest input value that should map to j'th output value */ -/* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */ -{ - /* Breakpoints are halfway between values returned by output_value */ - return (int) (((INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj)); -} - - -/* - * Create the colormap. - */ - -LOCAL(void) -create_colormap (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - JSAMPARRAY colormap; /* Created colormap */ - int total_colors; /* Number of distinct output colors */ - int i,j,k, nci, blksize, blkdist, ptr, val; - - /* Select number of colors for each component */ - total_colors = select_ncolors(cinfo, cquantize->Ncolors); - - /* Report selected color counts */ - if (cinfo->out_color_components == 3) - TRACEMS4(cinfo, 1, JTRC_QUANT_3_NCOLORS, - total_colors, cquantize->Ncolors[0], - cquantize->Ncolors[1], cquantize->Ncolors[2]); - else - TRACEMS1(cinfo, 1, JTRC_QUANT_NCOLORS, total_colors); - - /* Allocate and fill in the colormap. */ - /* The colors are ordered in the map in standard row-major order, */ - /* i.e. rightmost (highest-indexed) color changes most rapidly. */ - - colormap = (*cinfo->mem->alloc_sarray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - (JDIMENSION) total_colors, (JDIMENSION) cinfo->out_color_components); - - /* blksize is number of adjacent repeated entries for a component */ - /* blkdist is distance between groups of identical entries for a component */ - blkdist = total_colors; - - for (i = 0; i < cinfo->out_color_components; i++) { - /* fill in colormap entries for i'th color component */ - nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ - blksize = blkdist / nci; - for (j = 0; j < nci; j++) { - /* Compute j'th output value (out of nci) for component */ - val = output_value(cinfo, i, j, nci-1); - /* Fill in all colormap entries that have this value of this component */ - for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) { - /* fill in blksize entries beginning at ptr */ - for (k = 0; k < blksize; k++) - colormap[i][ptr+k] = (JSAMPLE) val; - } - } - blkdist = blksize; /* blksize of this color is blkdist of next */ - } - - /* Save the colormap in private storage, - * where it will survive color quantization mode changes. - */ - cquantize->sv_colormap = colormap; - cquantize->sv_actual = total_colors; -} - - -/* - * Create the color index table. - */ - -LOCAL(void) -create_colorindex (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - JSAMPROW indexptr; - int i,j,k, nci, blksize, val, pad; - - /* For ordered dither, we pad the color index tables by MAXJSAMPLE in - * each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE). - * This is not necessary in the other dithering modes. However, we - * flag whether it was done in case user changes dithering mode. - */ - if (cinfo->dither_mode == JDITHER_ORDERED) { - pad = MAXJSAMPLE*2; - cquantize->is_padded = TRUE; - } else { - pad = 0; - cquantize->is_padded = FALSE; - } - - cquantize->colorindex = (*cinfo->mem->alloc_sarray) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - (JDIMENSION) (MAXJSAMPLE+1 + pad), - (JDIMENSION) cinfo->out_color_components); - - /* blksize is number of adjacent repeated entries for a component */ - blksize = cquantize->sv_actual; - - for (i = 0; i < cinfo->out_color_components; i++) { - /* fill in colorindex entries for i'th color component */ - nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ - blksize = blksize / nci; - - /* adjust colorindex pointers to provide padding at negative indexes. */ - if (pad) - cquantize->colorindex[i] += MAXJSAMPLE; - - /* in loop, val = index of current output value, */ - /* and k = largest j that maps to current val */ - indexptr = cquantize->colorindex[i]; - val = 0; - k = largest_input_value(cinfo, i, 0, nci-1); - for (j = 0; j <= MAXJSAMPLE; j++) { - while (j > k) /* advance val if past boundary */ - k = largest_input_value(cinfo, i, ++val, nci-1); - /* premultiply so that no multiplication needed in main processing */ - indexptr[j] = (JSAMPLE) (val * blksize); - } - /* Pad at both ends if necessary */ - if (pad) - for (j = 1; j <= MAXJSAMPLE; j++) { - indexptr[-j] = indexptr[0]; - indexptr[MAXJSAMPLE+j] = indexptr[MAXJSAMPLE]; - } - } -} - - -/* - * Create an ordered-dither array for a component having ncolors - * distinct output values. - */ - -LOCAL(ODITHER_MATRIX_PTR) -make_odither_array (j_decompress_ptr cinfo, int ncolors) -{ - ODITHER_MATRIX_PTR odither; - int j,k; - INT32 num,den; - - odither = (ODITHER_MATRIX_PTR) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(ODITHER_MATRIX)); - /* The inter-value distance for this color is MAXJSAMPLE/(ncolors-1). - * Hence the dither value for the matrix cell with fill order f - * (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1). - * On 16-bit-int machine, be careful to avoid overflow. - */ - den = 2 * ODITHER_CELLS * ((INT32) (ncolors - 1)); - for (j = 0; j < ODITHER_SIZE; j++) { - for (k = 0; k < ODITHER_SIZE; k++) { - num = ((INT32) (ODITHER_CELLS-1 - 2*((int)base_dither_matrix[j][k]))) - * MAXJSAMPLE; - /* Ensure round towards zero despite C's lack of consistency - * about rounding negative values in integer division... - */ - odither[j][k] = (int) (num<0 ? -((-num)/den) : num/den); - } - } - return odither; -} - - -/* - * Create the ordered-dither tables. - * Components having the same number of representative colors may - * share a dither table. - */ - -LOCAL(void) -create_odither_tables (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - ODITHER_MATRIX_PTR odither; - int i, j, nci; - - for (i = 0; i < cinfo->out_color_components; i++) { - nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ - odither = NULL; /* search for matching prior component */ - for (j = 0; j < i; j++) { - if (nci == cquantize->Ncolors[j]) { - odither = cquantize->odither[j]; - break; - } - } - if (odither == NULL) /* need a new table? */ - odither = make_odither_array(cinfo, nci); - cquantize->odither[i] = odither; - } -} - - -/* - * Map some rows of pixels to the output colormapped representation. - */ - -METHODDEF(void) -color_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf, - JSAMPARRAY output_buf, int num_rows) -/* General case, no dithering */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - JSAMPARRAY colorindex = cquantize->colorindex; - int pixcode, ci; - JSAMPROW ptrin, ptrout; - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - int nc = cinfo->out_color_components; - - for (row = 0; row < num_rows; row++) { - ptrin = input_buf[row]; - ptrout = output_buf[row]; - for (col = width; col > 0; col--) { - pixcode = 0; - for (ci = 0; ci < nc; ci++) { - pixcode += GETJSAMPLE(colorindex[ci][GETJSAMPLE(*ptrin++)]); - } - *ptrout++ = (JSAMPLE) pixcode; - } - } -} - - -METHODDEF(void) -color_quantize3 (j_decompress_ptr cinfo, JSAMPARRAY input_buf, - JSAMPARRAY output_buf, int num_rows) -/* Fast path for out_color_components==3, no dithering */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - int pixcode; - JSAMPROW ptrin, ptrout; - JSAMPROW colorindex0 = cquantize->colorindex[0]; - JSAMPROW colorindex1 = cquantize->colorindex[1]; - JSAMPROW colorindex2 = cquantize->colorindex[2]; - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - - for (row = 0; row < num_rows; row++) { - ptrin = input_buf[row]; - ptrout = output_buf[row]; - for (col = width; col > 0; col--) { - pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*ptrin++)]); - pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*ptrin++)]); - pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*ptrin++)]); - *ptrout++ = (JSAMPLE) pixcode; - } - } -} - - -METHODDEF(void) -quantize_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, - JSAMPARRAY output_buf, int num_rows) -/* General case, with ordered dithering */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - JSAMPROW input_ptr; - JSAMPROW output_ptr; - JSAMPROW colorindex_ci; - int * dither; /* points to active row of dither matrix */ - int row_index, col_index; /* current indexes into dither matrix */ - int nc = cinfo->out_color_components; - int ci; - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - - for (row = 0; row < num_rows; row++) { - /* Initialize output values to 0 so can process components separately */ - jzero_far((void FAR *) output_buf[row], - (size_t) (width * SIZEOF(JSAMPLE))); - row_index = cquantize->row_index; - for (ci = 0; ci < nc; ci++) { - input_ptr = input_buf[row] + ci; - output_ptr = output_buf[row]; - colorindex_ci = cquantize->colorindex[ci]; - dither = cquantize->odither[ci][row_index]; - col_index = 0; - - for (col = width; col > 0; col--) { - /* Form pixel value + dither, range-limit to 0..MAXJSAMPLE, - * select output value, accumulate into output code for this pixel. - * Range-limiting need not be done explicitly, as we have extended - * the colorindex table to produce the right answers for out-of-range - * inputs. The maximum dither is +- MAXJSAMPLE; this sets the - * required amount of padding. - */ - *output_ptr += colorindex_ci[GETJSAMPLE(*input_ptr)+dither[col_index]]; - input_ptr += nc; - output_ptr++; - col_index = (col_index + 1) & ODITHER_MASK; - } - } - /* Advance row index for next row */ - row_index = (row_index + 1) & ODITHER_MASK; - cquantize->row_index = row_index; - } -} - - -METHODDEF(void) -quantize3_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, - JSAMPARRAY output_buf, int num_rows) -/* Fast path for out_color_components==3, with ordered dithering */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - int pixcode; - JSAMPROW input_ptr; - JSAMPROW output_ptr; - JSAMPROW colorindex0 = cquantize->colorindex[0]; - JSAMPROW colorindex1 = cquantize->colorindex[1]; - JSAMPROW colorindex2 = cquantize->colorindex[2]; - int * dither0; /* points to active row of dither matrix */ - int * dither1; - int * dither2; - int row_index, col_index; /* current indexes into dither matrix */ - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - - for (row = 0; row < num_rows; row++) { - row_index = cquantize->row_index; - input_ptr = input_buf[row]; - output_ptr = output_buf[row]; - dither0 = cquantize->odither[0][row_index]; - dither1 = cquantize->odither[1][row_index]; - dither2 = cquantize->odither[2][row_index]; - col_index = 0; - - for (col = width; col > 0; col--) { - pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*input_ptr++) + - dither0[col_index]]); - pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*input_ptr++) + - dither1[col_index]]); - pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*input_ptr++) + - dither2[col_index]]); - *output_ptr++ = (JSAMPLE) pixcode; - col_index = (col_index + 1) & ODITHER_MASK; - } - row_index = (row_index + 1) & ODITHER_MASK; - cquantize->row_index = row_index; - } -} - - -METHODDEF(void) -quantize_fs_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, - JSAMPARRAY output_buf, int num_rows) -/* General case, with Floyd-Steinberg dithering */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - LOCFSERROR cur; /* current error or pixel value */ - LOCFSERROR belowerr; /* error for pixel below cur */ - LOCFSERROR bpreverr; /* error for below/prev col */ - LOCFSERROR bnexterr; /* error for below/next col */ - LOCFSERROR delta; - FSERRPTR errorptr; /* => fserrors[] at column before current */ - JSAMPROW input_ptr; - JSAMPROW output_ptr; - JSAMPROW colorindex_ci; - JSAMPROW colormap_ci; - int pixcode; - int nc = cinfo->out_color_components; - int dir; /* 1 for left-to-right, -1 for right-to-left */ - int dirnc; /* dir * nc */ - int ci; - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - JSAMPLE *range_limit = cinfo->sample_range_limit; - SHIFT_TEMPS - - for (row = 0; row < num_rows; row++) { - /* Initialize output values to 0 so can process components separately */ - jzero_far((void FAR *) output_buf[row], - (size_t) (width * SIZEOF(JSAMPLE))); - for (ci = 0; ci < nc; ci++) { - input_ptr = input_buf[row] + ci; - output_ptr = output_buf[row]; - if (cquantize->on_odd_row) { - /* work right to left in this row */ - input_ptr += (width-1) * nc; /* so point to rightmost pixel */ - output_ptr += width-1; - dir = -1; - dirnc = -nc; - errorptr = cquantize->fserrors[ci] + (width+1); /* => entry after last column */ - } else { - /* work left to right in this row */ - dir = 1; - dirnc = nc; - errorptr = cquantize->fserrors[ci]; /* => entry before first column */ - } - colorindex_ci = cquantize->colorindex[ci]; - colormap_ci = cquantize->sv_colormap[ci]; - /* Preset error values: no error propagated to first pixel from left */ - cur = 0; - /* and no error propagated to row below yet */ - belowerr = bpreverr = 0; - - for (col = width; col > 0; col--) { - /* cur holds the error propagated from the previous pixel on the - * current line. Add the error propagated from the previous line - * to form the complete error correction term for this pixel, and - * round the error term (which is expressed * 16) to an integer. - * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct - * for either sign of the error value. - * Note: errorptr points to *previous* column's array entry. - */ - cur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4); - /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. - * The maximum error is +- MAXJSAMPLE; this sets the required size - * of the range_limit array. - */ - cur += GETJSAMPLE(*input_ptr); - cur = GETJSAMPLE(range_limit[cur]); - /* Select output value, accumulate into output code for this pixel */ - pixcode = GETJSAMPLE(colorindex_ci[cur]); - *output_ptr += (JSAMPLE) pixcode; - /* Compute actual representation error at this pixel */ - /* Note: we can do this even though we don't have the final */ - /* pixel code, because the colormap is orthogonal. */ - cur -= GETJSAMPLE(colormap_ci[pixcode]); - /* Compute error fractions to be propagated to adjacent pixels. - * Add these into the running sums, and simultaneously shift the - * next-line error sums left by 1 column. - */ - bnexterr = cur; - delta = cur * 2; - cur += delta; /* form error * 3 */ - errorptr[0] = (FSERROR) (bpreverr + cur); - cur += delta; /* form error * 5 */ - bpreverr = belowerr + cur; - belowerr = bnexterr; - cur += delta; /* form error * 7 */ - /* At this point cur contains the 7/16 error value to be propagated - * to the next pixel on the current line, and all the errors for the - * next line have been shifted over. We are therefore ready to move on. - */ - input_ptr += dirnc; /* advance input ptr to next column */ - output_ptr += dir; /* advance output ptr to next column */ - errorptr += dir; /* advance errorptr to current column */ - } - /* Post-loop cleanup: we must unload the final error value into the - * final fserrors[] entry. Note we need not unload belowerr because - * it is for the dummy column before or after the actual array. - */ - errorptr[0] = (FSERROR) bpreverr; /* unload prev err into array */ - } - cquantize->on_odd_row = (cquantize->on_odd_row ? FALSE : TRUE); - } -} - - -/* - * Allocate workspace for Floyd-Steinberg errors. - */ - -LOCAL(void) -alloc_fs_workspace (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - size_t arraysize; - int i; - - arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR)); - for (i = 0; i < cinfo->out_color_components; i++) { - cquantize->fserrors[i] = (FSERRPTR) - (*cinfo->mem->alloc_large)((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); - } -} - - -/* - * Initialize for one-pass color quantization. - */ - -METHODDEF(void) -start_pass_1_quant (j_decompress_ptr cinfo, boolean) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - size_t arraysize; - int i; - - /* Install my colormap. */ - cinfo->colormap = cquantize->sv_colormap; - cinfo->actual_number_of_colors = cquantize->sv_actual; - - /* Initialize for desired dithering mode. */ - switch (cinfo->dither_mode) { - case JDITHER_NONE: - if (cinfo->out_color_components == 3) - cquantize->pub.color_quantize = color_quantize3; - else - cquantize->pub.color_quantize = color_quantize; - break; - case JDITHER_ORDERED: - if (cinfo->out_color_components == 3) - cquantize->pub.color_quantize = quantize3_ord_dither; - else - cquantize->pub.color_quantize = quantize_ord_dither; - cquantize->row_index = 0; /* initialize state for ordered dither */ - /* If user changed to ordered dither from another mode, - * we must recreate the color index table with padding. - * This will cost extra space, but probably isn't very likely. - */ - if (! cquantize->is_padded) - create_colorindex(cinfo); - /* Create ordered-dither tables if we didn't already. */ - if (cquantize->odither[0] == NULL) - create_odither_tables(cinfo); - break; - case JDITHER_FS: - cquantize->pub.color_quantize = quantize_fs_dither; - cquantize->on_odd_row = FALSE; /* initialize state for F-S dither */ - /* Allocate Floyd-Steinberg workspace if didn't already. */ - if (cquantize->fserrors[0] == NULL) - alloc_fs_workspace(cinfo); - /* Initialize the propagated errors to zero. */ - arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR)); - for (i = 0; i < cinfo->out_color_components; i++) - jzero_far((void FAR *) cquantize->fserrors[i], arraysize); - break; - default: - ERREXIT(cinfo, JERR_NOT_COMPILED); - break; - } -} - - -/* - * Finish up at the end of the pass. - */ - -METHODDEF(void) -finish_pass_1_quant (j_decompress_ptr) -{ - /* no work in 1-pass case */ -} - - -/* - * Switch to a new external colormap between output passes. - * Shouldn't get to this module! - */ - -METHODDEF(void) -new_color_map_1_quant (j_decompress_ptr cinfo) -{ - ERREXIT(cinfo, JERR_MODE_CHANGE); -} - - -/* - * Module initialization routine for 1-pass color quantization. - */ - -GLOBAL(void) -jinit_1pass_quantizer (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize; - - cquantize = (my_cquantize_ptr) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_cquantizer)); - cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize; - cquantize->pub.start_pass = start_pass_1_quant; - cquantize->pub.finish_pass = finish_pass_1_quant; - cquantize->pub.new_color_map = new_color_map_1_quant; - cquantize->fserrors[0] = NULL; /* Flag FS workspace not allocated */ - cquantize->odither[0] = NULL; /* Also flag odither arrays not allocated */ - - /* Make sure my internal arrays won't overflow */ - if (cinfo->out_color_components > MAX_Q_COMPS) - ERREXIT1(cinfo, JERR_QUANT_COMPONENTS, MAX_Q_COMPS); - /* Make sure colormap indexes can be represented by JSAMPLEs */ - if (cinfo->desired_number_of_colors > (MAXJSAMPLE+1)) - ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1); - - /* Create the colormap and color index table. */ - create_colormap(cinfo); - create_colorindex(cinfo); - - /* Allocate Floyd-Steinberg workspace now if requested. - * We do this now since it is FAR storage and may affect the memory - * manager's space calculations. If the user changes to FS dither - * mode in a later pass, we will allocate the space then, and will - * possibly overrun the max_memory_to_use setting. - */ - if (cinfo->dither_mode == JDITHER_FS) - alloc_fs_workspace(cinfo); -} - -#endif /* QUANT_1PASS_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jquant2.c b/source/modules/juce_graphics/image_formats/jpglib/jquant2.c deleted file mode 100644 index 8f50d536a..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jquant2.c +++ /dev/null @@ -1,1310 +0,0 @@ -/* - * jquant2.c - * - * Copyright (C) 1991-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains 2-pass color quantization (color mapping) routines. - * These routines provide selection of a custom color map for an image, - * followed by mapping of the image to that color map, with optional - * Floyd-Steinberg dithering. - * It is also possible to use just the second pass to map to an arbitrary - * externally-given color map. - * - * Note: ordered dithering is not supported, since there isn't any fast - * way to compute intercolor distances; it's unclear that ordered dither's - * fundamental assumptions even hold with an irregularly spaced color map. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - -#ifdef QUANT_2PASS_SUPPORTED - - -/* - * This module implements the well-known Heckbert paradigm for color - * quantization. Most of the ideas used here can be traced back to - * Heckbert's seminal paper - * Heckbert, Paul. "Color Image Quantization for Frame Buffer Display", - * Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304. - * - * In the first pass over the image, we accumulate a histogram showing the - * usage count of each possible color. To keep the histogram to a reasonable - * size, we reduce the precision of the input; typical practice is to retain - * 5 or 6 bits per color, so that 8 or 4 different input values are counted - * in the same histogram cell. - * - * Next, the color-selection step begins with a box representing the whole - * color space, and repeatedly splits the "largest" remaining box until we - * have as many boxes as desired colors. Then the mean color in each - * remaining box becomes one of the possible output colors. - * - * The second pass over the image maps each input pixel to the closest output - * color (optionally after applying a Floyd-Steinberg dithering correction). - * This mapping is logically trivial, but making it go fast enough requires - * considerable care. - * - * Heckbert-style quantizers vary a good deal in their policies for choosing - * the "largest" box and deciding where to cut it. The particular policies - * used here have proved out well in experimental comparisons, but better ones - * may yet be found. - * - * In earlier versions of the IJG code, this module quantized in YCbCr color - * space, processing the raw upsampled data without a color conversion step. - * This allowed the color conversion math to be done only once per colormap - * entry, not once per pixel. However, that optimization precluded other - * useful optimizations (such as merging color conversion with upsampling) - * and it also interfered with desired capabilities such as quantizing to an - * externally-supplied colormap. We have therefore abandoned that approach. - * The present code works in the post-conversion color space, typically RGB. - * - * To improve the visual quality of the results, we actually work in scaled - * RGB space, giving G distances more weight than R, and R in turn more than - * B. To do everything in integer math, we must use integer scale factors. - * The 2/3/1 scale factors used here correspond loosely to the relative - * weights of the colors in the NTSC grayscale equation. - * If you want to use this code to quantize a non-RGB color space, you'll - * probably need to change these scale factors. - */ - -#define R_SCALE 2 /* scale R distances by this much */ -#define G_SCALE 3 /* scale G distances by this much */ -#define B_SCALE 1 /* and B by this much */ - -/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined - * in jmorecfg.h. As the code stands, it will do the right thing for R,G,B - * and B,G,R orders. If you define some other weird order in jmorecfg.h, - * you'll get compile errors until you extend this logic. In that case - * you'll probably want to tweak the histogram sizes too. - */ - -#if RGB_RED == 0 -#define C0_SCALE R_SCALE -#endif -#if RGB_BLUE == 0 -#define C0_SCALE B_SCALE -#endif -#if RGB_GREEN == 1 -#define C1_SCALE G_SCALE -#endif -#if RGB_RED == 2 -#define C2_SCALE R_SCALE -#endif -#if RGB_BLUE == 2 -#define C2_SCALE B_SCALE -#endif - - -/* - * First we have the histogram data structure and routines for creating it. - * - * The number of bits of precision can be adjusted by changing these symbols. - * We recommend keeping 6 bits for G and 5 each for R and B. - * If you have plenty of memory and cycles, 6 bits all around gives marginally - * better results; if you are short of memory, 5 bits all around will save - * some space but degrade the results. - * To maintain a fully accurate histogram, we'd need to allocate a "long" - * (preferably unsigned long) for each cell. In practice this is overkill; - * we can get by with 16 bits per cell. Few of the cell counts will overflow, - * and clamping those that do overflow to the maximum value will give close- - * enough results. This reduces the recommended histogram size from 256Kb - * to 128Kb, which is a useful savings on PC-class machines. - * (In the second pass the histogram space is re-used for pixel mapping data; - * in that capacity, each cell must be able to store zero to the number of - * desired colors. 16 bits/cell is plenty for that too.) - * Since the JPEG code is intended to run in small memory model on 80x86 - * machines, we can't just allocate the histogram in one chunk. Instead - * of a true 3-D array, we use a row of pointers to 2-D arrays. Each - * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and - * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that - * on 80x86 machines, the pointer row is in near memory but the actual - * arrays are in far memory (same arrangement as we use for image arrays). - */ - -#define MAXNUMCOLORS (MAXJSAMPLE+1) /* maximum size of colormap */ - -/* These will do the right thing for either R,G,B or B,G,R color order, - * but you may not like the results for other color orders. - */ -#define HIST_C0_BITS 5 /* bits of precision in R/B histogram */ -#define HIST_C1_BITS 6 /* bits of precision in G histogram */ -#define HIST_C2_BITS 5 /* bits of precision in B/R histogram */ - -/* Number of elements along histogram axes. */ -#define HIST_C0_ELEMS (1<cquantize; - JSAMPROW ptr; - histptr histp; - hist3d histogram = cquantize->histogram; - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - - for (row = 0; row < num_rows; row++) { - ptr = input_buf[row]; - for (col = width; col > 0; col--) { - /* get pixel value and index into the histogram */ - histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT] - [GETJSAMPLE(ptr[1]) >> C1_SHIFT] - [GETJSAMPLE(ptr[2]) >> C2_SHIFT]; - /* increment, check for overflow and undo increment if so. */ - if (++(*histp) <= 0) - (*histp)--; - ptr += 3; - } - } -} - - -/* - * Next we have the really interesting routines: selection of a colormap - * given the completed histogram. - * These routines work with a list of "boxes", each representing a rectangular - * subset of the input color space (to histogram precision). - */ - -typedef struct { - /* The bounds of the box (inclusive); expressed as histogram indexes */ - int c0min, c0max; - int c1min, c1max; - int c2min, c2max; - /* The volume (actually 2-norm) of the box */ - INT32 volume; - /* The number of nonzero histogram cells within this box */ - long colorcount; -} box; - -typedef box * boxptr; - - -LOCAL(boxptr) -find_biggest_color_pop (boxptr boxlist, int numboxes) -/* Find the splittable box with the largest color population */ -/* Returns NULL if no splittable boxes remain */ -{ - boxptr boxp; - int i; - long maxc = 0; - boxptr which = NULL; - - for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { - if (boxp->colorcount > maxc && boxp->volume > 0) { - which = boxp; - maxc = boxp->colorcount; - } - } - return which; -} - - -LOCAL(boxptr) -find_biggest_volume (boxptr boxlist, int numboxes) -/* Find the splittable box with the largest (scaled) volume */ -/* Returns NULL if no splittable boxes remain */ -{ - boxptr boxp; - int i; - INT32 maxv = 0; - boxptr which = NULL; - - for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { - if (boxp->volume > maxv) { - which = boxp; - maxv = boxp->volume; - } - } - return which; -} - - -LOCAL(void) -update_box (j_decompress_ptr cinfo, boxptr boxp) -/* Shrink the min/max bounds of a box to enclose only nonzero elements, */ -/* and recompute its volume and population */ -{ - my_cquantize_ptr2 cquantize = (my_cquantize_ptr2) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - histptr histp; - int c0,c1,c2; - int c0min,c0max,c1min,c1max,c2min,c2max; - INT32 dist0,dist1,dist2; - long ccount; - - c0min = boxp->c0min; c0max = boxp->c0max; - c1min = boxp->c1min; c1max = boxp->c1max; - c2min = boxp->c2min; c2max = boxp->c2max; - - if (c0max > c0min) - for (c0 = c0min; c0 <= c0max; c0++) - for (c1 = c1min; c1 <= c1max; c1++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) - if (*histp++ != 0) { - boxp->c0min = c0min = c0; - goto have_c0min; - } - } - have_c0min: - if (c0max > c0min) - for (c0 = c0max; c0 >= c0min; c0--) - for (c1 = c1min; c1 <= c1max; c1++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) - if (*histp++ != 0) { - boxp->c0max = c0max = c0; - goto have_c0max; - } - } - have_c0max: - if (c1max > c1min) - for (c1 = c1min; c1 <= c1max; c1++) - for (c0 = c0min; c0 <= c0max; c0++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) - if (*histp++ != 0) { - boxp->c1min = c1min = c1; - goto have_c1min; - } - } - have_c1min: - if (c1max > c1min) - for (c1 = c1max; c1 >= c1min; c1--) - for (c0 = c0min; c0 <= c0max; c0++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) - if (*histp++ != 0) { - boxp->c1max = c1max = c1; - goto have_c1max; - } - } - have_c1max: - if (c2max > c2min) - for (c2 = c2min; c2 <= c2max; c2++) - for (c0 = c0min; c0 <= c0max; c0++) { - histp = & histogram[c0][c1min][c2]; - for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) - if (*histp != 0) { - boxp->c2min = c2min = c2; - goto have_c2min; - } - } - have_c2min: - if (c2max > c2min) - for (c2 = c2max; c2 >= c2min; c2--) - for (c0 = c0min; c0 <= c0max; c0++) { - histp = & histogram[c0][c1min][c2]; - for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) - if (*histp != 0) { - boxp->c2max = c2max = c2; - goto have_c2max; - } - } - have_c2max: - - /* Update box volume. - * We use 2-norm rather than real volume here; this biases the method - * against making long narrow boxes, and it has the side benefit that - * a box is splittable iff norm > 0. - * Since the differences are expressed in histogram-cell units, - * we have to shift back to JSAMPLE units to get consistent distances; - * after which, we scale according to the selected distance scale factors. - */ - dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE; - dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE; - dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE; - boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2; - - /* Now scan remaining volume of box and compute population */ - ccount = 0; - for (c0 = c0min; c0 <= c0max; c0++) - for (c1 = c1min; c1 <= c1max; c1++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++, histp++) - if (*histp != 0) { - ccount++; - } - } - boxp->colorcount = ccount; -} - - -LOCAL(int) -median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes, - int desired_colors) -/* Repeatedly select and split the largest box until we have enough boxes */ -{ - int n,lb; - int c0,c1,c2,cmax; - boxptr b1,b2; - - while (numboxes < desired_colors) { - /* Select box to split. - * Current algorithm: by population for first half, then by volume. - */ - if (numboxes*2 <= desired_colors) { - b1 = find_biggest_color_pop(boxlist, numboxes); - } else { - b1 = find_biggest_volume(boxlist, numboxes); - } - if (b1 == NULL) /* no splittable boxes left! */ - break; - b2 = &boxlist[numboxes]; /* where new box will go */ - /* Copy the color bounds to the new box. */ - b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max; - b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min; - /* Choose which axis to split the box on. - * Current algorithm: longest scaled axis. - * See notes in update_box about scaling distances. - */ - c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE; - c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE; - c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE; - /* We want to break any ties in favor of green, then red, blue last. - * This code does the right thing for R,G,B or B,G,R color orders only. - */ -#if RGB_RED == 0 - cmax = c1; n = 1; - if (c0 > cmax) { cmax = c0; n = 0; } - if (c2 > cmax) { n = 2; } -#else - cmax = c1; n = 1; - if (c2 > cmax) { cmax = c2; n = 2; } - if (c0 > cmax) { n = 0; } -#endif - /* Choose split point along selected axis, and update box bounds. - * Current algorithm: split at halfway point. - * (Since the box has been shrunk to minimum volume, - * any split will produce two nonempty subboxes.) - * Note that lb value is max for lower box, so must be < old max. - */ - switch (n) { - case 0: - lb = (b1->c0max + b1->c0min) / 2; - b1->c0max = lb; - b2->c0min = lb+1; - break; - case 1: - lb = (b1->c1max + b1->c1min) / 2; - b1->c1max = lb; - b2->c1min = lb+1; - break; - case 2: - lb = (b1->c2max + b1->c2min) / 2; - b1->c2max = lb; - b2->c2min = lb+1; - break; - } - /* Update stats for boxes */ - update_box(cinfo, b1); - update_box(cinfo, b2); - numboxes++; - } - return numboxes; -} - - -LOCAL(void) -compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor) -/* Compute representative color for a box, put it in colormap[icolor] */ -{ - /* Current algorithm: mean weighted by pixels (not colors) */ - /* Note it is important to get the rounding correct! */ - my_cquantize_ptr2 cquantize = (my_cquantize_ptr2) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - histptr histp; - int c0,c1,c2; - int c0min,c0max,c1min,c1max,c2min,c2max; - long count; - long total = 0; - long c0total = 0; - long c1total = 0; - long c2total = 0; - - c0min = boxp->c0min; c0max = boxp->c0max; - c1min = boxp->c1min; c1max = boxp->c1max; - c2min = boxp->c2min; c2max = boxp->c2max; - - for (c0 = c0min; c0 <= c0max; c0++) - for (c1 = c1min; c1 <= c1max; c1++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) { - if ((count = *histp++) != 0) { - total += count; - c0total += ((c0 << C0_SHIFT) + ((1<>1)) * count; - c1total += ((c1 << C1_SHIFT) + ((1<>1)) * count; - c2total += ((c2 << C2_SHIFT) + ((1<>1)) * count; - } - } - } - - cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total); - cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total); - cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total); -} - - -LOCAL(void) -select_colors (j_decompress_ptr cinfo, int desired_colors) -/* Master routine for color selection */ -{ - boxptr boxlist; - int numboxes; - int i; - - /* Allocate workspace for box list */ - boxlist = (boxptr) (*cinfo->mem->alloc_small) - ((j_common_ptr) cinfo, JPOOL_IMAGE, desired_colors * SIZEOF(box)); - /* Initialize one box containing whole space */ - numboxes = 1; - boxlist[0].c0min = 0; - boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT; - boxlist[0].c1min = 0; - boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT; - boxlist[0].c2min = 0; - boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT; - /* Shrink it to actually-used volume and set its statistics */ - update_box(cinfo, & boxlist[0]); - /* Perform median-cut to produce final box list */ - numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors); - /* Compute the representative color for each box, fill colormap */ - for (i = 0; i < numboxes; i++) - compute_color(cinfo, & boxlist[i], i); - cinfo->actual_number_of_colors = numboxes; - TRACEMS1(cinfo, 1, JTRC_QUANT_SELECTED, numboxes); -} - - -/* - * These routines are concerned with the time-critical task of mapping input - * colors to the nearest color in the selected colormap. - * - * We re-use the histogram space as an "inverse color map", essentially a - * cache for the results of nearest-color searches. All colors within a - * histogram cell will be mapped to the same colormap entry, namely the one - * closest to the cell's center. This may not be quite the closest entry to - * the actual input color, but it's almost as good. A zero in the cache - * indicates we haven't found the nearest color for that cell yet; the array - * is cleared to zeroes before starting the mapping pass. When we find the - * nearest color for a cell, its colormap index plus one is recorded in the - * cache for future use. The pass2 scanning routines call fill_inverse_cmap - * when they need to use an unfilled entry in the cache. - * - * Our method of efficiently finding nearest colors is based on the "locally - * sorted search" idea described by Heckbert and on the incremental distance - * calculation described by Spencer W. Thomas in chapter III.1 of Graphics - * Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that - * the distances from a given colormap entry to each cell of the histogram can - * be computed quickly using an incremental method: the differences between - * distances to adjacent cells themselves differ by a constant. This allows a - * fairly fast implementation of the "brute force" approach of computing the - * distance from every colormap entry to every histogram cell. Unfortunately, - * it needs a work array to hold the best-distance-so-far for each histogram - * cell (because the inner loop has to be over cells, not colormap entries). - * The work array elements have to be INT32s, so the work array would need - * 256Kb at our recommended precision. This is not feasible in DOS machines. - * - * To get around these problems, we apply Thomas' method to compute the - * nearest colors for only the cells within a small subbox of the histogram. - * The work array need be only as big as the subbox, so the memory usage - * problem is solved. Furthermore, we need not fill subboxes that are never - * referenced in pass2; many images use only part of the color gamut, so a - * fair amount of work is saved. An additional advantage of this - * approach is that we can apply Heckbert's locality criterion to quickly - * eliminate colormap entries that are far away from the subbox; typically - * three-fourths of the colormap entries are rejected by Heckbert's criterion, - * and we need not compute their distances to individual cells in the subbox. - * The speed of this approach is heavily influenced by the subbox size: too - * small means too much overhead, too big loses because Heckbert's criterion - * can't eliminate as many colormap entries. Empirically the best subbox - * size seems to be about 1/512th of the histogram (1/8th in each direction). - * - * Thomas' article also describes a refined method which is asymptotically - * faster than the brute-force method, but it is also far more complex and - * cannot efficiently be applied to small subboxes. It is therefore not - * useful for programs intended to be portable to DOS machines. On machines - * with plenty of memory, filling the whole histogram in one shot with Thomas' - * refined method might be faster than the present code --- but then again, - * it might not be any faster, and it's certainly more complicated. - */ - - -/* log2(histogram cells in update box) for each axis; this can be adjusted */ -#define BOX_C0_LOG (HIST_C0_BITS-3) -#define BOX_C1_LOG (HIST_C1_BITS-3) -#define BOX_C2_LOG (HIST_C2_BITS-3) - -#define BOX_C0_ELEMS (1<actual_number_of_colors; - int maxc0, maxc1, maxc2; - int centerc0, centerc1, centerc2; - int i, x, ncolors; - INT32 minmaxdist, min_dist, max_dist, tdist; - INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */ - - /* Compute true coordinates of update box's upper corner and center. - * Actually we compute the coordinates of the center of the upper-corner - * histogram cell, which are the upper bounds of the volume we care about. - * Note that since ">>" rounds down, the "center" values may be closer to - * min than to max; hence comparisons to them must be "<=", not "<". - */ - maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT)); - centerc0 = (minc0 + maxc0) >> 1; - maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT)); - centerc1 = (minc1 + maxc1) >> 1; - maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT)); - centerc2 = (minc2 + maxc2) >> 1; - - /* For each color in colormap, find: - * 1. its minimum squared-distance to any point in the update box - * (zero if color is within update box); - * 2. its maximum squared-distance to any point in the update box. - * Both of these can be found by considering only the corners of the box. - * We save the minimum distance for each color in mindist[]; - * only the smallest maximum distance is of interest. - */ - minmaxdist = 0x7FFFFFFFL; - - for (i = 0; i < numcolors; i++) { - /* We compute the squared-c0-distance term, then add in the other two. */ - x = GETJSAMPLE(cinfo->colormap[0][i]); - if (x < minc0) { - tdist = (x - minc0) * C0_SCALE; - min_dist = tdist*tdist; - tdist = (x - maxc0) * C0_SCALE; - max_dist = tdist*tdist; - } else if (x > maxc0) { - tdist = (x - maxc0) * C0_SCALE; - min_dist = tdist*tdist; - tdist = (x - minc0) * C0_SCALE; - max_dist = tdist*tdist; - } else { - /* within cell range so no contribution to min_dist */ - min_dist = 0; - if (x <= centerc0) { - tdist = (x - maxc0) * C0_SCALE; - max_dist = tdist*tdist; - } else { - tdist = (x - minc0) * C0_SCALE; - max_dist = tdist*tdist; - } - } - - x = GETJSAMPLE(cinfo->colormap[1][i]); - if (x < minc1) { - tdist = (x - minc1) * C1_SCALE; - min_dist += tdist*tdist; - tdist = (x - maxc1) * C1_SCALE; - max_dist += tdist*tdist; - } else if (x > maxc1) { - tdist = (x - maxc1) * C1_SCALE; - min_dist += tdist*tdist; - tdist = (x - minc1) * C1_SCALE; - max_dist += tdist*tdist; - } else { - /* within cell range so no contribution to min_dist */ - if (x <= centerc1) { - tdist = (x - maxc1) * C1_SCALE; - max_dist += tdist*tdist; - } else { - tdist = (x - minc1) * C1_SCALE; - max_dist += tdist*tdist; - } - } - - x = GETJSAMPLE(cinfo->colormap[2][i]); - if (x < minc2) { - tdist = (x - minc2) * C2_SCALE; - min_dist += tdist*tdist; - tdist = (x - maxc2) * C2_SCALE; - max_dist += tdist*tdist; - } else if (x > maxc2) { - tdist = (x - maxc2) * C2_SCALE; - min_dist += tdist*tdist; - tdist = (x - minc2) * C2_SCALE; - max_dist += tdist*tdist; - } else { - /* within cell range so no contribution to min_dist */ - if (x <= centerc2) { - tdist = (x - maxc2) * C2_SCALE; - max_dist += tdist*tdist; - } else { - tdist = (x - minc2) * C2_SCALE; - max_dist += tdist*tdist; - } - } - - mindist[i] = min_dist; /* save away the results */ - if (max_dist < minmaxdist) - minmaxdist = max_dist; - } - - /* Now we know that no cell in the update box is more than minmaxdist - * away from some colormap entry. Therefore, only colors that are - * within minmaxdist of some part of the box need be considered. - */ - ncolors = 0; - for (i = 0; i < numcolors; i++) { - if (mindist[i] <= minmaxdist) - colorlist[ncolors++] = (JSAMPLE) i; - } - return ncolors; -} - - -LOCAL(void) -find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2, - int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[]) -/* Find the closest colormap entry for each cell in the update box, - * given the list of candidate colors prepared by find_nearby_colors. - * Return the indexes of the closest entries in the bestcolor[] array. - * This routine uses Thomas' incremental distance calculation method to - * find the distance from a colormap entry to successive cells in the box. - */ -{ - int ic0, ic1, ic2; - int i, icolor; - INT32 * bptr; /* pointer into bestdist[] array */ - JSAMPLE * cptr; /* pointer into bestcolor[] array */ - INT32 dist0, dist1; /* initial distance values */ - INT32 dist2; /* current distance in inner loop */ - INT32 xx0, xx1; /* distance increments */ - INT32 xx2; - INT32 inc0, inc1, inc2; /* initial values for increments */ - /* This array holds the distance to the nearest-so-far color for each cell */ - INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; - - /* Initialize best-distance for each cell of the update box */ - bptr = bestdist; - for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--) - *bptr++ = 0x7FFFFFFFL; - - /* For each color selected by find_nearby_colors, - * compute its distance to the center of each cell in the box. - * If that's less than best-so-far, update best distance and color number. - */ - - /* Nominal steps between cell centers ("x" in Thomas article) */ -#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE) -#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE) -#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE) - - for (i = 0; i < numcolors; i++) { - icolor = GETJSAMPLE(colorlist[i]); - /* Compute (square of) distance from minc0/c1/c2 to this color */ - inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE; - dist0 = inc0*inc0; - inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE; - dist0 += inc1*inc1; - inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE; - dist0 += inc2*inc2; - /* Form the initial difference increments */ - inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0; - inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1; - inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2; - /* Now loop over all cells in box, updating distance per Thomas method */ - bptr = bestdist; - cptr = bestcolor; - xx0 = inc0; - for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) { - dist1 = dist0; - xx1 = inc1; - for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) { - dist2 = dist1; - xx2 = inc2; - for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) { - if (dist2 < *bptr) { - *bptr = dist2; - *cptr = (JSAMPLE) icolor; - } - dist2 += xx2; - xx2 += 2 * STEP_C2 * STEP_C2; - bptr++; - cptr++; - } - dist1 += xx1; - xx1 += 2 * STEP_C1 * STEP_C1; - } - dist0 += xx0; - xx0 += 2 * STEP_C0 * STEP_C0; - } - } -} - - -LOCAL(void) -fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2) -/* Fill the inverse-colormap entries in the update box that contains */ -/* histogram cell c0/c1/c2. (Only that one cell MUST be filled, but */ -/* we can fill as many others as we wish.) */ -{ - my_cquantize_ptr2 cquantize = (my_cquantize_ptr2) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - int minc0, minc1, minc2; /* lower left corner of update box */ - int ic0, ic1, ic2; - JSAMPLE * cptr; /* pointer into bestcolor[] array */ - histptr cachep; /* pointer into main cache array */ - /* This array lists the candidate colormap indexes. */ - JSAMPLE colorlist[MAXNUMCOLORS]; - int numcolors; /* number of candidate colors */ - /* This array holds the actually closest colormap index for each cell. */ - JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; - - /* Convert cell coordinates to update box ID */ - c0 >>= BOX_C0_LOG; - c1 >>= BOX_C1_LOG; - c2 >>= BOX_C2_LOG; - - /* Compute true coordinates of update box's origin corner. - * Actually we compute the coordinates of the center of the corner - * histogram cell, which are the lower bounds of the volume we care about. - */ - minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1); - minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1); - minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1); - - /* Determine which colormap entries are close enough to be candidates - * for the nearest entry to some cell in the update box. - */ - numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist); - - /* Determine the actually nearest colors. */ - find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist, - bestcolor); - - /* Save the best color numbers (plus 1) in the main cache array */ - c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */ - c1 <<= BOX_C1_LOG; - c2 <<= BOX_C2_LOG; - cptr = bestcolor; - for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) { - for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) { - cachep = & histogram[c0+ic0][c1+ic1][c2]; - for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) { - *cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1); - } - } - } -} - - -/* - * Map some rows of pixels to the output colormapped representation. - */ - -METHODDEF(void) -pass2_no_dither (j_decompress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) -/* This version performs no dithering */ -{ - my_cquantize_ptr2 cquantize = (my_cquantize_ptr2) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - JSAMPROW inptr, outptr; - histptr cachep; - int c0, c1, c2; - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - - for (row = 0; row < num_rows; row++) { - inptr = input_buf[row]; - outptr = output_buf[row]; - for (col = width; col > 0; col--) { - /* get pixel value and index into the cache */ - c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT; - c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT; - c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT; - cachep = & histogram[c0][c1][c2]; - /* If we have not seen this color before, find nearest colormap entry */ - /* and update the cache */ - if (*cachep == 0) - fill_inverse_cmap(cinfo, c0,c1,c2); - /* Now emit the colormap index for this cell */ - *outptr++ = (JSAMPLE) (*cachep - 1); - } - } -} - - -METHODDEF(void) -pass2_fs_dither (j_decompress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) -/* This version performs Floyd-Steinberg dithering */ -{ - my_cquantize_ptr2 cquantize = (my_cquantize_ptr2) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */ - LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */ - LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */ - FSERRPTR errorptr; /* => fserrors[] at column before current */ - JSAMPROW inptr; /* => current input pixel */ - JSAMPROW outptr; /* => current output pixel */ - histptr cachep; - int dir; /* +1 or -1 depending on direction */ - int dir3; /* 3*dir, for advancing inptr & errorptr */ - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - JSAMPLE *range_limit = cinfo->sample_range_limit; - int *error_limit = cquantize->error_limiter; - JSAMPROW colormap0 = cinfo->colormap[0]; - JSAMPROW colormap1 = cinfo->colormap[1]; - JSAMPROW colormap2 = cinfo->colormap[2]; - SHIFT_TEMPS - - for (row = 0; row < num_rows; row++) { - inptr = input_buf[row]; - outptr = output_buf[row]; - if (cquantize->on_odd_row) { - /* work right to left in this row */ - inptr += (width-1) * 3; /* so point to rightmost pixel */ - outptr += width-1; - dir = -1; - dir3 = -3; - errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */ - cquantize->on_odd_row = FALSE; /* flip for next time */ - } else { - /* work left to right in this row */ - dir = 1; - dir3 = 3; - errorptr = cquantize->fserrors; /* => entry before first real column */ - cquantize->on_odd_row = TRUE; /* flip for next time */ - } - /* Preset error values: no error propagated to first pixel from left */ - cur0 = cur1 = cur2 = 0; - /* and no error propagated to row below yet */ - belowerr0 = belowerr1 = belowerr2 = 0; - bpreverr0 = bpreverr1 = bpreverr2 = 0; - - for (col = width; col > 0; col--) { - /* curN holds the error propagated from the previous pixel on the - * current line. Add the error propagated from the previous line - * to form the complete error correction term for this pixel, and - * round the error term (which is expressed * 16) to an integer. - * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct - * for either sign of the error value. - * Note: errorptr points to *previous* column's array entry. - */ - cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4); - cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4); - cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4); - /* Limit the error using transfer function set by init_error_limit. - * See comments with init_error_limit for rationale. - */ - cur0 = error_limit[cur0]; - cur1 = error_limit[cur1]; - cur2 = error_limit[cur2]; - /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. - * The maximum error is +- MAXJSAMPLE (or less with error limiting); - * this sets the required size of the range_limit array. - */ - cur0 += GETJSAMPLE(inptr[0]); - cur1 += GETJSAMPLE(inptr[1]); - cur2 += GETJSAMPLE(inptr[2]); - cur0 = GETJSAMPLE(range_limit[cur0]); - cur1 = GETJSAMPLE(range_limit[cur1]); - cur2 = GETJSAMPLE(range_limit[cur2]); - /* Index into the cache with adjusted pixel value */ - cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT]; - /* If we have not seen this color before, find nearest colormap */ - /* entry and update the cache */ - if (*cachep == 0) - fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT); - /* Now emit the colormap index for this cell */ - { int pixcode = *cachep - 1; - *outptr = (JSAMPLE) pixcode; - /* Compute representation error for this pixel */ - cur0 -= GETJSAMPLE(colormap0[pixcode]); - cur1 -= GETJSAMPLE(colormap1[pixcode]); - cur2 -= GETJSAMPLE(colormap2[pixcode]); - } - /* Compute error fractions to be propagated to adjacent pixels. - * Add these into the running sums, and simultaneously shift the - * next-line error sums left by 1 column. - */ - { LOCFSERROR bnexterr, delta; - - bnexterr = cur0; /* Process component 0 */ - delta = cur0 * 2; - cur0 += delta; /* form error * 3 */ - errorptr[0] = (FSERROR) (bpreverr0 + cur0); - cur0 += delta; /* form error * 5 */ - bpreverr0 = belowerr0 + cur0; - belowerr0 = bnexterr; - cur0 += delta; /* form error * 7 */ - bnexterr = cur1; /* Process component 1 */ - delta = cur1 * 2; - cur1 += delta; /* form error * 3 */ - errorptr[1] = (FSERROR) (bpreverr1 + cur1); - cur1 += delta; /* form error * 5 */ - bpreverr1 = belowerr1 + cur1; - belowerr1 = bnexterr; - cur1 += delta; /* form error * 7 */ - bnexterr = cur2; /* Process component 2 */ - delta = cur2 * 2; - cur2 += delta; /* form error * 3 */ - errorptr[2] = (FSERROR) (bpreverr2 + cur2); - cur2 += delta; /* form error * 5 */ - bpreverr2 = belowerr2 + cur2; - belowerr2 = bnexterr; - cur2 += delta; /* form error * 7 */ - } - /* At this point curN contains the 7/16 error value to be propagated - * to the next pixel on the current line, and all the errors for the - * next line have been shifted over. We are therefore ready to move on. - */ - inptr += dir3; /* Advance pixel pointers to next column */ - outptr += dir; - errorptr += dir3; /* advance errorptr to current column */ - } - /* Post-loop cleanup: we must unload the final error values into the - * final fserrors[] entry. Note we need not unload belowerrN because - * it is for the dummy column before or after the actual array. - */ - errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */ - errorptr[1] = (FSERROR) bpreverr1; - errorptr[2] = (FSERROR) bpreverr2; - } -} - - -/* - * Initialize the error-limiting transfer function (lookup table). - * The raw F-S error computation can potentially compute error values of up to - * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be - * much less, otherwise obviously wrong pixels will be created. (Typical - * effects include weird fringes at color-area boundaries, isolated bright - * pixels in a dark area, etc.) The standard advice for avoiding this problem - * is to ensure that the "corners" of the color cube are allocated as output - * colors; then repeated errors in the same direction cannot cause cascading - * error buildup. However, that only prevents the error from getting - * completely out of hand; Aaron Giles reports that error limiting improves - * the results even with corner colors allocated. - * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty - * well, but the smoother transfer function used below is even better. Thanks - * to Aaron Giles for this idea. - */ - -LOCAL(void) -init_error_limit (j_decompress_ptr cinfo) -/* Allocate and fill in the error_limiter table */ -{ - my_cquantize_ptr2 cquantize = (my_cquantize_ptr2) cinfo->cquantize; - int * table; - int in, out; - - table = (int *) (*cinfo->mem->alloc_small) - ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE*2+1) * SIZEOF(int)); - table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */ - cquantize->error_limiter = table; - -#define STEPSIZE ((MAXJSAMPLE+1)/16) - /* Map errors 1:1 up to +- MAXJSAMPLE/16 */ - out = 0; - for (in = 0; in < STEPSIZE; in++, out++) { - table[in] = out; table[-in] = -out; - } - /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */ - for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) { - table[in] = out; table[-in] = -out; - } - /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */ - for (; in <= MAXJSAMPLE; in++) { - table[in] = out; table[-in] = -out; - } -#undef STEPSIZE -} - - -/* - * Finish up at the end of each pass. - */ - -METHODDEF(void) -finish_pass1 (j_decompress_ptr cinfo) -{ - my_cquantize_ptr2 cquantize = (my_cquantize_ptr2) cinfo->cquantize; - - /* Select the representative colors and fill in cinfo->colormap */ - cinfo->colormap = cquantize->sv_colormap; - select_colors(cinfo, cquantize->desired); - /* Force next pass to zero the color index table */ - cquantize->needs_zeroed = TRUE; -} - - -METHODDEF(void) -finish_pass2 (j_decompress_ptr) -{ - /* no work */ -} - - -/* - * Initialize for each processing pass. - */ - -METHODDEF(void) -start_pass_2_quant (j_decompress_ptr cinfo, boolean is_pre_scan) -{ - my_cquantize_ptr2 cquantize = (my_cquantize_ptr2) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - int i; - - /* Only F-S dithering or no dithering is supported. */ - /* If user asks for ordered dither, give him F-S. */ - if (cinfo->dither_mode != JDITHER_NONE) - cinfo->dither_mode = JDITHER_FS; - - if (is_pre_scan) { - /* Set up method pointers */ - cquantize->pub.color_quantize = prescan_quantize; - cquantize->pub.finish_pass = finish_pass1; - cquantize->needs_zeroed = TRUE; /* Always zero histogram */ - } else { - /* Set up method pointers */ - if (cinfo->dither_mode == JDITHER_FS) - cquantize->pub.color_quantize = pass2_fs_dither; - else - cquantize->pub.color_quantize = pass2_no_dither; - cquantize->pub.finish_pass = finish_pass2; - - /* Make sure color count is acceptable */ - i = cinfo->actual_number_of_colors; - if (i < 1) - ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 1); - if (i > MAXNUMCOLORS) - ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); - - if (cinfo->dither_mode == JDITHER_FS) { - size_t arraysize = (size_t) ((cinfo->output_width + 2) * - (3 * SIZEOF(FSERROR))); - /* Allocate Floyd-Steinberg workspace if we didn't already. */ - if (cquantize->fserrors == NULL) - cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) - ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); - /* Initialize the propagated errors to zero. */ - jzero_far((void FAR *) cquantize->fserrors, arraysize); - /* Make the error-limit table if we didn't already. */ - if (cquantize->error_limiter == NULL) - init_error_limit(cinfo); - cquantize->on_odd_row = FALSE; - } - - } - /* Zero the histogram or inverse color map, if necessary */ - if (cquantize->needs_zeroed) { - for (i = 0; i < HIST_C0_ELEMS; i++) { - jzero_far((void FAR *) histogram[i], - HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); - } - cquantize->needs_zeroed = FALSE; - } -} - - -/* - * Switch to a new external colormap between output passes. - */ - -METHODDEF(void) -new_color_map_2_quant (j_decompress_ptr cinfo) -{ - my_cquantize_ptr2 cquantize = (my_cquantize_ptr2) cinfo->cquantize; - - /* Reset the inverse color map */ - cquantize->needs_zeroed = TRUE; -} - - -/* - * Module initialization routine for 2-pass color quantization. - */ - -GLOBAL(void) -jinit_2pass_quantizer (j_decompress_ptr cinfo) -{ - my_cquantize_ptr2 cquantize; - int i; - - cquantize = (my_cquantize_ptr2) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - SIZEOF(my_cquantizer2)); - cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize; - cquantize->pub.start_pass = start_pass_2_quant; - cquantize->pub.new_color_map = new_color_map_2_quant; - cquantize->fserrors = NULL; /* flag optional arrays not allocated */ - cquantize->error_limiter = NULL; - - /* Make sure jdmaster didn't give me a case I can't handle */ - if (cinfo->out_color_components != 3) - ERREXIT(cinfo, JERR_NOTIMPL); - - /* Allocate the histogram/inverse colormap storage */ - cquantize->histogram = (hist3d) (*cinfo->mem->alloc_small) - ((j_common_ptr) cinfo, JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF(hist2d)); - for (i = 0; i < HIST_C0_ELEMS; i++) { - cquantize->histogram[i] = (hist2d) (*cinfo->mem->alloc_large) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); - } - cquantize->needs_zeroed = TRUE; /* histogram is garbage now */ - - /* Allocate storage for the completed colormap, if required. - * We do this now since it is FAR storage and may affect - * the memory manager's space calculations. - */ - if (cinfo->enable_2pass_quant) { - /* Make sure color count is acceptable */ - int desired = cinfo->desired_number_of_colors; - /* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */ - if (desired < 8) - ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8); - /* Make sure colormap indexes can be represented by JSAMPLEs */ - if (desired > MAXNUMCOLORS) - ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); - cquantize->sv_colormap = (*cinfo->mem->alloc_sarray) - ((j_common_ptr) cinfo,JPOOL_IMAGE, (JDIMENSION) desired, (JDIMENSION) 3); - cquantize->desired = desired; - } else - cquantize->sv_colormap = NULL; - - /* Only F-S dithering or no dithering is supported. */ - /* If user asks for ordered dither, give him F-S. */ - if (cinfo->dither_mode != JDITHER_NONE) - cinfo->dither_mode = JDITHER_FS; - - /* Allocate Floyd-Steinberg workspace if necessary. - * This isn't really needed until pass 2, but again it is FAR storage. - * Although we will cope with a later change in dither_mode, - * we do not promise to honor max_memory_to_use if dither_mode changes. - */ - if (cinfo->dither_mode == JDITHER_FS) { - cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) - ((j_common_ptr) cinfo, JPOOL_IMAGE, - (size_t) ((cinfo->output_width + 2) * (3 * SIZEOF(FSERROR)))); - /* Might as well create the error-limiting table too. */ - init_error_limit(cinfo); - } -} - -#endif /* QUANT_2PASS_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/jpglib/jutils.c b/source/modules/juce_graphics/image_formats/jpglib/jutils.c deleted file mode 100644 index 68a808339..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jutils.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * jutils.c - * - * Copyright (C) 1991-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains tables and miscellaneous utility routines needed - * for both compression and decompression. - * Note we prefix all global names with "j" to minimize conflicts with - * a surrounding application. - */ - -#define JPEG_INTERNALS -#include "jinclude.h" -#include "jpeglib.h" - - -/* - * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element - * of a DCT block read in natural order (left to right, top to bottom). - */ - -#if 0 /* This table is not actually needed in v6a */ - -const int jpeg_zigzag_order[DCTSIZE2] = { - 0, 1, 5, 6, 14, 15, 27, 28, - 2, 4, 7, 13, 16, 26, 29, 42, - 3, 8, 12, 17, 25, 30, 41, 43, - 9, 11, 18, 24, 31, 40, 44, 53, - 10, 19, 23, 32, 39, 45, 52, 54, - 20, 22, 33, 38, 46, 51, 55, 60, - 21, 34, 37, 47, 50, 56, 59, 61, - 35, 36, 48, 49, 57, 58, 62, 63 -}; - -#endif - -/* - * jpeg_natural_order[i] is the natural-order position of the i'th element - * of zigzag order. - * - * When reading corrupted data, the Huffman decoders could attempt - * to reference an entry beyond the end of this array (if the decoded - * zero run length reaches past the end of the block). To prevent - * wild stores without adding an inner-loop test, we put some extra - * "63"s after the real entries. This will cause the extra coefficient - * to be stored in location 63 of the block, not somewhere random. - * The worst case would be a run-length of 15, which means we need 16 - * fake entries. - */ - -const int jpeg_natural_order[DCTSIZE2+16] = { - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63, - 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ - 63, 63, 63, 63, 63, 63, 63, 63 -}; - - -/* - * Arithmetic utilities - */ - -GLOBAL(long) -jdiv_round_up (long a, long b) -/* Compute a/b rounded up to next integer, ie, ceil(a/b) */ -/* Assumes a >= 0, b > 0 */ -{ - return (a + b - 1L) / b; -} - - -GLOBAL(long) -jround_up (long a, long b) -/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */ -/* Assumes a >= 0, b > 0 */ -{ - a += b - 1L; - return a - (a % b); -} - - -/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays - * and coefficient-block arrays. This won't work on 80x86 because the arrays - * are FAR and we're assuming a small-pointer memory model. However, some - * DOS compilers provide far-pointer versions of memcpy() and memset() even - * in the small-model libraries. These will be used if USE_FMEM is defined. - * Otherwise, the routines below do it the hard way. (The performance cost - * is not all that great, because these routines aren't very heavily used.) - */ - -#ifndef NEED_FAR_POINTERS /* normal case, same as regular macros */ -#define FMEMCOPY(dest,src,size) MEMCOPY(dest,src,size) -#define FMEMZERO(target,size) MEMZERO(target,size) -#else /* 80x86 case, define if we can */ -#ifdef USE_FMEM -#define FMEMCOPY(dest,src,size) _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size)) -#define FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size)) -#endif -#endif - - -GLOBAL(void) -jcopy_sample_rows (JSAMPARRAY input_array, int source_row, - JSAMPARRAY output_array, int dest_row, - int num_rows, JDIMENSION num_cols) -/* Copy some rows of samples from one place to another. - * num_rows rows are copied from input_array[source_row++] - * to output_array[dest_row++]; these areas may overlap for duplication. - * The source and destination arrays must be at least as wide as num_cols. - */ -{ - JSAMPROW inptr, outptr; -#ifdef FMEMCOPY - size_t count = (size_t) (num_cols * SIZEOF(JSAMPLE)); -#else - JDIMENSION count; -#endif - int row; - - input_array += source_row; - output_array += dest_row; - - for (row = num_rows; row > 0; row--) { - inptr = *input_array++; - outptr = *output_array++; -#ifdef FMEMCOPY - FMEMCOPY(outptr, inptr, count); -#else - for (count = num_cols; count > 0; count--) - *outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */ -#endif - } -} - - -GLOBAL(void) -jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row, - JDIMENSION num_blocks) -/* Copy a row of coefficient blocks from one place to another. */ -{ -#ifdef FMEMCOPY - FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF))); -#else - JCOEFPTR inptr, outptr; - long count; - - inptr = (JCOEFPTR) input_row; - outptr = (JCOEFPTR) output_row; - for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) { - *outptr++ = *inptr++; - } -#endif -} - - -GLOBAL(void) -jzero_far (void FAR * target, size_t bytestozero) -/* Zero out a chunk of FAR memory. */ -/* This might be sample-array data, block-array data, or alloc_large data. */ -{ -#ifdef FMEMZERO - FMEMZERO(target, bytestozero); -#else - char FAR * ptr = (char FAR *) target; - size_t count; - - for (count = bytestozero; count > 0; count--) { - *ptr++ = 0; - } -#endif -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/jversion.h b/source/modules/juce_graphics/image_formats/jpglib/jversion.h deleted file mode 100644 index dadd453a4..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/jversion.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * jversion.h - * - * Copyright (C) 1991-1998, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains software version identification. - */ - - -#define JVERSION "6b 27-Mar-1998" - -#define JCOPYRIGHT "Copyright (C) 1998, Thomas G. Lane" diff --git a/source/modules/juce_graphics/image_formats/jpglib/transupp.c b/source/modules/juce_graphics/image_formats/jpglib/transupp.c deleted file mode 100644 index 35e293e30..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/transupp.c +++ /dev/null @@ -1,928 +0,0 @@ -/* - * transupp.c - * - * Copyright (C) 1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains image transformation routines and other utility code - * used by the jpegtran sample application. These are NOT part of the core - * JPEG library. But we keep these routines separate from jpegtran.c to - * ease the task of maintaining jpegtran-like programs that have other user - * interfaces. - */ - -/* Although this file really shouldn't have access to the library internals, - * it's helpful to let it call jround_up() and jcopy_block_row(). - */ -#define JPEG_INTERNALS - -#include "jinclude.h" -#include "jpeglib.h" -#include "transupp.h" /* My own external interface */ - - -#if TRANSFORMS_SUPPORTED - -/* - * Lossless image transformation routines. These routines work on DCT - * coefficient arrays and thus do not require any lossy decompression - * or recompression of the image. - * Thanks to Guido Vollbeding for the initial design and code of this feature. - * - * Horizontal flipping is done in-place, using a single top-to-bottom - * pass through the virtual source array. It will thus be much the - * fastest option for images larger than main memory. - * - * The other routines require a set of destination virtual arrays, so they - * need twice as much memory as jpegtran normally does. The destination - * arrays are always written in normal scan order (top to bottom) because - * the virtual array manager expects this. The source arrays will be scanned - * in the corresponding order, which means multiple passes through the source - * arrays for most of the transforms. That could result in much thrashing - * if the image is larger than main memory. - * - * Some notes about the operating environment of the individual transform - * routines: - * 1. Both the source and destination virtual arrays are allocated from the - * source JPEG object, and therefore should be manipulated by calling the - * source's memory manager. - * 2. The destination's component count should be used. It may be smaller - * than the source's when forcing to grayscale. - * 3. Likewise the destination's sampling factors should be used. When - * forcing to grayscale the destination's sampling factors will be all 1, - * and we may as well take that as the effective iMCU size. - * 4. When "trim" is in effect, the destination's dimensions will be the - * trimmed values but the source's will be untrimmed. - * 5. All the routines assume that the source and destination buffers are - * padded out to a full iMCU boundary. This is true, although for the - * source buffer it is an undocumented property of jdcoefct.c. - * Notes 2,3,4 boil down to this: generally we should use the destination's - * dimensions and ignore the source's. - */ - - -LOCAL(void) -do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, - jvirt_barray_ptr *src_coef_arrays) -/* Horizontal flip; done in-place, so no separate dest array is required */ -{ - JDIMENSION MCU_cols, comp_width, blk_x, blk_y; - int ci, k, offset_y; - JBLOCKARRAY buffer; - JCOEFPTR ptr1, ptr2; - JCOEF temp1, temp2; - jpeg_component_info *compptr; - - /* Horizontal mirroring of DCT blocks is accomplished by swapping - * pairs of blocks in-place. Within a DCT block, we perform horizontal - * mirroring by changing the signs of odd-numbered columns. - * Partial iMCUs at the right edge are left untouched. - */ - MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); - - for (ci = 0; ci < dstinfo->num_components; ci++) { - compptr = dstinfo->comp_info + ci; - comp_width = MCU_cols * compptr->h_samp_factor; - for (blk_y = 0; blk_y < compptr->height_in_blocks; - blk_y += compptr->v_samp_factor) { - buffer = (*srcinfo->mem->access_virt_barray) - ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y, - (JDIMENSION) compptr->v_samp_factor, TRUE); - for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { - for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) { - ptr1 = buffer[offset_y][blk_x]; - ptr2 = buffer[offset_y][comp_width - blk_x - 1]; - /* this unrolled loop doesn't need to know which row it's on... */ - for (k = 0; k < DCTSIZE2; k += 2) { - temp1 = *ptr1; /* swap even column */ - temp2 = *ptr2; - *ptr1++ = temp2; - *ptr2++ = temp1; - temp1 = *ptr1; /* swap odd column with sign change */ - temp2 = *ptr2; - *ptr1++ = -temp2; - *ptr2++ = -temp1; - } - } - } - } - } -} - - -LOCAL(void) -do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, - jvirt_barray_ptr *src_coef_arrays, - jvirt_barray_ptr *dst_coef_arrays) -/* Vertical flip */ -{ - JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; - int ci, i, j, offset_y; - JBLOCKARRAY src_buffer, dst_buffer; - JBLOCKROW src_row_ptr, dst_row_ptr; - JCOEFPTR src_ptr, dst_ptr; - jpeg_component_info *compptr; - - /* We output into a separate array because we can't touch different - * rows of the source virtual array simultaneously. Otherwise, this - * is a pretty straightforward analog of horizontal flip. - * Within a DCT block, vertical mirroring is done by changing the signs - * of odd-numbered rows. - * Partial iMCUs at the bottom edge are copied verbatim. - */ - MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); - - for (ci = 0; ci < dstinfo->num_components; ci++) { - compptr = dstinfo->comp_info + ci; - comp_height = MCU_rows * compptr->v_samp_factor; - for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; - dst_blk_y += compptr->v_samp_factor) { - dst_buffer = (*srcinfo->mem->access_virt_barray) - ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, - (JDIMENSION) compptr->v_samp_factor, TRUE); - if (dst_blk_y < comp_height) { - /* Row is within the mirrorable area. */ - src_buffer = (*srcinfo->mem->access_virt_barray) - ((j_common_ptr) srcinfo, src_coef_arrays[ci], - comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, - (JDIMENSION) compptr->v_samp_factor, FALSE); - } else { - /* Bottom-edge blocks will be copied verbatim. */ - src_buffer = (*srcinfo->mem->access_virt_barray) - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, - (JDIMENSION) compptr->v_samp_factor, FALSE); - } - for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { - if (dst_blk_y < comp_height) { - /* Row is within the mirrorable area. */ - dst_row_ptr = dst_buffer[offset_y]; - src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; - for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; - dst_blk_x++) { - dst_ptr = dst_row_ptr[dst_blk_x]; - src_ptr = src_row_ptr[dst_blk_x]; - for (i = 0; i < DCTSIZE; i += 2) { - /* copy even row */ - for (j = 0; j < DCTSIZE; j++) - *dst_ptr++ = *src_ptr++; - /* copy odd row with sign change */ - for (j = 0; j < DCTSIZE; j++) - *dst_ptr++ = - *src_ptr++; - } - } - } else { - /* Just copy row verbatim. */ - jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y], - compptr->width_in_blocks); - } - } - } - } -} - - -LOCAL(void) -do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, - jvirt_barray_ptr *src_coef_arrays, - jvirt_barray_ptr *dst_coef_arrays) -/* Transpose source into destination */ -{ - JDIMENSION dst_blk_x, dst_blk_y; - int ci, i, j, offset_x, offset_y; - JBLOCKARRAY src_buffer, dst_buffer; - JCOEFPTR src_ptr, dst_ptr; - jpeg_component_info *compptr; - - /* Transposing pixels within a block just requires transposing the - * DCT coefficients. - * Partial iMCUs at the edges require no special treatment; we simply - * process all the available DCT blocks for every component. - */ - for (ci = 0; ci < dstinfo->num_components; ci++) { - compptr = dstinfo->comp_info + ci; - for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; - dst_blk_y += compptr->v_samp_factor) { - dst_buffer = (*srcinfo->mem->access_virt_barray) - ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, - (JDIMENSION) compptr->v_samp_factor, TRUE); - for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { - for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; - dst_blk_x += compptr->h_samp_factor) { - src_buffer = (*srcinfo->mem->access_virt_barray) - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, - (JDIMENSION) compptr->h_samp_factor, FALSE); - for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { - src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; - dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; - for (i = 0; i < DCTSIZE; i++) - for (j = 0; j < DCTSIZE; j++) - dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; - } - } - } - } - } -} - - -LOCAL(void) -do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, - jvirt_barray_ptr *src_coef_arrays, - jvirt_barray_ptr *dst_coef_arrays) -/* 90 degree rotation is equivalent to - * 1. Transposing the image; - * 2. Horizontal mirroring. - * These two steps are merged into a single processing routine. - */ -{ - JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; - int ci, i, j, offset_x, offset_y; - JBLOCKARRAY src_buffer, dst_buffer; - JCOEFPTR src_ptr, dst_ptr; - jpeg_component_info *compptr; - - /* Because of the horizontal mirror step, we can't process partial iMCUs - * at the (output) right edge properly. They just get transposed and - * not mirrored. - */ - MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); - - for (ci = 0; ci < dstinfo->num_components; ci++) { - compptr = dstinfo->comp_info + ci; - comp_width = MCU_cols * compptr->h_samp_factor; - for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; - dst_blk_y += compptr->v_samp_factor) { - dst_buffer = (*srcinfo->mem->access_virt_barray) - ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, - (JDIMENSION) compptr->v_samp_factor, TRUE); - for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { - for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; - dst_blk_x += compptr->h_samp_factor) { - src_buffer = (*srcinfo->mem->access_virt_barray) - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, - (JDIMENSION) compptr->h_samp_factor, FALSE); - for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { - src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; - if (dst_blk_x < comp_width) { - /* Block is within the mirrorable area. */ - dst_ptr = dst_buffer[offset_y] - [comp_width - dst_blk_x - offset_x - 1]; - for (i = 0; i < DCTSIZE; i++) { - for (j = 0; j < DCTSIZE; j++) - dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; - i++; - for (j = 0; j < DCTSIZE; j++) - dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; - } - } else { - /* Edge blocks are transposed but not mirrored. */ - dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; - for (i = 0; i < DCTSIZE; i++) - for (j = 0; j < DCTSIZE; j++) - dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; - } - } - } - } - } - } -} - - -LOCAL(void) -do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, - jvirt_barray_ptr *src_coef_arrays, - jvirt_barray_ptr *dst_coef_arrays) -/* 270 degree rotation is equivalent to - * 1. Horizontal mirroring; - * 2. Transposing the image. - * These two steps are merged into a single processing routine. - */ -{ - JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; - int ci, i, j, offset_x, offset_y; - JBLOCKARRAY src_buffer, dst_buffer; - JCOEFPTR src_ptr, dst_ptr; - jpeg_component_info *compptr; - - /* Because of the horizontal mirror step, we can't process partial iMCUs - * at the (output) bottom edge properly. They just get transposed and - * not mirrored. - */ - MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); - - for (ci = 0; ci < dstinfo->num_components; ci++) { - compptr = dstinfo->comp_info + ci; - comp_height = MCU_rows * compptr->v_samp_factor; - for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; - dst_blk_y += compptr->v_samp_factor) { - dst_buffer = (*srcinfo->mem->access_virt_barray) - ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, - (JDIMENSION) compptr->v_samp_factor, TRUE); - for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { - for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; - dst_blk_x += compptr->h_samp_factor) { - src_buffer = (*srcinfo->mem->access_virt_barray) - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, - (JDIMENSION) compptr->h_samp_factor, FALSE); - for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { - dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; - if (dst_blk_y < comp_height) { - /* Block is within the mirrorable area. */ - src_ptr = src_buffer[offset_x] - [comp_height - dst_blk_y - offset_y - 1]; - for (i = 0; i < DCTSIZE; i++) { - for (j = 0; j < DCTSIZE; j++) { - dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; - j++; - dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; - } - } - } else { - /* Edge blocks are transposed but not mirrored. */ - src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; - for (i = 0; i < DCTSIZE; i++) - for (j = 0; j < DCTSIZE; j++) - dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; - } - } - } - } - } - } -} - - -LOCAL(void) -do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, - jvirt_barray_ptr *src_coef_arrays, - jvirt_barray_ptr *dst_coef_arrays) -/* 180 degree rotation is equivalent to - * 1. Vertical mirroring; - * 2. Horizontal mirroring. - * These two steps are merged into a single processing routine. - */ -{ - JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; - int ci, i, j, offset_y; - JBLOCKARRAY src_buffer, dst_buffer; - JBLOCKROW src_row_ptr, dst_row_ptr; - JCOEFPTR src_ptr, dst_ptr; - jpeg_component_info *compptr; - - MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); - MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); - - for (ci = 0; ci < dstinfo->num_components; ci++) { - compptr = dstinfo->comp_info + ci; - comp_width = MCU_cols * compptr->h_samp_factor; - comp_height = MCU_rows * compptr->v_samp_factor; - for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; - dst_blk_y += compptr->v_samp_factor) { - dst_buffer = (*srcinfo->mem->access_virt_barray) - ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, - (JDIMENSION) compptr->v_samp_factor, TRUE); - if (dst_blk_y < comp_height) { - /* Row is within the vertically mirrorable area. */ - src_buffer = (*srcinfo->mem->access_virt_barray) - ((j_common_ptr) srcinfo, src_coef_arrays[ci], - comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, - (JDIMENSION) compptr->v_samp_factor, FALSE); - } else { - /* Bottom-edge rows are only mirrored horizontally. */ - src_buffer = (*srcinfo->mem->access_virt_barray) - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, - (JDIMENSION) compptr->v_samp_factor, FALSE); - } - for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { - if (dst_blk_y < comp_height) { - /* Row is within the mirrorable area. */ - dst_row_ptr = dst_buffer[offset_y]; - src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; - /* Process the blocks that can be mirrored both ways. */ - for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { - dst_ptr = dst_row_ptr[dst_blk_x]; - src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; - for (i = 0; i < DCTSIZE; i += 2) { - /* For even row, negate every odd column. */ - for (j = 0; j < DCTSIZE; j += 2) { - *dst_ptr++ = *src_ptr++; - *dst_ptr++ = - *src_ptr++; - } - /* For odd row, negate every even column. */ - for (j = 0; j < DCTSIZE; j += 2) { - *dst_ptr++ = - *src_ptr++; - *dst_ptr++ = *src_ptr++; - } - } - } - /* Any remaining right-edge blocks are only mirrored vertically. */ - for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { - dst_ptr = dst_row_ptr[dst_blk_x]; - src_ptr = src_row_ptr[dst_blk_x]; - for (i = 0; i < DCTSIZE; i += 2) { - for (j = 0; j < DCTSIZE; j++) - *dst_ptr++ = *src_ptr++; - for (j = 0; j < DCTSIZE; j++) - *dst_ptr++ = - *src_ptr++; - } - } - } else { - /* Remaining rows are just mirrored horizontally. */ - dst_row_ptr = dst_buffer[offset_y]; - src_row_ptr = src_buffer[offset_y]; - /* Process the blocks that can be mirrored. */ - for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { - dst_ptr = dst_row_ptr[dst_blk_x]; - src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; - for (i = 0; i < DCTSIZE2; i += 2) { - *dst_ptr++ = *src_ptr++; - *dst_ptr++ = - *src_ptr++; - } - } - /* Any remaining right-edge blocks are only copied. */ - for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { - dst_ptr = dst_row_ptr[dst_blk_x]; - src_ptr = src_row_ptr[dst_blk_x]; - for (i = 0; i < DCTSIZE2; i++) - *dst_ptr++ = *src_ptr++; - } - } - } - } - } -} - - -LOCAL(void) -do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, - jvirt_barray_ptr *src_coef_arrays, - jvirt_barray_ptr *dst_coef_arrays) -/* Transverse transpose is equivalent to - * 1. 180 degree rotation; - * 2. Transposition; - * or - * 1. Horizontal mirroring; - * 2. Transposition; - * 3. Horizontal mirroring. - * These steps are merged into a single processing routine. - */ -{ - JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; - int ci, i, j, offset_x, offset_y; - JBLOCKARRAY src_buffer, dst_buffer; - JCOEFPTR src_ptr, dst_ptr; - jpeg_component_info *compptr; - - MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); - MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); - - for (ci = 0; ci < dstinfo->num_components; ci++) { - compptr = dstinfo->comp_info + ci; - comp_width = MCU_cols * compptr->h_samp_factor; - comp_height = MCU_rows * compptr->v_samp_factor; - for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; - dst_blk_y += compptr->v_samp_factor) { - dst_buffer = (*srcinfo->mem->access_virt_barray) - ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, - (JDIMENSION) compptr->v_samp_factor, TRUE); - for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { - for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; - dst_blk_x += compptr->h_samp_factor) { - src_buffer = (*srcinfo->mem->access_virt_barray) - ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, - (JDIMENSION) compptr->h_samp_factor, FALSE); - for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { - if (dst_blk_y < comp_height) { - src_ptr = src_buffer[offset_x] - [comp_height - dst_blk_y - offset_y - 1]; - if (dst_blk_x < comp_width) { - /* Block is within the mirrorable area. */ - dst_ptr = dst_buffer[offset_y] - [comp_width - dst_blk_x - offset_x - 1]; - for (i = 0; i < DCTSIZE; i++) { - for (j = 0; j < DCTSIZE; j++) { - dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; - j++; - dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; - } - i++; - for (j = 0; j < DCTSIZE; j++) { - dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; - j++; - dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; - } - } - } else { - /* Right-edge blocks are mirrored in y only */ - dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; - for (i = 0; i < DCTSIZE; i++) { - for (j = 0; j < DCTSIZE; j++) { - dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; - j++; - dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; - } - } - } - } else { - src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; - if (dst_blk_x < comp_width) { - /* Bottom-edge blocks are mirrored in x only */ - dst_ptr = dst_buffer[offset_y] - [comp_width - dst_blk_x - offset_x - 1]; - for (i = 0; i < DCTSIZE; i++) { - for (j = 0; j < DCTSIZE; j++) - dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; - i++; - for (j = 0; j < DCTSIZE; j++) - dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; - } - } else { - /* At lower right corner, just transpose, no mirroring */ - dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; - for (i = 0; i < DCTSIZE; i++) - for (j = 0; j < DCTSIZE; j++) - dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; - } - } - } - } - } - } - } -} - - -/* Request any required workspace. - * - * We allocate the workspace virtual arrays from the source decompression - * object, so that all the arrays (both the original data and the workspace) - * will be taken into account while making memory management decisions. - * Hence, this routine must be called after jpeg_read_header (which reads - * the image dimensions) and before jpeg_read_coefficients (which realizes - * the source's virtual arrays). - */ - -GLOBAL(void) -jtransform_request_workspace (j_decompress_ptr srcinfo, - jpeg_transform_info *info) -{ - jvirt_barray_ptr *coef_arrays = NULL; - jpeg_component_info *compptr; - int ci; - - if (info->force_grayscale && - srcinfo->jpeg_color_space == JCS_YCbCr && - srcinfo->num_components == 3) { - /* We'll only process the first component */ - info->num_components = 1; - } else { - /* Process all the components */ - info->num_components = srcinfo->num_components; - } - - switch (info->transform) { - case JXFORM_NONE: - case JXFORM_FLIP_H: - /* Don't need a workspace array */ - break; - case JXFORM_FLIP_V: - case JXFORM_ROT_180: - /* Need workspace arrays having same dimensions as source image. - * Note that we allocate arrays padded out to the next iMCU boundary, - * so that transform routines need not worry about missing edge blocks. - */ - coef_arrays = (jvirt_barray_ptr *) - (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, - SIZEOF(jvirt_barray_ptr) * info->num_components); - for (ci = 0; ci < info->num_components; ci++) { - compptr = srcinfo->comp_info + ci; - coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) - ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, - (JDIMENSION) jround_up((long) compptr->width_in_blocks, - (long) compptr->h_samp_factor), - (JDIMENSION) jround_up((long) compptr->height_in_blocks, - (long) compptr->v_samp_factor), - (JDIMENSION) compptr->v_samp_factor); - } - break; - case JXFORM_TRANSPOSE: - case JXFORM_TRANSVERSE: - case JXFORM_ROT_90: - case JXFORM_ROT_270: - /* Need workspace arrays having transposed dimensions. - * Note that we allocate arrays padded out to the next iMCU boundary, - * so that transform routines need not worry about missing edge blocks. - */ - coef_arrays = (jvirt_barray_ptr *) - (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, - SIZEOF(jvirt_barray_ptr) * info->num_components); - for (ci = 0; ci < info->num_components; ci++) { - compptr = srcinfo->comp_info + ci; - coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) - ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, - (JDIMENSION) jround_up((long) compptr->height_in_blocks, - (long) compptr->v_samp_factor), - (JDIMENSION) jround_up((long) compptr->width_in_blocks, - (long) compptr->h_samp_factor), - (JDIMENSION) compptr->h_samp_factor); - } - break; - } - info->workspace_coef_arrays = coef_arrays; -} - - -/* Transpose destination image parameters */ - -LOCAL(void) -transpose_critical_parameters (j_compress_ptr dstinfo) -{ - int tblno, i, j, ci, itemp; - jpeg_component_info *compptr; - JQUANT_TBL *qtblptr; - JDIMENSION dtemp; - UINT16 qtemp; - - /* Transpose basic image dimensions */ - dtemp = dstinfo->image_width; - dstinfo->image_width = dstinfo->image_height; - dstinfo->image_height = dtemp; - - /* Transpose sampling factors */ - for (ci = 0; ci < dstinfo->num_components; ci++) { - compptr = dstinfo->comp_info + ci; - itemp = compptr->h_samp_factor; - compptr->h_samp_factor = compptr->v_samp_factor; - compptr->v_samp_factor = itemp; - } - - /* Transpose quantization tables */ - for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { - qtblptr = dstinfo->quant_tbl_ptrs[tblno]; - if (qtblptr != NULL) { - for (i = 0; i < DCTSIZE; i++) { - for (j = 0; j < i; j++) { - qtemp = qtblptr->quantval[i*DCTSIZE+j]; - qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i]; - qtblptr->quantval[j*DCTSIZE+i] = qtemp; - } - } - } - } -} - - -/* Trim off any partial iMCUs on the indicated destination edge */ - -LOCAL(void) -trim_right_edge (j_compress_ptr dstinfo) -{ - int ci, max_h_samp_factor; - JDIMENSION MCU_cols; - - /* We have to compute max_h_samp_factor ourselves, - * because it hasn't been set yet in the destination - * (and we don't want to use the source's value). - */ - max_h_samp_factor = 1; - for (ci = 0; ci < dstinfo->num_components; ci++) { - int h_samp_factor = dstinfo->comp_info[ci].h_samp_factor; - max_h_samp_factor = MAX(max_h_samp_factor, h_samp_factor); - } - MCU_cols = dstinfo->image_width / (max_h_samp_factor * DCTSIZE); - if (MCU_cols > 0) /* can't trim to 0 pixels */ - dstinfo->image_width = MCU_cols * (max_h_samp_factor * DCTSIZE); -} - -LOCAL(void) -trim_bottom_edge (j_compress_ptr dstinfo) -{ - int ci, max_v_samp_factor; - JDIMENSION MCU_rows; - - /* We have to compute max_v_samp_factor ourselves, - * because it hasn't been set yet in the destination - * (and we don't want to use the source's value). - */ - max_v_samp_factor = 1; - for (ci = 0; ci < dstinfo->num_components; ci++) { - int v_samp_factor = dstinfo->comp_info[ci].v_samp_factor; - max_v_samp_factor = MAX(max_v_samp_factor, v_samp_factor); - } - MCU_rows = dstinfo->image_height / (max_v_samp_factor * DCTSIZE); - if (MCU_rows > 0) /* can't trim to 0 pixels */ - dstinfo->image_height = MCU_rows * (max_v_samp_factor * DCTSIZE); -} - - -/* Adjust output image parameters as needed. - * - * This must be called after jpeg_copy_critical_parameters() - * and before jpeg_write_coefficients(). - * - * The return value is the set of virtual coefficient arrays to be written - * (either the ones allocated by jtransform_request_workspace, or the - * original source data arrays). The caller will need to pass this value - * to jpeg_write_coefficients(). - */ - -GLOBAL(jvirt_barray_ptr *) -jtransform_adjust_parameters (j_decompress_ptr, - j_compress_ptr dstinfo, - jvirt_barray_ptr *src_coef_arrays, - jpeg_transform_info *info) -{ - /* If force-to-grayscale is requested, adjust destination parameters */ - if (info->force_grayscale) { - /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed - * properly. Among other things, the target h_samp_factor & v_samp_factor - * will get set to 1, which typically won't match the source. - * In fact we do this even if the source is already grayscale; that - * provides an easy way of coercing a grayscale JPEG with funny sampling - * factors to the customary 1,1. (Some decoders fail on other factors.) - */ - if ((dstinfo->jpeg_color_space == JCS_YCbCr && - dstinfo->num_components == 3) || - (dstinfo->jpeg_color_space == JCS_GRAYSCALE && - dstinfo->num_components == 1)) { - /* We have to preserve the source's quantization table number. */ - int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no; - jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE); - dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no; - } else { - /* Sorry, can't do it */ - ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); - } - } - - /* Correct the destination's image dimensions etc if necessary */ - switch (info->transform) { - case JXFORM_NONE: - /* Nothing to do */ - break; - case JXFORM_FLIP_H: - if (info->trim) - trim_right_edge(dstinfo); - break; - case JXFORM_FLIP_V: - if (info->trim) - trim_bottom_edge(dstinfo); - break; - case JXFORM_TRANSPOSE: - transpose_critical_parameters(dstinfo); - /* transpose does NOT have to trim anything */ - break; - case JXFORM_TRANSVERSE: - transpose_critical_parameters(dstinfo); - if (info->trim) { - trim_right_edge(dstinfo); - trim_bottom_edge(dstinfo); - } - break; - case JXFORM_ROT_90: - transpose_critical_parameters(dstinfo); - if (info->trim) - trim_right_edge(dstinfo); - break; - case JXFORM_ROT_180: - if (info->trim) { - trim_right_edge(dstinfo); - trim_bottom_edge(dstinfo); - } - break; - case JXFORM_ROT_270: - transpose_critical_parameters(dstinfo); - if (info->trim) - trim_bottom_edge(dstinfo); - break; - } - - /* Return the appropriate output data set */ - if (info->workspace_coef_arrays != NULL) - return info->workspace_coef_arrays; - return src_coef_arrays; -} - - -/* Execute the actual transformation, if any. - * - * This must be called *after* jpeg_write_coefficients, because it depends - * on jpeg_write_coefficients to have computed subsidiary values such as - * the per-component width and height fields in the destination object. - * - * Note that some transformations will modify the source data arrays! - */ - -GLOBAL(void) -jtransform_execute_transformation (j_decompress_ptr srcinfo, - j_compress_ptr dstinfo, - jvirt_barray_ptr *src_coef_arrays, - jpeg_transform_info *info) -{ - jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays; - - switch (info->transform) { - case JXFORM_NONE: - break; - case JXFORM_FLIP_H: - do_flip_h(srcinfo, dstinfo, src_coef_arrays); - break; - case JXFORM_FLIP_V: - do_flip_v(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); - break; - case JXFORM_TRANSPOSE: - do_transpose(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); - break; - case JXFORM_TRANSVERSE: - do_transverse(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); - break; - case JXFORM_ROT_90: - do_rot_90(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); - break; - case JXFORM_ROT_180: - do_rot_180(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); - break; - case JXFORM_ROT_270: - do_rot_270(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); - break; - } -} - -#endif /* TRANSFORMS_SUPPORTED */ - - -/* Setup decompression object to save desired markers in memory. - * This must be called before jpeg_read_header() to have the desired effect. - */ - -GLOBAL(void) -jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option) -{ -#ifdef SAVE_MARKERS_SUPPORTED - int m; - - /* Save comments except under NONE option */ - if (option != JCOPYOPT_NONE) { - jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); - } - /* Save all types of APPn markers iff ALL option */ - if (option == JCOPYOPT_ALL) { - for (m = 0; m < 16; m++) - jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); - } -#endif /* SAVE_MARKERS_SUPPORTED */ -} - -/* Copy markers saved in the given source object to the destination object. - * This should be called just after jpeg_start_compress() or - * jpeg_write_coefficients(). - * Note that those routines will have written the SOI, and also the - * JFIF APP0 or Adobe APP14 markers if selected. - */ - -GLOBAL(void) -jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, - JCOPY_OPTION) -{ - jpeg_saved_marker_ptr marker; - - /* In the current implementation, we don't actually need to examine the - * option flag here; we just copy everything that got saved. - * But to avoid confusion, we do not output JFIF and Adobe APP14 markers - * if the encoder library already wrote one. - */ - for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) { - if (dstinfo->write_JFIF_header && - marker->marker == JPEG_APP0 && - marker->data_length >= 5 && - GETJOCTET(marker->data[0]) == 0x4A && - GETJOCTET(marker->data[1]) == 0x46 && - GETJOCTET(marker->data[2]) == 0x49 && - GETJOCTET(marker->data[3]) == 0x46 && - GETJOCTET(marker->data[4]) == 0) - continue; /* reject duplicate JFIF */ - if (dstinfo->write_Adobe_marker && - marker->marker == JPEG_APP0+14 && - marker->data_length >= 5 && - GETJOCTET(marker->data[0]) == 0x41 && - GETJOCTET(marker->data[1]) == 0x64 && - GETJOCTET(marker->data[2]) == 0x6F && - GETJOCTET(marker->data[3]) == 0x62 && - GETJOCTET(marker->data[4]) == 0x65) - continue; /* reject duplicate Adobe */ -#ifdef NEED_FAR_POINTERS - /* We could use jpeg_write_marker if the data weren't FAR... */ - { - unsigned int i; - jpeg_write_m_header(dstinfo, marker->marker, marker->data_length); - for (i = 0; i < marker->data_length; i++) - jpeg_write_m_byte(dstinfo, marker->data[i]); - } -#else - jpeg_write_marker(dstinfo, marker->marker, - marker->data, marker->data_length); -#endif - } -} diff --git a/source/modules/juce_graphics/image_formats/jpglib/transupp.h b/source/modules/juce_graphics/image_formats/jpglib/transupp.h deleted file mode 100644 index eb0b05566..000000000 --- a/source/modules/juce_graphics/image_formats/jpglib/transupp.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * transupp.h - * - * Copyright (C) 1997, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains declarations for image transformation routines and - * other utility code used by the jpegtran sample application. These are - * NOT part of the core JPEG library. But we keep these routines separate - * from jpegtran.c to ease the task of maintaining jpegtran-like programs - * that have other user interfaces. - * - * NOTE: all the routines declared here have very specific requirements - * about when they are to be executed during the reading and writing of the - * source and destination files. See the comments in transupp.c, or see - * jpegtran.c for an example of correct usage. - */ - -/* If you happen not to want the image transform support, disable it here */ -#ifndef TRANSFORMS_SUPPORTED -#define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */ -#endif - -/* Short forms of external names for systems with brain-damaged linkers. */ - -#ifdef NEED_SHORT_EXTERNAL_NAMES -#define jtransform_request_workspace jTrRequest -#define jtransform_adjust_parameters jTrAdjust -#define jtransform_execute_transformation jTrExec -#define jcopy_markers_setup jCMrkSetup -#define jcopy_markers_execute jCMrkExec -#endif /* NEED_SHORT_EXTERNAL_NAMES */ - - -/* - * Codes for supported types of image transformations. - */ - -typedef enum { - JXFORM_NONE, /* no transformation */ - JXFORM_FLIP_H, /* horizontal flip */ - JXFORM_FLIP_V, /* vertical flip */ - JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ - JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ - JXFORM_ROT_90, /* 90-degree clockwise rotation */ - JXFORM_ROT_180, /* 180-degree rotation */ - JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */ -} JXFORM_CODE; - -/* - * Although rotating and flipping data expressed as DCT coefficients is not - * hard, there is an asymmetry in the JPEG format specification for images - * whose dimensions aren't multiples of the iMCU size. The right and bottom - * image edges are padded out to the next iMCU boundary with junk data; but - * no padding is possible at the top and left edges. If we were to flip - * the whole image including the pad data, then pad garbage would become - * visible at the top and/or left, and real pixels would disappear into the - * pad margins --- perhaps permanently, since encoders & decoders may not - * bother to preserve DCT blocks that appear to be completely outside the - * nominal image area. So, we have to exclude any partial iMCUs from the - * basic transformation. - * - * Transpose is the only transformation that can handle partial iMCUs at the - * right and bottom edges completely cleanly. flip_h can flip partial iMCUs - * at the bottom, but leaves any partial iMCUs at the right edge untouched. - * Similarly flip_v leaves any partial iMCUs at the bottom edge untouched. - * The other transforms are defined as combinations of these basic transforms - * and process edge blocks in a way that preserves the equivalence. - * - * The "trim" option causes untransformable partial iMCUs to be dropped; - * this is not strictly lossless, but it usually gives the best-looking - * result for odd-size images. Note that when this option is active, - * the expected mathematical equivalences between the transforms may not hold. - * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim - * followed by -rot 180 -trim trims both edges.) - * - * We also offer a "force to grayscale" option, which simply discards the - * chrominance channels of a YCbCr image. This is lossless in the sense that - * the luminance channel is preserved exactly. It's not the same kind of - * thing as the rotate/flip transformations, but it's convenient to handle it - * as part of this package, mainly because the transformation routines have to - * be aware of the option to know how many components to work on. - */ - -typedef struct { - /* Options: set by caller */ - JXFORM_CODE transform; /* image transform operator */ - boolean trim; /* if TRUE, trim partial MCUs as needed */ - boolean force_grayscale; /* if TRUE, convert color image to grayscale */ - - /* Internal workspace: caller should not touch these */ - int num_components; /* # of components in workspace */ - jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */ -} jpeg_transform_info; - - -#if TRANSFORMS_SUPPORTED - -/* Request any required workspace */ -EXTERN(void) jtransform_request_workspace - JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info)); -/* Adjust output image parameters */ -EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters - JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, - jvirt_barray_ptr *src_coef_arrays, - jpeg_transform_info *info)); -/* Execute the actual transformation, if any */ -EXTERN(void) jtransform_execute_transformation - JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, - jvirt_barray_ptr *src_coef_arrays, - jpeg_transform_info *info)); - -#endif /* TRANSFORMS_SUPPORTED */ - - -/* - * Support for copying optional markers from source to destination file. - */ - -typedef enum { - JCOPYOPT_NONE, /* copy no optional markers */ - JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */ - JCOPYOPT_ALL /* copy all optional markers */ -} JCOPY_OPTION; - -#define JCOPYOPT_DEFAULT JCOPYOPT_COMMENTS /* recommended default */ - -/* Setup decompression object to save desired markers in memory */ -EXTERN(void) jcopy_markers_setup - JPP((j_decompress_ptr srcinfo, JCOPY_OPTION option)); -/* Copy markers saved in the given source object to the destination object */ -EXTERN(void) jcopy_markers_execute - JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, - JCOPY_OPTION option)); diff --git a/source/modules/juce_graphics/image_formats/juce_GIFLoader.cpp b/source/modules/juce_graphics/image_formats/juce_GIFLoader.cpp deleted file mode 100644 index 80a101e64..000000000 --- a/source/modules/juce_graphics/image_formats/juce_GIFLoader.cpp +++ /dev/null @@ -1,451 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -#if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && JUCE_USE_COREIMAGE_LOADER - Image juce_loadWithCoreImage (InputStream& input); -#else - -//============================================================================== -class GIFLoader -{ -public: - GIFLoader (InputStream& in) - : input (in), - dataBlockIsZero (false), fresh (false), finished (false), - currentBit (0), lastBit (0), lastByteIndex (0), - codeSize (0), setCodeSize (0), maxCode (0), maxCodeSize (0), - firstcode (0), oldcode (0), clearCode (0), endCode (0) - { - int imageWidth, imageHeight; - if (! getSizeFromHeader (imageWidth, imageHeight)) - return; - - uint8 buf [16]; - if (in.read (buf, 3) != 3) - return; - - int numColours = 2 << (buf[0] & 7); - int transparent = -1; - - if ((buf[0] & 0x80) != 0) - readPalette (numColours); - - for (;;) - { - if (input.read (buf, 1) != 1 || buf[0] == ';') - break; - - if (buf[0] == '!') - { - if (readExtension (transparent)) - continue; - - break; - } - - if (buf[0] != ',') - continue; - - if (input.read (buf, 9) == 9) - { - imageWidth = (int) ByteOrder::littleEndianShort (buf + 4); - imageHeight = (int) ByteOrder::littleEndianShort (buf + 6); - - numColours = 2 << (buf[8] & 7); - - if ((buf[8] & 0x80) != 0) - if (! readPalette (numColours)) - break; - - image = Image (transparent >= 0 ? Image::ARGB : Image::RGB, - imageWidth, imageHeight, transparent >= 0); - - image.getProperties()->set ("originalImageHadAlpha", transparent >= 0); - - readImage ((buf[8] & 0x40) != 0, transparent); - } - - break; - } - } - - Image image; - -private: - InputStream& input; - uint8 buffer [260]; - PixelARGB palette [256]; - bool dataBlockIsZero, fresh, finished; - int currentBit, lastBit, lastByteIndex; - int codeSize, setCodeSize; - int maxCode, maxCodeSize; - int firstcode, oldcode; - int clearCode, endCode; - enum { maxGifCode = 1 << 12 }; - int table [2] [maxGifCode]; - int stack [2 * maxGifCode]; - int* sp; - - bool getSizeFromHeader (int& w, int& h) - { - char b[6]; - - if (input.read (b, 6) == 6 - && (strncmp ("GIF87a", b, 6) == 0 - || strncmp ("GIF89a", b, 6) == 0)) - { - if (input.read (b, 4) == 4) - { - w = (int) ByteOrder::littleEndianShort (b); - h = (int) ByteOrder::littleEndianShort (b + 2); - return w > 0 && h > 0; - } - } - - return false; - } - - bool readPalette (const int numCols) - { - for (int i = 0; i < numCols; ++i) - { - uint8 rgb[4]; - input.read (rgb, 3); - - palette[i].setARGB (0xff, rgb[0], rgb[1], rgb[2]); - palette[i].premultiply(); - } - - return true; - } - - int readDataBlock (uint8* const dest) - { - uint8 n; - if (input.read (&n, 1) == 1) - { - dataBlockIsZero = (n == 0); - - if (dataBlockIsZero || (input.read (dest, n) == n)) - return n; - } - - return -1; - } - - int readExtension (int& transparent) - { - uint8 type; - if (input.read (&type, 1) != 1) - return false; - - uint8 b [260]; - int n = 0; - - if (type == 0xf9) - { - n = readDataBlock (b); - if (n < 0) - return 1; - - if ((b[0] & 1) != 0) - transparent = b[3]; - } - - do - { - n = readDataBlock (b); - } - while (n > 0); - - return n >= 0; - } - - void clearTable() - { - int i; - for (i = 0; i < clearCode; ++i) - { - table[0][i] = 0; - table[1][i] = i; - } - - for (; i < maxGifCode; ++i) - { - table[0][i] = 0; - table[1][i] = 0; - } - } - - void initialise (const int inputCodeSize) - { - setCodeSize = inputCodeSize; - codeSize = setCodeSize + 1; - clearCode = 1 << setCodeSize; - endCode = clearCode + 1; - maxCodeSize = 2 * clearCode; - maxCode = clearCode + 2; - - getCode (0, true); - - fresh = true; - clearTable(); - sp = stack; - } - - int readLZWByte() - { - if (fresh) - { - fresh = false; - - for (;;) - { - firstcode = oldcode = getCode (codeSize, false); - - if (firstcode != clearCode) - return firstcode; - } - } - - if (sp > stack) - return *--sp; - - int code; - - while ((code = getCode (codeSize, false)) >= 0) - { - if (code == clearCode) - { - clearTable(); - codeSize = setCodeSize + 1; - maxCodeSize = 2 * clearCode; - maxCode = clearCode + 2; - sp = stack; - firstcode = oldcode = getCode (codeSize, false); - return firstcode; - } - else if (code == endCode) - { - if (dataBlockIsZero) - return -2; - - uint8 buf [260]; - int n; - - while ((n = readDataBlock (buf)) > 0) - {} - - if (n != 0) - return -2; - } - - const int incode = code; - - if (code >= maxCode) - { - *sp++ = firstcode; - code = oldcode; - } - - while (code >= clearCode) - { - *sp++ = table[1][code]; - if (code == table[0][code]) - return -2; - - code = table[0][code]; - } - - *sp++ = firstcode = table[1][code]; - - if ((code = maxCode) < maxGifCode) - { - table[0][code] = oldcode; - table[1][code] = firstcode; - ++maxCode; - - if (maxCode >= maxCodeSize && maxCodeSize < maxGifCode) - { - maxCodeSize <<= 1; - ++codeSize; - } - } - - oldcode = incode; - - if (sp > stack) - return *--sp; - } - - return code; - } - - int getCode (const int codeSize_, const bool shouldInitialise) - { - if (shouldInitialise) - { - currentBit = 0; - lastBit = 0; - finished = false; - return 0; - } - - if ((currentBit + codeSize_) >= lastBit) - { - if (finished) - return -1; - - buffer[0] = buffer [lastByteIndex - 2]; - buffer[1] = buffer [lastByteIndex - 1]; - - const int n = readDataBlock (buffer + 2); - - if (n == 0) - finished = true; - - lastByteIndex = 2 + n; - currentBit = (currentBit - lastBit) + 16; - lastBit = (2 + n) * 8 ; - } - - int result = 0; - int i = currentBit; - - for (int j = 0; j < codeSize_; ++j) - { - result |= ((buffer[i >> 3] & (1 << (i & 7))) != 0) << j; - ++i; - } - - currentBit += codeSize_; - return result; - } - - bool readImage (const int interlace, const int transparent) - { - uint8 c; - if (input.read (&c, 1) != 1) - return false; - - initialise (c); - - if (transparent >= 0) - palette [transparent].setARGB (0, 0, 0, 0); - - int xpos = 0, ypos = 0, yStep = 8, pass = 0; - - const Image::BitmapData destData (image, Image::BitmapData::writeOnly); - uint8* p = destData.getPixelPointer (0, 0); - const bool hasAlpha = image.hasAlphaChannel(); - - for (;;) - { - const int index = readLZWByte(); - if (index < 0) - break; - - if (hasAlpha) - ((PixelARGB*) p)->set (palette [index]); - else - ((PixelRGB*) p)->set (palette [index]); - - p += destData.pixelStride; - - if (++xpos == destData.width) - { - xpos = 0; - - if (interlace) - { - ypos += yStep; - - while (ypos >= destData.height) - { - switch (++pass) - { - case 1: ypos = 4; yStep = 8; break; - case 2: ypos = 2; yStep = 4; break; - case 3: ypos = 1; yStep = 2; break; - default: return true; - } - } - } - else - { - if (++ypos >= destData.height) - break; - } - - p = destData.getPixelPointer (xpos, ypos); - } - } - - return true; - } - - JUCE_DECLARE_NON_COPYABLE (GIFLoader) -}; - -#endif - -//============================================================================== -GIFImageFormat::GIFImageFormat() {} -GIFImageFormat::~GIFImageFormat() {} - -String GIFImageFormat::getFormatName() { return "GIF"; } -bool GIFImageFormat::usesFileExtension (const File& f) { return f.hasFileExtension ("gif"); } - -bool GIFImageFormat::canUnderstand (InputStream& in) -{ - char header [4]; - - return (in.read (header, sizeof (header)) == sizeof (header)) - && header[0] == 'G' - && header[1] == 'I' - && header[2] == 'F'; -} - -Image GIFImageFormat::decodeImage (InputStream& in) -{ - #if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && JUCE_USE_COREIMAGE_LOADER - return juce_loadWithCoreImage (in); - #else - const ScopedPointer loader (new GIFLoader (in)); - return loader->image; - #endif -} - -bool GIFImageFormat::writeImageToStream (const Image& /*sourceImage*/, OutputStream& /*destStream*/) -{ - jassertfalse; // writing isn't implemented for GIFs! - return false; -} - -} // namespace juce diff --git a/source/modules/juce_graphics/image_formats/juce_JPEGLoader.cpp b/source/modules/juce_graphics/image_formats/juce_JPEGLoader.cpp deleted file mode 100644 index 793d10ba6..000000000 --- a/source/modules/juce_graphics/image_formats/juce_JPEGLoader.cpp +++ /dev/null @@ -1,456 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -#if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4365) -#endif - -namespace jpeglibNamespace -{ -#if JUCE_INCLUDE_JPEGLIB_CODE || ! defined (JUCE_INCLUDE_JPEGLIB_CODE) - #if JUCE_MINGW - typedef unsigned char boolean; - #endif - - #if JUCE_CLANG - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wconversion" - #pragma clang diagnostic ignored "-Wdeprecated-register" - #if __has_warning("-Wcomma") - #pragma clang diagnostic ignored "-Wcomma" - #endif - #endif - - #define JPEG_INTERNALS - #undef FAR - #include "jpglib/jpeglib.h" - - #include "jpglib/jcapimin.c" - #include "jpglib/jcapistd.c" - #include "jpglib/jccoefct.c" - #include "jpglib/jccolor.c" - #undef FIX - #include "jpglib/jcdctmgr.c" - #undef CONST_BITS - #include "jpglib/jchuff.c" - #undef emit_byte - #include "jpglib/jcinit.c" - #include "jpglib/jcmainct.c" - #include "jpglib/jcmarker.c" - #include "jpglib/jcmaster.c" - #include "jpglib/jcomapi.c" - #include "jpglib/jcparam.c" - #include "jpglib/jcphuff.c" - #include "jpglib/jcprepct.c" - #include "jpglib/jcsample.c" - #include "jpglib/jctrans.c" - #include "jpglib/jdapistd.c" - #include "jpglib/jdapimin.c" - #include "jpglib/jdatasrc.c" - #include "jpglib/jdcoefct.c" - #undef FIX - #include "jpglib/jdcolor.c" - #undef FIX - #include "jpglib/jddctmgr.c" - #undef CONST_BITS - #undef ASSIGN_STATE - #include "jpglib/jdhuff.c" - #include "jpglib/jdinput.c" - #include "jpglib/jdmainct.c" - #include "jpglib/jdmarker.c" - #include "jpglib/jdmaster.c" - #undef FIX - #include "jpglib/jdmerge.c" - #undef ASSIGN_STATE - #include "jpglib/jdphuff.c" - #include "jpglib/jdpostct.c" - #undef FIX - #include "jpglib/jdsample.c" - #include "jpglib/jdtrans.c" - #include "jpglib/jfdctflt.c" - #include "jpglib/jfdctint.c" - #undef CONST_BITS - #undef MULTIPLY - #undef FIX_0_541196100 - #include "jpglib/jfdctfst.c" - #undef FIX_0_541196100 - #include "jpglib/jidctflt.c" - #undef CONST_BITS - #undef FIX_1_847759065 - #undef MULTIPLY - #undef DEQUANTIZE - #undef DESCALE - #include "jpglib/jidctfst.c" - #undef CONST_BITS - #undef FIX_1_847759065 - #undef MULTIPLY - #undef DEQUANTIZE - #include "jpglib/jidctint.c" - #include "jpglib/jidctred.c" - #include "jpglib/jmemmgr.c" - #include "jpglib/jmemnobs.c" - #include "jpglib/jquant1.c" - #include "jpglib/jquant2.c" - #include "jpglib/jutils.c" - #include "jpglib/transupp.c" - - #if JUCE_CLANG - #pragma clang diagnostic pop - #endif -#else - #define JPEG_INTERNALS - #undef FAR - #include -#endif -} - -#undef max -#undef min - -#if JUCE_MSVC - #pragma warning (pop) -#endif - -//============================================================================== -namespace JPEGHelpers -{ - using namespace jpeglibNamespace; - - #if ! (JUCE_WINDOWS && (JUCE_MSVC || JUCE_CLANG)) - using jpeglibNamespace::boolean; - #endif - - static void fatalErrorHandler (j_common_ptr p) { *((bool*) (p->client_data)) = true; } - static void silentErrorCallback1 (j_common_ptr) {} - static void silentErrorCallback2 (j_common_ptr, int) {} - static void silentErrorCallback3 (j_common_ptr, char*) {} - - static void setupSilentErrorHandler (struct jpeg_error_mgr& err) - { - zerostruct (err); - - err.error_exit = fatalErrorHandler; - err.emit_message = silentErrorCallback2; - err.output_message = silentErrorCallback1; - err.format_message = silentErrorCallback3; - err.reset_error_mgr = silentErrorCallback1; - } - - //============================================================================== - #if ! JUCE_USING_COREIMAGE_LOADER - static void dummyCallback1 (j_decompress_ptr) {} - - static void jpegSkip (j_decompress_ptr decompStruct, long num) - { - decompStruct->src->next_input_byte += num; - - num = jmin (num, (long) decompStruct->src->bytes_in_buffer); - decompStruct->src->bytes_in_buffer -= (size_t) num; - } - - static boolean jpegFill (j_decompress_ptr) - { - return 0; - } - #endif - - //============================================================================== - const int jpegBufferSize = 512; - - struct JuceJpegDest : public jpeg_destination_mgr - { - OutputStream* output; - char* buffer; - }; - - static void jpegWriteInit (j_compress_ptr) {} - - static void jpegWriteTerminate (j_compress_ptr cinfo) - { - JuceJpegDest* const dest = static_cast (cinfo->dest); - - const size_t numToWrite = jpegBufferSize - dest->free_in_buffer; - dest->output->write (dest->buffer, numToWrite); - } - - static boolean jpegWriteFlush (j_compress_ptr cinfo) - { - JuceJpegDest* const dest = static_cast (cinfo->dest); - - const int numToWrite = jpegBufferSize; - - dest->next_output_byte = reinterpret_cast (dest->buffer); - dest->free_in_buffer = jpegBufferSize; - - return (boolean) dest->output->write (dest->buffer, (size_t) numToWrite); - } -} - -//============================================================================== -JPEGImageFormat::JPEGImageFormat() - : quality (-1.0f) -{ -} - -JPEGImageFormat::~JPEGImageFormat() {} - -void JPEGImageFormat::setQuality (const float newQuality) -{ - quality = newQuality; -} - -String JPEGImageFormat::getFormatName() { return "JPEG"; } -bool JPEGImageFormat::usesFileExtension (const File& f) { return f.hasFileExtension ("jpeg;jpg"); } - -bool JPEGImageFormat::canUnderstand (InputStream& in) -{ - const int bytesNeeded = 24; - uint8 header [bytesNeeded]; - - if (in.read (header, bytesNeeded) == bytesNeeded - && header[0] == 0xff - && header[1] == 0xd8 - && header[2] == 0xff) - return true; - - #if JUCE_USING_COREIMAGE_LOADER - return header[20] == 'j' - && header[21] == 'p' - && header[22] == '2' - && header[23] == ' '; - #endif - - return false; -} - -#if JUCE_USING_COREIMAGE_LOADER - Image juce_loadWithCoreImage (InputStream& input); -#endif - -Image JPEGImageFormat::decodeImage (InputStream& in) -{ -#if JUCE_USING_COREIMAGE_LOADER - return juce_loadWithCoreImage (in); -#else - using namespace jpeglibNamespace; - using namespace JPEGHelpers; - - MemoryOutputStream mb; - mb << in; - - Image image; - - if (mb.getDataSize() > 16) - { - struct jpeg_decompress_struct jpegDecompStruct; - - struct jpeg_error_mgr jerr; - setupSilentErrorHandler (jerr); - jpegDecompStruct.err = &jerr; - - jpeg_create_decompress (&jpegDecompStruct); - - jpegDecompStruct.src = (jpeg_source_mgr*)(jpegDecompStruct.mem->alloc_small) - ((j_common_ptr)(&jpegDecompStruct), JPOOL_PERMANENT, sizeof (jpeg_source_mgr)); - - bool hasFailed = false; - jpegDecompStruct.client_data = &hasFailed; - - jpegDecompStruct.src->init_source = dummyCallback1; - jpegDecompStruct.src->fill_input_buffer = jpegFill; - jpegDecompStruct.src->skip_input_data = jpegSkip; - jpegDecompStruct.src->resync_to_restart = jpeg_resync_to_restart; - jpegDecompStruct.src->term_source = dummyCallback1; - - jpegDecompStruct.src->next_input_byte = static_cast (mb.getData()); - jpegDecompStruct.src->bytes_in_buffer = mb.getDataSize(); - - jpeg_read_header (&jpegDecompStruct, TRUE); - - if (! hasFailed) - { - jpeg_calc_output_dimensions (&jpegDecompStruct); - - if (! hasFailed) - { - const int width = (int) jpegDecompStruct.output_width; - const int height = (int) jpegDecompStruct.output_height; - - jpegDecompStruct.out_color_space = JCS_RGB; - - JSAMPARRAY buffer - = (*jpegDecompStruct.mem->alloc_sarray) ((j_common_ptr) &jpegDecompStruct, - JPOOL_IMAGE, - (JDIMENSION) width * 3, 1); - - if (jpeg_start_decompress (&jpegDecompStruct) && ! hasFailed) - { - image = Image (Image::RGB, width, height, false); - image.getProperties()->set ("originalImageHadAlpha", false); - const bool hasAlphaChan = image.hasAlphaChannel(); // (the native image creator may not give back what we expect) - - const Image::BitmapData destData (image, Image::BitmapData::writeOnly); - - for (int y = 0; y < height; ++y) - { - jpeg_read_scanlines (&jpegDecompStruct, buffer, 1); - - if (hasFailed) - break; - - const uint8* src = *buffer; - uint8* dest = destData.getLinePointer (y); - - if (hasAlphaChan) - { - for (int i = width; --i >= 0;) - { - ((PixelARGB*) dest)->setARGB (0xff, src[0], src[1], src[2]); - ((PixelARGB*) dest)->premultiply(); - dest += destData.pixelStride; - src += 3; - } - } - else - { - for (int i = width; --i >= 0;) - { - ((PixelRGB*) dest)->setARGB (0xff, src[0], src[1], src[2]); - dest += destData.pixelStride; - src += 3; - } - } - } - - if (! hasFailed) - jpeg_finish_decompress (&jpegDecompStruct); - - in.setPosition (((char*) jpegDecompStruct.src->next_input_byte) - (char*) mb.getData()); - } - } - } - - jpeg_destroy_decompress (&jpegDecompStruct); - } - - return image; -#endif -} - -bool JPEGImageFormat::writeImageToStream (const Image& image, OutputStream& out) -{ - using namespace jpeglibNamespace; - using namespace JPEGHelpers; - - jpeg_compress_struct jpegCompStruct; - zerostruct (jpegCompStruct); - jpeg_create_compress (&jpegCompStruct); - - struct jpeg_error_mgr jerr; - setupSilentErrorHandler (jerr); - jpegCompStruct.err = &jerr; - - JuceJpegDest dest; - jpegCompStruct.dest = &dest; - - dest.output = &out; - HeapBlock tempBuffer (jpegBufferSize); - dest.buffer = tempBuffer; - dest.next_output_byte = (JOCTET*) dest.buffer; - dest.free_in_buffer = jpegBufferSize; - dest.init_destination = jpegWriteInit; - dest.empty_output_buffer = jpegWriteFlush; - dest.term_destination = jpegWriteTerminate; - - jpegCompStruct.image_width = (JDIMENSION) image.getWidth(); - jpegCompStruct.image_height = (JDIMENSION) image.getHeight(); - jpegCompStruct.input_components = 3; - jpegCompStruct.in_color_space = JCS_RGB; - jpegCompStruct.write_JFIF_header = 1; - - jpegCompStruct.X_density = 72; - jpegCompStruct.Y_density = 72; - - jpeg_set_defaults (&jpegCompStruct); - - jpegCompStruct.dct_method = JDCT_FLOAT; - jpegCompStruct.optimize_coding = 1; - - if (quality < 0.0f) - quality = 0.85f; - - jpeg_set_quality (&jpegCompStruct, jlimit (0, 100, roundToInt (quality * 100.0f)), TRUE); - - jpeg_start_compress (&jpegCompStruct, TRUE); - - const int strideBytes = (int) (jpegCompStruct.image_width * (unsigned int) jpegCompStruct.input_components); - - JSAMPARRAY buffer = (*jpegCompStruct.mem->alloc_sarray) ((j_common_ptr) &jpegCompStruct, - JPOOL_IMAGE, (JDIMENSION) strideBytes, 1); - - const Image::BitmapData srcData (image, Image::BitmapData::readOnly); - - while (jpegCompStruct.next_scanline < jpegCompStruct.image_height) - { - uint8* dst = *buffer; - - if (srcData.pixelFormat == Image::RGB) - { - const uint8* src = srcData.getLinePointer ((int) jpegCompStruct.next_scanline); - - for (int i = srcData.width; --i >= 0;) - { - *dst++ = ((const PixelRGB*) src)->getRed(); - *dst++ = ((const PixelRGB*) src)->getGreen(); - *dst++ = ((const PixelRGB*) src)->getBlue(); - src += srcData.pixelStride; - } - } - else - { - for (int x = 0; x < srcData.width; ++x) - { - const Colour pixel (srcData.getPixelColour (x, (int) jpegCompStruct.next_scanline)); - *dst++ = pixel.getRed(); - *dst++ = pixel.getGreen(); - *dst++ = pixel.getBlue(); - } - } - - jpeg_write_scanlines (&jpegCompStruct, buffer, 1); - } - - jpeg_finish_compress (&jpegCompStruct); - jpeg_destroy_compress (&jpegCompStruct); - - return true; -} - -} // namespace juce diff --git a/source/modules/juce_graphics/image_formats/juce_PNGLoader.cpp b/source/modules/juce_graphics/image_formats/juce_PNGLoader.cpp deleted file mode 100644 index ee0627317..000000000 --- a/source/modules/juce_graphics/image_formats/juce_PNGLoader.cpp +++ /dev/null @@ -1,605 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -#if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4390 4611 4365 4267) - #ifdef __INTEL_COMPILER - #pragma warning (disable: 2544 2545) - #endif -#endif - -namespace zlibNamespace -{ -#if JUCE_INCLUDE_ZLIB_CODE - #undef OS_CODE - #undef fdopen - #include "../../juce_core/zip/zlib/zlib.h" - #undef OS_CODE -#else - #include JUCE_ZLIB_INCLUDE_PATH -#endif -} - -#if ! defined (jmp_buf) || ! defined (longjmp) - #include -#endif - -namespace pnglibNamespace -{ - using namespace zlibNamespace; - -#if JUCE_INCLUDE_PNGLIB_CODE || ! defined (JUCE_INCLUDE_PNGLIB_CODE) - - #if _MSC_VER != 1310 - using std::calloc; // (causes conflict in VS.NET 2003) - using std::malloc; - using std::free; - #endif - - #if JUCE_CLANG - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wsign-conversion" - #if __has_warning("-Wcomma") - #pragma clang diagnostic ignored "-Wcomma" - #endif - #endif - - #undef check - using std::abs; - #define NO_DUMMY_DECL - #define PNGLCONF_H 1 - - #if JUCE_ANDROID - #define PNG_ARM_NEON_SUPPORTED - #endif - - #define PNG_16BIT_SUPPORTED - #define PNG_ALIGNED_MEMORY_SUPPORTED - #define PNG_BENIGN_ERRORS_SUPPORTED - #define PNG_BENIGN_READ_ERRORS_SUPPORTED - #define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED - #define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED - #define PNG_COLORSPACE_SUPPORTED - #define PNG_CONSOLE_IO_SUPPORTED - #define PNG_EASY_ACCESS_SUPPORTED - #define PNG_FIXED_POINT_SUPPORTED - #define PNG_FLOATING_ARITHMETIC_SUPPORTED - #define PNG_FLOATING_POINT_SUPPORTED - #define PNG_FORMAT_AFIRST_SUPPORTED - #define PNG_FORMAT_BGR_SUPPORTED - #define PNG_GAMMA_SUPPORTED - #define PNG_GET_PALETTE_MAX_SUPPORTED - #define PNG_HANDLE_AS_UNKNOWN_SUPPORTED - #define PNG_INCH_CONVERSIONS_SUPPORTED - #define PNG_INFO_IMAGE_SUPPORTED - #define PNG_IO_STATE_SUPPORTED - #define PNG_MNG_FEATURES_SUPPORTED - #define PNG_POINTER_INDEXING_SUPPORTED - #define PNG_PROGRESSIVE_READ_SUPPORTED - #define PNG_READ_16BIT_SUPPORTED - #define PNG_READ_ALPHA_MODE_SUPPORTED - #define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED - #define PNG_READ_BACKGROUND_SUPPORTED - #define PNG_READ_BGR_SUPPORTED - #define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED - #define PNG_READ_COMPOSITE_NODIV_SUPPORTED - #define PNG_READ_COMPRESSED_TEXT_SUPPORTED - #define PNG_READ_EXPAND_16_SUPPORTED - #define PNG_READ_EXPAND_SUPPORTED - #define PNG_READ_FILLER_SUPPORTED - #define PNG_READ_GAMMA_SUPPORTED - #define PNG_READ_GET_PALETTE_MAX_SUPPORTED - #define PNG_READ_GRAY_TO_RGB_SUPPORTED - #define PNG_READ_INTERLACING_SUPPORTED - #define PNG_READ_INT_FUNCTIONS_SUPPORTED - #define PNG_READ_INVERT_ALPHA_SUPPORTED - #define PNG_READ_INVERT_SUPPORTED - #define PNG_READ_OPT_PLTE_SUPPORTED - #define PNG_READ_PACKSWAP_SUPPORTED - #define PNG_READ_PACK_SUPPORTED - #define PNG_READ_QUANTIZE_SUPPORTED - #define PNG_READ_RGB_TO_GRAY_SUPPORTED - #define PNG_READ_SCALE_16_TO_8_SUPPORTED - #define PNG_READ_SHIFT_SUPPORTED - #define PNG_READ_STRIP_16_TO_8_SUPPORTED - #define PNG_READ_STRIP_ALPHA_SUPPORTED - #define PNG_READ_SUPPORTED - #define PNG_READ_SWAP_ALPHA_SUPPORTED - #define PNG_READ_SWAP_SUPPORTED - #define PNG_READ_TEXT_SUPPORTED - #define PNG_READ_TRANSFORMS_SUPPORTED - #define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED - #define PNG_READ_USER_CHUNKS_SUPPORTED - #define PNG_READ_USER_TRANSFORM_SUPPORTED - #define PNG_READ_bKGD_SUPPORTED - #define PNG_READ_cHRM_SUPPORTED - #define PNG_READ_gAMA_SUPPORTED - #define PNG_READ_hIST_SUPPORTED - #define PNG_READ_iCCP_SUPPORTED - #define PNG_READ_iTXt_SUPPORTED - #define PNG_READ_oFFs_SUPPORTED - #define PNG_READ_pCAL_SUPPORTED - #define PNG_READ_pHYs_SUPPORTED - #define PNG_READ_sBIT_SUPPORTED - #define PNG_READ_sCAL_SUPPORTED - #define PNG_READ_sPLT_SUPPORTED - #define PNG_READ_sRGB_SUPPORTED - #define PNG_READ_tEXt_SUPPORTED - #define PNG_READ_tIME_SUPPORTED - #define PNG_READ_tRNS_SUPPORTED - #define PNG_READ_zTXt_SUPPORTED - #define PNG_SAVE_INT_32_SUPPORTED - #define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED - #define PNG_SEQUENTIAL_READ_SUPPORTED - #define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED - #define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED - #define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED - #define PNG_SET_USER_LIMITS_SUPPORTED - #define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED - #define PNG_SIMPLIFIED_READ_BGR_SUPPORTED - #define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED - #define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED - #define PNG_STDIO_SUPPORTED - #define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED - #define PNG_TEXT_SUPPORTED - #define PNG_TIME_RFC1123_SUPPORTED - #define PNG_UNKNOWN_CHUNKS_SUPPORTED - #define PNG_USER_CHUNKS_SUPPORTED - #define PNG_USER_LIMITS_SUPPORTED - #define PNG_USER_TRANSFORM_INFO_SUPPORTED - #define PNG_USER_TRANSFORM_PTR_SUPPORTED - #define PNG_WARNINGS_SUPPORTED - #define PNG_WRITE_16BIT_SUPPORTED - #define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED - #define PNG_WRITE_BGR_SUPPORTED - #define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED - #define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED - #define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED - #define PNG_WRITE_FILLER_SUPPORTED - #define PNG_WRITE_FILTER_SUPPORTED - #define PNG_WRITE_FLUSH_SUPPORTED - #define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED - #define PNG_WRITE_INTERLACING_SUPPORTED - #define PNG_WRITE_INT_FUNCTIONS_SUPPORTED - #define PNG_WRITE_INVERT_ALPHA_SUPPORTED - #define PNG_WRITE_INVERT_SUPPORTED - #define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED - #define PNG_WRITE_PACKSWAP_SUPPORTED - #define PNG_WRITE_PACK_SUPPORTED - #define PNG_WRITE_SHIFT_SUPPORTED - #define PNG_WRITE_SUPPORTED - #define PNG_WRITE_SWAP_ALPHA_SUPPORTED - #define PNG_WRITE_SWAP_SUPPORTED - #define PNG_WRITE_TEXT_SUPPORTED - #define PNG_WRITE_TRANSFORMS_SUPPORTED - #define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - #define PNG_WRITE_USER_TRANSFORM_SUPPORTED - #define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - #define PNG_WRITE_bKGD_SUPPORTED - #define PNG_WRITE_cHRM_SUPPORTED - #define PNG_WRITE_gAMA_SUPPORTED - #define PNG_WRITE_hIST_SUPPORTED - #define PNG_WRITE_iCCP_SUPPORTED - #define PNG_WRITE_iTXt_SUPPORTED - #define PNG_WRITE_oFFs_SUPPORTED - #define PNG_WRITE_pCAL_SUPPORTED - #define PNG_WRITE_pHYs_SUPPORTED - #define PNG_WRITE_sBIT_SUPPORTED - #define PNG_WRITE_sCAL_SUPPORTED - #define PNG_WRITE_sPLT_SUPPORTED - #define PNG_WRITE_sRGB_SUPPORTED - #define PNG_WRITE_tEXt_SUPPORTED - #define PNG_WRITE_tIME_SUPPORTED - #define PNG_WRITE_tRNS_SUPPORTED - #define PNG_WRITE_zTXt_SUPPORTED - #define PNG_bKGD_SUPPORTED - #define PNG_cHRM_SUPPORTED - #define PNG_gAMA_SUPPORTED - #define PNG_hIST_SUPPORTED - #define PNG_iCCP_SUPPORTED - #define PNG_iTXt_SUPPORTED - #define PNG_oFFs_SUPPORTED - #define PNG_pCAL_SUPPORTED - #define PNG_pHYs_SUPPORTED - #define PNG_sBIT_SUPPORTED - #define PNG_sCAL_SUPPORTED - #define PNG_sPLT_SUPPORTED - #define PNG_sRGB_SUPPORTED - #define PNG_tEXt_SUPPORTED - #define PNG_tIME_SUPPORTED - #define PNG_tRNS_SUPPORTED - #define PNG_zTXt_SUPPORTED - - #define PNG_STRING_COPYRIGHT ""; - #define PNG_STRING_NEWLINE "\n" - #define PNG_LITERAL_SHARP 0x23 - #define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b - #define PNG_LITERAL_RIGHT_SQUARE_BRACKET 0x5d - - #define PNG_API_RULE 0 - #define PNG_CALLOC_SUPPORTED - #define PNG_COST_SHIFT 3 - #define PNG_DEFAULT_READ_MACROS 1 - #define PNG_GAMMA_THRESHOLD_FIXED 5000 - #define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE - #define PNG_INFLATE_BUF_SIZE 1024 - #define PNG_MAX_GAMMA_8 11 - #define PNG_QUANTIZE_BLUE_BITS 5 - #define PNG_QUANTIZE_GREEN_BITS 5 - #define PNG_QUANTIZE_RED_BITS 5 - #define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1) - #define PNG_TEXT_Z_DEFAULT_STRATEGY 0 - #define PNG_WEIGHT_SHIFT 8 - #define PNG_ZBUF_SIZE 8192 - #define PNG_Z_DEFAULT_COMPRESSION (-1) - #define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0 - #define PNG_Z_DEFAULT_STRATEGY 1 - #define PNG_sCAL_PRECISION 5 - #define PNG_sRGB_PROFILE_CHECKS 2 - - #define png_debug(a, b) - #define png_debug1(a, b, c) - #define png_debug2(a, b, c, d) - - #include "pnglib/png.h" - #include "pnglib/pngconf.h" - - #define PNG_NO_EXTERN - #include "pnglib/png.c" - #include "pnglib/pngerror.c" - #include "pnglib/pngget.c" - #include "pnglib/pngmem.c" - #include "pnglib/pngread.c" - #include "pnglib/pngpread.c" - #include "pnglib/pngrio.c" - #include "pnglib/pngrtran.c" - #include "pnglib/pngrutil.c" - #include "pnglib/pngset.c" - #include "pnglib/pngtrans.c" - #include "pnglib/pngwio.c" - #include "pnglib/pngwrite.c" - #include "pnglib/pngwtran.c" - #include "pnglib/pngwutil.c" - - #if JUCE_CLANG - #pragma clang diagnostic pop - #endif -#else - extern "C" - { - #include - #include - } -#endif -} - -#undef max -#undef min -#undef fdopen - -#if JUCE_MSVC - #pragma warning (pop) -#endif - -//============================================================================== -namespace PNGHelpers -{ - using namespace pnglibNamespace; - - static void JUCE_CDECL writeDataCallback (png_structp png, png_bytep data, png_size_t length) - { - static_cast (png_get_io_ptr (png))->write (data, length); - } - - #if ! JUCE_USING_COREIMAGE_LOADER - static void JUCE_CDECL readCallback (png_structp png, png_bytep data, png_size_t length) - { - static_cast (png_get_io_ptr (png))->read (data, (int) length); - } - - struct PNGErrorStruct {}; - - static void JUCE_CDECL errorCallback (png_structp p, png_const_charp) - { - #ifdef PNG_SETJMP_SUPPORTED - setjmp(png_jmpbuf(p)); - #else - longjmp (*(jmp_buf*) p->error_ptr, 1); - #endif - } - - static void JUCE_CDECL warningCallback (png_structp, png_const_charp) {} - - #if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4611) // (warning about setjmp) - #endif - - static bool readHeader (InputStream& in, png_structp pngReadStruct, png_infop pngInfoStruct, jmp_buf& errorJumpBuf, - png_uint_32& width, png_uint_32& height, int& bitDepth, int& colorType, int& interlaceType) noexcept - { - if (setjmp (errorJumpBuf) == 0) - { - // read the header.. - png_set_read_fn (pngReadStruct, &in, readCallback); - - png_read_info (pngReadStruct, pngInfoStruct); - - png_get_IHDR (pngReadStruct, pngInfoStruct, - &width, &height, - &bitDepth, &colorType, - &interlaceType, 0, 0); - - if (bitDepth == 16) - png_set_strip_16 (pngReadStruct); - - if (colorType == PNG_COLOR_TYPE_PALETTE) - png_set_expand (pngReadStruct); - - if (bitDepth < 8) - png_set_expand (pngReadStruct); - - if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb (pngReadStruct); - - return true; - } - - return false; - } - - static bool readImageData (png_structp pngReadStruct, png_infop pngInfoStruct, jmp_buf& errorJumpBuf, png_bytepp rows) noexcept - { - if (setjmp (errorJumpBuf) == 0) - { - if (png_get_valid (pngReadStruct, pngInfoStruct, PNG_INFO_tRNS)) - png_set_expand (pngReadStruct); - - png_set_add_alpha (pngReadStruct, 0xff, PNG_FILLER_AFTER); - - png_read_image (pngReadStruct, rows); - png_read_end (pngReadStruct, pngInfoStruct); - return true; - } - - return false; - } - - #if JUCE_MSVC - #pragma warning (pop) - #endif - - static Image createImageFromData (bool hasAlphaChan, int width, int height, png_bytepp rows) - { - // now convert the data to a juce image format.. - Image image (hasAlphaChan ? Image::ARGB : Image::RGB, width, height, hasAlphaChan); - - image.getProperties()->set ("originalImageHadAlpha", image.hasAlphaChannel()); - hasAlphaChan = image.hasAlphaChannel(); // (the native image creator may not give back what we expect) - - const Image::BitmapData destData (image, Image::BitmapData::writeOnly); - - for (int y = 0; y < (int) height; ++y) - { - const uint8* src = rows[y]; - uint8* dest = destData.getLinePointer (y); - - if (hasAlphaChan) - { - for (int i = (int) width; --i >= 0;) - { - ((PixelARGB*) dest)->setARGB (src[3], src[0], src[1], src[2]); - ((PixelARGB*) dest)->premultiply(); - dest += destData.pixelStride; - src += 4; - } - } - else - { - for (int i = (int) width; --i >= 0;) - { - ((PixelRGB*) dest)->setARGB (0, src[0], src[1], src[2]); - dest += destData.pixelStride; - src += 4; - } - } - } - - return image; - } - - static Image readImage (InputStream& in, png_structp pngReadStruct, png_infop pngInfoStruct) - { - jmp_buf errorJumpBuf; - png_set_error_fn (pngReadStruct, &errorJumpBuf, errorCallback, warningCallback); - - png_uint_32 width = 0, height = 0; - int bitDepth = 0, colorType = 0, interlaceType = 0; - - if (readHeader (in, pngReadStruct, pngInfoStruct, errorJumpBuf, - width, height, bitDepth, colorType, interlaceType)) - { - // Load the image into a temp buffer.. - const size_t lineStride = width * 4; - HeapBlock tempBuffer (height * lineStride); - HeapBlock rows (height); - - for (size_t y = 0; y < height; ++y) - rows[y] = (png_bytep) (tempBuffer + lineStride * y); - - png_bytep trans_alpha = nullptr; - png_color_16p trans_color = nullptr; - int num_trans = 0; - png_get_tRNS (pngReadStruct, pngInfoStruct, &trans_alpha, &num_trans, &trans_color); - - if (readImageData (pngReadStruct, pngInfoStruct, errorJumpBuf, rows)) - return createImageFromData ((colorType & PNG_COLOR_MASK_ALPHA) != 0 || num_trans != 0, - (int) width, (int) height, rows); - } - - return Image(); - } - - static Image readImage (InputStream& in) - { - if (png_structp pngReadStruct = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0)) - { - if (png_infop pngInfoStruct = png_create_info_struct (pngReadStruct)) - { - Image image (readImage (in, pngReadStruct, pngInfoStruct)); - png_destroy_read_struct (&pngReadStruct, &pngInfoStruct, 0); - return image; - } - - png_destroy_read_struct (&pngReadStruct, 0, 0); - } - - return Image(); - } - #endif -} - -//============================================================================== -PNGImageFormat::PNGImageFormat() {} -PNGImageFormat::~PNGImageFormat() {} - -String PNGImageFormat::getFormatName() { return "PNG"; } -bool PNGImageFormat::usesFileExtension (const File& f) { return f.hasFileExtension ("png"); } - -bool PNGImageFormat::canUnderstand (InputStream& in) -{ - const int bytesNeeded = 4; - char header [bytesNeeded]; - - return in.read (header, bytesNeeded) == bytesNeeded - && header[1] == 'P' - && header[2] == 'N' - && header[3] == 'G'; -} - -#if JUCE_USING_COREIMAGE_LOADER - Image juce_loadWithCoreImage (InputStream&); -#endif - -Image PNGImageFormat::decodeImage (InputStream& in) -{ - #if JUCE_USING_COREIMAGE_LOADER - return juce_loadWithCoreImage (in); - #else - return PNGHelpers::readImage (in); - #endif -} - -bool PNGImageFormat::writeImageToStream (const Image& image, OutputStream& out) -{ - using namespace pnglibNamespace; - const int width = image.getWidth(); - const int height = image.getHeight(); - - png_structp pngWriteStruct = png_create_write_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); - - if (pngWriteStruct == nullptr) - return false; - - png_infop pngInfoStruct = png_create_info_struct (pngWriteStruct); - - if (pngInfoStruct == nullptr) - { - png_destroy_write_struct (&pngWriteStruct, (png_infopp) nullptr); - return false; - } - - png_set_write_fn (pngWriteStruct, &out, PNGHelpers::writeDataCallback, 0); - - png_set_IHDR (pngWriteStruct, pngInfoStruct, (png_uint_32) width, (png_uint_32) height, 8, - image.hasAlphaChannel() ? PNG_COLOR_TYPE_RGB_ALPHA - : PNG_COLOR_TYPE_RGB, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, - PNG_FILTER_TYPE_BASE); - - HeapBlock rowData ((size_t) width * 4); - - png_color_8 sig_bit; - sig_bit.red = 8; - sig_bit.green = 8; - sig_bit.blue = 8; - sig_bit.gray = 0; - sig_bit.alpha = 8; - png_set_sBIT (pngWriteStruct, pngInfoStruct, &sig_bit); - - png_write_info (pngWriteStruct, pngInfoStruct); - - png_set_shift (pngWriteStruct, &sig_bit); - png_set_packing (pngWriteStruct); - - const Image::BitmapData srcData (image, Image::BitmapData::readOnly); - - for (int y = 0; y < height; ++y) - { - uint8* dst = rowData; - const uint8* src = srcData.getLinePointer (y); - - if (image.hasAlphaChannel()) - { - for (int i = width; --i >= 0;) - { - PixelARGB p (*(const PixelARGB*) src); - p.unpremultiply(); - - *dst++ = p.getRed(); - *dst++ = p.getGreen(); - *dst++ = p.getBlue(); - *dst++ = p.getAlpha(); - src += srcData.pixelStride; - } - } - else - { - for (int i = width; --i >= 0;) - { - *dst++ = ((const PixelRGB*) src)->getRed(); - *dst++ = ((const PixelRGB*) src)->getGreen(); - *dst++ = ((const PixelRGB*) src)->getBlue(); - src += srcData.pixelStride; - } - } - - png_bytep rowPtr = rowData; - png_write_rows (pngWriteStruct, &rowPtr, 1); - } - - png_write_end (pngWriteStruct, pngInfoStruct); - png_destroy_write_struct (&pngWriteStruct, &pngInfoStruct); - - return true; -} - -} // namespace juce diff --git a/source/modules/juce_graphics/image_formats/pnglib/LICENSE b/source/modules/juce_graphics/image_formats/pnglib/LICENSE deleted file mode 100644 index 462c70dfb..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/LICENSE +++ /dev/null @@ -1,109 +0,0 @@ - -This copy of the libpng notices is provided for your convenience. In case of -any discrepancy between this copy and the notices in the file png.h that is -included in the libpng distribution, the latter shall prevail. - -COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: - -If you modify libpng you may insert additional notices immediately following -this sentence. - -libpng versions 1.2.6, August 15, 2004, through 1.2.21, October 4, 2007, are -Copyright (c) 2004, 2006-2007 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-1.2.5 -with the following individual added to the list of Contributing Authors - - Cosmin Truta - -libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are -Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-1.0.6 -with the following individuals added to the list of Contributing Authors - - Simon-Pierre Cadieux - Eric S. Raymond - Gilles Vollant - -and with the following additions to the disclaimer: - - There is no warranty against interference with your enjoyment of the - library or against infringement. There is no warranty that our - efforts or the library will fulfill any of your particular purposes - or needs. This library is provided with all faults, and the entire - risk of satisfactory quality, performance, accuracy, and effort is with - the user. - -libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are -Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-0.96, -with the following individuals added to the list of Contributing Authors: - - Tom Lane - Glenn Randers-Pehrson - Willem van Schaik - -libpng versions 0.89, June 1996, through 0.96, May 1997, are -Copyright (c) 1996, 1997 Andreas Dilger -Distributed according to the same disclaimer and license as libpng-0.88, -with the following individuals added to the list of Contributing Authors: - - John Bowler - Kevin Bracey - Sam Bushell - Magnus Holmgren - Greg Roelofs - Tom Tanner - -libpng versions 0.5, May 1995, through 0.88, January 1996, are -Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - -For the purposes of this copyright and license, "Contributing Authors" -is defined as the following set of individuals: - - Andreas Dilger - Dave Martindale - Guy Eric Schalnat - Paul Schmidt - Tim Wegner - -The PNG Reference Library is supplied "AS IS". The Contributing Authors -and Group 42, Inc. disclaim all warranties, expressed or implied, -including, without limitation, the warranties of merchantability and of -fitness for any purpose. The Contributing Authors and Group 42, Inc. -assume no liability for direct, indirect, incidental, special, exemplary, -or consequential damages, which may result from the use of the PNG -Reference Library, even if advised of the possibility of such damage. - -Permission is hereby granted to use, copy, modify, and distribute this -source code, or portions hereof, for any purpose, without fee, subject -to the following restrictions: - -1. The origin of this source code must not be misrepresented. - -2. Altered versions must be plainly marked as such and must not - be misrepresented as being the original source. - -3. This Copyright notice may not be removed or altered from any - source or altered source distribution. - -The Contributing Authors and Group 42, Inc. specifically permit, without -fee, and encourage the use of this source code as a component to -supporting the PNG file format in commercial products. If you use this -source code in a product, acknowledgment is not required but would be -appreciated. - - -A "png_get_copyright" function is available, for convenient use in "about" -boxes and the like: - - printf("%s",png_get_copyright(NULL)); - -Also, the PNG logo (in PNG format, of course) is supplied in the -files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). - -Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a -certification mark of the Open Source Initiative. - -Glenn Randers-Pehrson -glennrp at users.sourceforge.net -October 4, 2007 diff --git a/source/modules/juce_graphics/image_formats/pnglib/libpng_readme.txt b/source/modules/juce_graphics/image_formats/pnglib/libpng_readme.txt deleted file mode 100644 index 75a4595a2..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/libpng_readme.txt +++ /dev/null @@ -1,2 +0,0 @@ - -These files are from the libpng library - http://www.libpng.org/ diff --git a/source/modules/juce_graphics/image_formats/pnglib/png.c b/source/modules/juce_graphics/image_formats/pnglib/png.c deleted file mode 100644 index 75e610521..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/png.c +++ /dev/null @@ -1,4295 +0,0 @@ - -/* png.c - location for general purpose libpng functions - * - * Last changed in libpng 1.6.1 [March 28, 2013] - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - */ - -#include "pngpriv.h" - -/* Generate a compiler error if there is an old png.h in the search path. */ -typedef png_libpng_version_1_6_1 Your_png_h_is_not_version_1_6_1; - -/* Tells libpng that we have already handled the first "num_bytes" bytes - * of the PNG file signature. If the PNG data is embedded into another - * stream we can set num_bytes = 8 so that libpng will not attempt to read - * or write any of the magic bytes before it starts on the IHDR. - */ - -#ifdef PNG_READ_SUPPORTED -void PNGAPI -png_set_sig_bytes(png_structrp png_ptr, int num_bytes) -{ - png_debug(1, "in png_set_sig_bytes"); - - if (png_ptr == NULL) - return; - - if (num_bytes > 8) - png_error(png_ptr, "Too many bytes for PNG signature"); - - png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes); -} - -/* Checks whether the supplied bytes match the PNG signature. We allow - * checking less than the full 8-byte signature so that those apps that - * already read the first few bytes of a file to determine the file type - * can simply check the remaining bytes for extra assurance. Returns - * an integer less than, equal to, or greater than zero if sig is found, - * respectively, to be less than, to match, or be greater than the correct - * PNG signature (this is the same behavior as strcmp, memcmp, etc). - */ -int PNGAPI -png_sig_cmp(png_const_bytep sig, png_size_t start, png_size_t num_to_check) -{ - png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; - - if (num_to_check > 8) - num_to_check = 8; - - else if (num_to_check < 1) - return (-1); - - if (start > 7) - return (-1); - - if (start + num_to_check > 8) - num_to_check = 8 - start; - - return ((int)(memcmp(&sig[start], &png_signature[start], num_to_check))); -} - -#endif /* PNG_READ_SUPPORTED */ - -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -/* Function to allocate memory for zlib */ -PNG_FUNCTION(voidpf /* PRIVATE */, -png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED) -{ - png_alloc_size_t num_bytes = size; - - if (png_ptr == NULL) - return NULL; - - if (items >= (~(png_alloc_size_t)0)/size) - { - png_warning (png_voidcast(png_structrp, png_ptr), - "Potential overflow in png_zalloc()"); - return NULL; - } - - num_bytes *= items; - return png_malloc_warn(png_voidcast(png_structrp, png_ptr), num_bytes); -} - -/* Function to free memory for zlib */ -void /* PRIVATE */ -png_zfree(voidpf png_ptr, voidpf ptr) -{ - png_free(png_voidcast(png_const_structrp,png_ptr), ptr); -} - -/* Reset the CRC variable to 32 bits of 1's. Care must be taken - * in case CRC is > 32 bits to leave the top bits 0. - */ -void /* PRIVATE */ -png_reset_crc(png_structrp png_ptr) -{ - /* The cast is safe because the crc is a 32 bit value. */ - png_ptr->crc = (png_uint_32)crc32(0, Z_NULL, 0); -} - -/* Calculate the CRC over a section of data. We can only pass as - * much data to this routine as the largest single buffer size. We - * also check that this data will actually be used before going to the - * trouble of calculating it. - */ -void /* PRIVATE */ -png_calculate_crc(png_structrp png_ptr, png_const_bytep ptr, png_size_t length) -{ - int need_crc = 1; - - if (PNG_CHUNK_ANCILLIARY(png_ptr->chunk_name)) - { - if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == - (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) - need_crc = 0; - } - - else /* critical */ - { - if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) - need_crc = 0; - } - - /* 'uLong' is defined in zlib.h as unsigned long; this means that on some - * systems it is a 64 bit value. crc32, however, returns 32 bits so the - * following cast is safe. 'uInt' may be no more than 16 bits, so it is - * necessary to perform a loop here. - */ - if (need_crc && length > 0) - { - uLong crc = png_ptr->crc; /* Should never issue a warning */ - - do - { - uInt safe_length = (uInt)length; - if (safe_length == 0) - safe_length = (uInt)-1; /* evil, but safe */ - - crc = crc32(crc, ptr, safe_length); - - /* The following should never issue compiler warnings; if they do the - * target system has characteristics that will probably violate other - * assumptions within the libpng code. - */ - ptr += safe_length; - length -= safe_length; - } - while (length > 0); - - /* And the following is always safe because the crc is only 32 bits. */ - png_ptr->crc = (png_uint_32)crc; - } -} - -/* Check a user supplied version number, called from both read and write - * functions that create a png_struct. - */ -int -png_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver) -{ - if (user_png_ver) - { - int i = 0; - - do - { - if (user_png_ver[i] != png_libpng_ver[i]) - png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; - } while (png_libpng_ver[i++]); - } - - else - png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; - - if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) - { - /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so - * we must recompile any applications that use any older library version. - * For versions after libpng 1.0, we will be compatible, so we need - * only check the first and third digits (note that when we reach version - * 1.10 we will need to check the fourth symbol, namely user_png_ver[3]). - */ - if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || - (user_png_ver[0] == '1' && (user_png_ver[2] != png_libpng_ver[2] || - user_png_ver[3] != png_libpng_ver[3])) || - (user_png_ver[0] == '0' && user_png_ver[2] < '9')) - { -#ifdef PNG_WARNINGS_SUPPORTED - size_t pos = 0; - char m[128]; - - pos = png_safecat(m, (sizeof m), pos, - "Application built with libpng-"); - pos = png_safecat(m, (sizeof m), pos, user_png_ver); - pos = png_safecat(m, (sizeof m), pos, " but running with "); - png_safecat(m, (sizeof m), pos, png_libpng_ver); - - png_warning(png_ptr, m); -#endif - -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - png_ptr->flags = 0; -#endif - - return 0; - } - } - - /* Success return. */ - return 1; -} - -/* Generic function to create a png_struct for either read or write - this - * contains the common initialization. - */ -PNG_FUNCTION(png_structp /* PRIVATE */, -png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp, - png_malloc_ptr, png_free_ptr),PNG_ALLOCATED) -{ - png_struct create_struct; -# ifdef PNG_SETJMP_SUPPORTED - jmp_buf create_jmp_buf; -# endif - - /* This temporary stack-allocated structure is used to provide a place to - * build enough context to allow the user provided memory allocator (if any) - * to be called. - */ - memset(&create_struct, 0, (sizeof create_struct)); - - /* Added at libpng-1.2.6 */ -# ifdef PNG_USER_LIMITS_SUPPORTED - create_struct.user_width_max = PNG_USER_WIDTH_MAX; - create_struct.user_height_max = PNG_USER_HEIGHT_MAX; - -# ifdef PNG_USER_CHUNK_CACHE_MAX - /* Added at libpng-1.2.43 and 1.4.0 */ - create_struct.user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX; -# endif - -# ifdef PNG_USER_CHUNK_MALLOC_MAX - /* Added at libpng-1.2.43 and 1.4.1, required only for read but exists - * in png_struct regardless. - */ - create_struct.user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX; -# endif -# endif - - /* The following two API calls simply set fields in png_struct, so it is safe - * to do them now even though error handling is not yet set up. - */ -# ifdef PNG_USER_MEM_SUPPORTED - png_set_mem_fn(&create_struct, mem_ptr, malloc_fn, free_fn); -# endif - - /* (*error_fn) can return control to the caller after the error_ptr is set, - * this will result in a memory leak unless the error_fn does something - * extremely sophisticated. The design lacks merit but is implicit in the - * API. - */ - png_set_error_fn(&create_struct, error_ptr, error_fn, warn_fn); - -# ifdef PNG_SETJMP_SUPPORTED - if (!setjmp(create_jmp_buf)) - { - /* Temporarily fake out the longjmp information until we have - * successfully completed this function. This only works if we have - * setjmp() support compiled in, but it is safe - this stuff should - * never happen. - */ - create_struct.jmp_buf_ptr = &create_jmp_buf; - create_struct.jmp_buf_size = 0; /*stack allocation*/ - create_struct.longjmp_fn = longjmp; -# else - { -# endif - /* Call the general version checker (shared with read and write code): - */ - if (png_user_version_check(&create_struct, user_png_ver)) - { - png_structrp png_ptr = png_voidcast(png_structrp, - png_malloc_warn(&create_struct, (sizeof *png_ptr))); - - if (png_ptr != NULL) - { - /* png_ptr->zstream holds a back-pointer to the png_struct, so - * this can only be done now: - */ - create_struct.zstream.zalloc = png_zalloc; - create_struct.zstream.zfree = png_zfree; - create_struct.zstream.opaque = png_ptr; - -# ifdef PNG_SETJMP_SUPPORTED - /* Eliminate the local error handling: */ - create_struct.jmp_buf_ptr = NULL; - create_struct.jmp_buf_size = 0; - create_struct.longjmp_fn = 0; -# endif - - *png_ptr = create_struct; - - /* This is the successful return point */ - return png_ptr; - } - } - } - - /* A longjmp because of a bug in the application storage allocator or a - * simple failure to allocate the png_struct. - */ - return NULL; -} - -/* Allocate the memory for an info_struct for the application. */ -PNG_FUNCTION(png_infop,PNGAPI -png_create_info_struct,(png_const_structrp png_ptr),PNG_ALLOCATED) -{ - png_inforp info_ptr; - - png_debug(1, "in png_create_info_struct"); - - if (png_ptr == NULL) - return NULL; - - /* Use the internal API that does not (or at least should not) error out, so - * that this call always returns ok. The application typically sets up the - * error handling *after* creating the info_struct because this is the way it - * has always been done in 'example.c'. - */ - info_ptr = png_voidcast(png_inforp, png_malloc_base(png_ptr, - (sizeof *info_ptr))); - - if (info_ptr != NULL) - memset(info_ptr, 0, (sizeof *info_ptr)); - - return info_ptr; -} - -/* This function frees the memory associated with a single info struct. - * Normally, one would use either png_destroy_read_struct() or - * png_destroy_write_struct() to free an info struct, but this may be - * useful for some applications. From libpng 1.6.0 this function is also used - * internally to implement the png_info release part of the 'struct' destroy - * APIs. This ensures that all possible approaches free the same data (all of - * it). - */ -void PNGAPI -png_destroy_info_struct(png_const_structrp png_ptr, png_infopp info_ptr_ptr) -{ - png_inforp info_ptr = NULL; - - png_debug(1, "in png_destroy_info_struct"); - - if (png_ptr == NULL) - return; - - if (info_ptr_ptr != NULL) - info_ptr = *info_ptr_ptr; - - if (info_ptr != NULL) - { - /* Do this first in case of an error below; if the app implements its own - * memory management this can lead to png_free calling png_error, which - * will abort this routine and return control to the app error handler. - * An infinite loop may result if it then tries to free the same info - * ptr. - */ - *info_ptr_ptr = NULL; - - png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); - memset(info_ptr, 0, (sizeof *info_ptr)); - png_free(png_ptr, info_ptr); - } -} - -/* Initialize the info structure. This is now an internal function (0.89) - * and applications using it are urged to use png_create_info_struct() - * instead. Use deprecated in 1.6.0, internal use removed (used internally it - * is just a memset). - * - * NOTE: it is almost inconceivable that this API is used because it bypasses - * the user-memory mechanism and the user error handling/warning mechanisms in - * those cases where it does anything other than a memset. - */ -PNG_FUNCTION(void,PNGAPI -png_info_init_3,(png_infopp ptr_ptr, png_size_t png_info_struct_size), - PNG_DEPRECATED) -{ - png_inforp info_ptr = *ptr_ptr; - - png_debug(1, "in png_info_init_3"); - - if (info_ptr == NULL) - return; - - if ((sizeof (png_info)) > png_info_struct_size) - { - *ptr_ptr = NULL; - /* The following line is why this API should not be used: */ - free(info_ptr); - info_ptr = png_voidcast(png_inforp, png_malloc_base(NULL, - (sizeof *info_ptr))); - *ptr_ptr = info_ptr; - } - - /* Set everything to 0 */ - memset(info_ptr, 0, (sizeof *info_ptr)); -} - -/* The following API is not called internally */ -void PNGAPI -png_data_freer(png_const_structrp png_ptr, png_inforp info_ptr, - int freer, png_uint_32 mask) -{ - png_debug(1, "in png_data_freer"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - if (freer == PNG_DESTROY_WILL_FREE_DATA) - info_ptr->free_me |= mask; - - else if (freer == PNG_USER_WILL_FREE_DATA) - info_ptr->free_me &= ~mask; - - else - png_error(png_ptr, "Unknown freer parameter in png_data_freer"); -} - -void PNGAPI -png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, - int num) -{ - png_debug(1, "in png_free_data"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - -#ifdef PNG_TEXT_SUPPORTED - /* Free text item num or (if num == -1) all text items */ - if ((mask & PNG_FREE_TEXT) & info_ptr->free_me) - { - if (num != -1) - { - if (info_ptr->text && info_ptr->text[num].key) - { - png_free(png_ptr, info_ptr->text[num].key); - info_ptr->text[num].key = NULL; - } - } - - else - { - int i; - for (i = 0; i < info_ptr->num_text; i++) - png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i); - png_free(png_ptr, info_ptr->text); - info_ptr->text = NULL; - info_ptr->num_text=0; - } - } -#endif - -#ifdef PNG_tRNS_SUPPORTED - /* Free any tRNS entry */ - if ((mask & PNG_FREE_TRNS) & info_ptr->free_me) - { - png_free(png_ptr, info_ptr->trans_alpha); - info_ptr->trans_alpha = NULL; - info_ptr->valid &= ~PNG_INFO_tRNS; - } -#endif - -#ifdef PNG_sCAL_SUPPORTED - /* Free any sCAL entry */ - if ((mask & PNG_FREE_SCAL) & info_ptr->free_me) - { - png_free(png_ptr, info_ptr->scal_s_width); - png_free(png_ptr, info_ptr->scal_s_height); - info_ptr->scal_s_width = NULL; - info_ptr->scal_s_height = NULL; - info_ptr->valid &= ~PNG_INFO_sCAL; - } -#endif - -#ifdef PNG_pCAL_SUPPORTED - /* Free any pCAL entry */ - if ((mask & PNG_FREE_PCAL) & info_ptr->free_me) - { - png_free(png_ptr, info_ptr->pcal_purpose); - png_free(png_ptr, info_ptr->pcal_units); - info_ptr->pcal_purpose = NULL; - info_ptr->pcal_units = NULL; - if (info_ptr->pcal_params != NULL) - { - unsigned int i; - for (i = 0; i < info_ptr->pcal_nparams; i++) - { - png_free(png_ptr, info_ptr->pcal_params[i]); - info_ptr->pcal_params[i] = NULL; - } - png_free(png_ptr, info_ptr->pcal_params); - info_ptr->pcal_params = NULL; - } - info_ptr->valid &= ~PNG_INFO_pCAL; - } -#endif - -#ifdef PNG_iCCP_SUPPORTED - /* Free any profile entry */ - if ((mask & PNG_FREE_ICCP) & info_ptr->free_me) - { - png_free(png_ptr, info_ptr->iccp_name); - png_free(png_ptr, info_ptr->iccp_profile); - info_ptr->iccp_name = NULL; - info_ptr->iccp_profile = NULL; - info_ptr->valid &= ~PNG_INFO_iCCP; - } -#endif - -#ifdef PNG_sPLT_SUPPORTED - /* Free a given sPLT entry, or (if num == -1) all sPLT entries */ - if ((mask & PNG_FREE_SPLT) & info_ptr->free_me) - { - if (num != -1) - { - if (info_ptr->splt_palettes) - { - png_free(png_ptr, info_ptr->splt_palettes[num].name); - png_free(png_ptr, info_ptr->splt_palettes[num].entries); - info_ptr->splt_palettes[num].name = NULL; - info_ptr->splt_palettes[num].entries = NULL; - } - } - - else - { - if (info_ptr->splt_palettes_num) - { - int i; - for (i = 0; i < info_ptr->splt_palettes_num; i++) - png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, (int)i); - - png_free(png_ptr, info_ptr->splt_palettes); - info_ptr->splt_palettes = NULL; - info_ptr->splt_palettes_num = 0; - } - info_ptr->valid &= ~PNG_INFO_sPLT; - } - } -#endif - -#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED - if ((mask & PNG_FREE_UNKN) & info_ptr->free_me) - { - if (num != -1) - { - if (info_ptr->unknown_chunks) - { - png_free(png_ptr, info_ptr->unknown_chunks[num].data); - info_ptr->unknown_chunks[num].data = NULL; - } - } - - else - { - int i; - - if (info_ptr->unknown_chunks_num) - { - for (i = 0; i < info_ptr->unknown_chunks_num; i++) - png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, (int)i); - - png_free(png_ptr, info_ptr->unknown_chunks); - info_ptr->unknown_chunks = NULL; - info_ptr->unknown_chunks_num = 0; - } - } - } -#endif - -#ifdef PNG_hIST_SUPPORTED - /* Free any hIST entry */ - if ((mask & PNG_FREE_HIST) & info_ptr->free_me) - { - png_free(png_ptr, info_ptr->hist); - info_ptr->hist = NULL; - info_ptr->valid &= ~PNG_INFO_hIST; - } -#endif - - /* Free any PLTE entry that was internally allocated */ - if ((mask & PNG_FREE_PLTE) & info_ptr->free_me) - { - png_free(png_ptr, info_ptr->palette); - info_ptr->palette = NULL; - info_ptr->valid &= ~PNG_INFO_PLTE; - info_ptr->num_palette = 0; - } - -#ifdef PNG_INFO_IMAGE_SUPPORTED - /* Free any image bits attached to the info structure */ - if ((mask & PNG_FREE_ROWS) & info_ptr->free_me) - { - if (info_ptr->row_pointers) - { - png_uint_32 row; - for (row = 0; row < info_ptr->height; row++) - { - png_free(png_ptr, info_ptr->row_pointers[row]); - info_ptr->row_pointers[row] = NULL; - } - png_free(png_ptr, info_ptr->row_pointers); - info_ptr->row_pointers = NULL; - } - info_ptr->valid &= ~PNG_INFO_IDAT; - } -#endif - - if (num != -1) - mask &= ~PNG_FREE_MUL; - - info_ptr->free_me &= ~mask; -} -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ - -/* This function returns a pointer to the io_ptr associated with the user - * functions. The application should free any memory associated with this - * pointer before png_write_destroy() or png_read_destroy() are called. - */ -png_voidp PNGAPI -png_get_io_ptr(png_const_structrp png_ptr) -{ - if (png_ptr == NULL) - return (NULL); - - return (png_ptr->io_ptr); -} - -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -# ifdef PNG_STDIO_SUPPORTED -/* Initialize the default input/output functions for the PNG file. If you - * use your own read or write routines, you can call either png_set_read_fn() - * or png_set_write_fn() instead of png_init_io(). If you have defined - * PNG_NO_STDIO or otherwise disabled PNG_STDIO_SUPPORTED, you must use a - * function of your own because "FILE *" isn't necessarily available. - */ -void PNGAPI -png_init_io(png_structrp png_ptr, png_FILE_p fp) -{ - png_debug(1, "in png_init_io"); - - if (png_ptr == NULL) - return; - - png_ptr->io_ptr = (png_voidp)fp; -} -# endif - -#ifdef PNG_SAVE_INT_32_SUPPORTED -/* The png_save_int_32 function assumes integers are stored in two's - * complement format. If this isn't the case, then this routine needs to - * be modified to write data in two's complement format. Note that, - * the following works correctly even if png_int_32 has more than 32 bits - * (compare the more complex code required on read for sign extension.) - */ -void PNGAPI -png_save_int_32(png_bytep buf, png_int_32 i) -{ - buf[0] = (png_byte)((i >> 24) & 0xff); - buf[1] = (png_byte)((i >> 16) & 0xff); - buf[2] = (png_byte)((i >> 8) & 0xff); - buf[3] = (png_byte)(i & 0xff); -} -#endif - -# ifdef PNG_TIME_RFC1123_SUPPORTED -/* Convert the supplied time into an RFC 1123 string suitable for use in - * a "Creation Time" or other text-based time string. - */ -int PNGAPI -png_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime) -{ - static PNG_CONST char short_months[12][4] = - {"Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - - if (out == NULL) - return 0; - - if (ptime->year > 9999 /* RFC1123 limitation */ || - ptime->month == 0 || ptime->month > 12 || - ptime->day == 0 || ptime->day > 31 || - ptime->hour > 23 || ptime->minute > 59 || - ptime->second > 60) - return 0; - - { - size_t pos = 0; - char number_buf[5]; /* enough for a four-digit year */ - -# define APPEND_STRING(string) pos = png_safecat(out, 29, pos, (string)) -# define APPEND_NUMBER(format, value)\ - APPEND_STRING(PNG_FORMAT_NUMBER(number_buf, format, (value))) -# define APPEND(ch) if (pos < 28) out[pos++] = (ch) - - APPEND_NUMBER(PNG_NUMBER_FORMAT_u, (unsigned)ptime->day); - APPEND(' '); - APPEND_STRING(short_months[(ptime->month - 1)]); - APPEND(' '); - APPEND_NUMBER(PNG_NUMBER_FORMAT_u, ptime->year); - APPEND(' '); - APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->hour); - APPEND(':'); - APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->minute); - APPEND(':'); - APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->second); - APPEND_STRING(" +0000"); /* This reliably terminates the buffer */ - -# undef APPEND -# undef APPEND_NUMBER -# undef APPEND_STRING - } - - return 1; -} - -# if PNG_LIBPNG_VER < 10700 -/* To do: remove the following from libpng-1.7 */ -/* Original API that uses a private buffer in png_struct. - * Deprecated because it causes png_struct to carry a spurious temporary - * buffer (png_struct::time_buffer), better to have the caller pass this in. - */ -png_const_charp PNGAPI -png_convert_to_rfc1123(png_structrp png_ptr, png_const_timep ptime) -{ - if (png_ptr != NULL) - { - /* The only failure above if png_ptr != NULL is from an invalid ptime */ - if (!png_convert_to_rfc1123_buffer(png_ptr->time_buffer, ptime)) - png_warning(png_ptr, "Ignoring invalid time value"); - - else - return png_ptr->time_buffer; - } - - return NULL; -} -# endif -# endif /* PNG_TIME_RFC1123_SUPPORTED */ - -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ - -png_const_charp PNGAPI -png_get_copyright(png_const_structrp png_ptr) -{ - PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ -#ifdef PNG_STRING_COPYRIGHT - return PNG_STRING_COPYRIGHT -#else -# ifdef __STDC__ - return PNG_STRING_NEWLINE \ - "libpng version 1.6.1 - March 28, 2013" PNG_STRING_NEWLINE \ - "Copyright (c) 1998-2013 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \ - "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ - "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \ - PNG_STRING_NEWLINE; -# else - return "libpng version 1.6.1 - March 28, 2013\ - Copyright (c) 1998-2013 Glenn Randers-Pehrson\ - Copyright (c) 1996-1997 Andreas Dilger\ - Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc."; -# endif -#endif -} - -/* The following return the library version as a short string in the - * format 1.0.0 through 99.99.99zz. To get the version of *.h files - * used with your application, print out PNG_LIBPNG_VER_STRING, which - * is defined in png.h. - * Note: now there is no difference between png_get_libpng_ver() and - * png_get_header_ver(). Due to the version_nn_nn_nn typedef guard, - * it is guaranteed that png.c uses the correct version of png.h. - */ -png_const_charp PNGAPI -png_get_libpng_ver(png_const_structrp png_ptr) -{ - /* Version of *.c files used when building libpng */ - return png_get_header_ver(png_ptr); -} - -png_const_charp PNGAPI -png_get_header_ver(png_const_structrp png_ptr) -{ - /* Version of *.h files used when building libpng */ - PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ - return PNG_LIBPNG_VER_STRING; -} - -png_const_charp PNGAPI -png_get_header_version(png_const_structrp png_ptr) -{ - /* Returns longer string containing both version and date */ - PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ -#ifdef __STDC__ - return PNG_HEADER_VERSION_STRING -# ifndef PNG_READ_SUPPORTED - " (NO READ SUPPORT)" -# endif - PNG_STRING_NEWLINE; -#else - return PNG_HEADER_VERSION_STRING; -#endif -} - -#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED -int PNGAPI -png_handle_as_unknown(png_const_structrp png_ptr, png_const_bytep chunk_name) -{ - /* Check chunk_name and return "keep" value if it's on the list, else 0 */ - png_const_bytep p, p_end; - - if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list == 0) - return PNG_HANDLE_CHUNK_AS_DEFAULT; - - p_end = png_ptr->chunk_list; - p = p_end + png_ptr->num_chunk_list*5; /* beyond end */ - - /* The code is the fifth byte after each four byte string. Historically this - * code was always searched from the end of the list, this is no longer - * necessary because the 'set' routine handles duplicate entries correcty. - */ - do /* num_chunk_list > 0, so at least one */ - { - p -= 5; - - if (!memcmp(chunk_name, p, 4)) - return p[4]; - } - while (p > p_end); - - /* This means that known chunks should be processed and unknown chunks should - * be handled according to the value of png_ptr->unknown_default; this can be - * confusing because, as a result, there are two levels of defaulting for - * unknown chunks. - */ - return PNG_HANDLE_CHUNK_AS_DEFAULT; -} - -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED -int /* PRIVATE */ -png_chunk_unknown_handling(png_const_structrp png_ptr, png_uint_32 chunk_name) -{ - png_byte chunk_string[5]; - - PNG_CSTRING_FROM_CHUNK(chunk_string, chunk_name); - return png_handle_as_unknown(png_ptr, chunk_string); -} -#endif /* READ_UNKNOWN_CHUNKS */ -#endif /* SET_UNKNOWN_CHUNKS */ - -#ifdef PNG_READ_SUPPORTED -/* This function, added to libpng-1.0.6g, is untested. */ -int PNGAPI -png_reset_zstream(png_structrp png_ptr) -{ - if (png_ptr == NULL) - return Z_STREAM_ERROR; - - /* WARNING: this resets the window bits to the maximum! */ - return (inflateReset(&png_ptr->zstream)); -} -#endif /* PNG_READ_SUPPORTED */ - -/* This function was added to libpng-1.0.7 */ -png_uint_32 PNGAPI -png_access_version_number(void) -{ - /* Version of *.c files used when building libpng */ - return((png_uint_32)PNG_LIBPNG_VER); -} - - - -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -/* Ensure that png_ptr->zstream.msg holds some appropriate error message string. - * If it doesn't 'ret' is used to set it to something appropriate, even in cases - * like Z_OK or Z_STREAM_END where the error code is apparently a success code. - */ -void /* PRIVATE */ -png_zstream_error(png_structrp png_ptr, int ret) -{ - /* Translate 'ret' into an appropriate error string, priority is given to the - * one in zstream if set. This always returns a string, even in cases like - * Z_OK or Z_STREAM_END where the error code is a success code. - */ - if (png_ptr->zstream.msg == NULL) switch (ret) - { - default: - case Z_OK: - png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return code"); - break; - - case Z_STREAM_END: - /* Normal exit */ - png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected end of LZ stream"); - break; - - case Z_NEED_DICT: - /* This means the deflate stream did not have a dictionary; this - * indicates a bogus PNG. - */ - png_ptr->zstream.msg = PNGZ_MSG_CAST("missing LZ dictionary"); - break; - - case Z_ERRNO: - /* gz APIs only: should not happen */ - png_ptr->zstream.msg = PNGZ_MSG_CAST("zlib IO error"); - break; - - case Z_STREAM_ERROR: - /* internal libpng error */ - png_ptr->zstream.msg = PNGZ_MSG_CAST("bad parameters to zlib"); - break; - - case Z_DATA_ERROR: - png_ptr->zstream.msg = PNGZ_MSG_CAST("damaged LZ stream"); - break; - - case Z_MEM_ERROR: - png_ptr->zstream.msg = PNGZ_MSG_CAST("insufficient memory"); - break; - - case Z_BUF_ERROR: - /* End of input or output; not a problem if the caller is doing - * incremental read or write. - */ - png_ptr->zstream.msg = PNGZ_MSG_CAST("truncated"); - break; - - case Z_VERSION_ERROR: - png_ptr->zstream.msg = PNGZ_MSG_CAST("unsupported zlib version"); - break; - - case PNG_UNEXPECTED_ZLIB_RETURN: - /* Compile errors here mean that zlib now uses the value co-opted in - * pngpriv.h for PNG_UNEXPECTED_ZLIB_RETURN; update the switch above - * and change pngpriv.h. Note that this message is "... return", - * whereas the default/Z_OK one is "... return code". - */ - png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return"); - break; - } -} - -/* png_convert_size: a PNGAPI but no longer in png.h, so deleted - * at libpng 1.5.5! - */ - -/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */ -#ifdef PNG_GAMMA_SUPPORTED /* always set if COLORSPACE */ -static int -png_colorspace_check_gamma(png_const_structrp png_ptr, - png_colorspacerp colorspace, png_fixed_point gAMA, int from) - /* This is called to check a new gamma value against an existing one. The - * routine returns false if the new gamma value should not be written. - * - * 'from' says where the new gamma value comes from: - * - * 0: the new gamma value is the libpng estimate for an ICC profile - * 1: the new gamma value comes from a gAMA chunk - * 2: the new gamma value comes from an sRGB chunk - */ -{ - png_fixed_point gtest; - - if ((colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 && - (!png_muldiv(>est, colorspace->gamma, PNG_FP_1, gAMA) || - png_gamma_significant(gtest))) - { - /* Either this is an sRGB image, in which case the calculated gamma - * approximation should match, or this is an image with a profile and the - * value libpng calculates for the gamma of the profile does not match the - * value recorded in the file. The former, sRGB, case is an error, the - * latter is just a warning. - */ - if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0 || from == 2) - { - png_chunk_report(png_ptr, "gamma value does not match sRGB", - PNG_CHUNK_ERROR); - /* Do not overwrite an sRGB value */ - return from == 2; - } - - else /* sRGB tag not involved */ - { - png_chunk_report(png_ptr, "gamma value does not match libpng estimate", - PNG_CHUNK_WARNING); - return from == 1; - } - } - - return 1; -} - -void /* PRIVATE */ -png_colorspace_set_gamma(png_const_structrp png_ptr, - png_colorspacerp colorspace, png_fixed_point gAMA) -{ - /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't - * occur. Since the fixed point representation is assymetrical it is - * possible for 1/gamma to overflow the limit of 21474 and this means the - * gamma value must be at least 5/100000 and hence at most 20000.0. For - * safety the limits here are a little narrower. The values are 0.00016 to - * 6250.0, which are truly ridiculous gamma values (and will produce - * displays that are all black or all white.) - * - * In 1.6.0 this test replaces the ones in pngrutil.c, in the gAMA chunk - * handling code, which only required the value to be >0. - */ - png_const_charp errmsg; - - if (gAMA < 16 || gAMA > 625000000) - errmsg = "gamma value out of range"; - -# ifdef PNG_READ_gAMA_SUPPORTED - /* Allow the application to set the gamma value more than once */ - else if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && - (colorspace->flags & PNG_COLORSPACE_FROM_gAMA) != 0) - errmsg = "duplicate"; -# endif - - /* Do nothing if the colorspace is already invalid */ - else if (colorspace->flags & PNG_COLORSPACE_INVALID) - return; - - else - { - if (png_colorspace_check_gamma(png_ptr, colorspace, gAMA, 1/*from gAMA*/)) - { - /* Store this gamma value. */ - colorspace->gamma = gAMA; - colorspace->flags |= - (PNG_COLORSPACE_HAVE_GAMMA | PNG_COLORSPACE_FROM_gAMA); - } - - /* At present if the check_gamma test fails the gamma of the colorspace is - * not updated however the colorspace is not invalidated. This - * corresponds to the case where the existing gamma comes from an sRGB - * chunk or profile. An error message has already been output. - */ - return; - } - - /* Error exit - errmsg has been set. */ - colorspace->flags |= PNG_COLORSPACE_INVALID; - png_chunk_report(png_ptr, errmsg, PNG_CHUNK_WRITE_ERROR); -} - -void /* PRIVATE */ -png_colorspace_sync_info(png_const_structrp png_ptr, png_inforp info_ptr) -{ - if (info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) - { - /* Everything is invalid */ - info_ptr->valid &= ~(PNG_INFO_gAMA|PNG_INFO_cHRM|PNG_INFO_sRGB| - PNG_INFO_iCCP); - -# ifdef PNG_COLORSPACE_SUPPORTED - /* Clean up the iCCP profile now if it won't be used. */ - png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, -1/*not used*/); -# else - PNG_UNUSED(png_ptr) -# endif - } - - else - { -# ifdef PNG_COLORSPACE_SUPPORTED - /* Leave the INFO_iCCP flag set if the pngset.c code has already set - * it; this allows a PNG to contain a profile which matches sRGB and - * yet still have that profile retrievable by the application. - */ - if (info_ptr->colorspace.flags & PNG_COLORSPACE_MATCHES_sRGB) - info_ptr->valid |= PNG_INFO_sRGB; - - else - info_ptr->valid &= ~PNG_INFO_sRGB; - - if (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) - info_ptr->valid |= PNG_INFO_cHRM; - - else - info_ptr->valid &= ~PNG_INFO_cHRM; -# endif - - if (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) - info_ptr->valid |= PNG_INFO_gAMA; - - else - info_ptr->valid &= ~PNG_INFO_gAMA; - } -} - -#ifdef PNG_READ_SUPPORTED -void /* PRIVATE */ -png_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr) -{ - if (info_ptr == NULL) /* reduce code size; check here not in the caller */ - return; - - info_ptr->colorspace = png_ptr->colorspace; - png_colorspace_sync_info(png_ptr, info_ptr); -} -#endif -#endif - -#ifdef PNG_COLORSPACE_SUPPORTED -/* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for - * cHRM, as opposed to using chromaticities. These internal APIs return - * non-zero on a parameter error. The X, Y and Z values are required to be - * positive and less than 1.0. - */ -static int -png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ) -{ - png_int_32 d, dwhite, whiteX, whiteY; - - d = XYZ->red_X + XYZ->red_Y + XYZ->red_Z; - if (!png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, d)) return 1; - if (!png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, d)) return 1; - dwhite = d; - whiteX = XYZ->red_X; - whiteY = XYZ->red_Y; - - d = XYZ->green_X + XYZ->green_Y + XYZ->green_Z; - if (!png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, d)) return 1; - if (!png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, d)) return 1; - dwhite += d; - whiteX += XYZ->green_X; - whiteY += XYZ->green_Y; - - d = XYZ->blue_X + XYZ->blue_Y + XYZ->blue_Z; - if (!png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, d)) return 1; - if (!png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, d)) return 1; - dwhite += d; - whiteX += XYZ->blue_X; - whiteY += XYZ->blue_Y; - - /* The reference white is simply the sum of the end-point (X,Y,Z) vectors, - * thus: - */ - if (!png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite)) return 1; - if (!png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite)) return 1; - - return 0; -} - -static int -png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy) -{ - png_fixed_point red_inverse, green_inverse, blue_scale; - png_fixed_point left, right, denominator; - - /* Check xy and, implicitly, z. Note that wide gamut color spaces typically - * have end points with 0 tristimulus values (these are impossible end - * points, but they are used to cover the possible colors.) - */ - if (xy->redx < 0 || xy->redx > PNG_FP_1) return 1; - if (xy->redy < 0 || xy->redy > PNG_FP_1-xy->redx) return 1; - if (xy->greenx < 0 || xy->greenx > PNG_FP_1) return 1; - if (xy->greeny < 0 || xy->greeny > PNG_FP_1-xy->greenx) return 1; - if (xy->bluex < 0 || xy->bluex > PNG_FP_1) return 1; - if (xy->bluey < 0 || xy->bluey > PNG_FP_1-xy->bluex) return 1; - if (xy->whitex < 0 || xy->whitex > PNG_FP_1) return 1; - if (xy->whitey < 0 || xy->whitey > PNG_FP_1-xy->whitex) return 1; - - /* The reverse calculation is more difficult because the original tristimulus - * value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8 - * derived values were recorded in the cHRM chunk; - * (red,green,blue,white)x(x,y). This loses one degree of freedom and - * therefore an arbitrary ninth value has to be introduced to undo the - * original transformations. - * - * Think of the original end-points as points in (X,Y,Z) space. The - * chromaticity values (c) have the property: - * - * C - * c = --------- - * X + Y + Z - * - * For each c (x,y,z) from the corresponding original C (X,Y,Z). Thus the - * three chromaticity values (x,y,z) for each end-point obey the - * relationship: - * - * x + y + z = 1 - * - * This describes the plane in (X,Y,Z) space that intersects each axis at the - * value 1.0; call this the chromaticity plane. Thus the chromaticity - * calculation has scaled each end-point so that it is on the x+y+z=1 plane - * and chromaticity is the intersection of the vector from the origin to the - * (X,Y,Z) value with the chromaticity plane. - * - * To fully invert the chromaticity calculation we would need the three - * end-point scale factors, (red-scale, green-scale, blue-scale), but these - * were not recorded. Instead we calculated the reference white (X,Y,Z) and - * recorded the chromaticity of this. The reference white (X,Y,Z) would have - * given all three of the scale factors since: - * - * color-C = color-c * color-scale - * white-C = red-C + green-C + blue-C - * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale - * - * But cHRM records only white-x and white-y, so we have lost the white scale - * factor: - * - * white-C = white-c*white-scale - * - * To handle this the inverse transformation makes an arbitrary assumption - * about white-scale: - * - * Assume: white-Y = 1.0 - * Hence: white-scale = 1/white-y - * Or: red-Y + green-Y + blue-Y = 1.0 - * - * Notice the last statement of the assumption gives an equation in three of - * the nine values we want to calculate. 8 more equations come from the - * above routine as summarised at the top above (the chromaticity - * calculation): - * - * Given: color-x = color-X / (color-X + color-Y + color-Z) - * Hence: (color-x - 1)*color-X + color.x*color-Y + color.x*color-Z = 0 - * - * This is 9 simultaneous equations in the 9 variables "color-C" and can be - * solved by Cramer's rule. Cramer's rule requires calculating 10 9x9 matrix - * determinants, however this is not as bad as it seems because only 28 of - * the total of 90 terms in the various matrices are non-zero. Nevertheless - * Cramer's rule is notoriously numerically unstable because the determinant - * calculation involves the difference of large, but similar, numbers. It is - * difficult to be sure that the calculation is stable for real world values - * and it is certain that it becomes unstable where the end points are close - * together. - * - * So this code uses the perhaps slightly less optimal but more - * understandable and totally obvious approach of calculating color-scale. - * - * This algorithm depends on the precision in white-scale and that is - * (1/white-y), so we can immediately see that as white-y approaches 0 the - * accuracy inherent in the cHRM chunk drops off substantially. - * - * libpng arithmetic: a simple invertion of the above equations - * ------------------------------------------------------------ - * - * white_scale = 1/white-y - * white-X = white-x * white-scale - * white-Y = 1.0 - * white-Z = (1 - white-x - white-y) * white_scale - * - * white-C = red-C + green-C + blue-C - * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale - * - * This gives us three equations in (red-scale,green-scale,blue-scale) where - * all the coefficients are now known: - * - * red-x*red-scale + green-x*green-scale + blue-x*blue-scale - * = white-x/white-y - * red-y*red-scale + green-y*green-scale + blue-y*blue-scale = 1 - * red-z*red-scale + green-z*green-scale + blue-z*blue-scale - * = (1 - white-x - white-y)/white-y - * - * In the last equation color-z is (1 - color-x - color-y) so we can add all - * three equations together to get an alternative third: - * - * red-scale + green-scale + blue-scale = 1/white-y = white-scale - * - * So now we have a Cramer's rule solution where the determinants are just - * 3x3 - far more tractible. Unfortunately 3x3 determinants still involve - * multiplication of three coefficients so we can't guarantee to avoid - * overflow in the libpng fixed point representation. Using Cramer's rule in - * floating point is probably a good choice here, but it's not an option for - * fixed point. Instead proceed to simplify the first two equations by - * eliminating what is likely to be the largest value, blue-scale: - * - * blue-scale = white-scale - red-scale - green-scale - * - * Hence: - * - * (red-x - blue-x)*red-scale + (green-x - blue-x)*green-scale = - * (white-x - blue-x)*white-scale - * - * (red-y - blue-y)*red-scale + (green-y - blue-y)*green-scale = - * 1 - blue-y*white-scale - * - * And now we can trivially solve for (red-scale,green-scale): - * - * green-scale = - * (white-x - blue-x)*white-scale - (red-x - blue-x)*red-scale - * ----------------------------------------------------------- - * green-x - blue-x - * - * red-scale = - * 1 - blue-y*white-scale - (green-y - blue-y) * green-scale - * --------------------------------------------------------- - * red-y - blue-y - * - * Hence: - * - * red-scale = - * ( (green-x - blue-x) * (white-y - blue-y) - - * (green-y - blue-y) * (white-x - blue-x) ) / white-y - * ------------------------------------------------------------------------- - * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x) - * - * green-scale = - * ( (red-y - blue-y) * (white-x - blue-x) - - * (red-x - blue-x) * (white-y - blue-y) ) / white-y - * ------------------------------------------------------------------------- - * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x) - * - * Accuracy: - * The input values have 5 decimal digits of accuracy. The values are all in - * the range 0 < value < 1, so simple products are in the same range but may - * need up to 10 decimal digits to preserve the original precision and avoid - * underflow. Because we are using a 32-bit signed representation we cannot - * match this; the best is a little over 9 decimal digits, less than 10. - * - * The approach used here is to preserve the maximum precision within the - * signed representation. Because the red-scale calculation above uses the - * difference between two products of values that must be in the range -1..+1 - * it is sufficient to divide the product by 7; ceil(100,000/32767*2). The - * factor is irrelevant in the calculation because it is applied to both - * numerator and denominator. - * - * Note that the values of the differences of the products of the - * chromaticities in the above equations tend to be small, for example for - * the sRGB chromaticities they are: - * - * red numerator: -0.04751 - * green numerator: -0.08788 - * denominator: -0.2241 (without white-y multiplication) - * - * The resultant Y coefficients from the chromaticities of some widely used - * color space definitions are (to 15 decimal places): - * - * sRGB - * 0.212639005871510 0.715168678767756 0.072192315360734 - * Kodak ProPhoto - * 0.288071128229293 0.711843217810102 0.000085653960605 - * Adobe RGB - * 0.297344975250536 0.627363566255466 0.075291458493998 - * Adobe Wide Gamut RGB - * 0.258728243040113 0.724682314948566 0.016589442011321 - */ - /* By the argument, above overflow should be impossible here. The return - * value of 2 indicates an internal error to the caller. - */ - if (!png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 7)) - return 2; - if (!png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 7)) - return 2; - denominator = left - right; - - /* Now find the red numerator. */ - if (!png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 7)) - return 2; - if (!png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 7)) - return 2; - - /* Overflow is possible here and it indicates an extreme set of PNG cHRM - * chunk values. This calculation actually returns the reciprocal of the - * scale value because this allows us to delay the multiplication of white-y - * into the denominator, which tends to produce a small number. - */ - if (!png_muldiv(&red_inverse, xy->whitey, denominator, left-right) || - red_inverse <= xy->whitey /* r+g+b scales = white scale */) - return 1; - - /* Similarly for green_inverse: */ - if (!png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 7)) - return 2; - if (!png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 7)) - return 2; - if (!png_muldiv(&green_inverse, xy->whitey, denominator, left-right) || - green_inverse <= xy->whitey) - return 1; - - /* And the blue scale, the checks above guarantee this can't overflow but it - * can still produce 0 for extreme cHRM values. - */ - blue_scale = png_reciprocal(xy->whitey) - png_reciprocal(red_inverse) - - png_reciprocal(green_inverse); - if (blue_scale <= 0) return 1; - - - /* And fill in the png_XYZ: */ - if (!png_muldiv(&XYZ->red_X, xy->redx, PNG_FP_1, red_inverse)) return 1; - if (!png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse)) return 1; - if (!png_muldiv(&XYZ->red_Z, PNG_FP_1 - xy->redx - xy->redy, PNG_FP_1, - red_inverse)) - return 1; - - if (!png_muldiv(&XYZ->green_X, xy->greenx, PNG_FP_1, green_inverse)) - return 1; - if (!png_muldiv(&XYZ->green_Y, xy->greeny, PNG_FP_1, green_inverse)) - return 1; - if (!png_muldiv(&XYZ->green_Z, PNG_FP_1 - xy->greenx - xy->greeny, PNG_FP_1, - green_inverse)) - return 1; - - if (!png_muldiv(&XYZ->blue_X, xy->bluex, blue_scale, PNG_FP_1)) return 1; - if (!png_muldiv(&XYZ->blue_Y, xy->bluey, blue_scale, PNG_FP_1)) return 1; - if (!png_muldiv(&XYZ->blue_Z, PNG_FP_1 - xy->bluex - xy->bluey, blue_scale, - PNG_FP_1)) - return 1; - - return 0; /*success*/ -} - -static int -png_XYZ_normalize(png_XYZ *XYZ) -{ - png_int_32 Y; - - if (XYZ->red_Y < 0 || XYZ->green_Y < 0 || XYZ->blue_Y < 0 || - XYZ->red_X < 0 || XYZ->green_X < 0 || XYZ->blue_X < 0 || - XYZ->red_Z < 0 || XYZ->green_Z < 0 || XYZ->blue_Z < 0) - return 1; - - /* Normalize by scaling so the sum of the end-point Y values is PNG_FP_1. - * IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore - * relying on addition of two positive values producing a negative one is not - * safe. - */ - Y = XYZ->red_Y; - if (0x7fffffff - Y < XYZ->green_X) return 1; - Y += XYZ->green_Y; - if (0x7fffffff - Y < XYZ->blue_X) return 1; - Y += XYZ->blue_Y; - - if (Y != PNG_FP_1) - { - if (!png_muldiv(&XYZ->red_X, XYZ->red_X, PNG_FP_1, Y)) return 1; - if (!png_muldiv(&XYZ->red_Y, XYZ->red_Y, PNG_FP_1, Y)) return 1; - if (!png_muldiv(&XYZ->red_Z, XYZ->red_Z, PNG_FP_1, Y)) return 1; - - if (!png_muldiv(&XYZ->green_X, XYZ->green_X, PNG_FP_1, Y)) return 1; - if (!png_muldiv(&XYZ->green_Y, XYZ->green_Y, PNG_FP_1, Y)) return 1; - if (!png_muldiv(&XYZ->green_Z, XYZ->green_Z, PNG_FP_1, Y)) return 1; - - if (!png_muldiv(&XYZ->blue_X, XYZ->blue_X, PNG_FP_1, Y)) return 1; - if (!png_muldiv(&XYZ->blue_Y, XYZ->blue_Y, PNG_FP_1, Y)) return 1; - if (!png_muldiv(&XYZ->blue_Z, XYZ->blue_Z, PNG_FP_1, Y)) return 1; - } - - return 0; -} - -static int -png_colorspace_endpoints_match(const png_xy *xy1, const png_xy *xy2, int delta) -{ - /* Allow an error of +/-0.01 (absolute value) on each chromaticity */ - return !(PNG_OUT_OF_RANGE(xy1->whitex, xy2->whitex,delta) || - PNG_OUT_OF_RANGE(xy1->whitey, xy2->whitey,delta) || - PNG_OUT_OF_RANGE(xy1->redx, xy2->redx, delta) || - PNG_OUT_OF_RANGE(xy1->redy, xy2->redy, delta) || - PNG_OUT_OF_RANGE(xy1->greenx, xy2->greenx,delta) || - PNG_OUT_OF_RANGE(xy1->greeny, xy2->greeny,delta) || - PNG_OUT_OF_RANGE(xy1->bluex, xy2->bluex, delta) || - PNG_OUT_OF_RANGE(xy1->bluey, xy2->bluey, delta)); -} - -/* Added in libpng-1.6.0, a different check for the validity of a set of cHRM - * chunk chromaticities. Earlier checks used to simply look for the overflow - * condition (where the determinant of the matrix to solve for XYZ ends up zero - * because the chromaticity values are not all distinct.) Despite this it is - * theoretically possible to produce chromaticities that are apparently valid - * but that rapidly degrade to invalid, potentially crashing, sets because of - * arithmetic inaccuracies when calculations are performed on them. The new - * check is to round-trip xy -> XYZ -> xy and then check that the result is - * within a small percentage of the original. - */ -static int -png_colorspace_check_xy(png_XYZ *XYZ, const png_xy *xy) -{ - int result; - png_xy xy_test; - - /* As a side-effect this routine also returns the XYZ endpoints. */ - result = png_XYZ_from_xy(XYZ, xy); - if (result) return result; - - result = png_xy_from_XYZ(&xy_test, XYZ); - if (result) return result; - - if (png_colorspace_endpoints_match(xy, &xy_test, - 5/*actually, the math is pretty accurate*/)) - return 0; - - /* Too much slip */ - return 1; -} - -/* This is the check going the other way. The XYZ is modified to normalize it - * (another side-effect) and the xy chromaticities are returned. - */ -static int -png_colorspace_check_XYZ(png_xy *xy, png_XYZ *XYZ) -{ - int result; - png_XYZ XYZtemp; - - result = png_XYZ_normalize(XYZ); - if (result) return result; - - result = png_xy_from_XYZ(xy, XYZ); - if (result) return result; - - XYZtemp = *XYZ; - return png_colorspace_check_xy(&XYZtemp, xy); -} - -/* Used to check for an endpoint match against sRGB */ -static const png_xy sRGB_xy = /* From ITU-R BT.709-3 */ -{ - /* color x y */ - /* red */ 64000, 33000, - /* green */ 30000, 60000, - /* blue */ 15000, 6000, - /* white */ 31270, 32900 -}; - -static int -png_colorspace_set_xy_and_XYZ(png_const_structrp png_ptr, - png_colorspacerp colorspace, const png_xy *xy, const png_XYZ *XYZ, - int preferred) -{ - if (colorspace->flags & PNG_COLORSPACE_INVALID) - return 0; - - /* The consistency check is performed on the chromaticities; this factors out - * variations because of the normalization (or not) of the end point Y - * values. - */ - if (preferred < 2 && (colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS)) - { - /* The end points must be reasonably close to any we already have. The - * following allows an error of up to +/-.001 - */ - if (!png_colorspace_endpoints_match(xy, &colorspace->end_points_xy, 100)) - { - colorspace->flags |= PNG_COLORSPACE_INVALID; - png_benign_error(png_ptr, "inconsistent chromaticities"); - return 0; /* failed */ - } - - /* Only overwrite with preferred values */ - if (!preferred) - return 1; /* ok, but no change */ - } - - colorspace->end_points_xy = *xy; - colorspace->end_points_XYZ = *XYZ; - colorspace->flags |= PNG_COLORSPACE_HAVE_ENDPOINTS; - - /* The end points are normally quoted to two decimal digits, so allow +/-0.01 - * on this test. - */ - if (png_colorspace_endpoints_match(xy, &sRGB_xy, 1000)) - colorspace->flags |= PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB; - - else - colorspace->flags &= PNG_COLORSPACE_CANCEL( - PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB); - - return 2; /* ok and changed */ -} - -int /* PRIVATE */ -png_colorspace_set_chromaticities(png_const_structrp png_ptr, - png_colorspacerp colorspace, const png_xy *xy, int preferred) -{ - /* We must check the end points to ensure they are reasonable - in the past - * color management systems have crashed as a result of getting bogus - * colorant values, while this isn't the fault of libpng it is the - * responsibility of libpng because PNG carries the bomb and libpng is in a - * position to protect against it. - */ - png_XYZ XYZ; - - switch (png_colorspace_check_xy(&XYZ, xy)) - { - case 0: /* success */ - return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, xy, &XYZ, - preferred); - - case 1: - /* We can't invert the chromaticities so we can't produce value XYZ - * values. Likely as not a color management system will fail too. - */ - colorspace->flags |= PNG_COLORSPACE_INVALID; - png_benign_error(png_ptr, "invalid chromaticities"); - break; - - default: - /* libpng is broken; this should be a warning but if it happens we - * want error reports so for the moment it is an error. - */ - colorspace->flags |= PNG_COLORSPACE_INVALID; - png_error(png_ptr, "internal error checking chromaticities"); - break; - } - - return 0; /* failed */ -} - -int /* PRIVATE */ -png_colorspace_set_endpoints(png_const_structrp png_ptr, - png_colorspacerp colorspace, const png_XYZ *XYZ_in, int preferred) -{ - png_XYZ XYZ = *XYZ_in; - png_xy xy; - - switch (png_colorspace_check_XYZ(&xy, &XYZ)) - { - case 0: - return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, &xy, &XYZ, - preferred); - - case 1: - /* End points are invalid. */ - colorspace->flags |= PNG_COLORSPACE_INVALID; - png_benign_error(png_ptr, "invalid end points"); - break; - - default: - colorspace->flags |= PNG_COLORSPACE_INVALID; - png_error(png_ptr, "internal error checking chromaticities"); - break; - } - - return 0; /* failed */ -} - -#if defined(PNG_sRGB_SUPPORTED) || defined(PNG_iCCP_SUPPORTED) -/* Error message generation */ -static char -png_icc_tag_char(png_uint_32 byte) -{ - byte &= 0xff; - if (byte >= 32 && byte <= 126) - return (char)byte; - else - return '?'; -} - -static void -png_icc_tag_name(char *name, png_uint_32 tag) -{ - name[0] = '\''; - name[1] = png_icc_tag_char(tag >> 24); - name[2] = png_icc_tag_char(tag >> 16); - name[3] = png_icc_tag_char(tag >> 8); - name[4] = png_icc_tag_char(tag ); - name[5] = '\''; -} - -static int -is_ICC_signature_char(png_alloc_size_t it) -{ - return it == 32 || (it >= 48 && it <= 57) || (it >= 65 && it <= 90) || - (it >= 97 && it <= 122); -} - -static int is_ICC_signature(png_alloc_size_t it) -{ - return is_ICC_signature_char(it >> 24) /* checks all the top bits */ && - is_ICC_signature_char((it >> 16) & 0xff) && - is_ICC_signature_char((it >> 8) & 0xff) && - is_ICC_signature_char(it & 0xff); -} - -static int -png_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace, - png_const_charp name, png_alloc_size_t value, png_const_charp reason) -{ - size_t pos; - char message[196]; /* see below for calculation */ - - if (colorspace != NULL) - colorspace->flags |= PNG_COLORSPACE_INVALID; - - pos = png_safecat(message, (sizeof message), 0, "profile '"); /* 9 chars */ - pos = png_safecat(message, pos+79, pos, name); /* Truncate to 79 chars */ - pos = png_safecat(message, (sizeof message), pos, "': "); /* +2 = 90 */ - if (is_ICC_signature(value)) - { - /* So 'value' is at most 4 bytes and the following cast is safe */ - png_icc_tag_name(message+pos, (png_uint_32)value); - pos += 6; /* total +8; less than the else clause */ - message[pos++] = ':'; - message[pos++] = ' '; - } -# ifdef PNG_WARNINGS_SUPPORTED - else - { - char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114*/ - - pos = png_safecat(message, (sizeof message), pos, - png_format_number(number, number+(sizeof number), - PNG_NUMBER_FORMAT_x, value)); - pos = png_safecat(message, (sizeof message), pos, "h: "); /*+2 = 116*/ - } -# endif - /* The 'reason' is an arbitrary message, allow +79 maximum 195 */ - png_safecat(message, (sizeof message), pos, reason); - - /* This is recoverable, but make it unconditionally an app_error on write to - * avoid writing invalid ICC profiles into PNG files. (I.e. we handle them - * on read, with a warning, but on write unless the app turns off - * application errors the PNG won't be written.) - */ - png_chunk_report(png_ptr, message, - (colorspace != NULL) ? PNG_CHUNK_ERROR : PNG_CHUNK_WRITE_ERROR); - - return 0; -} -#endif /* sRGB || iCCP */ - -#ifdef PNG_sRGB_SUPPORTED -int /* PRIVATE */ -png_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace, - int intent) -{ - /* sRGB sets known gamma, end points and (from the chunk) intent. */ - /* IMPORTANT: these are not necessarily the values found in an ICC profile - * because ICC profiles store values adapted to a D50 environment; it is - * expected that the ICC profile mediaWhitePointTag will be D50, see the - * checks and code elsewhere to understand this better. - * - * These XYZ values, which are accurate to 5dp, produce rgb to gray - * coefficients of (6968,23435,2366), which are reduced (because they add up - * to 32769 not 32768) to (6968,23434,2366). These are the values that - * libpng has traditionally used (and are the best values given the 15bit - * algorithm used by the rgb to gray code.) - */ - static const png_XYZ sRGB_XYZ = /* D65 XYZ (*not* the D50 adapted values!) */ - { - /* color X Y Z */ - /* red */ 41239, 21264, 1933, - /* green */ 35758, 71517, 11919, - /* blue */ 18048, 7219, 95053 - }; - - /* Do nothing if the colorspace is already invalidated. */ - if (colorspace->flags & PNG_COLORSPACE_INVALID) - return 0; - - /* Check the intent, then check for existing settings. It is valid for the - * PNG file to have cHRM or gAMA chunks along with sRGB, but the values must - * be consistent with the correct values. If, however, this function is - * called below because an iCCP chunk matches sRGB then it is quite - * conceivable that an older app recorded incorrect gAMA and cHRM because of - * an incorrect calculation based on the values in the profile - this does - * *not* invalidate the profile (though it still produces an error, which can - * be ignored.) - */ - if (intent < 0 || intent >= PNG_sRGB_INTENT_LAST) - return png_icc_profile_error(png_ptr, colorspace, "sRGB", - (unsigned)intent, "invalid sRGB rendering intent"); - - if ((colorspace->flags & PNG_COLORSPACE_HAVE_INTENT) != 0 && - colorspace->rendering_intent != intent) - return png_icc_profile_error(png_ptr, colorspace, "sRGB", - (unsigned)intent, "inconsistent rendering intents"); - - if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0) - { - png_benign_error(png_ptr, "duplicate sRGB information ignored"); - return 0; - } - - /* If the standard sRGB cHRM chunk does not match the one from the PNG file - * warn but overwrite the value with the correct one. - */ - if ((colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0 && - !png_colorspace_endpoints_match(&sRGB_xy, &colorspace->end_points_xy, - 100)) - png_chunk_report(png_ptr, "cHRM chunk does not match sRGB", - PNG_CHUNK_ERROR); - - /* This check is just done for the error reporting - the routine always - * returns true when the 'from' argument corresponds to sRGB (2). - */ - (void)png_colorspace_check_gamma(png_ptr, colorspace, PNG_GAMMA_sRGB_INVERSE, - 2/*from sRGB*/); - - /* intent: bugs in GCC force 'int' to be used as the parameter type. */ - colorspace->rendering_intent = (png_uint_16)intent; - colorspace->flags |= PNG_COLORSPACE_HAVE_INTENT; - - /* endpoints */ - colorspace->end_points_xy = sRGB_xy; - colorspace->end_points_XYZ = sRGB_XYZ; - colorspace->flags |= - (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB); - - /* gamma */ - colorspace->gamma = PNG_GAMMA_sRGB_INVERSE; - colorspace->flags |= PNG_COLORSPACE_HAVE_GAMMA; - - /* Finally record that we have an sRGB profile */ - colorspace->flags |= - (PNG_COLORSPACE_MATCHES_sRGB|PNG_COLORSPACE_FROM_sRGB); - - return 1; /* set */ -} -#endif /* sRGB */ - -#ifdef PNG_iCCP_SUPPORTED -/* Encoded value of D50 as an ICC XYZNumber. From the ICC 2010 spec the value - * is XYZ(0.9642,1.0,0.8249), which scales to: - * - * (63189.8112, 65536, 54060.6464) - */ -static const png_byte D50_nCIEXYZ[12] = - { 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d }; - -int /* PRIVATE */ -png_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace, - png_const_charp name, png_uint_32 profile_length) -{ - if (profile_length < 132) - return png_icc_profile_error(png_ptr, colorspace, name, profile_length, - "too short"); - - if (profile_length & 3) - return png_icc_profile_error(png_ptr, colorspace, name, profile_length, - "invalid length"); - - return 1; -} - -int /* PRIVATE */ -png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace, - png_const_charp name, png_uint_32 profile_length, - png_const_bytep profile/* first 132 bytes only */, int color_type) -{ - png_uint_32 temp; - - /* Length check; this cannot be ignored in this code because profile_length - * is used later to check the tag table, so even if the profile seems over - * long profile_length from the caller must be correct. The caller can fix - * this up on read or write by just passing in the profile header length. - */ - temp = png_get_uint_32(profile); - if (temp != profile_length) - return png_icc_profile_error(png_ptr, colorspace, name, temp, - "length does not match profile"); - - temp = png_get_uint_32(profile+128); /* tag count: 12 bytes/tag */ - if (temp > 357913930 || /* (2^32-4-132)/12: maxium possible tag count */ - profile_length < 132+12*temp) /* truncated tag table */ - return png_icc_profile_error(png_ptr, colorspace, name, temp, - "tag count too large"); - - /* The 'intent' must be valid or we can't store it, ICC limits the intent to - * 16 bits. - */ - temp = png_get_uint_32(profile+64); - if (temp >= 0xffff) /* The ICC limit */ - return png_icc_profile_error(png_ptr, colorspace, name, temp, - "invalid rendering intent"); - - /* This is just a warning because the profile may be valid in future - * versions. - */ - if (temp >= PNG_sRGB_INTENT_LAST) - (void)png_icc_profile_error(png_ptr, NULL, name, temp, - "intent outside defined range"); - - /* At this point the tag table can't be checked because it hasn't necessarily - * been loaded; however, various header fields can be checked. These checks - * are for values permitted by the PNG spec in an ICC profile; the PNG spec - * restricts the profiles that can be passed in an iCCP chunk (they must be - * appropriate to processing PNG data!) - */ - - /* Data checks (could be skipped). These checks must be independent of the - * version number; however, the version number doesn't accomodate changes in - * the header fields (just the known tags and the interpretation of the - * data.) - */ - temp = png_get_uint_32(profile+36); /* signature 'ascp' */ - if (temp != 0x61637370) - return png_icc_profile_error(png_ptr, colorspace, name, temp, - "invalid signature"); - - /* Currently the PCS illuminant/adopted white point (the computational - * white point) are required to be D50, - * however the profile contains a record of the illuminant so perhaps ICC - * expects to be able to change this in the future (despite the rationale in - * the introduction for using a fixed PCS adopted white.) Consequently the - * following is just a warning. - */ - if (memcmp(profile+68, D50_nCIEXYZ, 12) != 0) - (void)png_icc_profile_error(png_ptr, NULL, name, 0/*no tag value*/, - "PCS illuminant is not D50"); - - /* The PNG spec requires this: - * "If the iCCP chunk is present, the image samples conform to the colour - * space represented by the embedded ICC profile as defined by the - * International Color Consortium [ICC]. The colour space of the ICC profile - * shall be an RGB colour space for colour images (PNG colour types 2, 3, and - * 6), or a greyscale colour space for greyscale images (PNG colour types 0 - * and 4)." - * - * This checking code ensures the embedded profile (on either read or write) - * conforms to the specification requirements. Notice that an ICC 'gray' - * color-space profile contains the information to transform the monochrome - * data to XYZ or L*a*b (according to which PCS the profile uses) and this - * should be used in preference to the standard libpng K channel replication - * into R, G and B channels. - * - * Previously it was suggested that an RGB profile on grayscale data could be - * handled. However it it is clear that using an RGB profile in this context - * must be an error - there is no specification of what it means. Thus it is - * almost certainly more correct to ignore the profile. - */ - temp = png_get_uint_32(profile+16); /* data colour space field */ - switch (temp) - { - case 0x52474220: /* 'RGB ' */ - if (!(color_type & PNG_COLOR_MASK_COLOR)) - return png_icc_profile_error(png_ptr, colorspace, name, temp, - "RGB color space not permitted on grayscale PNG"); - break; - - case 0x47524159: /* 'GRAY' */ - if (color_type & PNG_COLOR_MASK_COLOR) - return png_icc_profile_error(png_ptr, colorspace, name, temp, - "Gray color space not permitted on RGB PNG"); - break; - - default: - return png_icc_profile_error(png_ptr, colorspace, name, temp, - "invalid ICC profile color space"); - } - - /* It is up to the application to check that the profile class matches the - * application requirements; the spec provides no guidance, but it's pretty - * weird if the profile is not scanner ('scnr'), monitor ('mntr'), printer - * ('prtr') or 'spac' (for generic color spaces). Issue a warning in these - * cases. Issue an error for device link or abstract profiles - these don't - * contain the records necessary to transform the color-space to anything - * other than the target device (and not even that for an abstract profile). - * Profiles of these classes may not be embedded in images. - */ - temp = png_get_uint_32(profile+12); /* profile/device class */ - switch (temp) - { - case 0x73636E72: /* 'scnr' */ - case 0x6D6E7472: /* 'mntr' */ - case 0x70727472: /* 'prtr' */ - case 0x73706163: /* 'spac' */ - /* All supported */ - break; - - case 0x61627374: /* 'abst' */ - /* May not be embedded in an image */ - return png_icc_profile_error(png_ptr, colorspace, name, temp, - "invalid embedded Abstract ICC profile"); - - case 0x6C696E6B: /* 'link' */ - /* DeviceLink profiles cannnot be interpreted in a non-device specific - * fashion, if an app uses the AToB0Tag in the profile the results are - * undefined unless the result is sent to the intended device, - * therefore a DeviceLink profile should not be found embedded in a - * PNG. - */ - return png_icc_profile_error(png_ptr, colorspace, name, temp, - "unexpected DeviceLink ICC profile class"); - - case 0x6E6D636C: /* 'nmcl' */ - /* A NamedColor profile is also device specific, however it doesn't - * contain an AToB0 tag that is open to misintrepretation. Almost - * certainly it will fail the tests below. - */ - (void)png_icc_profile_error(png_ptr, NULL, name, temp, - "unexpected NamedColor ICC profile class"); - break; - - default: - /* To allow for future enhancements to the profile accept unrecognized - * profile classes with a warning, these then hit the test below on the - * tag content to ensure they are backward compatible with one of the - * understood profiles. - */ - (void)png_icc_profile_error(png_ptr, NULL, name, temp, - "unrecognized ICC profile class"); - break; - } - - /* For any profile other than a device link one the PCS must be encoded - * either in XYZ or Lab. - */ - temp = png_get_uint_32(profile+20); - switch (temp) - { - case 0x58595A20: /* 'XYZ ' */ - case 0x4C616220: /* 'Lab ' */ - break; - - default: - return png_icc_profile_error(png_ptr, colorspace, name, temp, - "unexpected ICC PCS encoding"); - } - - return 1; -} - -int /* PRIVATE */ -png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace, - png_const_charp name, png_uint_32 profile_length, - png_const_bytep profile /* header plus whole tag table */) -{ - png_uint_32 tag_count = png_get_uint_32(profile+128); - png_uint_32 itag; - png_const_bytep tag = profile+132; /* The first tag */ - - /* First scan all the tags in the table and add bits to the icc_info value - * (temporarily in 'tags'). - */ - for (itag=0; itag < tag_count; ++itag, tag += 12) - { - png_uint_32 tag_id = png_get_uint_32(tag+0); - png_uint_32 tag_start = png_get_uint_32(tag+4); /* must be aligned */ - png_uint_32 tag_length = png_get_uint_32(tag+8);/* not padded */ - - /* The ICC specification does not exclude zero length tags, therefore the - * start might actually be anywhere if there is no data, but this would be - * a clear abuse of the intent of the standard so the start is checked for - * being in range. All defined tag types have an 8 byte header - a 4 byte - * type signature then 0. - */ - if ((tag_start & 3) != 0) - { - /* CNHP730S.icc shipped with Microsoft Windows 64 violates this, it is - * only a warning here because libpng does not care about the - * alignment. - */ - (void)png_icc_profile_error(png_ptr, NULL, name, tag_id, - "ICC profile tag start not a multiple of 4"); - } - - /* This is a hard error; potentially it can cause read outside the - * profile. - */ - if (tag_start > profile_length || tag_length > profile_length - tag_start) - return png_icc_profile_error(png_ptr, colorspace, name, tag_id, - "ICC profile tag outside profile"); - } - - return 1; /* success, maybe with warnings */ -} - -#ifdef PNG_sRGB_SUPPORTED -/* Information about the known ICC sRGB profiles */ -static const struct -{ - png_uint_32 adler, crc, length; - png_uint_32 md5[4]; - png_byte have_md5; - png_byte is_broken; - png_uint_16 intent; - -# define PNG_MD5(a,b,c,d) { a, b, c, d }, (a!=0)||(b!=0)||(c!=0)||(d!=0) -# define PNG_ICC_CHECKSUM(adler, crc, md5, intent, broke, date, length, fname)\ - { adler, crc, length, md5, broke, intent }, - -} png_sRGB_checks[] = -{ - /* This data comes from contrib/tools/checksum-icc run on downloads of - * all four ICC sRGB profiles from www.color.org. - */ - /* adler32, crc32, MD5[4], intent, date, length, file-name */ - PNG_ICC_CHECKSUM(0x0a3fd9f6, 0x3b8772b9, - PNG_MD5(0x29f83dde, 0xaff255ae, 0x7842fae4, 0xca83390d), 0, 0, - "2009/03/27 21:36:31", 3048, "sRGB_IEC61966-2-1_black_scaled.icc") - - /* ICC sRGB v2 perceptual no black-compensation: */ - PNG_ICC_CHECKSUM(0x4909e5e1, 0x427ebb21, - PNG_MD5(0xc95bd637, 0xe95d8a3b, 0x0df38f99, 0xc1320389), 1, 0, - "2009/03/27 21:37:45", 3052, "sRGB_IEC61966-2-1_no_black_scaling.icc") - - PNG_ICC_CHECKSUM(0xfd2144a1, 0x306fd8ae, - PNG_MD5(0xfc663378, 0x37e2886b, 0xfd72e983, 0x8228f1b8), 0, 0, - "2009/08/10 17:28:01", 60988, "sRGB_v4_ICC_preference_displayclass.icc") - - /* ICC sRGB v4 perceptual */ - PNG_ICC_CHECKSUM(0x209c35d2, 0xbbef7812, - PNG_MD5(0x34562abf, 0x994ccd06, 0x6d2c5721, 0xd0d68c5d), 0, 0, - "2007/07/25 00:05:37", 60960, "sRGB_v4_ICC_preference.icc") - - /* The following profiles have no known MD5 checksum. If there is a match - * on the (empty) MD5 the other fields are used to attempt a match and - * a warning is produced. The first two of these profiles have a 'cprt' tag - * which suggests that they were also made by Hewlett Packard. - */ - PNG_ICC_CHECKSUM(0xa054d762, 0x5d5129ce, - PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 0, - "2004/07/21 18:57:42", 3024, "sRGB_IEC61966-2-1_noBPC.icc") - - /* This is a 'mntr' (display) profile with a mediaWhitePointTag that does not - * match the D50 PCS illuminant in the header (it is in fact the D65 values, - * so the white point is recorded as the un-adapted value.) The profiles - * below only differ in one byte - the intent - and are basically the same as - * the previous profile except for the mediaWhitePointTag error and a missing - * chromaticAdaptationTag. - */ - PNG_ICC_CHECKSUM(0xf784f3fb, 0x182ea552, - PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 0, 1/*broken*/, - "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 perceptual") - - PNG_ICC_CHECKSUM(0x0398f3fc, 0xf29e526d, - PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 1/*broken*/, - "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 media-relative") -}; - -static int -png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr, - png_const_bytep profile, uLong adler) -{ - /* The quick check is to verify just the MD5 signature and trust the - * rest of the data. Because the profile has already been verified for - * correctness this is safe. png_colorspace_set_sRGB will check the 'intent' - * field too, so if the profile has been edited with an intent not defined - * by sRGB (but maybe defined by a later ICC specification) the read of - * the profile will fail at that point. - */ - png_uint_32 length = 0; - png_uint_32 intent = 0x10000; /* invalid */ -#if PNG_sRGB_PROFILE_CHECKS > 1 - uLong crc = 0; /* the value for 0 length data */ -#endif - unsigned int i; - - for (i=0; i < (sizeof png_sRGB_checks) / (sizeof png_sRGB_checks[0]); ++i) - { - if (png_get_uint_32(profile+84) == png_sRGB_checks[i].md5[0] && - png_get_uint_32(profile+88) == png_sRGB_checks[i].md5[1] && - png_get_uint_32(profile+92) == png_sRGB_checks[i].md5[2] && - png_get_uint_32(profile+96) == png_sRGB_checks[i].md5[3]) - { - /* This may be one of the old HP profiles without an MD5, in that - * case we can only use the length and Adler32 (note that these - * are not used by default if there is an MD5!) - */ -# if PNG_sRGB_PROFILE_CHECKS == 0 - if (png_sRGB_checks[i].have_md5) - return 1+png_sRGB_checks[i].is_broken; -# endif - - /* Profile is unsigned or more checks have been configured in. */ - if (length == 0) - { - length = png_get_uint_32(profile); - intent = png_get_uint_32(profile+64); - } - - /* Length *and* intent must match */ - if (length == png_sRGB_checks[i].length && - intent == png_sRGB_checks[i].intent) - { - /* Now calculate the adler32 if not done already. */ - if (adler == 0) - { - adler = adler32(0, NULL, 0); - adler = adler32(adler, profile, length); - } - - if (adler == png_sRGB_checks[i].adler) - { - /* These basic checks suggest that the data has not been - * modified, but if the check level is more than 1 perform - * our own crc32 checksum on the data. - */ -# if PNG_sRGB_PROFILE_CHECKS > 1 - if (crc == 0) - { - crc = crc32(0, NULL, 0); - crc = crc32(crc, profile, length); - } - - /* So this check must pass for the 'return' below to happen. - */ - if (crc == png_sRGB_checks[i].crc) -# endif - { - if (png_sRGB_checks[i].is_broken) - { - /* These profiles are known to have bad data that may cause - * problems if they are used, therefore attempt to - * discourage their use, skip the 'have_md5' warning below, - * which is made irrelevant by this error. - */ - png_chunk_report(png_ptr, "known incorrect sRGB profile", - PNG_CHUNK_ERROR); - } - - /* Warn that this being done; this isn't even an error since - * the profile is perfectly valid, but it would be nice if - * people used the up-to-date ones. - */ - else if (!png_sRGB_checks[i].have_md5) - { - png_chunk_report(png_ptr, - "out-of-date sRGB profile with no signature", - PNG_CHUNK_WARNING); - } - - return 1+png_sRGB_checks[i].is_broken; - } - } - } - -# if PNG_sRGB_PROFILE_CHECKS > 0 - /* The signature matched, but the profile had been changed in some - * way. This is an apparent violation of the ICC terms of use and, - * anyway, probably indicates a data error or uninformed hacking. - */ - if (png_sRGB_checks[i].have_md5) - png_benign_error(png_ptr, - "copyright violation: edited ICC profile ignored"); -# endif - } - } - - return 0; /* no match */ -} -#endif - -#ifdef PNG_sRGB_SUPPORTED -void /* PRIVATE */ -png_icc_set_sRGB(png_const_structrp png_ptr, - png_colorspacerp colorspace, png_const_bytep profile, uLong adler) -{ - /* Is this profile one of the known ICC sRGB profiles? If it is, just set - * the sRGB information. - */ - if (png_compare_ICC_profile_with_sRGB(png_ptr, profile, adler)) - (void)png_colorspace_set_sRGB(png_ptr, colorspace, - (int)/*already checked*/png_get_uint_32(profile+64)); -} -#endif /* PNG_READ_sRGB_SUPPORTED */ - -int /* PRIVATE */ -png_colorspace_set_ICC(png_const_structrp png_ptr, png_colorspacerp colorspace, - png_const_charp name, png_uint_32 profile_length, png_const_bytep profile, - int color_type) -{ - if (colorspace->flags & PNG_COLORSPACE_INVALID) - return 0; - - if (png_icc_check_length(png_ptr, colorspace, name, profile_length) && - png_icc_check_header(png_ptr, colorspace, name, profile_length, profile, - color_type) && - png_icc_check_tag_table(png_ptr, colorspace, name, profile_length, - profile)) - { - png_icc_set_sRGB(png_ptr, colorspace, profile, 0); - return 1; - } - - /* Failure case */ - return 0; -} -#endif /* iCCP */ - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -void /* PRIVATE */ -png_colorspace_set_rgb_coefficients(png_structrp png_ptr) -{ - /* Set the rgb_to_gray coefficients from the colorspace. */ - if (!png_ptr->rgb_to_gray_coefficients_set && - (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) - { - /* png_set_background has not been called, get the coefficients from the Y - * values of the colorspace colorants. - */ - png_fixed_point r = png_ptr->colorspace.end_points_XYZ.red_Y; - png_fixed_point g = png_ptr->colorspace.end_points_XYZ.green_Y; - png_fixed_point b = png_ptr->colorspace.end_points_XYZ.blue_Y; - png_fixed_point total = r+g+b; - - if (total > 0 && - r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 && - g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 && - b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 && - r+g+b <= 32769) - { - /* We allow 0 coefficients here. r+g+b may be 32769 if two or - * all of the coefficients were rounded up. Handle this by - * reducing the *largest* coefficient by 1; this matches the - * approach used for the default coefficients in pngrtran.c - */ - int add = 0; - - if (r+g+b > 32768) - add = -1; - else if (r+g+b < 32768) - add = 1; - - if (add != 0) - { - if (g >= r && g >= b) - g += add; - else if (r >= g && r >= b) - r += add; - else - b += add; - } - - /* Check for an internal error. */ - if (r+g+b != 32768) - png_error(png_ptr, - "internal error handling cHRM coefficients"); - - else - { - png_ptr->rgb_to_gray_red_coeff = (png_uint_16)r; - png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g; - } - } - - /* This is a png_error at present even though it could be ignored - - * it should never happen, but it is important that if it does, the - * bug is fixed. - */ - else - png_error(png_ptr, "internal error handling cHRM->XYZ"); - } -} -#endif - -#endif /* COLORSPACE */ - -void /* PRIVATE */ -png_check_IHDR(png_const_structrp png_ptr, - png_uint_32 width, png_uint_32 height, int bit_depth, - int color_type, int interlace_type, int compression_type, - int filter_type) -{ - int error = 0; - - /* Check for width and height valid values */ - if (width == 0) - { - png_warning(png_ptr, "Image width is zero in IHDR"); - error = 1; - } - - if (height == 0) - { - png_warning(png_ptr, "Image height is zero in IHDR"); - error = 1; - } - -# ifdef PNG_SET_USER_LIMITS_SUPPORTED - if (width > png_ptr->user_width_max) - -# else - if (width > PNG_USER_WIDTH_MAX) -# endif - { - png_warning(png_ptr, "Image width exceeds user limit in IHDR"); - error = 1; - } - -# ifdef PNG_SET_USER_LIMITS_SUPPORTED - if (height > png_ptr->user_height_max) -# else - if (height > PNG_USER_HEIGHT_MAX) -# endif - { - png_warning(png_ptr, "Image height exceeds user limit in IHDR"); - error = 1; - } - - if (width > PNG_UINT_31_MAX) - { - png_warning(png_ptr, "Invalid image width in IHDR"); - error = 1; - } - - if (height > PNG_UINT_31_MAX) - { - png_warning(png_ptr, "Invalid image height in IHDR"); - error = 1; - } - - if (width > (PNG_UINT_32_MAX - >> 3) /* 8-byte RGBA pixels */ - - 48 /* bigrowbuf hack */ - - 1 /* filter byte */ - - 7*8 /* rounding of width to multiple of 8 pixels */ - - 8) /* extra max_pixel_depth pad */ - png_warning(png_ptr, "Width is too large for libpng to process pixels"); - - /* Check other values */ - if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && - bit_depth != 8 && bit_depth != 16) - { - png_warning(png_ptr, "Invalid bit depth in IHDR"); - error = 1; - } - - if (color_type < 0 || color_type == 1 || - color_type == 5 || color_type > 6) - { - png_warning(png_ptr, "Invalid color type in IHDR"); - error = 1; - } - - if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) || - ((color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA || - color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8)) - { - png_warning(png_ptr, "Invalid color type/bit depth combination in IHDR"); - error = 1; - } - - if (interlace_type >= PNG_INTERLACE_LAST) - { - png_warning(png_ptr, "Unknown interlace method in IHDR"); - error = 1; - } - - if (compression_type != PNG_COMPRESSION_TYPE_BASE) - { - png_warning(png_ptr, "Unknown compression method in IHDR"); - error = 1; - } - -# ifdef PNG_MNG_FEATURES_SUPPORTED - /* Accept filter_method 64 (intrapixel differencing) only if - * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and - * 2. Libpng did not read a PNG signature (this filter_method is only - * used in PNG datastreams that are embedded in MNG datastreams) and - * 3. The application called png_permit_mng_features with a mask that - * included PNG_FLAG_MNG_FILTER_64 and - * 4. The filter_method is 64 and - * 5. The color_type is RGB or RGBA - */ - if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) && - png_ptr->mng_features_permitted) - png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); - - if (filter_type != PNG_FILTER_TYPE_BASE) - { - if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && - (filter_type == PNG_INTRAPIXEL_DIFFERENCING) && - ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) && - (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_RGB_ALPHA))) - { - png_warning(png_ptr, "Unknown filter method in IHDR"); - error = 1; - } - - if (png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) - { - png_warning(png_ptr, "Invalid filter method in IHDR"); - error = 1; - } - } - -# else - if (filter_type != PNG_FILTER_TYPE_BASE) - { - png_warning(png_ptr, "Unknown filter method in IHDR"); - error = 1; - } -# endif - - if (error == 1) - png_error(png_ptr, "Invalid IHDR data"); -} - -#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) -/* ASCII to fp functions */ -/* Check an ASCII formated floating point value, see the more detailed - * comments in pngpriv.h - */ -/* The following is used internally to preserve the sticky flags */ -#define png_fp_add(state, flags) ((state) |= (flags)) -#define png_fp_set(state, value) ((state) = (value) | ((state) & PNG_FP_STICKY)) - -int /* PRIVATE */ -png_check_fp_number(png_const_charp string, png_size_t size, int *statep, - png_size_tp whereami) -{ - int state = *statep; - png_size_t i = *whereami; - - while (i < size) - { - int type; - /* First find the type of the next character */ - switch (string[i]) - { - case 43: type = PNG_FP_SAW_SIGN; break; - case 45: type = PNG_FP_SAW_SIGN + PNG_FP_NEGATIVE; break; - case 46: type = PNG_FP_SAW_DOT; break; - case 48: type = PNG_FP_SAW_DIGIT; break; - case 49: case 50: case 51: case 52: - case 53: case 54: case 55: case 56: - case 57: type = PNG_FP_SAW_DIGIT + PNG_FP_NONZERO; break; - case 69: - case 101: type = PNG_FP_SAW_E; break; - default: goto PNG_FP_End; - } - - /* Now deal with this type according to the current - * state, the type is arranged to not overlap the - * bits of the PNG_FP_STATE. - */ - switch ((state & PNG_FP_STATE) + (type & PNG_FP_SAW_ANY)) - { - case PNG_FP_INTEGER + PNG_FP_SAW_SIGN: - if (state & PNG_FP_SAW_ANY) - goto PNG_FP_End; /* not a part of the number */ - - png_fp_add(state, type); - break; - - case PNG_FP_INTEGER + PNG_FP_SAW_DOT: - /* Ok as trailer, ok as lead of fraction. */ - if (state & PNG_FP_SAW_DOT) /* two dots */ - goto PNG_FP_End; - - else if (state & PNG_FP_SAW_DIGIT) /* trailing dot? */ - png_fp_add(state, type); - - else - png_fp_set(state, PNG_FP_FRACTION | type); - - break; - - case PNG_FP_INTEGER + PNG_FP_SAW_DIGIT: - if (state & PNG_FP_SAW_DOT) /* delayed fraction */ - png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT); - - png_fp_add(state, type | PNG_FP_WAS_VALID); - - break; - - case PNG_FP_INTEGER + PNG_FP_SAW_E: - if ((state & PNG_FP_SAW_DIGIT) == 0) - goto PNG_FP_End; - - png_fp_set(state, PNG_FP_EXPONENT); - - break; - - /* case PNG_FP_FRACTION + PNG_FP_SAW_SIGN: - goto PNG_FP_End; ** no sign in fraction */ - - /* case PNG_FP_FRACTION + PNG_FP_SAW_DOT: - goto PNG_FP_End; ** Because SAW_DOT is always set */ - - case PNG_FP_FRACTION + PNG_FP_SAW_DIGIT: - png_fp_add(state, type | PNG_FP_WAS_VALID); - break; - - case PNG_FP_FRACTION + PNG_FP_SAW_E: - /* This is correct because the trailing '.' on an - * integer is handled above - so we can only get here - * with the sequence ".E" (with no preceding digits). - */ - if ((state & PNG_FP_SAW_DIGIT) == 0) - goto PNG_FP_End; - - png_fp_set(state, PNG_FP_EXPONENT); - - break; - - case PNG_FP_EXPONENT + PNG_FP_SAW_SIGN: - if (state & PNG_FP_SAW_ANY) - goto PNG_FP_End; /* not a part of the number */ - - png_fp_add(state, PNG_FP_SAW_SIGN); - - break; - - /* case PNG_FP_EXPONENT + PNG_FP_SAW_DOT: - goto PNG_FP_End; */ - - case PNG_FP_EXPONENT + PNG_FP_SAW_DIGIT: - png_fp_add(state, PNG_FP_SAW_DIGIT | PNG_FP_WAS_VALID); - - break; - - /* case PNG_FP_EXPONEXT + PNG_FP_SAW_E: - goto PNG_FP_End; */ - - default: goto PNG_FP_End; /* I.e. break 2 */ - } - - /* The character seems ok, continue. */ - ++i; - } - -PNG_FP_End: - /* Here at the end, update the state and return the correct - * return code. - */ - *statep = state; - *whereami = i; - - return (state & PNG_FP_SAW_DIGIT) != 0; -} - - -/* The same but for a complete string. */ -int -png_check_fp_string(png_const_charp string, png_size_t size) -{ - int state=0; - png_size_t char_index=0; - - if (png_check_fp_number(string, size, &state, &char_index) && - (char_index == size || string[char_index] == 0)) - return state /* must be non-zero - see above */; - - return 0; /* i.e. fail */ -} -#endif /* pCAL or sCAL */ - -#ifdef PNG_sCAL_SUPPORTED -# ifdef PNG_FLOATING_POINT_SUPPORTED -/* Utility used below - a simple accurate power of ten from an integral - * exponent. - */ -static double -png_pow10(int power) -{ - int recip = 0; - double d = 1; - - /* Handle negative exponent with a reciprocal at the end because - * 10 is exact whereas .1 is inexact in base 2 - */ - if (power < 0) - { - if (power < DBL_MIN_10_EXP) return 0; - recip = 1, power = -power; - } - - if (power > 0) - { - /* Decompose power bitwise. */ - double mult = 10; - do - { - if (power & 1) d *= mult; - mult *= mult; - power >>= 1; - } - while (power > 0); - - if (recip) d = 1/d; - } - /* else power is 0 and d is 1 */ - - return d; -} - -/* Function to format a floating point value in ASCII with a given - * precision. - */ -void /* PRIVATE */ -png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size, - double fp, unsigned int precision) -{ - /* We use standard functions from math.h, but not printf because - * that would require stdio. The caller must supply a buffer of - * sufficient size or we will png_error. The tests on size and - * the space in ascii[] consumed are indicated below. - */ - if (precision < 1) - precision = DBL_DIG; - - /* Enforce the limit of the implementation precision too. */ - if (precision > DBL_DIG+1) - precision = DBL_DIG+1; - - /* Basic sanity checks */ - if (size >= precision+5) /* See the requirements below. */ - { - if (fp < 0) - { - fp = -fp; - *ascii++ = 45; /* '-' PLUS 1 TOTAL 1 */ - --size; - } - - if (fp >= DBL_MIN && fp <= DBL_MAX) - { - int exp_b10; /* A base 10 exponent */ - double base; /* 10^exp_b10 */ - - /* First extract a base 10 exponent of the number, - * the calculation below rounds down when converting - * from base 2 to base 10 (multiply by log10(2) - - * 0.3010, but 77/256 is 0.3008, so exp_b10 needs to - * be increased. Note that the arithmetic shift - * performs a floor() unlike C arithmetic - using a - * C multiply would break the following for negative - * exponents. - */ - (void)frexp(fp, &exp_b10); /* exponent to base 2 */ - - exp_b10 = (exp_b10 * 77) >> 8; /* <= exponent to base 10 */ - - /* Avoid underflow here. */ - base = png_pow10(exp_b10); /* May underflow */ - - while (base < DBL_MIN || base < fp) - { - /* And this may overflow. */ - double test = png_pow10(exp_b10+1); - - if (test <= DBL_MAX) - ++exp_b10, base = test; - - else - break; - } - - /* Normalize fp and correct exp_b10, after this fp is in the - * range [.1,1) and exp_b10 is both the exponent and the digit - * *before* which the decimal point should be inserted - * (starting with 0 for the first digit). Note that this - * works even if 10^exp_b10 is out of range because of the - * test on DBL_MAX above. - */ - fp /= base; - while (fp >= 1) fp /= 10, ++exp_b10; - - /* Because of the code above fp may, at this point, be - * less than .1, this is ok because the code below can - * handle the leading zeros this generates, so no attempt - * is made to correct that here. - */ - - { - int czero, clead, cdigits; - char exponent[10]; - - /* Allow up to two leading zeros - this will not lengthen - * the number compared to using E-n. - */ - if (exp_b10 < 0 && exp_b10 > -3) /* PLUS 3 TOTAL 4 */ - { - czero = -exp_b10; /* PLUS 2 digits: TOTAL 3 */ - exp_b10 = 0; /* Dot added below before first output. */ - } - else - czero = 0; /* No zeros to add */ - - /* Generate the digit list, stripping trailing zeros and - * inserting a '.' before a digit if the exponent is 0. - */ - clead = czero; /* Count of leading zeros */ - cdigits = 0; /* Count of digits in list. */ - - do - { - double d; - - fp *= 10; - /* Use modf here, not floor and subtract, so that - * the separation is done in one step. At the end - * of the loop don't break the number into parts so - * that the final digit is rounded. - */ - if (cdigits+czero-clead+1 < (int)precision) - fp = modf(fp, &d); - - else - { - d = floor(fp + .5); - - if (d > 9) - { - /* Rounding up to 10, handle that here. */ - if (czero > 0) - { - --czero, d = 1; - if (cdigits == 0) --clead; - } - else - { - while (cdigits > 0 && d > 9) - { - int ch = *--ascii; - - if (exp_b10 != (-1)) - ++exp_b10; - - else if (ch == 46) - { - ch = *--ascii, ++size; - /* Advance exp_b10 to '1', so that the - * decimal point happens after the - * previous digit. - */ - exp_b10 = 1; - } - - --cdigits; - d = ch - 47; /* I.e. 1+(ch-48) */ - } - - /* Did we reach the beginning? If so adjust the - * exponent but take into account the leading - * decimal point. - */ - if (d > 9) /* cdigits == 0 */ - { - if (exp_b10 == (-1)) - { - /* Leading decimal point (plus zeros?), if - * we lose the decimal point here it must - * be reentered below. - */ - int ch = *--ascii; - - if (ch == 46) - ++size, exp_b10 = 1; - - /* Else lost a leading zero, so 'exp_b10' is - * still ok at (-1) - */ - } - else - ++exp_b10; - - /* In all cases we output a '1' */ - d = 1; - } - } - } - fp = 0; /* Guarantees termination below. */ - } - - if (d == 0.0) - { - ++czero; - if (cdigits == 0) ++clead; - } - else - { - /* Included embedded zeros in the digit count. */ - cdigits += czero - clead; - clead = 0; - - while (czero > 0) - { - /* exp_b10 == (-1) means we just output the decimal - * place - after the DP don't adjust 'exp_b10' any - * more! - */ - if (exp_b10 != (-1)) - { - if (exp_b10 == 0) *ascii++ = 46, --size; - /* PLUS 1: TOTAL 4 */ - --exp_b10; - } - *ascii++ = 48, --czero; - } - - if (exp_b10 != (-1)) - { - if (exp_b10 == 0) *ascii++ = 46, --size; /* counted - above */ - --exp_b10; - } - *ascii++ = (char)(48 + (int)d), ++cdigits; - } - } - while (cdigits+czero-clead < (int)precision && fp > DBL_MIN); - - /* The total output count (max) is now 4+precision */ - - /* Check for an exponent, if we don't need one we are - * done and just need to terminate the string. At - * this point exp_b10==(-1) is effectively if flag - it got - * to '-1' because of the decrement after outputing - * the decimal point above (the exponent required is - * *not* -1!) - */ - if (exp_b10 >= (-1) && exp_b10 <= 2) - { - /* The following only happens if we didn't output the - * leading zeros above for negative exponent, so this - * doest add to the digit requirement. Note that the - * two zeros here can only be output if the two leading - * zeros were *not* output, so this doesn't increase - * the output count. - */ - while (--exp_b10 >= 0) *ascii++ = 48; - - *ascii = 0; - - /* Total buffer requirement (including the '\0') is - * 5+precision - see check at the start. - */ - return; - } - - /* Here if an exponent is required, adjust size for - * the digits we output but did not count. The total - * digit output here so far is at most 1+precision - no - * decimal point and no leading or trailing zeros have - * been output. - */ - size -= cdigits; - - *ascii++ = 69, --size; /* 'E': PLUS 1 TOTAL 2+precision */ - - /* The following use of an unsigned temporary avoids ambiguities in - * the signed arithmetic on exp_b10 and permits GCC at least to do - * better optimization. - */ - { - unsigned int uexp_b10; - - if (exp_b10 < 0) - { - *ascii++ = 45, --size; /* '-': PLUS 1 TOTAL 3+precision */ - uexp_b10 = -exp_b10; - } - - else - uexp_b10 = exp_b10; - - cdigits = 0; - - while (uexp_b10 > 0) - { - exponent[cdigits++] = (char)(48 + uexp_b10 % 10); - uexp_b10 /= 10; - } - } - - /* Need another size check here for the exponent digits, so - * this need not be considered above. - */ - if ((int)size > cdigits) - { - while (cdigits > 0) *ascii++ = exponent[--cdigits]; - - *ascii = 0; - - return; - } - } - } - else if (!(fp >= DBL_MIN)) - { - *ascii++ = 48; /* '0' */ - *ascii = 0; - return; - } - else - { - *ascii++ = 105; /* 'i' */ - *ascii++ = 110; /* 'n' */ - *ascii++ = 102; /* 'f' */ - *ascii = 0; - return; - } - } - - /* Here on buffer too small. */ - png_error(png_ptr, "ASCII conversion buffer too small"); -} - -# endif /* FLOATING_POINT */ - -# ifdef PNG_FIXED_POINT_SUPPORTED -/* Function to format a fixed point value in ASCII. - */ -void /* PRIVATE */ -png_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii, - png_size_t size, png_fixed_point fp) -{ - /* Require space for 10 decimal digits, a decimal point, a minus sign and a - * trailing \0, 13 characters: - */ - if (size > 12) - { - png_uint_32 num; - - /* Avoid overflow here on the minimum integer. */ - if (fp < 0) - *ascii++ = 45, --size, num = -fp; - else - num = fp; - - if (num <= 0x80000000) /* else overflowed */ - { - unsigned int ndigits = 0, first = 16 /* flag value */; - char digits[10]; - - while (num) - { - /* Split the low digit off num: */ - unsigned int tmp = num/10; - num -= tmp*10; - digits[ndigits++] = (char)(48 + num); - /* Record the first non-zero digit, note that this is a number - * starting at 1, it's not actually the array index. - */ - if (first == 16 && num > 0) - first = ndigits; - num = tmp; - } - - if (ndigits > 0) - { - while (ndigits > 5) *ascii++ = digits[--ndigits]; - /* The remaining digits are fractional digits, ndigits is '5' or - * smaller at this point. It is certainly not zero. Check for a - * non-zero fractional digit: - */ - if (first <= 5) - { - unsigned int i; - *ascii++ = 46; /* decimal point */ - /* ndigits may be <5 for small numbers, output leading zeros - * then ndigits digits to first: - */ - i = 5; - while (ndigits < i) *ascii++ = 48, --i; - while (ndigits >= first) *ascii++ = digits[--ndigits]; - /* Don't output the trailing zeros! */ - } - } - else - *ascii++ = 48; - - /* And null terminate the string: */ - *ascii = 0; - return; - } - } - - /* Here on buffer too small. */ - png_error(png_ptr, "ASCII conversion buffer too small"); -} -# endif /* FIXED_POINT */ -#endif /* READ_SCAL */ - -#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ - !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ - (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \ - defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \ - defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \ - (defined(PNG_sCAL_SUPPORTED) && \ - defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)) -png_fixed_point -png_fixed(png_const_structrp png_ptr, double fp, png_const_charp) -{ - double r = floor(100000 * fp + .5); - - if (r > 2147483647. || r < -2147483648.) - png_fixed_error(png_ptr, text); - - return (png_fixed_point)r; -} -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) || \ - defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED) -/* muldiv functions */ -/* This API takes signed arguments and rounds the result to the nearest - * integer (or, for a fixed point number - the standard argument - to - * the nearest .00001). Overflow and divide by zero are signalled in - * the result, a boolean - true on success, false on overflow. - */ -int -png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times, - png_int_32 divisor) -{ - /* Return a * times / divisor, rounded. */ - if (divisor != 0) - { - if (a == 0 || times == 0) - { - *res = 0; - return 1; - } - else - { -#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED - double r = a; - r *= times; - r /= divisor; - r = floor(r+.5); - - /* A png_fixed_point is a 32-bit integer. */ - if (r <= 2147483647. && r >= -2147483648.) - { - *res = (png_fixed_point)r; - return 1; - } -#else - int negative = 0; - png_uint_32 A, T, D; - png_uint_32 s16, s32, s00; - - if (a < 0) - negative = 1, A = -a; - else - A = a; - - if (times < 0) - negative = !negative, T = -times; - else - T = times; - - if (divisor < 0) - negative = !negative, D = -divisor; - else - D = divisor; - - /* Following can't overflow because the arguments only - * have 31 bits each, however the result may be 32 bits. - */ - s16 = (A >> 16) * (T & 0xffff) + - (A & 0xffff) * (T >> 16); - /* Can't overflow because the a*times bit is only 30 - * bits at most. - */ - s32 = (A >> 16) * (T >> 16) + (s16 >> 16); - s00 = (A & 0xffff) * (T & 0xffff); - - s16 = (s16 & 0xffff) << 16; - s00 += s16; - - if (s00 < s16) - ++s32; /* carry */ - - if (s32 < D) /* else overflow */ - { - /* s32.s00 is now the 64-bit product, do a standard - * division, we know that s32 < D, so the maximum - * required shift is 31. - */ - int bitshift = 32; - png_fixed_point result = 0; /* NOTE: signed */ - - while (--bitshift >= 0) - { - png_uint_32 d32, d00; - - if (bitshift > 0) - d32 = D >> (32-bitshift), d00 = D << bitshift; - - else - d32 = 0, d00 = D; - - if (s32 > d32) - { - if (s00 < d00) --s32; /* carry */ - s32 -= d32, s00 -= d00, result += 1<= d00) - s32 = 0, s00 -= d00, result += 1<= (D >> 1)) - ++result; - - if (negative) - result = -result; - - /* Check for overflow. */ - if ((negative && result <= 0) || (!negative && result >= 0)) - { - *res = result; - return 1; - } - } -#endif - } - } - - return 0; -} -#endif /* READ_GAMMA || INCH_CONVERSIONS */ - -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED) -/* The following is for when the caller doesn't much care about the - * result. - */ -png_fixed_point -png_muldiv_warn(png_const_structrp png_ptr, png_fixed_point a, png_int_32 times, - png_int_32 divisor) -{ - png_fixed_point result; - - if (png_muldiv(&result, a, times, divisor)) - return result; - - png_warning(png_ptr, "fixed point overflow ignored"); - return 0; -} -#endif - -#ifdef PNG_GAMMA_SUPPORTED /* more fixed point functions for gamma */ -/* Calculate a reciprocal, return 0 on div-by-zero or overflow. */ -png_fixed_point -png_reciprocal(png_fixed_point a) -{ -#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED - double r = floor(1E10/a+.5); - - if (r <= 2147483647. && r >= -2147483648.) - return (png_fixed_point)r; -#else - png_fixed_point res; - - if (png_muldiv(&res, 100000, 100000, a)) - return res; -#endif - - return 0; /* error/overflow */ -} - -/* This is the shared test on whether a gamma value is 'significant' - whether - * it is worth doing gamma correction. - */ -int /* PRIVATE */ -png_gamma_significant(png_fixed_point gamma_val) -{ - return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED || - gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED; -} -#endif - -#ifdef PNG_READ_GAMMA_SUPPORTED -/* A local convenience routine. */ -static png_fixed_point -png_product2(png_fixed_point a, png_fixed_point b) -{ - /* The required result is 1/a * 1/b; the following preserves accuracy. */ -#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED - double r = a * 1E-5; - r *= b; - r = floor(r+.5); - - if (r <= 2147483647. && r >= -2147483648.) - return (png_fixed_point)r; -#else - png_fixed_point res; - - if (png_muldiv(&res, a, b, 100000)) - return res; -#endif - - return 0; /* overflow */ -} - -/* The inverse of the above. */ -png_fixed_point -png_reciprocal2(png_fixed_point a, png_fixed_point b) -{ - /* The required result is 1/a * 1/b; the following preserves accuracy. */ -#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED - double r = 1E15/a; - r /= b; - r = floor(r+.5); - - if (r <= 2147483647. && r >= -2147483648.) - return (png_fixed_point)r; -#else - /* This may overflow because the range of png_fixed_point isn't symmetric, - * but this API is only used for the product of file and screen gamma so it - * doesn't matter that the smallest number it can produce is 1/21474, not - * 1/100000 - */ - png_fixed_point res = png_product2(a, b); - - if (res != 0) - return png_reciprocal(res); -#endif - - return 0; /* overflow */ -} -#endif /* READ_GAMMA */ - -#ifdef PNG_READ_GAMMA_SUPPORTED /* gamma table code */ -#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED -/* Fixed point gamma. - * - * The code to calculate the tables used below can be found in the shell script - * contrib/tools/intgamma.sh - * - * To calculate gamma this code implements fast log() and exp() calls using only - * fixed point arithmetic. This code has sufficient precision for either 8-bit - * or 16-bit sample values. - * - * The tables used here were calculated using simple 'bc' programs, but C double - * precision floating point arithmetic would work fine. - * - * 8-bit log table - * This is a table of -log(value/255)/log(2) for 'value' in the range 128 to - * 255, so it's the base 2 logarithm of a normalized 8-bit floating point - * mantissa. The numbers are 32-bit fractions. - */ -static const png_uint_32 -png_8bit_l2[128] = -{ - 4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U, - 3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U, - 3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U, - 3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U, - 3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U, - 2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U, - 2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U, - 2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U, - 2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U, - 2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U, - 1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U, - 1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U, - 1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U, - 1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U, - 1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U, - 971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U, - 803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U, - 639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U, - 479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U, - 324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U, - 172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U, - 24347096U, 0U - -#if 0 - /* The following are the values for 16-bit tables - these work fine for the - * 8-bit conversions but produce very slightly larger errors in the 16-bit - * log (about 1.2 as opposed to 0.7 absolute error in the final value). To - * use these all the shifts below must be adjusted appropriately. - */ - 65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054, - 57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803, - 50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068, - 43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782, - 37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887, - 31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339, - 25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098, - 20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132, - 15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415, - 10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523, - 6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495, - 1119, 744, 372 -#endif -}; - -static png_int_32 -png_log8bit(unsigned int x) -{ - unsigned int lg2 = 0; - /* Each time 'x' is multiplied by 2, 1 must be subtracted off the final log, - * because the log is actually negate that means adding 1. The final - * returned value thus has the range 0 (for 255 input) to 7.994 (for 1 - * input), return -1 for the overflow (log 0) case, - so the result is - * always at most 19 bits. - */ - if ((x &= 0xff) == 0) - return -1; - - if ((x & 0xf0) == 0) - lg2 = 4, x <<= 4; - - if ((x & 0xc0) == 0) - lg2 += 2, x <<= 2; - - if ((x & 0x80) == 0) - lg2 += 1, x <<= 1; - - /* result is at most 19 bits, so this cast is safe: */ - return (png_int_32)((lg2 << 16) + ((png_8bit_l2[x-128]+32768)>>16)); -} - -/* The above gives exact (to 16 binary places) log2 values for 8-bit images, - * for 16-bit images we use the most significant 8 bits of the 16-bit value to - * get an approximation then multiply the approximation by a correction factor - * determined by the remaining up to 8 bits. This requires an additional step - * in the 16-bit case. - * - * We want log2(value/65535), we have log2(v'/255), where: - * - * value = v' * 256 + v'' - * = v' * f - * - * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128 - * to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less - * than 258. The final factor also needs to correct for the fact that our 8-bit - * value is scaled by 255, whereas the 16-bit values must be scaled by 65535. - * - * This gives a final formula using a calculated value 'x' which is value/v' and - * scaling by 65536 to match the above table: - * - * log2(x/257) * 65536 - * - * Since these numbers are so close to '1' we can use simple linear - * interpolation between the two end values 256/257 (result -368.61) and 258/257 - * (result 367.179). The values used below are scaled by a further 64 to give - * 16-bit precision in the interpolation: - * - * Start (256): -23591 - * Zero (257): 0 - * End (258): 23499 - */ -static png_int_32 -png_log16bit(png_uint_32 x) -{ - unsigned int lg2 = 0; - - /* As above, but now the input has 16 bits. */ - if ((x &= 0xffff) == 0) - return -1; - - if ((x & 0xff00) == 0) - lg2 = 8, x <<= 8; - - if ((x & 0xf000) == 0) - lg2 += 4, x <<= 4; - - if ((x & 0xc000) == 0) - lg2 += 2, x <<= 2; - - if ((x & 0x8000) == 0) - lg2 += 1, x <<= 1; - - /* Calculate the base logarithm from the top 8 bits as a 28-bit fractional - * value. - */ - lg2 <<= 28; - lg2 += (png_8bit_l2[(x>>8)-128]+8) >> 4; - - /* Now we need to interpolate the factor, this requires a division by the top - * 8 bits. Do this with maximum precision. - */ - x = ((x << 16) + (x >> 9)) / (x >> 8); - - /* Since we divided by the top 8 bits of 'x' there will be a '1' at 1<<24, - * the value at 1<<16 (ignoring this) will be 0 or 1; this gives us exactly - * 16 bits to interpolate to get the low bits of the result. Round the - * answer. Note that the end point values are scaled by 64 to retain overall - * precision and that 'lg2' is current scaled by an extra 12 bits, so adjust - * the overall scaling by 6-12. Round at every step. - */ - x -= 1U << 24; - - if (x <= 65536U) /* <= '257' */ - lg2 += ((23591U * (65536U-x)) + (1U << (16+6-12-1))) >> (16+6-12); - - else - lg2 -= ((23499U * (x-65536U)) + (1U << (16+6-12-1))) >> (16+6-12); - - /* Safe, because the result can't have more than 20 bits: */ - return (png_int_32)((lg2 + 2048) >> 12); -} - -/* The 'exp()' case must invert the above, taking a 20-bit fixed point - * logarithmic value and returning a 16 or 8-bit number as appropriate. In - * each case only the low 16 bits are relevant - the fraction - since the - * integer bits (the top 4) simply determine a shift. - * - * The worst case is the 16-bit distinction between 65535 and 65534, this - * requires perhaps spurious accuracty in the decoding of the logarithm to - * distinguish log2(65535/65534.5) - 10^-5 or 17 bits. There is little chance - * of getting this accuracy in practice. - * - * To deal with this the following exp() function works out the exponent of the - * frational part of the logarithm by using an accurate 32-bit value from the - * top four fractional bits then multiplying in the remaining bits. - */ -static const png_uint_32 -png_32bit_exp[16] = -{ - /* NOTE: the first entry is deliberately set to the maximum 32-bit value. */ - 4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U, - 3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U, - 2553802834U, 2445529972U, 2341847524U, 2242560872U -}; - -/* Adjustment table; provided to explain the numbers in the code below. */ -#if 0 -for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"} - 11 44937.64284865548751208448 - 10 45180.98734845585101160448 - 9 45303.31936980687359311872 - 8 45364.65110595323018870784 - 7 45395.35850361789624614912 - 6 45410.72259715102037508096 - 5 45418.40724413220722311168 - 4 45422.25021786898173001728 - 3 45424.17186732298419044352 - 2 45425.13273269940811464704 - 1 45425.61317555035558641664 - 0 45425.85339951654943850496 -#endif - -static png_uint_32 -png_exp(png_fixed_point x) -{ - if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */ - { - /* Obtain a 4-bit approximation */ - png_uint_32 e = png_32bit_exp[(x >> 12) & 0xf]; - - /* Incorporate the low 12 bits - these decrease the returned value by - * multiplying by a number less than 1 if the bit is set. The multiplier - * is determined by the above table and the shift. Notice that the values - * converge on 45426 and this is used to allow linear interpolation of the - * low bits. - */ - if (x & 0x800) - e -= (((e >> 16) * 44938U) + 16U) >> 5; - - if (x & 0x400) - e -= (((e >> 16) * 45181U) + 32U) >> 6; - - if (x & 0x200) - e -= (((e >> 16) * 45303U) + 64U) >> 7; - - if (x & 0x100) - e -= (((e >> 16) * 45365U) + 128U) >> 8; - - if (x & 0x080) - e -= (((e >> 16) * 45395U) + 256U) >> 9; - - if (x & 0x040) - e -= (((e >> 16) * 45410U) + 512U) >> 10; - - /* And handle the low 6 bits in a single block. */ - e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9; - - /* Handle the upper bits of x. */ - e >>= x >> 16; - return e; - } - - /* Check for overflow */ - if (x <= 0) - return png_32bit_exp[0]; - - /* Else underflow */ - return 0; -} - -static png_byte -png_exp8bit(png_fixed_point lg2) -{ - /* Get a 32-bit value: */ - png_uint_32 x = png_exp(lg2); - - /* Convert the 32-bit value to 0..255 by multiplying by 256-1, note that the - * second, rounding, step can't overflow because of the first, subtraction, - * step. - */ - x -= x >> 8; - return (png_byte)((x + 0x7fffffU) >> 24); -} - -static png_uint_16 -png_exp16bit(png_fixed_point lg2) -{ - /* Get a 32-bit value: */ - png_uint_32 x = png_exp(lg2); - - /* Convert the 32-bit value to 0..65535 by multiplying by 65536-1: */ - x -= x >> 16; - return (png_uint_16)((x + 32767U) >> 16); -} -#endif /* FLOATING_ARITHMETIC */ - -png_byte -png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val) -{ - if (value > 0 && value < 255) - { -# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED - double r = floor(255*pow(value/255.,gamma_val*.00001)+.5); - return (png_byte)r; -# else - png_int_32 lg2 = png_log8bit(value); - png_fixed_point res; - - if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1)) - return png_exp8bit(res); - - /* Overflow. */ - value = 0; -# endif - } - - return (png_byte)value; -} - -png_uint_16 -png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val) -{ - if (value > 0 && value < 65535) - { -# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED - double r = floor(65535*pow(value/65535.,gamma_val*.00001)+.5); - return (png_uint_16)r; -# else - png_int_32 lg2 = png_log16bit(value); - png_fixed_point res; - - if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1)) - return png_exp16bit(res); - - /* Overflow. */ - value = 0; -# endif - } - - return (png_uint_16)value; -} - -/* This does the right thing based on the bit_depth field of the - * png_struct, interpreting values as 8-bit or 16-bit. While the result - * is nominally a 16-bit value if bit depth is 8 then the result is - * 8-bit (as are the arguments.) - */ -png_uint_16 /* PRIVATE */ -png_gamma_correct(png_structrp png_ptr, unsigned int value, - png_fixed_point gamma_val) -{ - if (png_ptr->bit_depth == 8) - return png_gamma_8bit_correct(value, gamma_val); - - else - return png_gamma_16bit_correct(value, gamma_val); -} - -/* Internal function to build a single 16-bit table - the table consists of - * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount - * to shift the input values right (or 16-number_of_signifiant_bits). - * - * The caller is responsible for ensuring that the table gets cleaned up on - * png_error (i.e. if one of the mallocs below fails) - i.e. the *table argument - * should be somewhere that will be cleaned. - */ -static void -png_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable, - PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val) -{ - /* Various values derived from 'shift': */ - PNG_CONST unsigned int num = 1U << (8U - shift); - PNG_CONST unsigned int max = (1U << (16U - shift))-1U; - PNG_CONST unsigned int max_by_2 = 1U << (15U-shift); - unsigned int i; - - png_uint_16pp table = *ptable = - (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p))); - - for (i = 0; i < num; i++) - { - png_uint_16p sub_table = table[i] = - (png_uint_16p)png_malloc(png_ptr, 256 * (sizeof (png_uint_16))); - - /* The 'threshold' test is repeated here because it can arise for one of - * the 16-bit tables even if the others don't hit it. - */ - if (png_gamma_significant(gamma_val)) - { - /* The old code would overflow at the end and this would cause the - * 'pow' function to return a result >1, resulting in an - * arithmetic error. This code follows the spec exactly; ig is - * the recovered input sample, it always has 8-16 bits. - * - * We want input * 65535/max, rounded, the arithmetic fits in 32 - * bits (unsigned) so long as max <= 32767. - */ - unsigned int j; - for (j = 0; j < 256; j++) - { - png_uint_32 ig = (j << (8-shift)) + i; -# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED - /* Inline the 'max' scaling operation: */ - double d = floor(65535*pow(ig/(double)max, gamma_val*.00001)+.5); - sub_table[j] = (png_uint_16)d; -# else - if (shift) - ig = (ig * 65535U + max_by_2)/max; - - sub_table[j] = png_gamma_16bit_correct(ig, gamma_val); -# endif - } - } - else - { - /* We must still build a table, but do it the fast way. */ - unsigned int j; - - for (j = 0; j < 256; j++) - { - png_uint_32 ig = (j << (8-shift)) + i; - - if (shift) - ig = (ig * 65535U + max_by_2)/max; - - sub_table[j] = (png_uint_16)ig; - } - } - } -} - -/* NOTE: this function expects the *inverse* of the overall gamma transformation - * required. - */ -static void -png_build_16to8_table(png_structrp png_ptr, png_uint_16pp *ptable, - PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val) -{ - PNG_CONST unsigned int num = 1U << (8U - shift); - PNG_CONST unsigned int max = (1U << (16U - shift))-1U; - unsigned int i; - png_uint_32 last; - - png_uint_16pp table = *ptable = - (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p))); - - /* 'num' is the number of tables and also the number of low bits of low - * bits of the input 16-bit value used to select a table. Each table is - * itself index by the high 8 bits of the value. - */ - for (i = 0; i < num; i++) - table[i] = (png_uint_16p)png_malloc(png_ptr, - 256 * (sizeof (png_uint_16))); - - /* 'gamma_val' is set to the reciprocal of the value calculated above, so - * pow(out,g) is an *input* value. 'last' is the last input value set. - * - * In the loop 'i' is used to find output values. Since the output is - * 8-bit there are only 256 possible values. The tables are set up to - * select the closest possible output value for each input by finding - * the input value at the boundary between each pair of output values - * and filling the table up to that boundary with the lower output - * value. - * - * The boundary values are 0.5,1.5..253.5,254.5. Since these are 9-bit - * values the code below uses a 16-bit value in i; the values start at - * 128.5 (for 0.5) and step by 257, for a total of 254 values (the last - * entries are filled with 255). Start i at 128 and fill all 'last' - * table entries <= 'max' - */ - last = 0; - for (i = 0; i < 255; ++i) /* 8-bit output value */ - { - /* Find the corresponding maximum input value */ - png_uint_16 out = (png_uint_16)(i * 257U); /* 16-bit output value */ - - /* Find the boundary value in 16 bits: */ - png_uint_32 bound = png_gamma_16bit_correct(out+128U, gamma_val); - - /* Adjust (round) to (16-shift) bits: */ - bound = (bound * max + 32768U)/65535U + 1U; - - while (last < bound) - { - table[last & (0xffU >> shift)][last >> (8U - shift)] = out; - last++; - } - } - - /* And fill in the final entries. */ - while (last < (num << 8)) - { - table[last & (0xff >> shift)][last >> (8U - shift)] = 65535U; - last++; - } -} - -/* Build a single 8-bit table: same as the 16-bit case but much simpler (and - * typically much faster). Note that libpng currently does no sBIT processing - * (apparently contrary to the spec) so a 256 entry table is always generated. - */ -static void -png_build_8bit_table(png_structrp png_ptr, png_bytepp ptable, - PNG_CONST png_fixed_point gamma_val) -{ - unsigned int i; - png_bytep table = *ptable = (png_bytep)png_malloc(png_ptr, 256); - - if (png_gamma_significant(gamma_val)) for (i=0; i<256; i++) - table[i] = png_gamma_8bit_correct(i, gamma_val); - - else for (i=0; i<256; ++i) - table[i] = (png_byte)i; -} - -/* Used from png_read_destroy and below to release the memory used by the gamma - * tables. - */ -void /* PRIVATE */ -png_destroy_gamma_table(png_structrp png_ptr) -{ - png_free(png_ptr, png_ptr->gamma_table); - png_ptr->gamma_table = NULL; - - if (png_ptr->gamma_16_table != NULL) - { - int i; - int istop = (1 << (8 - png_ptr->gamma_shift)); - for (i = 0; i < istop; i++) - { - png_free(png_ptr, png_ptr->gamma_16_table[i]); - } - png_free(png_ptr, png_ptr->gamma_16_table); - png_ptr->gamma_16_table = NULL; - } - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ - defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ - defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - png_free(png_ptr, png_ptr->gamma_from_1); - png_ptr->gamma_from_1 = NULL; - png_free(png_ptr, png_ptr->gamma_to_1); - png_ptr->gamma_to_1 = NULL; - - if (png_ptr->gamma_16_from_1 != NULL) - { - int i; - int istop = (1 << (8 - png_ptr->gamma_shift)); - for (i = 0; i < istop; i++) - { - png_free(png_ptr, png_ptr->gamma_16_from_1[i]); - } - png_free(png_ptr, png_ptr->gamma_16_from_1); - png_ptr->gamma_16_from_1 = NULL; - } - if (png_ptr->gamma_16_to_1 != NULL) - { - int i; - int istop = (1 << (8 - png_ptr->gamma_shift)); - for (i = 0; i < istop; i++) - { - png_free(png_ptr, png_ptr->gamma_16_to_1[i]); - } - png_free(png_ptr, png_ptr->gamma_16_to_1); - png_ptr->gamma_16_to_1 = NULL; - } -#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ -} - -/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit - * tables, we don't make a full table if we are reducing to 8-bit in - * the future. Note also how the gamma_16 tables are segmented so that - * we don't need to allocate > 64K chunks for a full 16-bit table. - */ -void /* PRIVATE */ -png_build_gamma_table(png_structrp png_ptr, int bit_depth) -{ - png_debug(1, "in png_build_gamma_table"); - - /* Remove any existing table; this copes with multiple calls to - * png_read_update_info. The warning is because building the gamma tables - * multiple times is a performance hit - it's harmless but the ability to call - * png_read_update_info() multiple times is new in 1.5.6 so it seems sensible - * to warn if the app introduces such a hit. - */ - if (png_ptr->gamma_table != NULL || png_ptr->gamma_16_table != NULL) - { - png_warning(png_ptr, "gamma table being rebuilt"); - png_destroy_gamma_table(png_ptr); - } - - if (bit_depth <= 8) - { - png_build_8bit_table(png_ptr, &png_ptr->gamma_table, - png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma, - png_ptr->screen_gamma) : PNG_FP_1); - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ - defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ - defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) - { - png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1, - png_reciprocal(png_ptr->colorspace.gamma)); - - png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1, - png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) : - png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */); - } -#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ - } - else - { - png_byte shift, sig_bit; - - if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) - { - sig_bit = png_ptr->sig_bit.red; - - if (png_ptr->sig_bit.green > sig_bit) - sig_bit = png_ptr->sig_bit.green; - - if (png_ptr->sig_bit.blue > sig_bit) - sig_bit = png_ptr->sig_bit.blue; - } - else - sig_bit = png_ptr->sig_bit.gray; - - /* 16-bit gamma code uses this equation: - * - * ov = table[(iv & 0xff) >> gamma_shift][iv >> 8] - * - * Where 'iv' is the input color value and 'ov' is the output value - - * pow(iv, gamma). - * - * Thus the gamma table consists of up to 256 256 entry tables. The table - * is selected by the (8-gamma_shift) most significant of the low 8 bits of - * the color value then indexed by the upper 8 bits: - * - * table[low bits][high 8 bits] - * - * So the table 'n' corresponds to all those 'iv' of: - * - * ..<(n+1 << gamma_shift)-1> - * - */ - if (sig_bit > 0 && sig_bit < 16U) - shift = (png_byte)(16U - sig_bit); /* shift == insignificant bits */ - - else - shift = 0; /* keep all 16 bits */ - - if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) - { - /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively - * the significant bits in the *input* when the output will - * eventually be 8 bits. By default it is 11. - */ - if (shift < (16U - PNG_MAX_GAMMA_8)) - shift = (16U - PNG_MAX_GAMMA_8); - } - - if (shift > 8U) - shift = 8U; /* Guarantees at least one table! */ - - png_ptr->gamma_shift = shift; - -#ifdef PNG_16BIT_SUPPORTED - /* NOTE: prior to 1.5.4 this test used to include PNG_BACKGROUND (now - * PNG_COMPOSE). This effectively smashed the background calculation for - * 16-bit output because the 8-bit table assumes the result will be reduced - * to 8 bits. - */ - if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) -#endif - png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift, - png_ptr->screen_gamma > 0 ? png_product2(png_ptr->colorspace.gamma, - png_ptr->screen_gamma) : PNG_FP_1); - -#ifdef PNG_16BIT_SUPPORTED - else - png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift, - png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma, - png_ptr->screen_gamma) : PNG_FP_1); -#endif - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ - defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ - defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) - { - png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift, - png_reciprocal(png_ptr->colorspace.gamma)); - - /* Notice that the '16 from 1' table should be full precision, however - * the lookup on this table still uses gamma_shift, so it can't be. - * TODO: fix this. - */ - png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift, - png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) : - png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */); - } -#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ - } -} -#endif /* READ_GAMMA */ - -/* HARDWARE OPTION SUPPORT */ -#ifdef PNG_SET_OPTION_SUPPORTED -int PNGAPI -png_set_option(png_structrp png_ptr, int option, int onoff) -{ - if (png_ptr != NULL && option >= 0 && option < PNG_OPTION_NEXT && - (option & 1) == 0) - { - int mask = 3 << option; - int setting = (2 + (onoff != 0)) << option; - int current = png_ptr->options; - - png_ptr->options = (png_byte)((current & ~mask) | setting); - - return (current & mask) >> option; - } - - return PNG_OPTION_INVALID; -} -#endif - -/* sRGB support */ -#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ - defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) -/* sRGB conversion tables; these are machine generated with the code in - * contrib/tools/makesRGB.c. The actual sRGB transfer curve defined in the - * specification (see the article at http://en.wikipedia.org/wiki/SRGB) - * is used, not the gamma=1/2.2 approximation use elsewhere in libpng. - * The sRGB to linear table is exact (to the nearest 16 bit linear fraction). - * The inverse (linear to sRGB) table has accuracies as follows: - * - * For all possible (255*65535+1) input values: - * - * error: -0.515566 - 0.625971, 79441 (0.475369%) of readings inexact - * - * For the input values corresponding to the 65536 16-bit values: - * - * error: -0.513727 - 0.607759, 308 (0.469978%) of readings inexact - * - * In all cases the inexact readings are off by one. - */ - -#ifdef PNG_SIMPLIFIED_READ_SUPPORTED -/* The convert-to-sRGB table is only currently required for read. */ -const png_uint_16 png_sRGB_table[256] = -{ - 0,20,40,60,80,99,119,139, - 159,179,199,219,241,264,288,313, - 340,367,396,427,458,491,526,562, - 599,637,677,718,761,805,851,898, - 947,997,1048,1101,1156,1212,1270,1330, - 1391,1453,1517,1583,1651,1720,1790,1863, - 1937,2013,2090,2170,2250,2333,2418,2504, - 2592,2681,2773,2866,2961,3058,3157,3258, - 3360,3464,3570,3678,3788,3900,4014,4129, - 4247,4366,4488,4611,4736,4864,4993,5124, - 5257,5392,5530,5669,5810,5953,6099,6246, - 6395,6547,6700,6856,7014,7174,7335,7500, - 7666,7834,8004,8177,8352,8528,8708,8889, - 9072,9258,9445,9635,9828,10022,10219,10417, - 10619,10822,11028,11235,11446,11658,11873,12090, - 12309,12530,12754,12980,13209,13440,13673,13909, - 14146,14387,14629,14874,15122,15371,15623,15878, - 16135,16394,16656,16920,17187,17456,17727,18001, - 18277,18556,18837,19121,19407,19696,19987,20281, - 20577,20876,21177,21481,21787,22096,22407,22721, - 23038,23357,23678,24002,24329,24658,24990,25325, - 25662,26001,26344,26688,27036,27386,27739,28094, - 28452,28813,29176,29542,29911,30282,30656,31033, - 31412,31794,32179,32567,32957,33350,33745,34143, - 34544,34948,35355,35764,36176,36591,37008,37429, - 37852,38278,38706,39138,39572,40009,40449,40891, - 41337,41785,42236,42690,43147,43606,44069,44534, - 45002,45473,45947,46423,46903,47385,47871,48359, - 48850,49344,49841,50341,50844,51349,51858,52369, - 52884,53401,53921,54445,54971,55500,56032,56567, - 57105,57646,58190,58737,59287,59840,60396,60955, - 61517,62082,62650,63221,63795,64372,64952,65535 -}; - -#endif /* simplified read only */ - -/* The base/delta tables are required for both read and write (but currently - * only the simplified versions.) - */ -const png_uint_16 png_sRGB_base[512] = -{ - 128,1782,3383,4644,5675,6564,7357,8074, - 8732,9346,9921,10463,10977,11466,11935,12384, - 12816,13233,13634,14024,14402,14769,15125,15473, - 15812,16142,16466,16781,17090,17393,17690,17981, - 18266,18546,18822,19093,19359,19621,19879,20133, - 20383,20630,20873,21113,21349,21583,21813,22041, - 22265,22487,22707,22923,23138,23350,23559,23767, - 23972,24175,24376,24575,24772,24967,25160,25352, - 25542,25730,25916,26101,26284,26465,26645,26823, - 27000,27176,27350,27523,27695,27865,28034,28201, - 28368,28533,28697,28860,29021,29182,29341,29500, - 29657,29813,29969,30123,30276,30429,30580,30730, - 30880,31028,31176,31323,31469,31614,31758,31902, - 32045,32186,32327,32468,32607,32746,32884,33021, - 33158,33294,33429,33564,33697,33831,33963,34095, - 34226,34357,34486,34616,34744,34873,35000,35127, - 35253,35379,35504,35629,35753,35876,35999,36122, - 36244,36365,36486,36606,36726,36845,36964,37083, - 37201,37318,37435,37551,37668,37783,37898,38013, - 38127,38241,38354,38467,38580,38692,38803,38915, - 39026,39136,39246,39356,39465,39574,39682,39790, - 39898,40005,40112,40219,40325,40431,40537,40642, - 40747,40851,40955,41059,41163,41266,41369,41471, - 41573,41675,41777,41878,41979,42079,42179,42279, - 42379,42478,42577,42676,42775,42873,42971,43068, - 43165,43262,43359,43456,43552,43648,43743,43839, - 43934,44028,44123,44217,44311,44405,44499,44592, - 44685,44778,44870,44962,45054,45146,45238,45329, - 45420,45511,45601,45692,45782,45872,45961,46051, - 46140,46229,46318,46406,46494,46583,46670,46758, - 46846,46933,47020,47107,47193,47280,47366,47452, - 47538,47623,47709,47794,47879,47964,48048,48133, - 48217,48301,48385,48468,48552,48635,48718,48801, - 48884,48966,49048,49131,49213,49294,49376,49458, - 49539,49620,49701,49782,49862,49943,50023,50103, - 50183,50263,50342,50422,50501,50580,50659,50738, - 50816,50895,50973,51051,51129,51207,51285,51362, - 51439,51517,51594,51671,51747,51824,51900,51977, - 52053,52129,52205,52280,52356,52432,52507,52582, - 52657,52732,52807,52881,52956,53030,53104,53178, - 53252,53326,53400,53473,53546,53620,53693,53766, - 53839,53911,53984,54056,54129,54201,54273,54345, - 54417,54489,54560,54632,54703,54774,54845,54916, - 54987,55058,55129,55199,55269,55340,55410,55480, - 55550,55620,55689,55759,55828,55898,55967,56036, - 56105,56174,56243,56311,56380,56448,56517,56585, - 56653,56721,56789,56857,56924,56992,57059,57127, - 57194,57261,57328,57395,57462,57529,57595,57662, - 57728,57795,57861,57927,57993,58059,58125,58191, - 58256,58322,58387,58453,58518,58583,58648,58713, - 58778,58843,58908,58972,59037,59101,59165,59230, - 59294,59358,59422,59486,59549,59613,59677,59740, - 59804,59867,59930,59993,60056,60119,60182,60245, - 60308,60370,60433,60495,60558,60620,60682,60744, - 60806,60868,60930,60992,61054,61115,61177,61238, - 61300,61361,61422,61483,61544,61605,61666,61727, - 61788,61848,61909,61969,62030,62090,62150,62211, - 62271,62331,62391,62450,62510,62570,62630,62689, - 62749,62808,62867,62927,62986,63045,63104,63163, - 63222,63281,63340,63398,63457,63515,63574,63632, - 63691,63749,63807,63865,63923,63981,64039,64097, - 64155,64212,64270,64328,64385,64443,64500,64557, - 64614,64672,64729,64786,64843,64900,64956,65013, - 65070,65126,65183,65239,65296,65352,65409,65465 -}; - -const png_byte png_sRGB_delta[512] = -{ - 207,201,158,129,113,100,90,82,77,72,68,64,61,59,56,54, - 52,50,49,47,46,45,43,42,41,40,39,39,38,37,36,36, - 35,34,34,33,33,32,32,31,31,30,30,30,29,29,28,28, - 28,27,27,27,27,26,26,26,25,25,25,25,24,24,24,24, - 23,23,23,23,23,22,22,22,22,22,22,21,21,21,21,21, - 21,20,20,20,20,20,20,20,20,19,19,19,19,19,19,19, - 19,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17, - 17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,15,15,15,15,15,15,15,15,15,15,15,15, - 15,15,15,15,14,14,14,14,14,14,14,14,14,14,14,14, - 14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13, - 13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,12, - 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, - 12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11, - 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, - 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, - 11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, - 10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 -}; -#endif /* SIMPLIFIED READ/WRITE sRGB support */ - -/* SIMPLIFIED READ/WRITE SUPPORT */ -#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ - defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) -static int -png_image_free_function(png_voidp argument) -{ - png_imagep image = png_voidcast(png_imagep, argument); - png_controlp cp = image->opaque; - png_control c; - - /* Double check that we have a png_ptr - it should be impossible to get here - * without one. - */ - if (cp->png_ptr == NULL) - return 0; - - /* First free any data held in the control structure. */ -# ifdef PNG_STDIO_SUPPORTED - if (cp->owned_file) - { - FILE *fp = png_voidcast(FILE*, cp->png_ptr->io_ptr); - cp->owned_file = 0; - - /* Ignore errors here. */ - if (fp != NULL) - { - cp->png_ptr->io_ptr = NULL; - (void)fclose(fp); - } - } -# endif - - /* Copy the control structure so that the original, allocated, version can be - * safely freed. Notice that a png_error here stops the remainder of the - * cleanup, but this is probably fine because that would indicate bad memory - * problems anyway. - */ - c = *cp; - image->opaque = &c; - png_free(c.png_ptr, cp); - - /* Then the structures, calling the correct API. */ - if (c.for_write) - { -# ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED - png_destroy_write_struct(&c.png_ptr, &c.info_ptr); -# else - png_error(c.png_ptr, "simplified write not supported"); -# endif - } - else - { -# ifdef PNG_SIMPLIFIED_READ_SUPPORTED - png_destroy_read_struct(&c.png_ptr, &c.info_ptr, NULL); -# else - png_error(c.png_ptr, "simplified read not supported"); -# endif - } - - /* Success. */ - return 1; -} - -void PNGAPI -png_image_free(png_imagep image) -{ - /* Safely call the real function, but only if doing so is safe at this point - * (if not inside an error handling context). Otherwise assume - * png_safe_execute will call this API after the return. - */ - if (image != NULL && image->opaque != NULL && - image->opaque->error_buf == NULL) - { - /* Ignore errors here: */ - (void)png_safe_execute(image, png_image_free_function, image); - image->opaque = NULL; - } -} - -int /* PRIVATE */ -png_image_error(png_imagep image, png_const_charp error_message) -{ - /* Utility to log an error. */ - png_safecat(image->message, (sizeof image->message), 0, error_message); - image->warning_or_error |= PNG_IMAGE_ERROR; - png_image_free(image); - return 0; -} - -#endif /* SIMPLIFIED READ/WRITE */ -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/png.h b/source/modules/juce_graphics/image_formats/pnglib/png.h deleted file mode 100644 index d447233c0..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/png.h +++ /dev/null @@ -1,3292 +0,0 @@ - -/* png.h - header file for PNG reference library - * - * libpng version 1.6.1 - March 28, 2013 - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license (See LICENSE, below) - * - * Authors and maintainers: - * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat - * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger - * libpng versions 0.97, January 1998, through 1.6.1 - March 28, 2013: Glenn - * See also "Contributing Authors", below. - * - * Note about libpng version numbers: - * - * Due to various miscommunications, unforeseen code incompatibilities - * and occasional factors outside the authors' control, version numbering - * on the library has not always been consistent and straightforward. - * The following table summarizes matters since version 0.89c, which was - * the first widely used release: - * - * source png.h png.h shared-lib - * version string int version - * ------- ------ ----- ---------- - * 0.89c "1.0 beta 3" 0.89 89 1.0.89 - * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90] - * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95] - * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96] - * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97] - * 0.97c 0.97 97 2.0.97 - * 0.98 0.98 98 2.0.98 - * 0.99 0.99 98 2.0.99 - * 0.99a-m 0.99 99 2.0.99 - * 1.00 1.00 100 2.1.0 [100 should be 10000] - * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000] - * 1.0.1 png.h string is 10001 2.1.0 - * 1.0.1a-e identical to the 10002 from here on, the shared library - * 1.0.2 source version) 10002 is 2.V where V is the source code - * 1.0.2a-b 10003 version, except as noted. - * 1.0.3 10003 - * 1.0.3a-d 10004 - * 1.0.4 10004 - * 1.0.4a-f 10005 - * 1.0.5 (+ 2 patches) 10005 - * 1.0.5a-d 10006 - * 1.0.5e-r 10100 (not source compatible) - * 1.0.5s-v 10006 (not binary compatible) - * 1.0.6 (+ 3 patches) 10006 (still binary incompatible) - * 1.0.6d-f 10007 (still binary incompatible) - * 1.0.6g 10007 - * 1.0.6h 10007 10.6h (testing xy.z so-numbering) - * 1.0.6i 10007 10.6i - * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0) - * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible) - * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible) - * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible) - * 1.0.7 1 10007 (still compatible) - * 1.0.8beta1-4 1 10008 2.1.0.8beta1-4 - * 1.0.8rc1 1 10008 2.1.0.8rc1 - * 1.0.8 1 10008 2.1.0.8 - * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 - * 1.0.9rc1 1 10009 2.1.0.9rc1 - * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 - * 1.0.9rc2 1 10009 2.1.0.9rc2 - * 1.0.9 1 10009 2.1.0.9 - * 1.0.10beta1 1 10010 2.1.0.10beta1 - * 1.0.10rc1 1 10010 2.1.0.10rc1 - * 1.0.10 1 10010 2.1.0.10 - * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 - * 1.0.11rc1 1 10011 2.1.0.11rc1 - * 1.0.11 1 10011 2.1.0.11 - * 1.0.12beta1-2 2 10012 2.1.0.12beta1-2 - * 1.0.12rc1 2 10012 2.1.0.12rc1 - * 1.0.12 2 10012 2.1.0.12 - * 1.1.0a-f - 10100 2.1.1.0a-f (branch abandoned) - * 1.2.0beta1-2 2 10200 2.1.2.0beta1-2 - * 1.2.0beta3-5 3 10200 3.1.2.0beta3-5 - * 1.2.0rc1 3 10200 3.1.2.0rc1 - * 1.2.0 3 10200 3.1.2.0 - * 1.2.1beta1-4 3 10201 3.1.2.1beta1-4 - * 1.2.1rc1-2 3 10201 3.1.2.1rc1-2 - * 1.2.1 3 10201 3.1.2.1 - * 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6 - * 1.0.13beta1 10 10013 10.so.0.1.0.13beta1 - * 1.0.13rc1 10 10013 10.so.0.1.0.13rc1 - * 1.2.2rc1 12 10202 12.so.0.1.2.2rc1 - * 1.0.13 10 10013 10.so.0.1.0.13 - * 1.2.2 12 10202 12.so.0.1.2.2 - * 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6 - * 1.2.3 12 10203 12.so.0.1.2.3 - * 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3 - * 1.0.14rc1 13 10014 10.so.0.1.0.14rc1 - * 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 - * 1.0.14 10 10014 10.so.0.1.0.14 - * 1.2.4 13 10204 12.so.0.1.2.4 - * 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 - * 1.0.15rc1-3 10 10015 10.so.0.1.0.15rc1-3 - * 1.2.5rc1-3 13 10205 12.so.0.1.2.5rc1-3 - * 1.0.15 10 10015 10.so.0.1.0.15 - * 1.2.5 13 10205 12.so.0.1.2.5 - * 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4 - * 1.0.16 10 10016 10.so.0.1.0.16 - * 1.2.6 13 10206 12.so.0.1.2.6 - * 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2 - * 1.0.17rc1 10 10017 12.so.0.1.0.17rc1 - * 1.2.7rc1 13 10207 12.so.0.1.2.7rc1 - * 1.0.17 10 10017 12.so.0.1.0.17 - * 1.2.7 13 10207 12.so.0.1.2.7 - * 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5 - * 1.0.18rc1-5 10 10018 12.so.0.1.0.18rc1-5 - * 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5 - * 1.0.18 10 10018 12.so.0.1.0.18 - * 1.2.8 13 10208 12.so.0.1.2.8 - * 1.2.9beta1-3 13 10209 12.so.0.1.2.9beta1-3 - * 1.2.9beta4-11 13 10209 12.so.0.9[.0] - * 1.2.9rc1 13 10209 12.so.0.9[.0] - * 1.2.9 13 10209 12.so.0.9[.0] - * 1.2.10beta1-7 13 10210 12.so.0.10[.0] - * 1.2.10rc1-2 13 10210 12.so.0.10[.0] - * 1.2.10 13 10210 12.so.0.10[.0] - * 1.4.0beta1-5 14 10400 14.so.0.0[.0] - * 1.2.11beta1-4 13 10211 12.so.0.11[.0] - * 1.4.0beta7-8 14 10400 14.so.0.0[.0] - * 1.2.11 13 10211 12.so.0.11[.0] - * 1.2.12 13 10212 12.so.0.12[.0] - * 1.4.0beta9-14 14 10400 14.so.0.0[.0] - * 1.2.13 13 10213 12.so.0.13[.0] - * 1.4.0beta15-36 14 10400 14.so.0.0[.0] - * 1.4.0beta37-87 14 10400 14.so.14.0[.0] - * 1.4.0rc01 14 10400 14.so.14.0[.0] - * 1.4.0beta88-109 14 10400 14.so.14.0[.0] - * 1.4.0rc02-08 14 10400 14.so.14.0[.0] - * 1.4.0 14 10400 14.so.14.0[.0] - * 1.4.1beta01-03 14 10401 14.so.14.1[.0] - * 1.4.1rc01 14 10401 14.so.14.1[.0] - * 1.4.1beta04-12 14 10401 14.so.14.1[.0] - * 1.4.1 14 10401 14.so.14.1[.0] - * 1.4.2 14 10402 14.so.14.2[.0] - * 1.4.3 14 10403 14.so.14.3[.0] - * 1.4.4 14 10404 14.so.14.4[.0] - * 1.5.0beta01-58 15 10500 15.so.15.0[.0] - * 1.5.0rc01-07 15 10500 15.so.15.0[.0] - * 1.5.0 15 10500 15.so.15.0[.0] - * 1.5.1beta01-11 15 10501 15.so.15.1[.0] - * 1.5.1rc01-02 15 10501 15.so.15.1[.0] - * 1.5.1 15 10501 15.so.15.1[.0] - * 1.5.2beta01-03 15 10502 15.so.15.2[.0] - * 1.5.2rc01-03 15 10502 15.so.15.2[.0] - * 1.5.2 15 10502 15.so.15.2[.0] - * 1.5.3beta01-10 15 10503 15.so.15.3[.0] - * 1.5.3rc01-02 15 10503 15.so.15.3[.0] - * 1.5.3beta11 15 10503 15.so.15.3[.0] - * 1.5.3 [omitted] - * 1.5.4beta01-08 15 10504 15.so.15.4[.0] - * 1.5.4rc01 15 10504 15.so.15.4[.0] - * 1.5.4 15 10504 15.so.15.4[.0] - * 1.5.5beta01-08 15 10505 15.so.15.5[.0] - * 1.5.5rc01 15 10505 15.so.15.5[.0] - * 1.5.5 15 10505 15.so.15.5[.0] - * 1.5.6beta01-07 15 10506 15.so.15.6[.0] - * 1.5.6rc01-03 15 10506 15.so.15.6[.0] - * 1.5.6 15 10506 15.so.15.6[.0] - * 1.5.7beta01-05 15 10507 15.so.15.7[.0] - * 1.5.7rc01-03 15 10507 15.so.15.7[.0] - * 1.5.7 15 10507 15.so.15.7[.0] - * 1.6.0beta01-40 16 10600 16.so.16.0[.0] - * 1.6.0rc01-08 16 10600 16.so.16.0[.0] - * 1.6.0 16 10600 16.so.16.0[.0] - * 1.6.1beta01-10 16 10601 16.so.16.1[.0] - * 1.6.1rc01 16 10601 16.so.16.1[.0] - * 1.6.1 16 10601 16.so.16.1[.0] - * - * Henceforth the source version will match the shared-library major - * and minor numbers; the shared-library major version number will be - * used for changes in backward compatibility, as it is intended. The - * PNG_LIBPNG_VER macro, which is not used within libpng but is available - * for applications, is an unsigned integer of the form xyyzz corresponding - * to the source version x.y.z (leading zeros in y and z). Beta versions - * were given the previous public release number plus a letter, until - * version 1.0.6j; from then on they were given the upcoming public - * release number plus "betaNN" or "rcNN". - * - * Binary incompatibility exists only when applications make direct access - * to the info_ptr or png_ptr members through png.h, and the compiled - * application is loaded with a different version of the library. - * - * DLLNUM will change each time there are forward or backward changes - * in binary compatibility (e.g., when a new feature is added). - * - * See libpng-manual.txt or libpng.3 for more information. The PNG - * specification is available as a W3C Recommendation and as an ISO - * Specification, defines should NOT be changed. - */ -#define PNG_INFO_gAMA 0x0001 -#define PNG_INFO_sBIT 0x0002 -#define PNG_INFO_cHRM 0x0004 -#define PNG_INFO_PLTE 0x0008 -#define PNG_INFO_tRNS 0x0010 -#define PNG_INFO_bKGD 0x0020 -#define PNG_INFO_hIST 0x0040 -#define PNG_INFO_pHYs 0x0080 -#define PNG_INFO_oFFs 0x0100 -#define PNG_INFO_tIME 0x0200 -#define PNG_INFO_pCAL 0x0400 -#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */ -#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */ -#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ -#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ -#define PNG_INFO_IDAT 0x8000 /* ESR, 1.0.6 */ - -/* This is used for the transformation routines, as some of them - * change these values for the row. It also should enable using - * the routines for other purposes. - */ -typedef struct png_row_info_struct -{ - png_uint_32 width; /* width of row */ - png_size_t rowbytes; /* number of bytes in row */ - png_byte color_type; /* color type of row */ - png_byte bit_depth; /* bit depth of row */ - png_byte channels; /* number of channels (1, 2, 3, or 4) */ - png_byte pixel_depth; /* bits per pixel (depth * channels) */ -} png_row_info; - -typedef png_row_info * png_row_infop; -typedef png_row_info * * png_row_infopp; - -/* These are the function types for the I/O functions and for the functions - * that allow the user to override the default I/O functions with his or her - * own. The png_error_ptr type should match that of user-supplied warning - * and error functions, while the png_rw_ptr type should match that of the - * user read/write data functions. Note that the 'write' function must not - * modify the buffer it is passed. The 'read' function, on the other hand, is - * expected to return the read data in the buffer. - */ -typedef PNG_CALLBACK(void, *png_error_ptr, (png_structp, png_const_charp)); -typedef PNG_CALLBACK(void, *png_rw_ptr, (png_structp, png_bytep, png_size_t)); -typedef PNG_CALLBACK(void, *png_flush_ptr, (png_structp)); -typedef PNG_CALLBACK(void, *png_read_status_ptr, (png_structp, png_uint_32, - int)); -typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32, - int)); - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop)); -typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop)); - -/* The following callback receives png_uint_32 row_number, int pass for the - * png_bytep data of the row. When transforming an interlaced image the - * row number is the row number within the sub-image of the interlace pass, so - * the value will increase to the height of the sub-image (not the full image) - * then reset to 0 for the next pass. - * - * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to - * find the output pixel (x,y) given an interlaced sub-image pixel - * (row,col,pass). (See below for these macros.) - */ -typedef PNG_CALLBACK(void, *png_progressive_row_ptr, (png_structp, png_bytep, - png_uint_32, int)); -#endif - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) -typedef PNG_CALLBACK(void, *png_user_transform_ptr, (png_structp, png_row_infop, - png_bytep)); -#endif - -#ifdef PNG_USER_CHUNKS_SUPPORTED -typedef PNG_CALLBACK(int, *png_user_chunk_ptr, (png_structp, - png_unknown_chunkp)); -#endif -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED -/* not used anywhere */ -/* typedef PNG_CALLBACK(void, *png_unknown_chunk_ptr, (png_structp)); */ -#endif - -#ifdef PNG_SETJMP_SUPPORTED -/* This must match the function definition in , and the application - * must include this before png.h to obtain the definition of jmp_buf. The - * function is required to be PNG_NORETURN, but this is not checked. If the - * function does return the application will crash via an abort() or similar - * system level call. - * - * If you get a warning here while building the library you may need to make - * changes to ensure that pnglibconf.h records the calling convention used by - * your compiler. This may be very difficult - try using a different compiler - * to build the library! - */ -PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), typedef); -#endif - -/* Transform masks for the high-level interface */ -#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */ -#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */ -#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */ -#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */ -#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */ -#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */ -#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */ -#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */ -#define PNG_TRANSFORM_BGR 0x0080 /* read and write */ -#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */ -#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */ -#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */ -#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* write only */ -/* Added to libpng-1.2.34 */ -#define PNG_TRANSFORM_STRIP_FILLER_BEFORE PNG_TRANSFORM_STRIP_FILLER -#define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */ -/* Added to libpng-1.4.0 */ -#define PNG_TRANSFORM_GRAY_TO_RGB 0x2000 /* read only */ -/* Added to libpng-1.5.4 */ -#define PNG_TRANSFORM_EXPAND_16 0x4000 /* read only */ -#define PNG_TRANSFORM_SCALE_16 0x8000 /* read only */ - -/* Flags for MNG supported features */ -#define PNG_FLAG_MNG_EMPTY_PLTE 0x01 -#define PNG_FLAG_MNG_FILTER_64 0x04 -#define PNG_ALL_MNG_FEATURES 0x05 - -/* NOTE: prior to 1.5 these functions had no 'API' style declaration, - * this allowed the zlib default functions to be used on Windows - * platforms. In 1.5 the zlib default malloc (which just calls malloc and - * ignores the first argument) should be completely compatible with the - * following. - */ -typedef PNG_CALLBACK(png_voidp, *png_malloc_ptr, (png_structp, - png_alloc_size_t)); -typedef PNG_CALLBACK(void, *png_free_ptr, (png_structp, png_voidp)); - -/* Section 3: exported functions - * Here are the function definitions most commonly used. This is not - * the place to find out how to use libpng. See libpng-manual.txt for the - * full explanation, see example.c for the summary. This just provides - * a simple one line description of the use of each function. - * - * The PNG_EXPORT() and PNG_EXPORTA() macros used below are defined in - * pngconf.h and in the *.dfn files in the scripts directory. - * - * PNG_EXPORT(ordinal, type, name, (args)); - * - * ordinal: ordinal that is used while building - * *.def files. The ordinal value is only - * relevant when preprocessing png.h with - * the *.dfn files for building symbol table - * entries, and are removed by pngconf.h. - * type: return type of the function - * name: function name - * args: function arguments, with types - * - * When we wish to append attributes to a function prototype we use - * the PNG_EXPORTA() macro instead. - * - * PNG_EXPORTA(ordinal, type, name, (args), attributes); - * - * ordinal, type, name, and args: same as in PNG_EXPORT(). - * attributes: function attributes - */ - -/* Returns the version number of the library */ -PNG_EXPORT(1, png_uint_32, png_access_version_number, (void)); - -/* Tell lib we have already handled the first magic bytes. - * Handling more than 8 bytes from the beginning of the file is an error. - */ -PNG_EXPORT(2, void, png_set_sig_bytes, (png_structrp png_ptr, int num_bytes)); - -/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a - * PNG file. Returns zero if the supplied bytes match the 8-byte PNG - * signature, and non-zero otherwise. Having num_to_check == 0 or - * start > 7 will always fail (ie return non-zero). - */ -PNG_EXPORT(3, int, png_sig_cmp, (png_const_bytep sig, png_size_t start, - png_size_t num_to_check)); - -/* Simple signature checking function. This is the same as calling - * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n). - */ -#define png_check_sig(sig, n) !png_sig_cmp((sig), 0, (n)) - -/* Allocate and initialize png_ptr struct for reading, and any other memory. */ -PNG_EXPORTA(4, png_structp, png_create_read_struct, - (png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn), - PNG_ALLOCATED); - -/* Allocate and initialize png_ptr struct for writing, and any other memory */ -PNG_EXPORTA(5, png_structp, png_create_write_struct, - (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, - png_error_ptr warn_fn), - PNG_ALLOCATED); - -PNG_EXPORT(6, png_size_t, png_get_compression_buffer_size, - (png_const_structrp png_ptr)); - -PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structrp png_ptr, - png_size_t size)); - -/* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp - * match up. - */ -#ifdef PNG_SETJMP_SUPPORTED -/* This function returns the jmp_buf built in to *png_ptr. It must be - * supplied with an appropriate 'longjmp' function to use on that jmp_buf - * unless the default error function is overridden in which case NULL is - * acceptable. The size of the jmp_buf is checked against the actual size - * allocated by the library - the call will return NULL on a mismatch - * indicating an ABI mismatch. - */ -PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, (png_structrp png_ptr, - png_longjmp_ptr longjmp_fn, size_t jmp_buf_size)); -# define png_jmpbuf(png_ptr) \ - (*png_set_longjmp_fn((png_ptr), longjmp, (sizeof (jmp_buf)))) -#else -# define png_jmpbuf(png_ptr) \ - (LIBPNG_WAS_COMPILED_WITH__PNG_NO_SETJMP) -#endif -/* This function should be used by libpng applications in place of - * longjmp(png_ptr->jmpbuf, val). If longjmp_fn() has been set, it - * will use it; otherwise it will call PNG_ABORT(). This function was - * added in libpng-1.5.0. - */ -PNG_EXPORTA(9, void, png_longjmp, (png_const_structrp png_ptr, int val), - PNG_NORETURN); - -#ifdef PNG_READ_SUPPORTED -/* Reset the compression stream */ -PNG_EXPORTA(10, int, png_reset_zstream, (png_structrp png_ptr), PNG_DEPRECATED); -#endif - -/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ -#ifdef PNG_USER_MEM_SUPPORTED -PNG_EXPORTA(11, png_structp, png_create_read_struct_2, - (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, - png_error_ptr warn_fn, - png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn), - PNG_ALLOCATED); -PNG_EXPORTA(12, png_structp, png_create_write_struct_2, - (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, - png_error_ptr warn_fn, - png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn), - PNG_ALLOCATED); -#endif - -/* Write the PNG file signature. */ -PNG_EXPORT(13, void, png_write_sig, (png_structrp png_ptr)); - -/* Write a PNG chunk - size, type, (optional) data, CRC. */ -PNG_EXPORT(14, void, png_write_chunk, (png_structrp png_ptr, png_const_bytep - chunk_name, png_const_bytep data, png_size_t length)); - -/* Write the start of a PNG chunk - length and chunk name. */ -PNG_EXPORT(15, void, png_write_chunk_start, (png_structrp png_ptr, - png_const_bytep chunk_name, png_uint_32 length)); - -/* Write the data of a PNG chunk started with png_write_chunk_start(). */ -PNG_EXPORT(16, void, png_write_chunk_data, (png_structrp png_ptr, - png_const_bytep data, png_size_t length)); - -/* Finish a chunk started with png_write_chunk_start() (includes CRC). */ -PNG_EXPORT(17, void, png_write_chunk_end, (png_structrp png_ptr)); - -/* Allocate and initialize the info structure */ -PNG_EXPORTA(18, png_infop, png_create_info_struct, (png_const_structrp png_ptr), - PNG_ALLOCATED); - -/* DEPRECATED: this function allowed init structures to be created using the - * default allocation method (typically malloc). Use is deprecated in 1.6.0 and - * the API will be removed in the future. - */ -PNG_EXPORTA(19, void, png_info_init_3, (png_infopp info_ptr, - png_size_t png_info_struct_size), PNG_DEPRECATED); - -/* Writes all the PNG information before the image. */ -PNG_EXPORT(20, void, png_write_info_before_PLTE, - (png_structrp png_ptr, png_const_inforp info_ptr)); -PNG_EXPORT(21, void, png_write_info, - (png_structrp png_ptr, png_const_inforp info_ptr)); - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -/* Read the information before the actual image data. */ -PNG_EXPORT(22, void, png_read_info, - (png_structrp png_ptr, png_inforp info_ptr)); -#endif - -#ifdef PNG_TIME_RFC1123_SUPPORTED - /* Convert to a US string format: there is no localization support in this - * routine. The original implementation used a 29 character buffer in - * png_struct, this will be removed in future versions. - */ -#if PNG_LIBPNG_VER < 10700 -/* To do: remove this from libpng17 (and from libpng17/png.c and pngstruct.h) */ -PNG_EXPORTA(23, png_const_charp, png_convert_to_rfc1123, (png_structrp png_ptr, - png_const_timep ptime),PNG_DEPRECATED); -#endif -PNG_EXPORT(241, int, png_convert_to_rfc1123_buffer, (char out[29], - png_const_timep ptime)); -#endif - -#ifdef PNG_CONVERT_tIME_SUPPORTED -/* Convert from a struct tm to png_time */ -PNG_EXPORT(24, void, png_convert_from_struct_tm, (png_timep ptime, - const struct tm * ttime)); - -/* Convert from time_t to png_time. Uses gmtime() */ -PNG_EXPORT(25, void, png_convert_from_time_t, (png_timep ptime, time_t ttime)); -#endif /* PNG_CONVERT_tIME_SUPPORTED */ - -#ifdef PNG_READ_EXPAND_SUPPORTED -/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ -PNG_EXPORT(26, void, png_set_expand, (png_structrp png_ptr)); -PNG_EXPORT(27, void, png_set_expand_gray_1_2_4_to_8, (png_structrp png_ptr)); -PNG_EXPORT(28, void, png_set_palette_to_rgb, (png_structrp png_ptr)); -PNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structrp png_ptr)); -#endif - -#ifdef PNG_READ_EXPAND_16_SUPPORTED -/* Expand to 16-bit channels, forces conversion of palette to RGB and expansion - * of a tRNS chunk if present. - */ -PNG_EXPORT(221, void, png_set_expand_16, (png_structrp png_ptr)); -#endif - -#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) -/* Use blue, green, red order for pixels. */ -PNG_EXPORT(30, void, png_set_bgr, (png_structrp png_ptr)); -#endif - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED -/* Expand the grayscale to 24-bit RGB if necessary. */ -PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structrp png_ptr)); -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -/* Reduce RGB to grayscale. */ -#define PNG_ERROR_ACTION_NONE 1 -#define PNG_ERROR_ACTION_WARN 2 -#define PNG_ERROR_ACTION_ERROR 3 -#define PNG_RGB_TO_GRAY_DEFAULT (-1)/*for red/green coefficients*/ - -PNG_FP_EXPORT(32, void, png_set_rgb_to_gray, (png_structrp png_ptr, - int error_action, double red, double green)) -PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, (png_structrp png_ptr, - int error_action, png_fixed_point red, png_fixed_point green)) - -PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structrp - png_ptr)); -#endif - -#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED -PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth, - png_colorp palette)); -#endif - -#ifdef PNG_READ_ALPHA_MODE_SUPPORTED -/* How the alpha channel is interpreted - this affects how the color channels of - * a PNG file are returned when an alpha channel, or tRNS chunk in a palette - * file, is present. - * - * This has no effect on the way pixels are written into a PNG output - * datastream. The color samples in a PNG datastream are never premultiplied - * with the alpha samples. - * - * The default is to return data according to the PNG specification: the alpha - * channel is a linear measure of the contribution of the pixel to the - * corresponding composited pixel. The gamma encoded color channels must be - * scaled according to the contribution and to do this it is necessary to undo - * the encoding, scale the color values, perform the composition and reencode - * the values. This is the 'PNG' mode. - * - * The alternative is to 'associate' the alpha with the color information by - * storing color channel values that have been scaled by the alpha. The - * advantage is that the color channels can be resampled (the image can be - * scaled) in this form. The disadvantage is that normal practice is to store - * linear, not (gamma) encoded, values and this requires 16-bit channels for - * still images rather than the 8-bit channels that are just about sufficient if - * gamma encoding is used. In addition all non-transparent pixel values, - * including completely opaque ones, must be gamma encoded to produce the final - * image. This is the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' mode (the - * latter being the two common names for associated alpha color channels.) - * - * Since it is not necessary to perform arithmetic on opaque color values so - * long as they are not to be resampled and are in the final color space it is - * possible to optimize the handling of alpha by storing the opaque pixels in - * the PNG format (adjusted for the output color space) while storing partially - * opaque pixels in the standard, linear, format. The accuracy required for - * standard alpha composition is relatively low, because the pixels are - * isolated, therefore typically the accuracy loss in storing 8-bit linear - * values is acceptable. (This is not true if the alpha channel is used to - * simulate transparency over large areas - use 16 bits or the PNG mode in - * this case!) This is the 'OPTIMIZED' mode. For this mode a pixel is - * treated as opaque only if the alpha value is equal to the maximum value. - * - * The final choice is to gamma encode the alpha channel as well. This is - * broken because, in practice, no implementation that uses this choice - * correctly undoes the encoding before handling alpha composition. Use this - * choice only if other serious errors in the software or hardware you use - * mandate it; the typical serious error is for dark halos to appear around - * opaque areas of the composited PNG image because of arithmetic overflow. - * - * The API function png_set_alpha_mode specifies which of these choices to use - * with an enumerated 'mode' value and the gamma of the required output: - */ -#define PNG_ALPHA_PNG 0 /* according to the PNG standard */ -#define PNG_ALPHA_STANDARD 1 /* according to Porter/Duff */ -#define PNG_ALPHA_ASSOCIATED 1 /* as above; this is the normal practice */ -#define PNG_ALPHA_PREMULTIPLIED 1 /* as above */ -#define PNG_ALPHA_OPTIMIZED 2 /* 'PNG' for opaque pixels, else 'STANDARD' */ -#define PNG_ALPHA_BROKEN 3 /* the alpha channel is gamma encoded */ - -PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structrp png_ptr, int mode, - double output_gamma)) -PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structrp png_ptr, - int mode, png_fixed_point output_gamma)) -#endif - -#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED) -/* The output_gamma value is a screen gamma in libpng terminology: it expresses - * how to decode the output values, not how they are encoded. The values used - * correspond to the normal numbers used to describe the overall gamma of a - * computer display system; for example 2.2 for an sRGB conformant system. The - * values are scaled by 100000 in the _fixed version of the API (so 220000 for - * sRGB.) - * - * The inverse of the value is always used to provide a default for the PNG file - * encoding if it has no gAMA chunk and if png_set_gamma() has not been called - * to override the PNG gamma information. - * - * When the ALPHA_OPTIMIZED mode is selected the output gamma is used to encode - * opaque pixels however pixels with lower alpha values are not encoded, - * regardless of the output gamma setting. - * - * When the standard Porter Duff handling is requested with mode 1 the output - * encoding is set to be linear and the output_gamma value is only relevant - * as a default for input data that has no gamma information. The linear output - * encoding will be overridden if png_set_gamma() is called - the results may be - * highly unexpected! - * - * The following numbers are derived from the sRGB standard and the research - * behind it. sRGB is defined to be approximated by a PNG gAMA chunk value of - * 0.45455 (1/2.2) for PNG. The value implicitly includes any viewing - * correction required to take account of any differences in the color - * environment of the original scene and the intended display environment; the - * value expresses how to *decode* the image for display, not how the original - * data was *encoded*. - * - * sRGB provides a peg for the PNG standard by defining a viewing environment. - * sRGB itself, and earlier TV standards, actually use a more complex transform - * (a linear portion then a gamma 2.4 power law) than PNG can express. (PNG is - * limited to simple power laws.) By saying that an image for direct display on - * an sRGB conformant system should be stored with a gAMA chunk value of 45455 - * (11.3.3.2 and 11.3.3.5 of the ISO PNG specification) the PNG specification - * makes it possible to derive values for other display systems and - * environments. - * - * The Mac value is deduced from the sRGB based on an assumption that the actual - * extra viewing correction used in early Mac display systems was implemented as - * a power 1.45 lookup table. - * - * Any system where a programmable lookup table is used or where the behavior of - * the final display device characteristics can be changed requires system - * specific code to obtain the current characteristic. However this can be - * difficult and most PNG gamma correction only requires an approximate value. - * - * By default, if png_set_alpha_mode() is not called, libpng assumes that all - * values are unencoded, linear, values and that the output device also has a - * linear characteristic. This is only very rarely correct - it is invariably - * better to call png_set_alpha_mode() with PNG_DEFAULT_sRGB than rely on the - * default if you don't know what the right answer is! - * - * The special value PNG_GAMMA_MAC_18 indicates an older Mac system (pre Mac OS - * 10.6) which used a correction table to implement a somewhat lower gamma on an - * otherwise sRGB system. - * - * Both these values are reserved (not simple gamma values) in order to allow - * more precise correction internally in the future. - * - * NOTE: the following values can be passed to either the fixed or floating - * point APIs, but the floating point API will also accept floating point - * values. - */ -#define PNG_DEFAULT_sRGB -1 /* sRGB gamma and color space */ -#define PNG_GAMMA_MAC_18 -2 /* Old Mac '1.8' gamma and color space */ -#define PNG_GAMMA_sRGB 220000 /* Television standards--matches sRGB gamma */ -#define PNG_GAMMA_LINEAR PNG_FP_1 /* Linear */ -#endif - -/* The following are examples of calls to png_set_alpha_mode to achieve the - * required overall gamma correction and, where necessary, alpha - * premultiplication. - * - * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); - * This is the default libpng handling of the alpha channel - it is not - * pre-multiplied into the color components. In addition the call states - * that the output is for a sRGB system and causes all PNG files without gAMA - * chunks to be assumed to be encoded using sRGB. - * - * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); - * In this case the output is assumed to be something like an sRGB conformant - * display preceeded by a power-law lookup table of power 1.45. This is how - * early Mac systems behaved. - * - * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR); - * This is the classic Jim Blinn approach and will work in academic - * environments where everything is done by the book. It has the shortcoming - * of assuming that input PNG data with no gamma information is linear - this - * is unlikely to be correct unless the PNG files where generated locally. - * Most of the time the output precision will be so low as to show - * significant banding in dark areas of the image. - * - * png_set_expand_16(pp); - * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB); - * This is a somewhat more realistic Jim Blinn inspired approach. PNG files - * are assumed to have the sRGB encoding if not marked with a gamma value and - * the output is always 16 bits per component. This permits accurate scaling - * and processing of the data. If you know that your input PNG files were - * generated locally you might need to replace PNG_DEFAULT_sRGB with the - * correct value for your system. - * - * png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB); - * If you just need to composite the PNG image onto an existing background - * and if you control the code that does this you can use the optimization - * setting. In this case you just copy completely opaque pixels to the - * output. For pixels that are not completely transparent (you just skip - * those) you do the composition math using png_composite or png_composite_16 - * below then encode the resultant 8-bit or 16-bit values to match the output - * encoding. - * - * Other cases - * If neither the PNG nor the standard linear encoding work for you because - * of the software or hardware you use then you have a big problem. The PNG - * case will probably result in halos around the image. The linear encoding - * will probably result in a washed out, too bright, image (it's actually too - * contrasty.) Try the ALPHA_OPTIMIZED mode above - this will probably - * substantially reduce the halos. Alternatively try: - * - * png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB); - * This option will also reduce the halos, but there will be slight dark - * halos round the opaque parts of the image where the background is light. - * In the OPTIMIZED mode the halos will be light halos where the background - * is dark. Take your pick - the halos are unavoidable unless you can get - * your hardware/software fixed! (The OPTIMIZED approach is slightly - * faster.) - * - * When the default gamma of PNG files doesn't match the output gamma. - * If you have PNG files with no gamma information png_set_alpha_mode allows - * you to provide a default gamma, but it also sets the ouput gamma to the - * matching value. If you know your PNG files have a gamma that doesn't - * match the output you can take advantage of the fact that - * png_set_alpha_mode always sets the output gamma but only sets the PNG - * default if it is not already set: - * - * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); - * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); - * The first call sets both the default and the output gamma values, the - * second call overrides the output gamma without changing the default. This - * is easier than achieving the same effect with png_set_gamma. You must use - * PNG_ALPHA_PNG for the first call - internal checking in png_set_alpha will - * fire if more than one call to png_set_alpha_mode and png_set_background is - * made in the same read operation, however multiple calls with PNG_ALPHA_PNG - * are ignored. - */ - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED -PNG_EXPORT(36, void, png_set_strip_alpha, (png_structrp png_ptr)); -#endif - -#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ - defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) -PNG_EXPORT(37, void, png_set_swap_alpha, (png_structrp png_ptr)); -#endif - -#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ - defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) -PNG_EXPORT(38, void, png_set_invert_alpha, (png_structrp png_ptr)); -#endif - -#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) -/* Add a filler byte to 8-bit Gray or 24-bit RGB images. */ -PNG_EXPORT(39, void, png_set_filler, (png_structrp png_ptr, png_uint_32 filler, - int flags)); -/* The values of the PNG_FILLER_ defines should NOT be changed */ -# define PNG_FILLER_BEFORE 0 -# define PNG_FILLER_AFTER 1 -/* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */ -PNG_EXPORT(40, void, png_set_add_alpha, (png_structrp png_ptr, - png_uint_32 filler, int flags)); -#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ - -#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) -/* Swap bytes in 16-bit depth files. */ -PNG_EXPORT(41, void, png_set_swap, (png_structrp png_ptr)); -#endif - -#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) -/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ -PNG_EXPORT(42, void, png_set_packing, (png_structrp png_ptr)); -#endif - -#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ - defined(PNG_WRITE_PACKSWAP_SUPPORTED) -/* Swap packing order of pixels in bytes. */ -PNG_EXPORT(43, void, png_set_packswap, (png_structrp png_ptr)); -#endif - -#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) -/* Converts files to legal bit depths. */ -PNG_EXPORT(44, void, png_set_shift, (png_structrp png_ptr, png_const_color_8p - true_bits)); -#endif - -#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ - defined(PNG_WRITE_INTERLACING_SUPPORTED) -/* Have the code handle the interlacing. Returns the number of passes. - * MUST be called before png_read_update_info or png_start_read_image, - * otherwise it will not have the desired effect. Note that it is still - * necessary to call png_read_row or png_read_rows png_get_image_height - * times for each pass. -*/ -PNG_EXPORT(45, int, png_set_interlace_handling, (png_structrp png_ptr)); -#endif - -#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) -/* Invert monochrome files */ -PNG_EXPORT(46, void, png_set_invert_mono, (png_structrp png_ptr)); -#endif - -#ifdef PNG_READ_BACKGROUND_SUPPORTED -/* Handle alpha and tRNS by replacing with a background color. Prior to - * libpng-1.5.4 this API must not be called before the PNG file header has been - * read. Doing so will result in unexpected behavior and possible warnings or - * errors if the PNG file contains a bKGD chunk. - */ -PNG_FP_EXPORT(47, void, png_set_background, (png_structrp png_ptr, - png_const_color_16p background_color, int background_gamma_code, - int need_expand, double background_gamma)) -PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structrp png_ptr, - png_const_color_16p background_color, int background_gamma_code, - int need_expand, png_fixed_point background_gamma)) -#endif -#ifdef PNG_READ_BACKGROUND_SUPPORTED -# define PNG_BACKGROUND_GAMMA_UNKNOWN 0 -# define PNG_BACKGROUND_GAMMA_SCREEN 1 -# define PNG_BACKGROUND_GAMMA_FILE 2 -# define PNG_BACKGROUND_GAMMA_UNIQUE 3 -#endif - -#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED -/* Scale a 16-bit depth file down to 8-bit, accurately. */ -PNG_EXPORT(229, void, png_set_scale_16, (png_structrp png_ptr)); -#endif - -#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED -#define PNG_READ_16_TO_8 SUPPORTED /* Name prior to 1.5.4 */ -/* Strip the second byte of information from a 16-bit depth file. */ -PNG_EXPORT(48, void, png_set_strip_16, (png_structrp png_ptr)); -#endif - -#ifdef PNG_READ_QUANTIZE_SUPPORTED -/* Turn on quantizing, and reduce the palette to the number of colors - * available. - */ -PNG_EXPORT(49, void, png_set_quantize, (png_structrp png_ptr, - png_colorp palette, int num_palette, int maximum_colors, - png_const_uint_16p histogram, int full_quantize)); -#endif - -#ifdef PNG_READ_GAMMA_SUPPORTED -/* The threshold on gamma processing is configurable but hard-wired into the - * library. The following is the floating point variant. - */ -#define PNG_GAMMA_THRESHOLD (PNG_GAMMA_THRESHOLD_FIXED*.00001) - -/* Handle gamma correction. Screen_gamma=(display_exponent). - * NOTE: this API simply sets the screen and file gamma values. It will - * therefore override the value for gamma in a PNG file if it is called after - * the file header has been read - use with care - call before reading the PNG - * file for best results! - * - * These routines accept the same gamma values as png_set_alpha_mode (described - * above). The PNG_GAMMA_ defines and PNG_DEFAULT_sRGB can be passed to either - * API (floating point or fixed.) Notice, however, that the 'file_gamma' value - * is the inverse of a 'screen gamma' value. - */ -PNG_FP_EXPORT(50, void, png_set_gamma, (png_structrp png_ptr, - double screen_gamma, double override_file_gamma)) -PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structrp png_ptr, - png_fixed_point screen_gamma, png_fixed_point override_file_gamma)) -#endif - -#ifdef PNG_WRITE_FLUSH_SUPPORTED -/* Set how many lines between output flushes - 0 for no flushing */ -PNG_EXPORT(51, void, png_set_flush, (png_structrp png_ptr, int nrows)); -/* Flush the current PNG output buffer */ -PNG_EXPORT(52, void, png_write_flush, (png_structrp png_ptr)); -#endif - -/* Optional update palette with requested transformations */ -PNG_EXPORT(53, void, png_start_read_image, (png_structrp png_ptr)); - -/* Optional call to update the users info structure */ -PNG_EXPORT(54, void, png_read_update_info, (png_structrp png_ptr, - png_inforp info_ptr)); - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -/* Read one or more rows of image data. */ -PNG_EXPORT(55, void, png_read_rows, (png_structrp png_ptr, png_bytepp row, - png_bytepp display_row, png_uint_32 num_rows)); -#endif - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -/* Read a row of data. */ -PNG_EXPORT(56, void, png_read_row, (png_structrp png_ptr, png_bytep row, - png_bytep display_row)); -#endif - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -/* Read the whole image into memory at once. */ -PNG_EXPORT(57, void, png_read_image, (png_structrp png_ptr, png_bytepp image)); -#endif - -/* Write a row of image data */ -PNG_EXPORT(58, void, png_write_row, (png_structrp png_ptr, - png_const_bytep row)); - -/* Write a few rows of image data: (*row) is not written; however, the type - * is declared as writeable to maintain compatibility with previous versions - * of libpng and to allow the 'display_row' array from read_rows to be passed - * unchanged to write_rows. - */ -PNG_EXPORT(59, void, png_write_rows, (png_structrp png_ptr, png_bytepp row, - png_uint_32 num_rows)); - -/* Write the image data */ -PNG_EXPORT(60, void, png_write_image, (png_structrp png_ptr, png_bytepp image)); - -/* Write the end of the PNG file. */ -PNG_EXPORT(61, void, png_write_end, (png_structrp png_ptr, - png_inforp info_ptr)); - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -/* Read the end of the PNG file. */ -PNG_EXPORT(62, void, png_read_end, (png_structrp png_ptr, png_inforp info_ptr)); -#endif - -/* Free any memory associated with the png_info_struct */ -PNG_EXPORT(63, void, png_destroy_info_struct, (png_const_structrp png_ptr, - png_infopp info_ptr_ptr)); - -/* Free any memory associated with the png_struct and the png_info_structs */ -PNG_EXPORT(64, void, png_destroy_read_struct, (png_structpp png_ptr_ptr, - png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); - -/* Free any memory associated with the png_struct and the png_info_structs */ -PNG_EXPORT(65, void, png_destroy_write_struct, (png_structpp png_ptr_ptr, - png_infopp info_ptr_ptr)); - -/* Set the libpng method of handling chunk CRC errors */ -PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, - int ancil_action)); - -/* Values for png_set_crc_action() say how to handle CRC errors in - * ancillary and critical chunks, and whether to use the data contained - * therein. Note that it is impossible to "discard" data in a critical - * chunk. For versions prior to 0.90, the action was always error/quit, - * whereas in version 0.90 and later, the action for CRC errors in ancillary - * chunks is warn/discard. These values should NOT be changed. - * - * value action:critical action:ancillary - */ -#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */ -#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */ -#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */ -#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */ -#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ -#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ - -/* These functions give the user control over the scan-line filtering in - * libpng and the compression methods used by zlib. These functions are - * mainly useful for testing, as the defaults should work with most users. - * Those users who are tight on memory or want faster performance at the - * expense of compression can modify them. See the compression library - * header file (zlib.h) for an explination of the compression functions. - */ - -/* Set the filtering method(s) used by libpng. Currently, the only valid - * value for "method" is 0. - */ -PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method, - int filters)); - -/* Flags for png_set_filter() to say which filters to use. The flags - * are chosen so that they don't conflict with real filter types - * below, in case they are supplied instead of the #defined constants. - * These values should NOT be changed. - */ -#define PNG_NO_FILTERS 0x00 -#define PNG_FILTER_NONE 0x08 -#define PNG_FILTER_SUB 0x10 -#define PNG_FILTER_UP 0x20 -#define PNG_FILTER_AVG 0x40 -#define PNG_FILTER_PAETH 0x80 -#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \ - PNG_FILTER_AVG | PNG_FILTER_PAETH) - -/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now. - * These defines should NOT be changed. - */ -#define PNG_FILTER_VALUE_NONE 0 -#define PNG_FILTER_VALUE_SUB 1 -#define PNG_FILTER_VALUE_UP 2 -#define PNG_FILTER_VALUE_AVG 3 -#define PNG_FILTER_VALUE_PAETH 4 -#define PNG_FILTER_VALUE_LAST 5 - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* EXPERIMENTAL */ -/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_ - * defines, either the default (minimum-sum-of-absolute-differences), or - * the experimental method (weighted-minimum-sum-of-absolute-differences). - * - * Weights are factors >= 1.0, indicating how important it is to keep the - * filter type consistent between rows. Larger numbers mean the current - * filter is that many times as likely to be the same as the "num_weights" - * previous filters. This is cumulative for each previous row with a weight. - * There needs to be "num_weights" values in "filter_weights", or it can be - * NULL if the weights aren't being specified. Weights have no influence on - * the selection of the first row filter. Well chosen weights can (in theory) - * improve the compression for a given image. - * - * Costs are factors >= 1.0 indicating the relative decoding costs of a - * filter type. Higher costs indicate more decoding expense, and are - * therefore less likely to be selected over a filter with lower computational - * costs. There needs to be a value in "filter_costs" for each valid filter - * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't - * setting the costs. Costs try to improve the speed of decompression without - * unduly increasing the compressed image size. - * - * A negative weight or cost indicates the default value is to be used, and - * values in the range [0.0, 1.0) indicate the value is to remain unchanged. - * The default values for both weights and costs are currently 1.0, but may - * change if good general weighting/cost heuristics can be found. If both - * the weights and costs are set to 1.0, this degenerates the WEIGHTED method - * to the UNWEIGHTED method, but with added encoding time/computation. - */ -PNG_FP_EXPORT(68, void, png_set_filter_heuristics, (png_structrp png_ptr, - int heuristic_method, int num_weights, png_const_doublep filter_weights, - png_const_doublep filter_costs)) -PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed, - (png_structrp png_ptr, int heuristic_method, int num_weights, - png_const_fixed_point_p filter_weights, - png_const_fixed_point_p filter_costs)) -#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ - -/* Heuristic used for row filter selection. These defines should NOT be - * changed. - */ -#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ -#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ -#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ -#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ - -#ifdef PNG_WRITE_SUPPORTED -/* Set the library compression level. Currently, valid values range from - * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 - * (0 - no compression, 9 - "maximal" compression). Note that tests have - * shown that zlib compression levels 3-6 usually perform as well as level 9 - * for PNG images, and do considerably fewer caclulations. In the future, - * these values may not correspond directly to the zlib compression levels. - */ -PNG_EXPORT(69, void, png_set_compression_level, (png_structrp png_ptr, - int level)); - -PNG_EXPORT(70, void, png_set_compression_mem_level, (png_structrp png_ptr, - int mem_level)); - -PNG_EXPORT(71, void, png_set_compression_strategy, (png_structrp png_ptr, - int strategy)); - -/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a - * smaller value of window_bits if it can do so safely. - */ -PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structrp png_ptr, - int window_bits)); - -PNG_EXPORT(73, void, png_set_compression_method, (png_structrp png_ptr, - int method)); -#endif - -#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED -/* Also set zlib parameters for compressing non-IDAT chunks */ -PNG_EXPORT(222, void, png_set_text_compression_level, (png_structrp png_ptr, - int level)); - -PNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structrp png_ptr, - int mem_level)); - -PNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structrp png_ptr, - int strategy)); - -/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a - * smaller value of window_bits if it can do so safely. - */ -PNG_EXPORT(225, void, png_set_text_compression_window_bits, - (png_structrp png_ptr, int window_bits)); - -PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr, - int method)); -#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ - -/* These next functions are called for input/output, memory, and error - * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, - * and call standard C I/O routines such as fread(), fwrite(), and - * fprintf(). These functions can be made to use other I/O routines - * at run time for those applications that need to handle I/O in a - * different manner by calling png_set_???_fn(). See libpng-manual.txt for - * more information. - */ - -#ifdef PNG_STDIO_SUPPORTED -/* Initialize the input/output for the PNG file to the default functions. */ -PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp)); -#endif - -/* Replace the (error and abort), and warning functions with user - * supplied functions. If no messages are to be printed you must still - * write and use replacement functions. The replacement error_fn should - * still do a longjmp to the last setjmp location if you are using this - * method of error handling. If error_fn or warning_fn is NULL, the - * default function will be used. - */ - -PNG_EXPORT(75, void, png_set_error_fn, (png_structrp png_ptr, - png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn)); - -/* Return the user pointer associated with the error functions */ -PNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structrp png_ptr)); - -/* Replace the default data output functions with a user supplied one(s). - * If buffered output is not used, then output_flush_fn can be set to NULL. - * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time - * output_flush_fn will be ignored (and thus can be NULL). - * It is probably a mistake to use NULL for output_flush_fn if - * write_data_fn is not also NULL unless you have built libpng with - * PNG_WRITE_FLUSH_SUPPORTED undefined, because in this case libpng's - * default flush function, which uses the standard *FILE structure, will - * be used. - */ -PNG_EXPORT(77, void, png_set_write_fn, (png_structrp png_ptr, png_voidp io_ptr, - png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); - -/* Replace the default data input function with a user supplied one. */ -PNG_EXPORT(78, void, png_set_read_fn, (png_structrp png_ptr, png_voidp io_ptr, - png_rw_ptr read_data_fn)); - -/* Return the user pointer associated with the I/O functions */ -PNG_EXPORT(79, png_voidp, png_get_io_ptr, (png_const_structrp png_ptr)); - -PNG_EXPORT(80, void, png_set_read_status_fn, (png_structrp png_ptr, - png_read_status_ptr read_row_fn)); - -PNG_EXPORT(81, void, png_set_write_status_fn, (png_structrp png_ptr, - png_write_status_ptr write_row_fn)); - -#ifdef PNG_USER_MEM_SUPPORTED -/* Replace the default memory allocation functions with user supplied one(s). */ -PNG_EXPORT(82, void, png_set_mem_fn, (png_structrp png_ptr, png_voidp mem_ptr, - png_malloc_ptr malloc_fn, png_free_ptr free_fn)); -/* Return the user pointer associated with the memory functions */ -PNG_EXPORT(83, png_voidp, png_get_mem_ptr, (png_const_structrp png_ptr)); -#endif - -#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED -PNG_EXPORT(84, void, png_set_read_user_transform_fn, (png_structrp png_ptr, - png_user_transform_ptr read_user_transform_fn)); -#endif - -#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED -PNG_EXPORT(85, void, png_set_write_user_transform_fn, (png_structrp png_ptr, - png_user_transform_ptr write_user_transform_fn)); -#endif - -#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED -PNG_EXPORT(86, void, png_set_user_transform_info, (png_structrp png_ptr, - png_voidp user_transform_ptr, int user_transform_depth, - int user_transform_channels)); -/* Return the user pointer associated with the user transform functions */ -PNG_EXPORT(87, png_voidp, png_get_user_transform_ptr, - (png_const_structrp png_ptr)); -#endif - -#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED -/* Return information about the row currently being processed. Note that these - * APIs do not fail but will return unexpected results if called outside a user - * transform callback. Also note that when transforming an interlaced image the - * row number is the row number within the sub-image of the interlace pass, so - * the value will increase to the height of the sub-image (not the full image) - * then reset to 0 for the next pass. - * - * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to - * find the output pixel (x,y) given an interlaced sub-image pixel - * (row,col,pass). (See below for these macros.) - */ -PNG_EXPORT(217, png_uint_32, png_get_current_row_number, (png_const_structrp)); -PNG_EXPORT(218, png_byte, png_get_current_pass_number, (png_const_structrp)); -#endif - -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED -/* This callback is called only for *unknown* chunks. If - * PNG_HANDLE_AS_UNKNOWN_SUPPORTED is set then it is possible to set known - * chunks to be treated as unknown, however in this case the callback must do - * any processing required by the chunk (e.g. by calling the appropriate - * png_set_ APIs.) - * - * There is no write support - on write, by default, all the chunks in the - * 'unknown' list are written in the specified position. - * - * The integer return from the callback function is interpreted thus: - * - * negative: An error occured, png_chunk_error will be called. - * zero: The chunk was not handled, the chunk will be saved. A critical - * chunk will cause an error at this point unless it is to be saved. - * positive: The chunk was handled, libpng will ignore/discard it. - * - * See "INTERACTION WTIH USER CHUNK CALLBACKS" below for important notes about - * how this behavior will change in libpng 1.7 - */ -PNG_EXPORT(88, void, png_set_read_user_chunk_fn, (png_structrp png_ptr, - png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); -#endif - -#ifdef PNG_USER_CHUNKS_SUPPORTED -PNG_EXPORT(89, png_voidp, png_get_user_chunk_ptr, (png_const_structrp png_ptr)); -#endif - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -/* Sets the function callbacks for the push reader, and a pointer to a - * user-defined structure available to the callback functions. - */ -PNG_EXPORT(90, void, png_set_progressive_read_fn, (png_structrp png_ptr, - png_voidp progressive_ptr, png_progressive_info_ptr info_fn, - png_progressive_row_ptr row_fn, png_progressive_end_ptr end_fn)); - -/* Returns the user pointer associated with the push read functions */ -PNG_EXPORT(91, png_voidp, png_get_progressive_ptr, - (png_const_structrp png_ptr)); - -/* Function to be called when data becomes available */ -PNG_EXPORT(92, void, png_process_data, (png_structrp png_ptr, - png_inforp info_ptr, png_bytep buffer, png_size_t buffer_size)); - -/* A function which may be called *only* within png_process_data to stop the - * processing of any more data. The function returns the number of bytes - * remaining, excluding any that libpng has cached internally. A subsequent - * call to png_process_data must supply these bytes again. If the argument - * 'save' is set to true the routine will first save all the pending data and - * will always return 0. - */ -PNG_EXPORT(219, png_size_t, png_process_data_pause, (png_structrp, int save)); - -/* A function which may be called *only* outside (after) a call to - * png_process_data. It returns the number of bytes of data to skip in the - * input. Normally it will return 0, but if it returns a non-zero value the - * application must skip than number of bytes of input data and pass the - * following data to the next call to png_process_data. - */ -PNG_EXPORT(220, png_uint_32, png_process_data_skip, (png_structrp)); - -#ifdef PNG_READ_INTERLACING_SUPPORTED -/* Function that combines rows. 'new_row' is a flag that should come from - * the callback and be non-NULL if anything needs to be done; the library - * stores its own version of the new data internally and ignores the passed - * in value. - */ -PNG_EXPORT(93, void, png_progressive_combine_row, (png_const_structrp png_ptr, - png_bytep old_row, png_const_bytep new_row)); -#endif /* PNG_READ_INTERLACING_SUPPORTED */ -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ - -PNG_EXPORTA(94, png_voidp, png_malloc, (png_const_structrp png_ptr, - png_alloc_size_t size), PNG_ALLOCATED); -/* Added at libpng version 1.4.0 */ -PNG_EXPORTA(95, png_voidp, png_calloc, (png_const_structrp png_ptr, - png_alloc_size_t size), PNG_ALLOCATED); - -/* Added at libpng version 1.2.4 */ -PNG_EXPORTA(96, png_voidp, png_malloc_warn, (png_const_structrp png_ptr, - png_alloc_size_t size), PNG_ALLOCATED); - -/* Frees a pointer allocated by png_malloc() */ -PNG_EXPORT(97, void, png_free, (png_const_structrp png_ptr, png_voidp ptr)); - -/* Free data that was allocated internally */ -PNG_EXPORT(98, void, png_free_data, (png_const_structrp png_ptr, - png_inforp info_ptr, png_uint_32 free_me, int num)); - -/* Reassign responsibility for freeing existing data, whether allocated - * by libpng or by the application; this works on the png_info structure passed - * in, it does not change the state for other png_info structures. - * - * It is unlikely that this function works correctly as of 1.6.0 and using it - * may result either in memory leaks or double free of allocated data. - */ -PNG_EXPORTA(99, void, png_data_freer, (png_const_structrp png_ptr, - png_inforp info_ptr, int freer, png_uint_32 mask), PNG_DEPRECATED); - -/* Assignments for png_data_freer */ -#define PNG_DESTROY_WILL_FREE_DATA 1 -#define PNG_SET_WILL_FREE_DATA 1 -#define PNG_USER_WILL_FREE_DATA 2 -/* Flags for png_ptr->free_me and info_ptr->free_me */ -#define PNG_FREE_HIST 0x0008 -#define PNG_FREE_ICCP 0x0010 -#define PNG_FREE_SPLT 0x0020 -#define PNG_FREE_ROWS 0x0040 -#define PNG_FREE_PCAL 0x0080 -#define PNG_FREE_SCAL 0x0100 -#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED -# define PNG_FREE_UNKN 0x0200 -#endif -/* PNG_FREE_LIST 0x0400 removed in 1.6.0 because it is ignored */ -#define PNG_FREE_PLTE 0x1000 -#define PNG_FREE_TRNS 0x2000 -#define PNG_FREE_TEXT 0x4000 -#define PNG_FREE_ALL 0x7fff -#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ - -#ifdef PNG_USER_MEM_SUPPORTED -PNG_EXPORTA(100, png_voidp, png_malloc_default, (png_const_structrp png_ptr, - png_alloc_size_t size), PNG_ALLOCATED PNG_DEPRECATED); -PNG_EXPORTA(101, void, png_free_default, (png_const_structrp png_ptr, - png_voidp ptr), PNG_DEPRECATED); -#endif - -#ifdef PNG_ERROR_TEXT_SUPPORTED -/* Fatal error in PNG image of libpng - can't continue */ -PNG_EXPORTA(102, void, png_error, (png_const_structrp png_ptr, - png_const_charp error_message), PNG_NORETURN); - -/* The same, but the chunk name is prepended to the error string. */ -PNG_EXPORTA(103, void, png_chunk_error, (png_const_structrp png_ptr, - png_const_charp error_message), PNG_NORETURN); - -#else -/* Fatal error in PNG image of libpng - can't continue */ -PNG_EXPORTA(104, void, png_err, (png_const_structrp png_ptr), PNG_NORETURN); -#endif - -#ifdef PNG_WARNINGS_SUPPORTED -/* Non-fatal error in libpng. Can continue, but may have a problem. */ -PNG_EXPORT(105, void, png_warning, (png_const_structrp png_ptr, - png_const_charp warning_message)); - -/* Non-fatal error in libpng, chunk name is prepended to message. */ -PNG_EXPORT(106, void, png_chunk_warning, (png_const_structrp png_ptr, - png_const_charp warning_message)); -#endif - -#ifdef PNG_BENIGN_ERRORS_SUPPORTED -/* Benign error in libpng. Can continue, but may have a problem. - * User can choose whether to handle as a fatal error or as a warning. */ -PNG_EXPORT(107, void, png_benign_error, (png_const_structrp png_ptr, - png_const_charp warning_message)); - -#ifdef PNG_READ_SUPPORTED -/* Same, chunk name is prepended to message (only during read) */ -PNG_EXPORT(108, void, png_chunk_benign_error, (png_const_structrp png_ptr, - png_const_charp warning_message)); -#endif - -PNG_EXPORT(109, void, png_set_benign_errors, - (png_structrp png_ptr, int allowed)); -#else -# ifdef PNG_ALLOW_BENIGN_ERRORS -# define png_benign_error png_warning -# define png_chunk_benign_error png_chunk_warning -# else -# define png_benign_error png_error -# define png_chunk_benign_error png_chunk_error -# endif -#endif - -/* The png_set_ functions are for storing values in the png_info_struct. - * Similarly, the png_get_ calls are used to read values from the - * png_info_struct, either storing the parameters in the passed variables, or - * setting pointers into the png_info_struct where the data is stored. The - * png_get_ functions return a non-zero value if the data was available - * in info_ptr, or return zero and do not change any of the parameters if the - * data was not available. - * - * These functions should be used instead of directly accessing png_info - * to avoid problems with future changes in the size and internal layout of - * png_info_struct. - */ -/* Returns "flag" if chunk data is valid in info_ptr. */ -PNG_EXPORT(110, png_uint_32, png_get_valid, (png_const_structrp png_ptr, - png_const_inforp info_ptr, png_uint_32 flag)); - -/* Returns number of bytes needed to hold a transformed row. */ -PNG_EXPORT(111, png_size_t, png_get_rowbytes, (png_const_structrp png_ptr, - png_const_inforp info_ptr)); - -#ifdef PNG_INFO_IMAGE_SUPPORTED -/* Returns row_pointers, which is an array of pointers to scanlines that was - * returned from png_read_png(). - */ -PNG_EXPORT(112, png_bytepp, png_get_rows, (png_const_structrp png_ptr, - png_const_inforp info_ptr)); - -/* Set row_pointers, which is an array of pointers to scanlines for use - * by png_write_png(). - */ -PNG_EXPORT(113, void, png_set_rows, (png_const_structrp png_ptr, - png_inforp info_ptr, png_bytepp row_pointers)); -#endif - -/* Returns number of color channels in image. */ -PNG_EXPORT(114, png_byte, png_get_channels, (png_const_structrp png_ptr, - png_const_inforp info_ptr)); - -#ifdef PNG_EASY_ACCESS_SUPPORTED -/* Returns image width in pixels. */ -PNG_EXPORT(115, png_uint_32, png_get_image_width, (png_const_structrp png_ptr, - png_const_inforp info_ptr)); - -/* Returns image height in pixels. */ -PNG_EXPORT(116, png_uint_32, png_get_image_height, (png_const_structrp png_ptr, - png_const_inforp info_ptr)); - -/* Returns image bit_depth. */ -PNG_EXPORT(117, png_byte, png_get_bit_depth, (png_const_structrp png_ptr, - png_const_inforp info_ptr)); - -/* Returns image color_type. */ -PNG_EXPORT(118, png_byte, png_get_color_type, (png_const_structrp png_ptr, - png_const_inforp info_ptr)); - -/* Returns image filter_type. */ -PNG_EXPORT(119, png_byte, png_get_filter_type, (png_const_structrp png_ptr, - png_const_inforp info_ptr)); - -/* Returns image interlace_type. */ -PNG_EXPORT(120, png_byte, png_get_interlace_type, (png_const_structrp png_ptr, - png_const_inforp info_ptr)); - -/* Returns image compression_type. */ -PNG_EXPORT(121, png_byte, png_get_compression_type, (png_const_structrp png_ptr, - png_const_inforp info_ptr)); - -/* Returns image resolution in pixels per meter, from pHYs chunk data. */ -PNG_EXPORT(122, png_uint_32, png_get_pixels_per_meter, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); -PNG_EXPORT(123, png_uint_32, png_get_x_pixels_per_meter, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); -PNG_EXPORT(124, png_uint_32, png_get_y_pixels_per_meter, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); - -/* Returns pixel aspect ratio, computed from pHYs chunk data. */ -PNG_FP_EXPORT(125, float, png_get_pixel_aspect_ratio, - (png_const_structrp png_ptr, png_const_inforp info_ptr)) -PNG_FIXED_EXPORT(210, png_fixed_point, png_get_pixel_aspect_ratio_fixed, - (png_const_structrp png_ptr, png_const_inforp info_ptr)) - -/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ -PNG_EXPORT(126, png_int_32, png_get_x_offset_pixels, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); -PNG_EXPORT(127, png_int_32, png_get_y_offset_pixels, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); -PNG_EXPORT(128, png_int_32, png_get_x_offset_microns, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); -PNG_EXPORT(129, png_int_32, png_get_y_offset_microns, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); - -#endif /* PNG_EASY_ACCESS_SUPPORTED */ - -#ifdef PNG_READ_SUPPORTED -/* Returns pointer to signature string read from PNG header */ -PNG_EXPORT(130, png_const_bytep, png_get_signature, (png_const_structrp png_ptr, - png_const_inforp info_ptr)); -#endif - -#ifdef PNG_bKGD_SUPPORTED -PNG_EXPORT(131, png_uint_32, png_get_bKGD, (png_const_structrp png_ptr, - png_inforp info_ptr, png_color_16p *background)); -#endif - -#ifdef PNG_bKGD_SUPPORTED -PNG_EXPORT(132, void, png_set_bKGD, (png_const_structrp png_ptr, - png_inforp info_ptr, png_const_color_16p background)); -#endif - -#ifdef PNG_cHRM_SUPPORTED -PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structrp png_ptr, - png_const_inforp info_ptr, double *white_x, double *white_y, double *red_x, - double *red_y, double *green_x, double *green_y, double *blue_x, - double *blue_y)) -PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_const_structrp png_ptr, - png_const_inforp info_ptr, double *red_X, double *red_Y, double *red_Z, - double *green_X, double *green_Y, double *green_Z, double *blue_X, - double *blue_Y, double *blue_Z)) -PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - png_fixed_point *int_white_x, png_fixed_point *int_white_y, - png_fixed_point *int_red_x, png_fixed_point *int_red_y, - png_fixed_point *int_green_x, png_fixed_point *int_green_y, - png_fixed_point *int_blue_x, png_fixed_point *int_blue_y)) -PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - png_fixed_point *int_red_X, png_fixed_point *int_red_Y, - png_fixed_point *int_red_Z, png_fixed_point *int_green_X, - png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, - png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, - png_fixed_point *int_blue_Z)) -#endif - -#ifdef PNG_cHRM_SUPPORTED -PNG_FP_EXPORT(135, void, png_set_cHRM, (png_const_structrp png_ptr, - png_inforp info_ptr, - double white_x, double white_y, double red_x, double red_y, double green_x, - double green_y, double blue_x, double blue_y)) -PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_const_structrp png_ptr, - png_inforp info_ptr, double red_X, double red_Y, double red_Z, - double green_X, double green_Y, double green_Z, double blue_X, - double blue_Y, double blue_Z)) -PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_const_structrp png_ptr, - png_inforp info_ptr, png_fixed_point int_white_x, - png_fixed_point int_white_y, png_fixed_point int_red_x, - png_fixed_point int_red_y, png_fixed_point int_green_x, - png_fixed_point int_green_y, png_fixed_point int_blue_x, - png_fixed_point int_blue_y)) -PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr, - png_inforp info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y, - png_fixed_point int_red_Z, png_fixed_point int_green_X, - png_fixed_point int_green_Y, png_fixed_point int_green_Z, - png_fixed_point int_blue_X, png_fixed_point int_blue_Y, - png_fixed_point int_blue_Z)) -#endif - -#ifdef PNG_gAMA_SUPPORTED -PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, (png_const_structrp png_ptr, - png_const_inforp info_ptr, double *file_gamma)) -PNG_FIXED_EXPORT(138, png_uint_32, png_get_gAMA_fixed, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - png_fixed_point *int_file_gamma)) -#endif - -#ifdef PNG_gAMA_SUPPORTED -PNG_FP_EXPORT(139, void, png_set_gAMA, (png_const_structrp png_ptr, - png_inforp info_ptr, double file_gamma)) -PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_const_structrp png_ptr, - png_inforp info_ptr, png_fixed_point int_file_gamma)) -#endif - -#ifdef PNG_hIST_SUPPORTED -PNG_EXPORT(141, png_uint_32, png_get_hIST, (png_const_structrp png_ptr, - png_inforp info_ptr, png_uint_16p *hist)); -#endif - -#ifdef PNG_hIST_SUPPORTED -PNG_EXPORT(142, void, png_set_hIST, (png_const_structrp png_ptr, - png_inforp info_ptr, png_const_uint_16p hist)); -#endif - -PNG_EXPORT(143, png_uint_32, png_get_IHDR, (png_const_structrp png_ptr, - png_const_inforp info_ptr, png_uint_32 *width, png_uint_32 *height, - int *bit_depth, int *color_type, int *interlace_method, - int *compression_method, int *filter_method)); - -PNG_EXPORT(144, void, png_set_IHDR, (png_const_structrp png_ptr, - png_inforp info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, - int color_type, int interlace_method, int compression_method, - int filter_method)); - -#ifdef PNG_oFFs_SUPPORTED -PNG_EXPORT(145, png_uint_32, png_get_oFFs, (png_const_structrp png_ptr, - png_const_inforp info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, - int *unit_type)); -#endif - -#ifdef PNG_oFFs_SUPPORTED -PNG_EXPORT(146, void, png_set_oFFs, (png_const_structrp png_ptr, - png_inforp info_ptr, png_int_32 offset_x, png_int_32 offset_y, - int unit_type)); -#endif - -#ifdef PNG_pCAL_SUPPORTED -PNG_EXPORT(147, png_uint_32, png_get_pCAL, (png_const_structrp png_ptr, - png_inforp info_ptr, png_charp *purpose, png_int_32 *X0, - png_int_32 *X1, int *type, int *nparams, png_charp *units, - png_charpp *params)); -#endif - -#ifdef PNG_pCAL_SUPPORTED -PNG_EXPORT(148, void, png_set_pCAL, (png_const_structrp png_ptr, - png_inforp info_ptr, png_const_charp purpose, png_int_32 X0, png_int_32 X1, - int type, int nparams, png_const_charp units, png_charpp params)); -#endif - -#ifdef PNG_pHYs_SUPPORTED -PNG_EXPORT(149, png_uint_32, png_get_pHYs, (png_const_structrp png_ptr, - png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, - int *unit_type)); -#endif - -#ifdef PNG_pHYs_SUPPORTED -PNG_EXPORT(150, void, png_set_pHYs, (png_const_structrp png_ptr, - png_inforp info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); -#endif - -PNG_EXPORT(151, png_uint_32, png_get_PLTE, (png_const_structrp png_ptr, - png_inforp info_ptr, png_colorp *palette, int *num_palette)); - -PNG_EXPORT(152, void, png_set_PLTE, (png_structrp png_ptr, - png_inforp info_ptr, png_const_colorp palette, int num_palette)); - -#ifdef PNG_sBIT_SUPPORTED -PNG_EXPORT(153, png_uint_32, png_get_sBIT, (png_const_structrp png_ptr, - png_inforp info_ptr, png_color_8p *sig_bit)); -#endif - -#ifdef PNG_sBIT_SUPPORTED -PNG_EXPORT(154, void, png_set_sBIT, (png_const_structrp png_ptr, - png_inforp info_ptr, png_const_color_8p sig_bit)); -#endif - -#ifdef PNG_sRGB_SUPPORTED -PNG_EXPORT(155, png_uint_32, png_get_sRGB, (png_const_structrp png_ptr, - png_const_inforp info_ptr, int *file_srgb_intent)); -#endif - -#ifdef PNG_sRGB_SUPPORTED -PNG_EXPORT(156, void, png_set_sRGB, (png_const_structrp png_ptr, - png_inforp info_ptr, int srgb_intent)); -PNG_EXPORT(157, void, png_set_sRGB_gAMA_and_cHRM, (png_const_structrp png_ptr, - png_inforp info_ptr, int srgb_intent)); -#endif - -#ifdef PNG_iCCP_SUPPORTED -PNG_EXPORT(158, png_uint_32, png_get_iCCP, (png_const_structrp png_ptr, - png_inforp info_ptr, png_charpp name, int *compression_type, - png_bytepp profile, png_uint_32 *proflen)); -#endif - -#ifdef PNG_iCCP_SUPPORTED -PNG_EXPORT(159, void, png_set_iCCP, (png_const_structrp png_ptr, - png_inforp info_ptr, png_const_charp name, int compression_type, - png_const_bytep profile, png_uint_32 proflen)); -#endif - -#ifdef PNG_sPLT_SUPPORTED -PNG_EXPORT(160, int, png_get_sPLT, (png_const_structrp png_ptr, - png_inforp info_ptr, png_sPLT_tpp entries)); -#endif - -#ifdef PNG_sPLT_SUPPORTED -PNG_EXPORT(161, void, png_set_sPLT, (png_const_structrp png_ptr, - png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)); -#endif - -#ifdef PNG_TEXT_SUPPORTED -/* png_get_text also returns the number of text chunks in *num_text */ -PNG_EXPORT(162, int, png_get_text, (png_const_structrp png_ptr, - png_inforp info_ptr, png_textp *text_ptr, int *num_text)); -#endif - -/* Note while png_set_text() will accept a structure whose text, - * language, and translated keywords are NULL pointers, the structure - * returned by png_get_text will always contain regular - * zero-terminated C strings. They might be empty strings but - * they will never be NULL pointers. - */ - -#ifdef PNG_TEXT_SUPPORTED -PNG_EXPORT(163, void, png_set_text, (png_const_structrp png_ptr, - png_inforp info_ptr, png_const_textp text_ptr, int num_text)); -#endif - -#ifdef PNG_tIME_SUPPORTED -PNG_EXPORT(164, png_uint_32, png_get_tIME, (png_const_structrp png_ptr, - png_inforp info_ptr, png_timep *mod_time)); -#endif - -#ifdef PNG_tIME_SUPPORTED -PNG_EXPORT(165, void, png_set_tIME, (png_const_structrp png_ptr, - png_inforp info_ptr, png_const_timep mod_time)); -#endif - -#ifdef PNG_tRNS_SUPPORTED -PNG_EXPORT(166, png_uint_32, png_get_tRNS, (png_const_structrp png_ptr, - png_inforp info_ptr, png_bytep *trans_alpha, int *num_trans, - png_color_16p *trans_color)); -#endif - -#ifdef PNG_tRNS_SUPPORTED -PNG_EXPORT(167, void, png_set_tRNS, (png_structrp png_ptr, - png_inforp info_ptr, png_const_bytep trans_alpha, int num_trans, - png_const_color_16p trans_color)); -#endif - -#ifdef PNG_sCAL_SUPPORTED -PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, (png_const_structrp png_ptr, - png_const_inforp info_ptr, int *unit, double *width, double *height)) -#if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \ - defined(PNG_FLOATING_POINT_SUPPORTED) -/* NOTE: this API is currently implemented using floating point arithmetic, - * consequently it can only be used on systems with floating point support. - * In any case the range of values supported by png_fixed_point is small and it - * is highly recommended that png_get_sCAL_s be used instead. - */ -PNG_FIXED_EXPORT(214, png_uint_32, png_get_sCAL_fixed, - (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, - png_fixed_point *width, png_fixed_point *height)) -#endif -PNG_EXPORT(169, png_uint_32, png_get_sCAL_s, - (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, - png_charpp swidth, png_charpp sheight)); - -PNG_FP_EXPORT(170, void, png_set_sCAL, (png_const_structrp png_ptr, - png_inforp info_ptr, int unit, double width, double height)) -PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, (png_const_structrp png_ptr, - png_inforp info_ptr, int unit, png_fixed_point width, - png_fixed_point height)) -PNG_EXPORT(171, void, png_set_sCAL_s, (png_const_structrp png_ptr, - png_inforp info_ptr, int unit, - png_const_charp swidth, png_const_charp sheight)); -#endif /* PNG_sCAL_SUPPORTED */ - -#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED -/* Provide the default handling for all unknown chunks or, optionally, for - * specific unknown chunks. - * - * NOTE: prior to 1.6.0 the handling specified for particular chunks on read was - * ignored and the default was used, the per-chunk setting only had an effect on - * write. If you wish to have chunk-specific handling on read in code that must - * work on earlier versions you must use a user chunk callback to specify the - * desired handling (keep or discard.) - * - * The 'keep' parameter is a PNG_HANDLE_CHUNK_ value as listed below. The - * parameter is interpreted as follows: - * - * READ: - * PNG_HANDLE_CHUNK_AS_DEFAULT: - * Known chunks: do normal libpng processing, do not keep the chunk (but - * see the comments below about PNG_HANDLE_AS_UNKNOWN_SUPPORTED) - * Unknown chunks: for a specific chunk use the global default, when used - * as the default discard the chunk data. - * PNG_HANDLE_CHUNK_NEVER: - * Discard the chunk data. - * PNG_HANDLE_CHUNK_IF_SAFE: - * Keep the chunk data if the chunk is not critical else raise a chunk - * error. - * PNG_HANDLE_CHUNK_ALWAYS: - * Keep the chunk data. - * - * If the chunk data is saved it can be retrieved using png_get_unknown_chunks, - * below. Notice that specifying "AS_DEFAULT" as a global default is equivalent - * to specifying "NEVER", however when "AS_DEFAULT" is used for specific chunks - * it simply resets the behavior to the libpng default. - * - * INTERACTION WTIH USER CHUNK CALLBACKS: - * The per-chunk handling is always used when there is a png_user_chunk_ptr - * callback and the callback returns 0; the chunk is then always stored *unless* - * it is critical and the per-chunk setting is other than ALWAYS. Notice that - * the global default is *not* used in this case. (In effect the per-chunk - * value is incremented to at least IF_SAFE.) - * - * IMPORTANT NOTE: this behavior will change in libpng 1.7 - the global and - * per-chunk defaults will be honored. If you want to preserve the current - * behavior when your callback returns 0 you must set PNG_HANDLE_CHUNK_IF_SAFE - * as the default - if you don't do this libpng 1.6 will issue a warning. - * - * If you want unhandled unknown chunks to be discarded in libpng 1.6 and - * earlier simply return '1' (handled). - * - * PNG_HANDLE_AS_UNKNOWN_SUPPORTED: - * If this is *not* set known chunks will always be handled by libpng and - * will never be stored in the unknown chunk list. Known chunks listed to - * png_set_keep_unknown_chunks will have no effect. If it is set then known - * chunks listed with a keep other than AS_DEFAULT will *never* be processed - * by libpng, in addition critical chunks must either be processed by the - * callback or saved. - * - * The IHDR and IEND chunks must not be listed. Because this turns off the - * default handling for chunks that would otherwise be recognized the - * behavior of libpng transformations may well become incorrect! - * - * WRITE: - * When writing chunks the options only apply to the chunks specified by - * png_set_unknown_chunks (below), libpng will *always* write known chunks - * required by png_set_ calls and will always write the core critical chunks - * (as required for PLTE). - * - * Each chunk in the png_set_unknown_chunks list is looked up in the - * png_set_keep_unknown_chunks list to find the keep setting, this is then - * interpreted as follows: - * - * PNG_HANDLE_CHUNK_AS_DEFAULT: - * Write safe-to-copy chunks and write other chunks if the global - * default is set to _ALWAYS, otherwise don't write this chunk. - * PNG_HANDLE_CHUNK_NEVER: - * Do not write the chunk. - * PNG_HANDLE_CHUNK_IF_SAFE: - * Write the chunk if it is safe-to-copy, otherwise do not write it. - * PNG_HANDLE_CHUNK_ALWAYS: - * Write the chunk. - * - * Note that the default behavior is effectively the opposite of the read case - - * in read unknown chunks are not stored by default, in write they are written - * by default. Also the behavior of PNG_HANDLE_CHUNK_IF_SAFE is very different - * - on write the safe-to-copy bit is checked, on read the critical bit is - * checked and on read if the chunk is critical an error will be raised. - * - * num_chunks: - * =========== - * If num_chunks is positive, then the "keep" parameter specifies the manner - * for handling only those chunks appearing in the chunk_list array, - * otherwise the chunk list array is ignored. - * - * If num_chunks is 0 the "keep" parameter specifies the default behavior for - * unknown chunks, as described above. - * - * If num_chunks is negative, then the "keep" parameter specifies the manner - * for handling all unknown chunks plus all chunks recognized by libpng - * except for the IHDR, PLTE, tRNS, IDAT, and IEND chunks (which continue to - * be processed by libpng. - */ -PNG_EXPORT(172, void, png_set_keep_unknown_chunks, (png_structrp png_ptr, - int keep, png_const_bytep chunk_list, int num_chunks)); - -/* The "keep" PNG_HANDLE_CHUNK_ parameter for the specified chunk is returned; - * the result is therefore true (non-zero) if special handling is required, - * false for the default handling. - */ -PNG_EXPORT(173, int, png_handle_as_unknown, (png_const_structrp png_ptr, - png_const_bytep chunk_name)); -#endif - -#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED -PNG_EXPORT(174, void, png_set_unknown_chunks, (png_const_structrp png_ptr, - png_inforp info_ptr, png_const_unknown_chunkp unknowns, - int num_unknowns)); - /* NOTE: prior to 1.6.0 this routine set the 'location' field of the added - * unknowns to the location currently stored in the png_struct. This is - * invariably the wrong value on write. To fix this call the following API - * for each chunk in the list with the correct location. If you know your - * code won't be compiled on earlier versions you can rely on - * png_set_unknown_chunks(write-ptr, png_get_unknown_chunks(read-ptr)) doing - * the correct thing. - */ - -PNG_EXPORT(175, void, png_set_unknown_chunk_location, - (png_const_structrp png_ptr, png_inforp info_ptr, int chunk, int location)); - -PNG_EXPORT(176, int, png_get_unknown_chunks, (png_const_structrp png_ptr, - png_inforp info_ptr, png_unknown_chunkpp entries)); -#endif - -/* Png_free_data() will turn off the "valid" flag for anything it frees. - * If you need to turn it off for a chunk that your application has freed, - * you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); - */ -PNG_EXPORT(177, void, png_set_invalid, (png_const_structrp png_ptr, - png_inforp info_ptr, int mask)); - -#ifdef PNG_INFO_IMAGE_SUPPORTED -/* The "params" pointer is currently not used and is for future expansion. */ -PNG_EXPORT(178, void, png_read_png, (png_structrp png_ptr, png_inforp info_ptr, - int transforms, png_voidp params)); -PNG_EXPORT(179, void, png_write_png, (png_structrp png_ptr, png_inforp info_ptr, - int transforms, png_voidp params)); -#endif - -PNG_EXPORT(180, png_const_charp, png_get_copyright, - (png_const_structrp png_ptr)); -PNG_EXPORT(181, png_const_charp, png_get_header_ver, - (png_const_structrp png_ptr)); -PNG_EXPORT(182, png_const_charp, png_get_header_version, - (png_const_structrp png_ptr)); -PNG_EXPORT(183, png_const_charp, png_get_libpng_ver, - (png_const_structrp png_ptr)); - -#ifdef PNG_MNG_FEATURES_SUPPORTED -PNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structrp png_ptr, - png_uint_32 mng_features_permitted)); -#endif - -/* For use in png_set_keep_unknown, added to version 1.2.6 */ -#define PNG_HANDLE_CHUNK_AS_DEFAULT 0 -#define PNG_HANDLE_CHUNK_NEVER 1 -#define PNG_HANDLE_CHUNK_IF_SAFE 2 -#define PNG_HANDLE_CHUNK_ALWAYS 3 -#define PNG_HANDLE_CHUNK_LAST 4 - -/* Strip the prepended error numbers ("#nnn ") from error and warning - * messages before passing them to the error or warning handler. - */ -#ifdef PNG_ERROR_NUMBERS_SUPPORTED -PNG_EXPORT(185, void, png_set_strip_error_numbers, (png_structrp png_ptr, - png_uint_32 strip_mode)); -#endif - -/* Added in libpng-1.2.6 */ -#ifdef PNG_SET_USER_LIMITS_SUPPORTED -PNG_EXPORT(186, void, png_set_user_limits, (png_structrp png_ptr, - png_uint_32 user_width_max, png_uint_32 user_height_max)); -PNG_EXPORT(187, png_uint_32, png_get_user_width_max, - (png_const_structrp png_ptr)); -PNG_EXPORT(188, png_uint_32, png_get_user_height_max, - (png_const_structrp png_ptr)); -/* Added in libpng-1.4.0 */ -PNG_EXPORT(189, void, png_set_chunk_cache_max, (png_structrp png_ptr, - png_uint_32 user_chunk_cache_max)); -PNG_EXPORT(190, png_uint_32, png_get_chunk_cache_max, - (png_const_structrp png_ptr)); -/* Added in libpng-1.4.1 */ -PNG_EXPORT(191, void, png_set_chunk_malloc_max, (png_structrp png_ptr, - png_alloc_size_t user_chunk_cache_max)); -PNG_EXPORT(192, png_alloc_size_t, png_get_chunk_malloc_max, - (png_const_structrp png_ptr)); -#endif - -#if defined(PNG_INCH_CONVERSIONS_SUPPORTED) -PNG_EXPORT(193, png_uint_32, png_get_pixels_per_inch, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); - -PNG_EXPORT(194, png_uint_32, png_get_x_pixels_per_inch, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); - -PNG_EXPORT(195, png_uint_32, png_get_y_pixels_per_inch, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); - -PNG_FP_EXPORT(196, float, png_get_x_offset_inches, - (png_const_structrp png_ptr, png_const_inforp info_ptr)) -#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ -PNG_FIXED_EXPORT(211, png_fixed_point, png_get_x_offset_inches_fixed, - (png_const_structrp png_ptr, png_const_inforp info_ptr)) -#endif - -PNG_FP_EXPORT(197, float, png_get_y_offset_inches, (png_const_structrp png_ptr, - png_const_inforp info_ptr)) -#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ -PNG_FIXED_EXPORT(212, png_fixed_point, png_get_y_offset_inches_fixed, - (png_const_structrp png_ptr, png_const_inforp info_ptr)) -#endif - -# ifdef PNG_pHYs_SUPPORTED -PNG_EXPORT(198, png_uint_32, png_get_pHYs_dpi, (png_const_structrp png_ptr, - png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, - int *unit_type)); -# endif /* PNG_pHYs_SUPPORTED */ -#endif /* PNG_INCH_CONVERSIONS_SUPPORTED */ - -/* Added in libpng-1.4.0 */ -#ifdef PNG_IO_STATE_SUPPORTED -PNG_EXPORT(199, png_uint_32, png_get_io_state, (png_const_structrp png_ptr)); - -/* Removed from libpng 1.6; use png_get_io_chunk_type. */ -PNG_REMOVED(200, png_const_bytep, png_get_io_chunk_name, (png_structrp png_ptr), - PNG_DEPRECATED) - -PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type, - (png_const_structrp png_ptr)); - -/* The flags returned by png_get_io_state() are the following: */ -# define PNG_IO_NONE 0x0000 /* no I/O at this moment */ -# define PNG_IO_READING 0x0001 /* currently reading */ -# define PNG_IO_WRITING 0x0002 /* currently writing */ -# define PNG_IO_SIGNATURE 0x0010 /* currently at the file signature */ -# define PNG_IO_CHUNK_HDR 0x0020 /* currently at the chunk header */ -# define PNG_IO_CHUNK_DATA 0x0040 /* currently at the chunk data */ -# define PNG_IO_CHUNK_CRC 0x0080 /* currently at the chunk crc */ -# define PNG_IO_MASK_OP 0x000f /* current operation: reading/writing */ -# define PNG_IO_MASK_LOC 0x00f0 /* current location: sig/hdr/data/crc */ -#endif /* ?PNG_IO_STATE_SUPPORTED */ - -/* Interlace support. The following macros are always defined so that if - * libpng interlace handling is turned off the macros may be used to handle - * interlaced images within the application. - */ -#define PNG_INTERLACE_ADAM7_PASSES 7 - -/* Two macros to return the first row and first column of the original, - * full, image which appears in a given pass. 'pass' is in the range 0 - * to 6 and the result is in the range 0 to 7. - */ -#define PNG_PASS_START_ROW(pass) (((1&~(pass))<<(3-((pass)>>1)))&7) -#define PNG_PASS_START_COL(pass) (((1& (pass))<<(3-(((pass)+1)>>1)))&7) - -/* A macro to return the offset between pixels in the output row for a pair of - * pixels in the input - effectively the inverse of the 'COL_SHIFT' macro that - * follows. Note that ROW_OFFSET is the offset from one row to the next whereas - * COL_OFFSET is from one column to the next, within a row. - */ -#define PNG_PASS_ROW_OFFSET(pass) ((pass)>2?(8>>(((pass)-1)>>1)):8) -#define PNG_PASS_COL_OFFSET(pass) (1<<((7-(pass))>>1)) - -/* Two macros to help evaluate the number of rows or columns in each - * pass. This is expressed as a shift - effectively log2 of the number or - * rows or columns in each 8x8 tile of the original image. - */ -#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3) -#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3) - -/* Hence two macros to determine the number of rows or columns in a given - * pass of an image given its height or width. In fact these macros may - * return non-zero even though the sub-image is empty, because the other - * dimension may be empty for a small image. - */ -#define PNG_PASS_ROWS(height, pass) (((height)+(((1<>PNG_PASS_ROW_SHIFT(pass)) -#define PNG_PASS_COLS(width, pass) (((width)+(((1<>PNG_PASS_COL_SHIFT(pass)) - -/* For the reader row callbacks (both progressive and sequential) it is - * necessary to find the row in the output image given a row in an interlaced - * image, so two more macros: - */ -#define PNG_ROW_FROM_PASS_ROW(y_in, pass) \ - (((y_in)<>(((7-(off))-(pass))<<2)) & 0xF) | \ - ((0x01145AF0>>(((7-(off))-(pass))<<2)) & 0xF0)) - -#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \ - ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1) -#define PNG_COL_IN_INTERLACE_PASS(x, pass) \ - ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1) - -#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED -/* With these routines we avoid an integer divide, which will be slower on - * most machines. However, it does take more operations than the corresponding - * divide method, so it may be slower on a few RISC systems. There are two - * shifts (by 8 or 16 bits) and an addition, versus a single integer divide. - * - * Note that the rounding factors are NOT supposed to be the same! 128 and - * 32768 are correct for the NODIV code; 127 and 32767 are correct for the - * standard method. - * - * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ] - */ - - /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ - -# define png_composite(composite, fg, alpha, bg) \ - { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) \ - * (png_uint_16)(alpha) \ - + (png_uint_16)(bg)*(png_uint_16)(255 \ - - (png_uint_16)(alpha)) + 128); \ - (composite) = (png_byte)((temp + (temp >> 8)) >> 8); } - -# define png_composite_16(composite, fg, alpha, bg) \ - { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) \ - * (png_uint_32)(alpha) \ - + (png_uint_32)(bg)*(65535 \ - - (png_uint_32)(alpha)) + 32768); \ - (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); } - -#else /* Standard method using integer division */ - -# define png_composite(composite, fg, alpha, bg) \ - (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \ - (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ - 127) / 255) - -# define png_composite_16(composite, fg, alpha, bg) \ - (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \ - (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) + \ - 32767) / 65535) -#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */ - -#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED -PNG_EXPORT(201, png_uint_32, png_get_uint_32, (png_const_bytep buf)); -PNG_EXPORT(202, png_uint_16, png_get_uint_16, (png_const_bytep buf)); -PNG_EXPORT(203, png_int_32, png_get_int_32, (png_const_bytep buf)); -#endif - -PNG_EXPORT(204, png_uint_32, png_get_uint_31, (png_const_structrp png_ptr, - png_const_bytep buf)); -/* No png_get_int_16 -- may be added if there's a real need for it. */ - -/* Place a 32-bit number into a buffer in PNG byte order (big-endian). */ -#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED -PNG_EXPORT(205, void, png_save_uint_32, (png_bytep buf, png_uint_32 i)); -#endif -#ifdef PNG_SAVE_INT_32_SUPPORTED -PNG_EXPORT(206, void, png_save_int_32, (png_bytep buf, png_int_32 i)); -#endif - -/* Place a 16-bit number into a buffer in PNG byte order. - * The parameter is declared unsigned int, not png_uint_16, - * just to avoid potential problems on pre-ANSI C compilers. - */ -#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED -PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i)); -/* No png_save_int_16 -- may be added if there's a real need for it. */ -#endif - -#ifdef PNG_USE_READ_MACROS -/* Inline macros to do direct reads of bytes from the input buffer. - * The png_get_int_32() routine assumes we are using two's complement - * format for negative values, which is almost certainly true. - */ -# define PNG_get_uint_32(buf) \ - (((png_uint_32)(*(buf)) << 24) + \ - ((png_uint_32)(*((buf) + 1)) << 16) + \ - ((png_uint_32)(*((buf) + 2)) << 8) + \ - ((png_uint_32)(*((buf) + 3)))) - - /* From libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the - * function) incorrectly returned a value of type png_uint_32. - */ -# define PNG_get_uint_16(buf) \ - ((png_uint_16) \ - (((unsigned int)(*(buf)) << 8) + \ - ((unsigned int)(*((buf) + 1))))) - -# define PNG_get_int_32(buf) \ - ((png_int_32)((*(buf) & 0x80) \ - ? -((png_int_32)((png_get_uint_32(buf) ^ 0xffffffffL) + 1)) \ - : (png_int_32)png_get_uint_32(buf))) - - /* If PNG_PREFIX is defined the same thing as below happens in pnglibconf.h, - * but defining a macro name prefixed with PNG_PREFIX. - */ -# ifndef PNG_PREFIX -# define png_get_uint_32(buf) PNG_get_uint_32(buf) -# define png_get_uint_16(buf) PNG_get_uint_16(buf) -# define png_get_int_32(buf) PNG_get_int_32(buf) -# endif -#else -# ifdef PNG_PREFIX - /* No macros; revert to the (redefined) function */ -# define PNG_get_uint_32 (png_get_uint_32) -# define PNG_get_uint_16 (png_get_uint_16) -# define PNG_get_int_32 (png_get_int_32) -# endif -#endif - -/******************************************************************************* - * SIMPLIFIED API - ******************************************************************************* - * - * Please read the documentation in libpng-manual.txt (TODO: write said - * documentation) if you don't understand what follows. - * - * The simplified API hides the details of both libpng and the PNG file format - * itself. It allows PNG files to be read into a very limited number of - * in-memory bitmap formats or to be written from the same formats. If these - * formats do not accomodate your needs then you can, and should, use the more - * sophisticated APIs above - these support a wide variety of in-memory formats - * and a wide variety of sophisticated transformations to those formats as well - * as a wide variety of APIs to manipulate ancillary information. - * - * To read a PNG file using the simplified API: - * - * 1) Declare a 'png_image' structure (see below) on the stack and set the - * version field to PNG_IMAGE_VERSION. - * 2) Call the appropriate png_image_begin_read... function. - * 3) Set the png_image 'format' member to the required sample format. - * 4) Allocate a buffer for the image and, if required, the color-map. - * 5) Call png_image_finish_read to read the image and, if required, the - * color-map into your buffers. - * - * There are no restrictions on the format of the PNG input itself; all valid - * color types, bit depths, and interlace methods are acceptable, and the - * input image is transformed as necessary to the requested in-memory format - * during the png_image_finish_read() step. The only caveat is that if you - * request a color-mapped image from a PNG that is full-color or makes - * complex use of an alpha channel the transformation is extremely lossy and the - * result may look terrible. - * - * To write a PNG file using the simplified API: - * - * 1) Declare a 'png_image' structure on the stack and memset() it to all zero. - * 2) Initialize the members of the structure that describe the image, setting - * the 'format' member to the format of the image samples. - * 3) Call the appropriate png_image_write... function with a pointer to the - * image and, if necessary, the color-map to write the PNG data. - * - * png_image is a structure that describes the in-memory format of an image - * when it is being read or defines the in-memory format of an image that you - * need to write: - */ -#define PNG_IMAGE_VERSION 1 - -typedef struct png_control *png_controlp; -typedef struct -{ - png_controlp opaque; /* Initialize to NULL, free with png_image_free */ - png_uint_32 version; /* Set to PNG_IMAGE_VERSION */ - png_uint_32 width; /* Image width in pixels (columns) */ - png_uint_32 height; /* Image height in pixels (rows) */ - png_uint_32 format; /* Image format as defined below */ - png_uint_32 flags; /* A bit mask containing informational flags */ - png_uint_32 colormap_entries; - /* Number of entries in the color-map */ - - /* In the event of an error or warning the following field will be set to a - * non-zero value and the 'message' field will contain a '\0' terminated - * string with the libpng error or warning message. If both warnings and - * an error were encountered, only the error is recorded. If there - * are multiple warnings, only the first one is recorded. - * - * The upper 30 bits of this value are reserved, the low two bits contain - * a value as follows: - */ -# define PNG_IMAGE_WARNING 1 -# define PNG_IMAGE_ERROR 2 - /* - * The result is a two bit code such that a value more than 1 indicates - * a failure in the API just called: - * - * 0 - no warning or error - * 1 - warning - * 2 - error - * 3 - error preceded by warning - */ -# define PNG_IMAGE_FAILED(png_cntrl) ((((png_cntrl).warning_or_error)&0x03)>1) - - png_uint_32 warning_or_error; - - char message[64]; -} png_image, *png_imagep; - -/* The samples of the image have one to four channels whose components have - * original values in the range 0 to 1.0: - * - * 1: A single gray or luminance channel (G). - * 2: A gray/luminance channel and an alpha channel (GA). - * 3: Three red, green, blue color channels (RGB). - * 4: Three color channels and an alpha channel (RGBA). - * - * The components are encoded in one of two ways: - * - * a) As a small integer, value 0..255, contained in a single byte. For the - * alpha channel the original value is simply value/255. For the color or - * luminance channels the value is encoded according to the sRGB specification - * and matches the 8-bit format expected by typical display devices. - * - * The color/gray channels are not scaled (pre-multiplied) by the alpha - * channel and are suitable for passing to color management software. - * - * b) As a value in the range 0..65535, contained in a 2-byte integer. All - * channels can be converted to the original value by dividing by 65535; all - * channels are linear. Color channels use the RGB encoding (RGB end-points) of - * the sRGB specification. This encoding is identified by the - * PNG_FORMAT_FLAG_LINEAR flag below. - * - * When the simplified API needs to convert between sRGB and linear colorspaces, - * the actual sRGB transfer curve defined in the sRGB specification (see the - * article at http://en.wikipedia.org/wiki/SRGB) is used, not the gamma=1/2.2 - * approximation used elsewhere in libpng. - * - * When an alpha channel is present it is expected to denote pixel coverage - * of the color or luminance channels and is returned as an associated alpha - * channel: the color/gray channels are scaled (pre-multiplied) by the alpha - * value. - * - * The samples are either contained directly in the image data, between 1 and 8 - * bytes per pixel according to the encoding, or are held in a color-map indexed - * by bytes in the image data. In the case of a color-map the color-map entries - * are individual samples, encoded as above, and the image data has one byte per - * pixel to select the relevant sample from the color-map. - */ - -/* PNG_FORMAT_* - * - * #defines to be used in png_image::format. Each #define identifies a - * particular layout of sample data and, if present, alpha values. There are - * separate defines for each of the two component encodings. - * - * A format is built up using single bit flag values. All combinations are - * valid. Formats can be built up from the flag values or you can use one of - * the predefined values below. When testing formats always use the FORMAT_FLAG - * macros to test for individual features - future versions of the library may - * add new flags. - * - * When reading or writing color-mapped images the format should be set to the - * format of the entries in the color-map then png_image_{read,write}_colormap - * called to read or write the color-map and set the format correctly for the - * image data. Do not set the PNG_FORMAT_FLAG_COLORMAP bit directly! - * - * NOTE: libpng can be built with particular features disabled, if you see - * compiler errors because the definition of one of the following flags has been - * compiled out it is because libpng does not have the required support. It is - * possible, however, for the libpng configuration to enable the format on just - * read or just write; in that case you may see an error at run time. You can - * guard against this by checking for the definition of the appropriate - * "_SUPPORTED" macro, one of: - * - * PNG_SIMPLIFIED_{READ,WRITE}_{BGR,AFIRST}_SUPPORTED - */ -#define PNG_FORMAT_FLAG_ALPHA 0x01U /* format with an alpha channel */ -#define PNG_FORMAT_FLAG_COLOR 0x02U /* color format: otherwise grayscale */ -#define PNG_FORMAT_FLAG_LINEAR 0x04U /* 2 byte channels else 1 byte */ -#define PNG_FORMAT_FLAG_COLORMAP 0x08U /* image data is color-mapped */ - -#ifdef PNG_FORMAT_BGR_SUPPORTED -# define PNG_FORMAT_FLAG_BGR 0x10U /* BGR colors, else order is RGB */ -#endif - -#ifdef PNG_FORMAT_AFIRST_SUPPORTED -# define PNG_FORMAT_FLAG_AFIRST 0x20U /* alpha channel comes first */ -#endif - -/* Commonly used formats have predefined macros. - * - * First the single byte (sRGB) formats: - */ -#define PNG_FORMAT_GRAY 0 -#define PNG_FORMAT_GA PNG_FORMAT_FLAG_ALPHA -#define PNG_FORMAT_AG (PNG_FORMAT_GA|PNG_FORMAT_FLAG_AFIRST) -#define PNG_FORMAT_RGB PNG_FORMAT_FLAG_COLOR -#define PNG_FORMAT_BGR (PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_BGR) -#define PNG_FORMAT_RGBA (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_ALPHA) -#define PNG_FORMAT_ARGB (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_AFIRST) -#define PNG_FORMAT_BGRA (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_ALPHA) -#define PNG_FORMAT_ABGR (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_AFIRST) - -/* Then the linear 2-byte formats. When naming these "Y" is used to - * indicate a luminance (gray) channel. - */ -#define PNG_FORMAT_LINEAR_Y PNG_FORMAT_FLAG_LINEAR -#define PNG_FORMAT_LINEAR_Y_ALPHA (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_ALPHA) -#define PNG_FORMAT_LINEAR_RGB (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR) -#define PNG_FORMAT_LINEAR_RGB_ALPHA \ - (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA) - -/* With color-mapped formats the image data is one byte for each pixel, the byte - * is an index into the color-map which is formatted as above. To obtain a - * color-mapped format it is sufficient just to add the PNG_FOMAT_FLAG_COLORMAP - * to one of the above definitions, or you can use one of the definitions below. - */ -#define PNG_FORMAT_RGB_COLORMAP (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_COLORMAP) -#define PNG_FORMAT_BGR_COLORMAP (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_COLORMAP) -#define PNG_FORMAT_RGBA_COLORMAP (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_COLORMAP) -#define PNG_FORMAT_ARGB_COLORMAP (PNG_FORMAT_ARGB|PNG_FORMAT_FLAG_COLORMAP) -#define PNG_FORMAT_BGRA_COLORMAP (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_COLORMAP) -#define PNG_FORMAT_ABGR_COLORMAP (PNG_FORMAT_ABGR|PNG_FORMAT_FLAG_COLORMAP) - -/* PNG_IMAGE macros - * - * These are convenience macros to derive information from a png_image - * structure. The PNG_IMAGE_SAMPLE_ macros return values appropriate to the - * actual image sample values - either the entries in the color-map or the - * pixels in the image. The PNG_IMAGE_PIXEL_ macros return corresponding values - * for the pixels and will always return 1 for color-mapped formats. The - * remaining macros return information about the rows in the image and the - * complete image. - * - * NOTE: All the macros that take a png_image::format parameter are compile time - * constants if the format parameter is, itself, a constant. Therefore these - * macros can be used in array declarations and case labels where required. - * Similarly the macros are also pre-processor constants (sizeof is not used) so - * they can be used in #if tests. - * - * First the information about the samples. - */ -#define PNG_IMAGE_SAMPLE_CHANNELS(fmt)\ - (((fmt)&(PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA))+1) - /* Return the total number of channels in a given format: 1..4 */ - -#define PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)\ - ((((fmt) & PNG_FORMAT_FLAG_LINEAR) >> 2)+1) - /* Return the size in bytes of a single component of a pixel or color-map - * entry (as appropriate) in the image: 1 or 2. - */ - -#define PNG_IMAGE_SAMPLE_SIZE(fmt)\ - (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)) - /* This is the size of the sample data for one sample. If the image is - * color-mapped it is the size of one color-map entry (and image pixels are - * one byte in size), otherwise it is the size of one image pixel. - */ - -#define PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(fmt)\ - (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * 256) - /* The maximum size of the color-map required by the format expressed in a - * count of components. This can be used to compile-time allocate a - * color-map: - * - * png_uint_16 colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(linear_fmt)]; - * - * png_byte colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(sRGB_fmt)]; - * - * Alternatively use the PNG_IMAGE_COLORMAP_SIZE macro below to use the - * information from one of the png_image_begin_read_ APIs and dynamically - * allocate the required memory. - */ - -/* Corresponding information about the pixels */ -#define PNG_IMAGE_PIXEL_(test,fmt)\ - (((fmt)&PNG_FORMAT_FLAG_COLORMAP)?1:test(fmt)) - -#define PNG_IMAGE_PIXEL_CHANNELS(fmt)\ - PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_CHANNELS,fmt) - /* The number of separate channels (components) in a pixel; 1 for a - * color-mapped image. - */ - -#define PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)\ - PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_COMPONENT_SIZE,fmt) - /* The size, in bytes, of each component in a pixel; 1 for a color-mapped - * image. - */ - -#define PNG_IMAGE_PIXEL_SIZE(fmt) PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_SIZE,fmt) - /* The size, in bytes, of a complete pixel; 1 for a color-mapped image. */ - -/* Information about the whole row, or whole image */ -#define PNG_IMAGE_ROW_STRIDE(image)\ - (PNG_IMAGE_PIXEL_CHANNELS((image).format) * (image).width) - /* Return the total number of components in a single row of the image; this - * is the minimum 'row stride', the minimum count of components between each - * row. For a color-mapped image this is the minimum number of bytes in a - * row. - */ - -#define PNG_IMAGE_BUFFER_SIZE(image, row_stride)\ - (PNG_IMAGE_PIXEL_COMPONENT_SIZE((image).format)*(image).height*(row_stride)) - /* Return the size, in bytes, of an image buffer given a png_image and a row - * stride - the number of components to leave space for in each row. - */ - -#define PNG_IMAGE_SIZE(image)\ - PNG_IMAGE_BUFFER_SIZE(image, PNG_IMAGE_ROW_STRIDE(image)) - /* Return the size, in bytes, of the image in memory given just a png_image; - * the row stride is the minimum stride required for the image. - */ - -#define PNG_IMAGE_COLORMAP_SIZE(image)\ - (PNG_IMAGE_SAMPLE_SIZE((image).format) * (image).colormap_entries) - /* Return the size, in bytes, of the color-map of this image. If the image - * format is not a color-map format this will return a size sufficient for - * 256 entries in the given format; check PNG_FORMAT_FLAG_COLORMAP if - * you don't want to allocate a color-map in this case. - */ - -/* PNG_IMAGE_FLAG_* - * - * Flags containing additional information about the image are held in the - * 'flags' field of png_image. - */ -#define PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB 0x01 - /* This indicates the the RGB values of the in-memory bitmap do not - * correspond to the red, green and blue end-points defined by sRGB. - */ - -#define PNG_IMAGE_FLAG_FAST 0x02 - /* On write emphasise speed over compression; the resultant PNG file will be - * larger but will be produced significantly faster, particular for large - * images. Do not use this option for images which will be distributed, only - * used it when producing intermediate files that will be read back in - * repeatedly. For a typical 24-bit image the option will double the read - * speed at the cost of increasing the image size by 25%, however for many - * more compressible images the PNG file can be 10 times larger with only a - * slight speed gain. - */ - -#define PNG_IMAGE_FLAG_16BIT_sRGB 0x04 - /* On read if the image is a 16-bit per component image and there is no gAMA - * or sRGB chunk assume that the components are sRGB encoded. Notice that - * images output by the simplified API always have gamma information; setting - * this flag only affects the interpretation of 16-bit images from an - * external source. It is recommended that the application expose this flag - * to the user; the user can normally easily recognize the difference between - * linear and sRGB encoding. This flag has no effect on write - the data - * passed to the write APIs must have the correct encoding (as defined - * above.) - * - * If the flag is not set (the default) input 16-bit per component data is - * assumed to be linear. - * - * NOTE: the flag can only be set after the png_image_begin_read_ call, - * because that call initializes the 'flags' field. - */ - -#ifdef PNG_SIMPLIFIED_READ_SUPPORTED -/* READ APIs - * --------- - * - * The png_image passed to the read APIs must have been initialized by setting - * the png_controlp field 'opaque' to NULL (or, safer, memset the whole thing.) - */ -#ifdef PNG_STDIO_SUPPORTED -PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image, - const char *file_name)); - /* The named file is opened for read and the image header is filled in - * from the PNG header in the file. - */ - -PNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image, - FILE* file)); - /* The PNG header is read from the stdio FILE object. */ -#endif /* PNG_STDIO_SUPPORTED */ - -PNG_EXPORT(236, int, png_image_begin_read_from_memory, (png_imagep image, - png_const_voidp memory, png_size_t size)); - /* The PNG header is read from the given memory buffer. */ - -PNG_EXPORT(237, int, png_image_finish_read, (png_imagep image, - png_const_colorp background, void *buffer, png_int_32 row_stride, - void *colormap)); - /* Finish reading the image into the supplied buffer and clean up the - * png_image structure. - * - * row_stride is the step, in byte or 2-byte units as appropriate, - * between adjacent rows. A positive stride indicates that the top-most row - * is first in the buffer - the normal top-down arrangement. A negative - * stride indicates that the bottom-most row is first in the buffer. - * - * background need only be supplied if an alpha channel must be removed from - * a png_byte format and the removal is to be done by compositing on a solid - * color; otherwise it may be NULL and any composition will be done directly - * onto the buffer. The value is an sRGB color to use for the background, - * for grayscale output the green channel is used. - * - * background must be supplied when an alpha channel must be removed from a - * single byte color-mapped output format, in other words if: - * - * 1) The original format from png_image_begin_read_from_* had - * PNG_FORMAT_FLAG_ALPHA set. - * 2) The format set by the application does not. - * 3) The format set by the application has PNG_FORMAT_FLAG_COLORMAP set and - * PNG_FORMAT_FLAG_LINEAR *not* set. - * - * For linear output removing the alpha channel is always done by compositing - * on black and background is ignored. - * - * colormap must be supplied when PNG_FORMAT_FLAG_COLORMAP is set. It must - * be at least the size (in bytes) returned by PNG_IMAGE_COLORMAP_SIZE. - * image->colormap_entries will be updated to the actual number of entries - * written to the colormap; this may be less than the original value. - */ - -PNG_EXPORT(238, void, png_image_free, (png_imagep image)); - /* Free any data allocated by libpng in image->opaque, setting the pointer to - * NULL. May be called at any time after the structure is initialized. - */ -#endif /* PNG_SIMPLIFIED_READ_SUPPORTED */ - -#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED -/* WRITE APIS - * ---------- - * For write you must initialize a png_image structure to describe the image to - * be written. To do this use memset to set the whole structure to 0 then - * initialize fields describing your image. - * - * version: must be set to PNG_IMAGE_VERSION - * opaque: must be initialized to NULL - * width: image width in pixels - * height: image height in rows - * format: the format of the data (image and color-map) you wish to write - * flags: set to 0 unless one of the defined flags applies; set - * PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB for color format images where the RGB - * values do not correspond to the colors in sRGB. - * colormap_entries: set to the number of entries in the color-map (0 to 256) - */ -PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image, - const char *file, int convert_to_8bit, const void *buffer, - png_int_32 row_stride, const void *colormap)); - /* Write the image to the named file. */ - -PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file, - int convert_to_8_bit, const void *buffer, png_int_32 row_stride, - const void *colormap)); - /* Write the image to the given (FILE*). */ - -/* With both write APIs if image is in one of the linear formats with 16-bit - * data then setting convert_to_8_bit will cause the output to be an 8-bit PNG - * gamma encoded according to the sRGB specification, otherwise a 16-bit linear - * encoded PNG file is written. - * - * With color-mapped data formats the colormap parameter point to a color-map - * with at least image->colormap_entries encoded in the specified format. If - * the format is linear the written PNG color-map will be converted to sRGB - * regardless of the convert_to_8_bit flag. - * - * With all APIs row_stride is handled as in the read APIs - it is the spacing - * from one row to the next in component sized units (1 or 2 bytes) and if - * negative indicates a bottom-up row layout in the buffer. - * - * Note that the write API does not support interlacing or sub-8-bit pixels. - */ -#endif /* PNG_SIMPLIFIED_WRITE_SUPPORTED */ -/******************************************************************************* - * END OF SIMPLIFIED API - ******************************************************************************/ - -#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED -PNG_EXPORT(242, void, png_set_check_for_invalid_index, - (png_structrp png_ptr, int allowed)); -# ifdef PNG_GET_PALETTE_MAX_SUPPORTED -PNG_EXPORT(243, int, png_get_palette_max, (png_const_structp png_ptr, - png_const_infop info_ptr)); -# endif -#endif /* CHECK_FOR_INVALID_INDEX */ - -/******************************************************************************* - * IMPLEMENTATION OPTIONS - ******************************************************************************* - * - * Support for arbitrary implementation-specific optimizations. The API allows - * particular options to be turned on or off. 'Option' is the number of the - * option and 'onoff' is 0 (off) or non-0 (on). The value returned is given - * by the PNG_OPTION_ defines below. - * - * HARDWARE: normally hardware capabilites, such as the Intel SSE instructions, - * are detected at run time, however sometimes it may be impossible - * to do this in user mode, in which case it is necessary to discover - * the capabilities in an OS specific way. Such capabilities are - * listed here when libpng has support for them and must be turned - * ON by the application if present. - * - * SOFTWARE: sometimes software optimizations actually result in performance - * decrease on some architectures or systems, or with some sets of - * PNG images. 'Software' options allow such optimizations to be - * selected at run time. - */ -#ifdef PNG_SET_OPTION_SUPPORTED -#ifdef PNG_ARM_NEON_API_SUPPORTED -# define PNG_ARM_NEON 0 /* HARDWARE: ARM Neon SIMD instructions supported */ -#endif -#define PNG_OPTION_NEXT 2 /* Next option - numbers must be even */ - -/* Return values: NOTE: there are four values and 'off' is *not* zero */ -#define PNG_OPTION_UNSET 0 /* Unset - defaults to off */ -#define PNG_OPTION_INVALID 1 /* Option number out of range */ -#define PNG_OPTION_OFF 2 -#define PNG_OPTION_ON 3 - -PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option, - int onoff)); -#endif - -/******************************************************************************* - * END OF HARDWARE OPTIONS - ******************************************************************************/ - -/* Maintainer: Put new public prototypes here ^, in libpng.3, and project - * defs, scripts/pnglibconf.h, and scripts/pnglibconf.h.prebuilt - */ - -/* The last ordinal number (this is the *last* one already used; the next - * one to use is one more than this.) Maintainer, remember to add an entry to - * scripts/symbols.def as well. - */ -#ifdef PNG_EXPORT_LAST_ORDINAL - PNG_EXPORT_LAST_ORDINAL(244); -#endif - -#endif /* PNG_VERSION_INFO_ONLY */ -/* Do not put anything past this line */ -#endif /* PNG_H */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pngconf.h b/source/modules/juce_graphics/image_formats/pnglib/pngconf.h deleted file mode 100644 index b3ceeae42..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pngconf.h +++ /dev/null @@ -1,616 +0,0 @@ - -/* pngconf.h - machine configurable file for libpng - * - * libpng version 1.6.1 - March 28, 2013 - * - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - */ - -/* Any machine specific code is near the front of this file, so if you - * are configuring libpng for a machine, you may want to read the section - * starting here down to where it starts to typedef png_color, png_text, - * and png_info. - */ - -#ifndef PNGCONF_H -#define PNGCONF_H - -/* To do: Do all of this in scripts/pnglibconf.dfa */ -#ifdef PNG_SAFE_LIMITS_SUPPORTED -# ifdef PNG_USER_WIDTH_MAX -# undef PNG_USER_WIDTH_MAX -# define PNG_USER_WIDTH_MAX 1000000L -# endif -# ifdef PNG_USER_HEIGHT_MAX -# undef PNG_USER_HEIGHT_MAX -# define PNG_USER_HEIGHT_MAX 1000000L -# endif -# ifdef PNG_USER_CHUNK_MALLOC_MAX -# undef PNG_USER_CHUNK_MALLOC_MAX -# define PNG_USER_CHUNK_MALLOC_MAX 4000000L -# endif -# ifdef PNG_USER_CHUNK_CACHE_MAX -# undef PNG_USER_CHUNK_CACHE_MAX -# define PNG_USER_CHUNK_CACHE_MAX 128 -# endif -#endif - -#ifndef PNG_BUILDING_SYMBOL_TABLE /* else includes may cause problems */ - -/* From libpng 1.6.0 libpng requires an ANSI X3.159-1989 ("ISOC90") compliant C - * compiler for correct compilation. The following header files are required by - * the standard. If your compiler doesn't provide these header files, or they - * do not match the standard, you will need to provide/improve them. - */ -#include -#include - -/* Library header files. These header files are all defined by ISOC90; libpng - * expects conformant implementations, however, an ISOC90 conformant system need - * not provide these header files if the functionality cannot be implemented. - * In this case it will be necessary to disable the relevant parts of libpng in - * the build of pnglibconf.h. - * - * Prior to 1.6.0 string.h was included here; the API changes in 1.6.0 to not - * include this unnecessary header file. - */ - -#ifdef PNG_STDIO_SUPPORTED - /* Required for the definition of FILE: */ -# include -#endif - -#ifdef PNG_SETJMP_SUPPORTED - /* Required for the definition of jmp_buf and the declaration of longjmp: */ -# include -#endif - -#ifdef PNG_CONVERT_tIME_SUPPORTED - /* Required for struct tm: */ -# include -#endif - -#endif /* PNG_BUILDING_SYMBOL_TABLE */ - -/* Prior to 1.6.0 it was possible to turn off 'const' in declarations using - * PNG_NO_CONST; this is no longer supported except for data declarations which - * apparently still cause problems in 2011 on some compilers. - */ -#define PNG_CONST const /* backward compatibility only */ - -/* This controls optimization of the reading of 16 and 32 bit values - * from PNG files. It can be set on a per-app-file basis - it - * just changes whether a macro is used when the function is called. - * The library builder sets the default; if read functions are not - * built into the library the macro implementation is forced on. - */ -#ifndef PNG_READ_INT_FUNCTIONS_SUPPORTED -# define PNG_USE_READ_MACROS -#endif -#if !defined(PNG_NO_USE_READ_MACROS) && !defined(PNG_USE_READ_MACROS) -# if PNG_DEFAULT_READ_MACROS -# define PNG_USE_READ_MACROS -# endif -#endif - -/* COMPILER SPECIFIC OPTIONS. - * - * These options are provided so that a variety of difficult compilers - * can be used. Some are fixed at build time (e.g. PNG_API_RULE - * below) but still have compiler specific implementations, others - * may be changed on a per-file basis when compiling against libpng. - */ - -/* The PNGARG macro was used in versions of libpng prior to 1.6.0 to protect - * against legacy (pre ISOC90) compilers that did not understand function - * prototypes. It is not required for modern C compilers. - */ -#ifndef PNGARG -# define PNGARG(arglist) arglist -#endif - -/* Function calling conventions. - * ============================= - * Normally it is not necessary to specify to the compiler how to call - * a function - it just does it - however on x86 systems derived from - * Microsoft and Borland C compilers ('IBM PC', 'DOS', 'Windows' systems - * and some others) there are multiple ways to call a function and the - * default can be changed on the compiler command line. For this reason - * libpng specifies the calling convention of every exported function and - * every function called via a user supplied function pointer. This is - * done in this file by defining the following macros: - * - * PNGAPI Calling convention for exported functions. - * PNGCBAPI Calling convention for user provided (callback) functions. - * PNGCAPI Calling convention used by the ANSI-C library (required - * for longjmp callbacks and sometimes used internally to - * specify the calling convention for zlib). - * - * These macros should never be overridden. If it is necessary to - * change calling convention in a private build this can be done - * by setting PNG_API_RULE (which defaults to 0) to one of the values - * below to select the correct 'API' variants. - * - * PNG_API_RULE=0 Use PNGCAPI - the 'C' calling convention - throughout. - * This is correct in every known environment. - * PNG_API_RULE=1 Use the operating system convention for PNGAPI and - * the 'C' calling convention (from PNGCAPI) for - * callbacks (PNGCBAPI). This is no longer required - * in any known environment - if it has to be used - * please post an explanation of the problem to the - * libpng mailing list. - * - * These cases only differ if the operating system does not use the C - * calling convention, at present this just means the above cases - * (x86 DOS/Windows sytems) and, even then, this does not apply to - * Cygwin running on those systems. - * - * Note that the value must be defined in pnglibconf.h so that what - * the application uses to call the library matches the conventions - * set when building the library. - */ - -/* Symbol export - * ============= - * When building a shared library it is almost always necessary to tell - * the compiler which symbols to export. The png.h macro 'PNG_EXPORT' - * is used to mark the symbols. On some systems these symbols can be - * extracted at link time and need no special processing by the compiler, - * on other systems the symbols are flagged by the compiler and just - * the declaration requires a special tag applied (unfortunately) in a - * compiler dependent way. Some systems can do either. - * - * A small number of older systems also require a symbol from a DLL to - * be flagged to the program that calls it. This is a problem because - * we do not know in the header file included by application code that - * the symbol will come from a shared library, as opposed to a statically - * linked one. For this reason the application must tell us by setting - * the magic flag PNG_USE_DLL to turn on the special processing before - * it includes png.h. - * - * Four additional macros are used to make this happen: - * - * PNG_IMPEXP The magic (if any) to cause a symbol to be exported from - * the build or imported if PNG_USE_DLL is set - compiler - * and system specific. - * - * PNG_EXPORT_TYPE(type) A macro that pre or appends PNG_IMPEXP to - * 'type', compiler specific. - * - * PNG_DLL_EXPORT Set to the magic to use during a libpng build to - * make a symbol exported from the DLL. Not used in the - * public header files; see pngpriv.h for how it is used - * in the libpng build. - * - * PNG_DLL_IMPORT Set to the magic to force the libpng symbols to come - * from a DLL - used to define PNG_IMPEXP when - * PNG_USE_DLL is set. - */ - -/* System specific discovery. - * ========================== - * This code is used at build time to find PNG_IMPEXP, the API settings - * and PNG_EXPORT_TYPE(), it may also set a macro to indicate the DLL - * import processing is possible. On Windows systems it also sets - * compiler-specific macros to the values required to change the calling - * conventions of the various functions. - */ -#if defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\ - defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) - /* Windows system (DOS doesn't support DLLs). Includes builds under Cygwin or - * MinGW on any architecture currently supported by Windows. Also includes - * Watcom builds but these need special treatment because they are not - * compatible with GCC or Visual C because of different calling conventions. - */ -# if PNG_API_RULE == 2 - /* If this line results in an error, either because __watcall is not - * understood or because of a redefine just below you cannot use *this* - * build of the library with the compiler you are using. *This* build was - * build using Watcom and applications must also be built using Watcom! - */ -# define PNGCAPI __watcall -# endif - -# if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER >= 800)) -# define PNGCAPI __cdecl -# if PNG_API_RULE == 1 - /* If this line results in an error __stdcall is not understood and - * PNG_API_RULE should not have been set to '1'. - */ -# define PNGAPI __stdcall -# endif -# else - /* An older compiler, or one not detected (erroneously) above, - * if necessary override on the command line to get the correct - * variants for the compiler. - */ -# ifndef PNGCAPI -# define PNGCAPI _cdecl -# endif -# if PNG_API_RULE == 1 && !defined(PNGAPI) -# define PNGAPI _stdcall -# endif -# endif /* compiler/api */ - /* NOTE: PNGCBAPI always defaults to PNGCAPI. */ - -# if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD) -# error "PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed" -# endif - -# if (defined(_MSC_VER) && _MSC_VER < 800) ||\ - (defined(__BORLANDC__) && __BORLANDC__ < 0x500) - /* older Borland and MSC - * compilers used '__export' and required this to be after - * the type. - */ -# ifndef PNG_EXPORT_TYPE -# define PNG_EXPORT_TYPE(type) type PNG_IMPEXP -# endif -# define PNG_DLL_EXPORT __export -# else /* newer compiler */ -# define PNG_DLL_EXPORT __declspec(dllexport) -# ifndef PNG_DLL_IMPORT -# define PNG_DLL_IMPORT __declspec(dllimport) -# endif -# endif /* compiler */ - -#else /* !Windows */ -# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) -# define PNGAPI _System -# else /* !Windows/x86 && !OS/2 */ - /* Use the defaults, or define PNG*API on the command line (but - * this will have to be done for every compile!) - */ -# endif /* other system, !OS/2 */ -#endif /* !Windows/x86 */ - -/* Now do all the defaulting . */ -#ifndef PNGCAPI -# define PNGCAPI -#endif -#ifndef PNGCBAPI -# define PNGCBAPI PNGCAPI -#endif -#ifndef PNGAPI -# define PNGAPI PNGCAPI -#endif - -/* PNG_IMPEXP may be set on the compilation system command line or (if not set) - * then in an internal header file when building the library, otherwise (when - * using the library) it is set here. - */ -#ifndef PNG_IMPEXP -# if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT) - /* This forces use of a DLL, disallowing static linking */ -# define PNG_IMPEXP PNG_DLL_IMPORT -# endif - -# ifndef PNG_IMPEXP -# define PNG_IMPEXP -# endif -#endif - -/* In 1.5.2 the definition of PNG_FUNCTION has been changed to always treat - * 'attributes' as a storage class - the attributes go at the start of the - * function definition, and attributes are always appended regardless of the - * compiler. This considerably simplifies these macros but may cause problems - * if any compilers both need function attributes and fail to handle them as - * a storage class (this is unlikely.) - */ -#ifndef PNG_FUNCTION -# define PNG_FUNCTION(type, name, args, attributes) attributes type name args -#endif - -#ifndef PNG_EXPORT_TYPE -# define PNG_EXPORT_TYPE(type) PNG_IMPEXP type -#endif - - /* The ordinal value is only relevant when preprocessing png.h for symbol - * table entries, so we discard it here. See the .dfn files in the - * scripts directory. - */ -#ifndef PNG_EXPORTA - -# define PNG_EXPORTA(ordinal, type, name, args, attributes)\ - PNG_FUNCTION(PNG_EXPORT_TYPE(type),(PNGAPI name),PNGARG(args), \ - extern attributes) -#endif - -/* ANSI-C (C90) does not permit a macro to be invoked with an empty argument, - * so make something non-empty to satisfy the requirement: - */ -#define PNG_EMPTY /*empty list*/ - -#define PNG_EXPORT(ordinal, type, name, args)\ - PNG_EXPORTA(ordinal, type, name, args, PNG_EMPTY) - -/* Use PNG_REMOVED to comment out a removed interface. */ -#ifndef PNG_REMOVED -# define PNG_REMOVED(ordinal, type, name, args, attributes) -#endif - -#ifndef PNG_CALLBACK -# define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) PNGARG(args) -#endif - -/* Support for compiler specific function attributes. These are used - * so that where compiler support is available incorrect use of API - * functions in png.h will generate compiler warnings. - * - * Added at libpng-1.2.41. - */ - -#ifndef PNG_NO_PEDANTIC_WARNINGS -# ifndef PNG_PEDANTIC_WARNINGS_SUPPORTED -# define PNG_PEDANTIC_WARNINGS_SUPPORTED -# endif -#endif - -#ifdef PNG_PEDANTIC_WARNINGS_SUPPORTED - /* Support for compiler specific function attributes. These are used - * so that where compiler support is available, incorrect use of API - * functions in png.h will generate compiler warnings. Added at libpng - * version 1.2.41. Disabling these removes the warnings but may also produce - * less efficient code. - */ -# if defined(__GNUC__) -# ifndef PNG_USE_RESULT -# define PNG_USE_RESULT __attribute__((__warn_unused_result__)) -# endif -# ifndef PNG_NORETURN -# define PNG_NORETURN __attribute__((__noreturn__)) -# endif -# if __GNUC__ >= 3 -# ifndef PNG_ALLOCATED -# define PNG_ALLOCATED __attribute__((__malloc__)) -# endif -# ifndef PNG_DEPRECATED -# define PNG_DEPRECATED __attribute__((__deprecated__)) -# endif -# ifndef PNG_PRIVATE -# if 0 /* Doesn't work so we use deprecated instead*/ -# define PNG_PRIVATE \ - __attribute__((warning("This function is not exported by libpng."))) -# else -# define PNG_PRIVATE \ - __attribute__((__deprecated__)) -# endif -# endif -# if ((__GNUC__ != 3) || !defined(__GNUC_MINOR__) || (__GNUC_MINOR__ >= 1)) -# ifndef PNG_RESTRICT -# define PNG_RESTRICT __restrict -# endif -# endif /* __GNUC__ == 3.0 */ -# endif /* __GNUC__ >= 3 */ - -# elif defined(_MSC_VER) && (_MSC_VER >= 1300) -# ifndef PNG_USE_RESULT -# define PNG_USE_RESULT /* not supported */ -# endif -# ifndef PNG_NORETURN -# define PNG_NORETURN __declspec(noreturn) -# endif -# ifndef PNG_ALLOCATED -# if (_MSC_VER >= 1400) -# define PNG_ALLOCATED __declspec(restrict) -# endif -# endif -# ifndef PNG_DEPRECATED -# define PNG_DEPRECATED __declspec(deprecated) -# endif -# ifndef PNG_PRIVATE -# define PNG_PRIVATE __declspec(deprecated) -# endif -# ifndef PNG_RESTRICT -# if (_MSC_VER >= 1400) -# define PNG_RESTRICT __restrict -# endif -# endif - -# elif defined(__WATCOMC__) -# ifndef PNG_RESTRICT -# define PNG_RESTRICT __restrict -# endif -# endif /* _MSC_VER */ -#endif /* PNG_PEDANTIC_WARNINGS */ - -#ifndef PNG_DEPRECATED -# define PNG_DEPRECATED /* Use of this function is deprecated */ -#endif -#ifndef PNG_USE_RESULT -# define PNG_USE_RESULT /* The result of this function must be checked */ -#endif -#ifndef PNG_NORETURN -# define PNG_NORETURN /* This function does not return */ -#endif -#ifndef PNG_ALLOCATED -# define PNG_ALLOCATED /* The result of the function is new memory */ -#endif -#ifndef PNG_PRIVATE -# define PNG_PRIVATE /* This is a private libpng function */ -#endif -#ifndef PNG_RESTRICT -# define PNG_RESTRICT /* The C99 "restrict" feature */ -#endif -#ifndef PNG_FP_EXPORT /* A floating point API. */ -# ifdef PNG_FLOATING_POINT_SUPPORTED -# define PNG_FP_EXPORT(ordinal, type, name, args)\ - PNG_EXPORT(ordinal, type, name, args); -# else /* No floating point APIs */ -# define PNG_FP_EXPORT(ordinal, type, name, args) -# endif -#endif -#ifndef PNG_FIXED_EXPORT /* A fixed point API. */ -# ifdef PNG_FIXED_POINT_SUPPORTED -# define PNG_FIXED_EXPORT(ordinal, type, name, args)\ - PNG_EXPORT(ordinal, type, name, args); -# else /* No fixed point APIs */ -# define PNG_FIXED_EXPORT(ordinal, type, name, args) -# endif -#endif - -#ifndef PNG_BUILDING_SYMBOL_TABLE -/* Some typedefs to get us started. These should be safe on most of the common - * platforms. - * - * png_uint_32 and png_int_32 may, currently, be larger than required to hold a - * 32-bit value however this is not normally advisable. - * - * png_uint_16 and png_int_16 should always be two bytes in size - this is - * verified at library build time. - * - * png_byte must always be one byte in size. - * - * The checks below use constants from limits.h, as defined by the ISOC90 - * standard. - */ -#if CHAR_BIT == 8 && UCHAR_MAX == 255 - typedef unsigned char png_byte; -#else -# error "libpng requires 8 bit bytes" -#endif - -#if INT_MIN == -32768 && INT_MAX == 32767 - typedef int png_int_16; -#elif SHRT_MIN == -32768 && SHRT_MAX == 32767 - typedef short png_int_16; -#else -# error "libpng requires a signed 16 bit type" -#endif - -#if UINT_MAX == 65535 - typedef unsigned int png_uint_16; -#elif USHRT_MAX == 65535 - typedef unsigned short png_uint_16; -#else -# error "libpng requires an unsigned 16 bit type" -#endif - -#if INT_MIN < -2147483646 && INT_MAX > 2147483646 - typedef int png_int_32; -#elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646 - typedef long int png_int_32; -#else -# error "libpng requires a signed 32 bit (or more) type" -#endif - -#if UINT_MAX > 4294967294 - typedef unsigned int png_uint_32; -#elif ULONG_MAX > 4294967294 - typedef unsigned long int png_uint_32; -#else -# error "libpng requires an unsigned 32 bit (or more) type" -#endif - -/* Prior to 1.6.0 it was possible to disable the use of size_t, 1.6.0, however, - * requires an ISOC90 compiler and relies on consistent behavior of sizeof. - */ -typedef size_t png_size_t; -typedef ptrdiff_t png_ptrdiff_t; - -/* libpng needs to know the maximum value of 'size_t' and this controls the - * definition of png_alloc_size_t, below. This maximum value of size_t limits - * but does not control the maximum allocations the library makes - there is - * direct application control of this through png_set_user_limits(). - */ -#ifndef PNG_SMALL_SIZE_T - /* Compiler specific tests for systems where size_t is known to be less than - * 32 bits (some of these systems may no longer work because of the lack of - * 'far' support; see above.) - */ -# if (defined(__TURBOC__) && !defined(__FLAT__)) ||\ - (defined(_MSC_VER) && defined(MAXSEG_64K)) -# define PNG_SMALL_SIZE_T -# endif -#endif - -/* png_alloc_size_t is guaranteed to be no smaller than png_size_t, and no - * smaller than png_uint_32. Casts from png_size_t or png_uint_32 to - * png_alloc_size_t are not necessary; in fact, it is recommended not to use - * them at all so that the compiler can complain when something turns out to be - * problematic. - * - * Casts in the other direction (from png_alloc_size_t to png_size_t or - * png_uint_32) should be explicitly applied; however, we do not expect to - * encounter practical situations that require such conversions. - * - * PNG_SMALL_SIZE_T must be defined if the maximum value of size_t is less than - * 4294967295 - i.e. less than the maximum value of png_uint_32. - */ -#ifdef PNG_SMALL_SIZE_T - typedef png_uint_32 png_alloc_size_t; -#else - typedef png_size_t png_alloc_size_t; -#endif - -/* Prior to 1.6.0 libpng offered limited support for Microsoft C compiler - * implementations of Intel CPU specific support of user-mode segmented address - * spaces, where 16-bit pointers address more than 65536 bytes of memory using - * separate 'segment' registers. The implementation requires two different - * types of pointer (only one of which includes the segment value.) - * - * If required this support is available in version 1.2 of libpng and may be - * available in versions through 1.5, although the correctness of the code has - * not been verified recently. - */ - -/* Typedef for floating-point numbers that are converted to fixed-point with a - * multiple of 100,000, e.g., gamma - */ -typedef png_int_32 png_fixed_point; - -/* Add typedefs for pointers */ -typedef void * png_voidp; -typedef const void * png_const_voidp; -typedef png_byte * png_bytep; -typedef const png_byte * png_const_bytep; -typedef png_uint_32 * png_uint_32p; -typedef const png_uint_32 * png_const_uint_32p; -typedef png_int_32 * png_int_32p; -typedef const png_int_32 * png_const_int_32p; -typedef png_uint_16 * png_uint_16p; -typedef const png_uint_16 * png_const_uint_16p; -typedef png_int_16 * png_int_16p; -typedef const png_int_16 * png_const_int_16p; -typedef char * png_charp; -typedef const char * png_const_charp; -typedef png_fixed_point * png_fixed_point_p; -typedef const png_fixed_point * png_const_fixed_point_p; -typedef png_size_t * png_size_tp; -typedef const png_size_t * png_const_size_tp; - -#ifdef PNG_STDIO_SUPPORTED -typedef FILE * png_FILE_p; -#endif - -#ifdef PNG_FLOATING_POINT_SUPPORTED -typedef double * png_doublep; -typedef const double * png_const_doublep; -#endif - -/* Pointers to pointers; i.e. arrays */ -typedef png_byte * * png_bytepp; -typedef png_uint_32 * * png_uint_32pp; -typedef png_int_32 * * png_int_32pp; -typedef png_uint_16 * * png_uint_16pp; -typedef png_int_16 * * png_int_16pp; -typedef const char * * png_const_charpp; -typedef char * * png_charpp; -typedef png_fixed_point * * png_fixed_point_pp; -#ifdef PNG_FLOATING_POINT_SUPPORTED -typedef double * * png_doublepp; -#endif - -/* Pointers to pointers to pointers; i.e., pointer to array */ -typedef char * * * png_charppp; - -#endif /* PNG_BUILDING_SYMBOL_TABLE */ - -#endif /* PNGCONF_H */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pngerror.c b/source/modules/juce_graphics/image_formats/pnglib/pngerror.c deleted file mode 100644 index f40cc8301..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pngerror.c +++ /dev/null @@ -1,932 +0,0 @@ - -/* pngerror.c - stub functions for i/o and memory allocation - * - * Last changed in libpng 1.6.1 [March 28, 2013] - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file provides a location for all error handling. Users who - * need special error handling are expected to write replacement functions - * and use png_set_error_fn() to use those functions. See the instructions - * at each function. - */ - -#include "pngpriv.h" - -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) - -static PNG_FUNCTION(void, png_default_error,PNGARG((png_const_structrp png_ptr, - png_const_charp error_message)),PNG_NORETURN); - -#ifdef PNG_WARNINGS_SUPPORTED -static void /* PRIVATE */ -png_default_warning PNGARG((png_const_structrp png_ptr, - png_const_charp warning_message)); -#endif /* PNG_WARNINGS_SUPPORTED */ - -/* This function is called whenever there is a fatal error. This function - * should not be changed. If there is a need to handle errors differently, - * you should supply a replacement error function and use png_set_error_fn() - * to replace the error function at run-time. - */ -#ifdef PNG_ERROR_TEXT_SUPPORTED -PNG_FUNCTION(void,PNGAPI -png_error,(png_const_structrp png_ptr, png_const_charp error_message), - PNG_NORETURN) -{ -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - char msg[16]; - if (png_ptr != NULL) - { - if (png_ptr->flags& - (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) - { - if (*error_message == PNG_LITERAL_SHARP) - { - /* Strip "#nnnn " from beginning of error message. */ - int offset; - for (offset = 1; offset<15; offset++) - if (error_message[offset] == ' ') - break; - - if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) - { - int i; - for (i = 0; i < offset - 1; i++) - msg[i] = error_message[i + 1]; - msg[i - 1] = '\0'; - error_message = msg; - } - - else - error_message += offset; - } - - else - { - if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) - { - msg[0] = '0'; - msg[1] = '\0'; - error_message = msg; - } - } - } - } -#endif - if (png_ptr != NULL && png_ptr->error_fn != NULL) - (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), - error_message); - - /* If the custom handler doesn't exist, or if it returns, - use the default handler, which will not return. */ - png_default_error(png_ptr, error_message); -} -#else -PNG_FUNCTION(void,PNGAPI -png_err,(png_const_structrp png_ptr),PNG_NORETURN) -{ - /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed - * erroneously as '\0', instead of the empty string "". This was - * apparently an error, introduced in libpng-1.2.20, and png_default_error - * will crash in this case. - */ - if (png_ptr != NULL && png_ptr->error_fn != NULL) - (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), ""); - - /* If the custom handler doesn't exist, or if it returns, - use the default handler, which will not return. */ - png_default_error(png_ptr, ""); -} -#endif /* PNG_ERROR_TEXT_SUPPORTED */ - -/* Utility to safely appends strings to a buffer. This never errors out so - * error checking is not required in the caller. - */ -size_t -png_safecat(png_charp buffer, size_t bufsize, size_t pos, - png_const_charp string) -{ - if (buffer != NULL && pos < bufsize) - { - if (string != NULL) - while (*string != '\0' && pos < bufsize-1) - buffer[pos++] = *string++; - - buffer[pos] = '\0'; - } - - return pos; -} - -#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED) -/* Utility to dump an unsigned value into a buffer, given a start pointer and - * and end pointer (which should point just *beyond* the end of the buffer!) - * Returns the pointer to the start of the formatted string. - */ -png_charp -png_format_number(png_const_charp start, png_charp end, int format, - png_alloc_size_t number) -{ - int count = 0; /* number of digits output */ - int mincount = 1; /* minimum number required */ - int output = 0; /* digit output (for the fixed point format) */ - - *--end = '\0'; - - /* This is written so that the loop always runs at least once, even with - * number zero. - */ - while (end > start && (number != 0 || count < mincount)) - { - - static const char digits[] = "0123456789ABCDEF"; - - switch (format) - { - case PNG_NUMBER_FORMAT_fixed: - /* Needs five digits (the fraction) */ - mincount = 5; - if (output || number % 10 != 0) - { - *--end = digits[number % 10]; - output = 1; - } - number /= 10; - break; - - case PNG_NUMBER_FORMAT_02u: - /* Expects at least 2 digits. */ - mincount = 2; - /* FALL THROUGH */ - - case PNG_NUMBER_FORMAT_u: - *--end = digits[number % 10]; - number /= 10; - break; - - case PNG_NUMBER_FORMAT_02x: - /* This format expects at least two digits */ - mincount = 2; - /* FALL THROUGH */ - - case PNG_NUMBER_FORMAT_x: - *--end = digits[number & 0xf]; - number >>= 4; - break; - - default: /* an error */ - number = 0; - break; - } - - /* Keep track of the number of digits added */ - ++count; - - /* Float a fixed number here: */ - if (format == PNG_NUMBER_FORMAT_fixed) if (count == 5) if (end > start) - { - /* End of the fraction, but maybe nothing was output? In that case - * drop the decimal point. If the number is a true zero handle that - * here. - */ - if (output) - *--end = '.'; - else if (number == 0) /* and !output */ - *--end = '0'; - } - } - - return end; -} -#endif - -#ifdef PNG_WARNINGS_SUPPORTED -/* This function is called whenever there is a non-fatal error. This function - * should not be changed. If there is a need to handle warnings differently, - * you should supply a replacement warning function and use - * png_set_error_fn() to replace the warning function at run-time. - */ -void PNGAPI -png_warning(png_const_structrp png_ptr, png_const_charp warning_message) -{ - int offset = 0; - if (png_ptr != NULL) - { -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - if (png_ptr->flags& - (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) -#endif - { - if (*warning_message == PNG_LITERAL_SHARP) - { - for (offset = 1; offset < 15; offset++) - if (warning_message[offset] == ' ') - break; - } - } - } - if (png_ptr != NULL && png_ptr->warning_fn != NULL) - (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr), - warning_message + offset); - else - png_default_warning(png_ptr, warning_message + offset); -} - -/* These functions support 'formatted' warning messages with up to - * PNG_WARNING_PARAMETER_COUNT parameters. In the format string the parameter - * is introduced by @, where 'number' starts at 1. This follows the - * standard established by X/Open for internationalizable error messages. - */ -void -png_warning_parameter(png_warning_parameters p, int number, - png_const_charp string) -{ - if (number > 0 && number <= PNG_WARNING_PARAMETER_COUNT) - (void)png_safecat(p[number-1], (sizeof p[number-1]), 0, string); -} - -void -png_warning_parameter_unsigned(png_warning_parameters p, int number, int format, - png_alloc_size_t value) -{ - char buffer[PNG_NUMBER_BUFFER_SIZE]; - png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value)); -} - -void -png_warning_parameter_signed(png_warning_parameters p, int number, int format, - png_int_32 value) -{ - png_alloc_size_t u; - png_charp str; - char buffer[PNG_NUMBER_BUFFER_SIZE]; - - /* Avoid overflow by doing the negate in a png_alloc_size_t: */ - u = (png_alloc_size_t)value; - if (value < 0) - u = ~u + 1; - - str = PNG_FORMAT_NUMBER(buffer, format, u); - - if (value < 0 && str > buffer) - *--str = '-'; - - png_warning_parameter(p, number, str); -} - -void -png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p, - png_const_charp message) -{ - /* The internal buffer is just 192 bytes - enough for all our messages, - * overflow doesn't happen because this code checks! If someone figures - * out how to send us a message longer than 192 bytes, all that will - * happen is that the message will be truncated appropriately. - */ - size_t i = 0; /* Index in the msg[] buffer: */ - char msg[192]; - - /* Each iteration through the following loop writes at most one character - * to msg[i++] then returns here to validate that there is still space for - * the trailing '\0'. It may (in the case of a parameter) read more than - * one character from message[]; it must check for '\0' and continue to the - * test if it finds the end of string. - */ - while (i<(sizeof msg)-1 && *message != '\0') - { - /* '@' at end of string is now just printed (previously it was skipped); - * it is an error in the calling code to terminate the string with @. - */ - if (p != NULL && *message == '@' && message[1] != '\0') - { - int parameter_char = *++message; /* Consume the '@' */ - static const char valid_parameters[] = "123456789"; - int parameter = 0; - - /* Search for the parameter digit, the index in the string is the - * parameter to use. - */ - while (valid_parameters[parameter] != parameter_char && - valid_parameters[parameter] != '\0') - ++parameter; - - /* If the parameter digit is out of range it will just get printed. */ - if (parameter < PNG_WARNING_PARAMETER_COUNT) - { - /* Append this parameter */ - png_const_charp parm = p[parameter]; - png_const_charp pend = p[parameter] + (sizeof p[parameter]); - - /* No need to copy the trailing '\0' here, but there is no guarantee - * that parm[] has been initialized, so there is no guarantee of a - * trailing '\0': - */ - while (i<(sizeof msg)-1 && *parm != '\0' && parm < pend) - msg[i++] = *parm++; - - /* Consume the parameter digit too: */ - ++message; - continue; - } - - /* else not a parameter and there is a character after the @ sign; just - * copy that. This is known not to be '\0' because of the test above. - */ - } - - /* At this point *message can't be '\0', even in the bad parameter case - * above where there is a lone '@' at the end of the message string. - */ - msg[i++] = *message++; - } - - /* i is always less than (sizeof msg), so: */ - msg[i] = '\0'; - - /* And this is the formatted message. It may be larger than - * PNG_MAX_ERROR_TEXT, but that is only used for 'chunk' errors and these - * are not (currently) formatted. - */ - png_warning(png_ptr, msg); -} -#endif /* PNG_WARNINGS_SUPPORTED */ - -#ifdef PNG_BENIGN_ERRORS_SUPPORTED -void PNGAPI -png_benign_error(png_const_structrp png_ptr, png_const_charp error_message) -{ - if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) - { -# ifdef PNG_READ_SUPPORTED - if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && - png_ptr->chunk_name != 0) - png_chunk_warning(png_ptr, error_message); - else -# endif - png_warning(png_ptr, error_message); - } - - else - { -# ifdef PNG_READ_SUPPORTED - if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && - png_ptr->chunk_name != 0) - png_chunk_error(png_ptr, error_message); - else -# endif - png_error(png_ptr, error_message); - } -} - -void /* PRIVATE */ -png_app_warning(png_const_structrp png_ptr, png_const_charp error_message) -{ - if (png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN) - png_warning(png_ptr, error_message); - else - png_error(png_ptr, error_message); -} - -void /* PRIVATE */ -png_app_error(png_const_structrp png_ptr, png_const_charp error_message) -{ - if (png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN) - png_warning(png_ptr, error_message); - else - png_error(png_ptr, error_message); -} -#endif /* BENIGN_ERRORS */ - -/* These utilities are used internally to build an error message that relates - * to the current chunk. The chunk name comes from png_ptr->chunk_name, - * this is used to prefix the message. The message is limited in length - * to 63 bytes, the name characters are output as hex digits wrapped in [] - * if the character is invalid. - */ -#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) -static PNG_CONST char png_digit[16] = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F' -}; - -#define PNG_MAX_ERROR_TEXT 196 /* Currently limited be profile_error in png.c */ -#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED) -static void /* PRIVATE */ -png_format_buffer(png_const_structrp png_ptr, png_charp buffer, png_const_charp - error_message) -{ - png_uint_32 chunk_name = png_ptr->chunk_name; - int iout = 0, ishift = 24; - - while (ishift >= 0) - { - int c = (int)(chunk_name >> ishift) & 0xff; - - ishift -= 8; - if (isnonalpha(c)) - { - buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET; - buffer[iout++] = png_digit[(c & 0xf0) >> 4]; - buffer[iout++] = png_digit[c & 0x0f]; - buffer[iout++] = PNG_LITERAL_RIGHT_SQUARE_BRACKET; - } - - else - { - buffer[iout++] = (char)c; - } - } - - if (error_message == NULL) - buffer[iout] = '\0'; - - else - { - int iin = 0; - - buffer[iout++] = ':'; - buffer[iout++] = ' '; - - while (iin < PNG_MAX_ERROR_TEXT-1 && error_message[iin] != '\0') - buffer[iout++] = error_message[iin++]; - - /* iin < PNG_MAX_ERROR_TEXT, so the following is safe: */ - buffer[iout] = '\0'; - } -} -#endif /* PNG_WARNINGS_SUPPORTED || PNG_ERROR_TEXT_SUPPORTED */ - -#if defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) -PNG_FUNCTION(void,PNGAPI -png_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message), - PNG_NORETURN) -{ - char msg[18+PNG_MAX_ERROR_TEXT]; - if (png_ptr == NULL) - png_error(png_ptr, error_message); - - else - { - png_format_buffer(png_ptr, msg, error_message); - png_error(png_ptr, msg); - } -} -#endif /* PNG_READ_SUPPORTED && PNG_ERROR_TEXT_SUPPORTED */ - -#ifdef PNG_WARNINGS_SUPPORTED -void PNGAPI -png_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message) -{ - char msg[18+PNG_MAX_ERROR_TEXT]; - if (png_ptr == NULL) - png_warning(png_ptr, warning_message); - - else - { - png_format_buffer(png_ptr, msg, warning_message); - png_warning(png_ptr, msg); - } -} -#endif /* PNG_WARNINGS_SUPPORTED */ - -#ifdef PNG_READ_SUPPORTED -#ifdef PNG_BENIGN_ERRORS_SUPPORTED -void PNGAPI -png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp - error_message) -{ - if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) - png_chunk_warning(png_ptr, error_message); - - else - png_chunk_error(png_ptr, error_message); -} -#endif -#endif /* PNG_READ_SUPPORTED */ - -void /* PRIVATE */ -png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error) -{ - /* This is always supported, but for just read or just write it - * unconditionally does the right thing. - */ -# if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) - if (png_ptr->mode & PNG_IS_READ_STRUCT) -# endif - -# ifdef PNG_READ_SUPPORTED - { - if (error < PNG_CHUNK_ERROR) - png_chunk_warning(png_ptr, message); - - else - png_chunk_benign_error(png_ptr, message); - } -# endif - -# if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) - else if (!(png_ptr->mode & PNG_IS_READ_STRUCT)) -# endif - -# ifdef PNG_WRITE_SUPPORTED - { - if (error < PNG_CHUNK_WRITE_ERROR) - png_app_warning(png_ptr, message); - - else - png_app_error(png_ptr, message); - } -# endif -} - -#ifdef PNG_ERROR_TEXT_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_FUNCTION(void, -png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN) -{ -# define fixed_message "fixed point overflow in " -# define fixed_message_ln ((sizeof fixed_message)-1) - int iin; - char msg[fixed_message_ln+PNG_MAX_ERROR_TEXT]; - memcpy(msg, fixed_message, fixed_message_ln); - iin = 0; - if (name != NULL) while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0) - { - msg[fixed_message_ln + iin] = name[iin]; - ++iin; - } - msg[fixed_message_ln + iin] = 0; - png_error(png_ptr, msg); -} -#endif -#endif - -#ifdef PNG_SETJMP_SUPPORTED -/* This API only exists if ANSI-C style error handling is used, - * otherwise it is necessary for png_default_error to be overridden. - */ -jmp_buf* PNGAPI -png_set_longjmp_fn(png_structrp png_ptr, png_longjmp_ptr longjmp_fn, - size_t jmp_buf_size) -{ - /* From libpng 1.6.0 the app gets one chance to set a 'jmpbuf_size' value - * and it must not change after that. Libpng doesn't care how big the - * buffer is, just that it doesn't change. - * - * If the buffer size is no *larger* than the size of jmp_buf when libpng is - * compiled a built in jmp_buf is returned; this preserves the pre-1.6.0 - * semantics that this call will not fail. If the size is larger, however, - * the buffer is allocated and this may fail, causing the function to return - * NULL. - */ - if (png_ptr == NULL) - return NULL; - - if (png_ptr->jmp_buf_ptr == NULL) - { - png_ptr->jmp_buf_size = 0; /* not allocated */ - - if (jmp_buf_size <= (sizeof png_ptr->jmp_buf_local)) - png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; - - else - { - png_ptr->jmp_buf_ptr = png_voidcast(jmp_buf *, - png_malloc_warn(png_ptr, jmp_buf_size)); - - if (png_ptr->jmp_buf_ptr == NULL) - return NULL; /* new NULL return on OOM */ - - png_ptr->jmp_buf_size = jmp_buf_size; - } - } - - else /* Already allocated: check the size */ - { - size_t size = png_ptr->jmp_buf_size; - - if (size == 0) - { - size = (sizeof png_ptr->jmp_buf_local); - if (png_ptr->jmp_buf_ptr != &png_ptr->jmp_buf_local) - { - /* This is an internal error in libpng: somehow we have been left - * with a stack allocated jmp_buf when the application regained - * control. It's always possible to fix this up, but for the moment - * this is a png_error because that makes it easy to detect. - */ - png_error(png_ptr, "Libpng jmp_buf still allocated"); - /* png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; */ - } - } - - if (size != jmp_buf_size) - { - png_warning(png_ptr, "Application jmp_buf size changed"); - return NULL; /* caller will probably crash: no choice here */ - } - } - - /* Finally fill in the function, now we have a satisfactory buffer. It is - * valid to change the function on every call. - */ - png_ptr->longjmp_fn = longjmp_fn; - return png_ptr->jmp_buf_ptr; -} - -void /* PRIVATE */ -png_free_jmpbuf(png_structrp png_ptr) -{ - if (png_ptr != NULL) - { - jmp_buf *jb = png_ptr->jmp_buf_ptr; - - /* A size of 0 is used to indicate a local, stack, allocation of the - * pointer; used here and in png.c - */ - if (jb != NULL && png_ptr->jmp_buf_size > 0) - { - - /* This stuff is so that a failure to free the error control structure - * does not leave libpng in a state with no valid error handling: the - * free always succeeds, if there is an error it gets ignored. - */ - if (jb != &png_ptr->jmp_buf_local) - { - /* Make an internal, libpng, jmp_buf to return here */ - jmp_buf free_jmp_buf; - - if (!setjmp(free_jmp_buf)) - { - png_ptr->jmp_buf_ptr = &free_jmp_buf; /* come back here */ - png_ptr->jmp_buf_size = 0; /* stack allocation */ - png_ptr->longjmp_fn = longjmp; - png_free(png_ptr, jb); /* Return to setjmp on error */ - } - } - } - - /* *Always* cancel everything out: */ - png_ptr->jmp_buf_size = 0; - png_ptr->jmp_buf_ptr = NULL; - png_ptr->longjmp_fn = 0; - } -} -#endif - -/* This is the default error handling function. Note that replacements for - * this function MUST NOT RETURN, or the program will likely crash. This - * function is used by default, or if the program supplies NULL for the - * error function pointer in png_set_error_fn(). - */ -static PNG_FUNCTION(void /* PRIVATE */, -png_default_error,(png_const_structrp png_ptr, png_const_charp error_message), - PNG_NORETURN) -{ -#ifdef PNG_CONSOLE_IO_SUPPORTED -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - /* Check on NULL only added in 1.5.4 */ - if (error_message != NULL && *error_message == PNG_LITERAL_SHARP) - { - /* Strip "#nnnn " from beginning of error message. */ - int offset; - char error_number[16]; - for (offset = 0; offset<15; offset++) - { - error_number[offset] = error_message[offset + 1]; - if (error_message[offset] == ' ') - break; - } - - if ((offset > 1) && (offset < 15)) - { - error_number[offset - 1] = '\0'; - fprintf(stderr, "libpng error no. %s: %s", - error_number, error_message + offset + 1); - fprintf(stderr, PNG_STRING_NEWLINE); - } - - else - { - fprintf(stderr, "libpng error: %s, offset=%d", - error_message, offset); - fprintf(stderr, PNG_STRING_NEWLINE); - } - } - else -#endif - { - fprintf(stderr, "libpng error: %s", error_message ? error_message : - "undefined"); - fprintf(stderr, PNG_STRING_NEWLINE); - } -#else - PNG_UNUSED(error_message) /* Make compiler happy */ -#endif - png_longjmp(png_ptr, 1); -} - -PNG_FUNCTION(void,PNGAPI -png_longjmp,(png_const_structrp, int),PNG_NORETURN) -{ -#ifdef PNG_SETJMP_SUPPORTED - if (png_ptr && png_ptr->longjmp_fn && png_ptr->jmp_buf_ptr) - png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val); -#endif - - /* Here if not setjmp support or if png_ptr is null. */ - PNG_ABORT(); -} - -#ifdef PNG_WARNINGS_SUPPORTED -/* This function is called when there is a warning, but the library thinks - * it can continue anyway. Replacement functions don't have to do anything - * here if you don't want them to. In the default configuration, png_ptr is - * not used, but it is passed in case it may be useful. - */ -static void /* PRIVATE */ -png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message) -{ -#ifdef PNG_CONSOLE_IO_SUPPORTED -# ifdef PNG_ERROR_NUMBERS_SUPPORTED - if (*warning_message == PNG_LITERAL_SHARP) - { - int offset; - char warning_number[16]; - for (offset = 0; offset < 15; offset++) - { - warning_number[offset] = warning_message[offset + 1]; - if (warning_message[offset] == ' ') - break; - } - - if ((offset > 1) && (offset < 15)) - { - warning_number[offset + 1] = '\0'; - fprintf(stderr, "libpng warning no. %s: %s", - warning_number, warning_message + offset); - fprintf(stderr, PNG_STRING_NEWLINE); - } - - else - { - fprintf(stderr, "libpng warning: %s", - warning_message); - fprintf(stderr, PNG_STRING_NEWLINE); - } - } - else -# endif - - { - fprintf(stderr, "libpng warning: %s", warning_message); - fprintf(stderr, PNG_STRING_NEWLINE); - } -#else - PNG_UNUSED(warning_message) /* Make compiler happy */ -#endif - PNG_UNUSED(png_ptr) /* Make compiler happy */ -} -#endif /* PNG_WARNINGS_SUPPORTED */ - -/* This function is called when the application wants to use another method - * of handling errors and warnings. Note that the error function MUST NOT - * return to the calling routine or serious problems will occur. The return - * method used in the default routine calls longjmp(png_ptr->jmp_buf_ptr, 1) - */ -void PNGAPI -png_set_error_fn(png_structrp png_ptr, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warning_fn) -{ - if (png_ptr == NULL) - return; - - png_ptr->error_ptr = error_ptr; - png_ptr->error_fn = error_fn; -#ifdef PNG_WARNINGS_SUPPORTED - png_ptr->warning_fn = warning_fn; -#else - PNG_UNUSED(warning_fn) -#endif -} - - -/* This function returns a pointer to the error_ptr associated with the user - * functions. The application should free any memory associated with this - * pointer before png_write_destroy and png_read_destroy are called. - */ -png_voidp PNGAPI -png_get_error_ptr(png_const_structrp png_ptr) -{ - if (png_ptr == NULL) - return NULL; - - return ((png_voidp)png_ptr->error_ptr); -} - - -#ifdef PNG_ERROR_NUMBERS_SUPPORTED -void PNGAPI -png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode) -{ - if (png_ptr != NULL) - { - png_ptr->flags &= - ((~(PNG_FLAG_STRIP_ERROR_NUMBERS | - PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode); - } -} -#endif - -#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ - defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) - /* Currently the above both depend on SETJMP_SUPPORTED, however it would be - * possible to implement without setjmp support just so long as there is some - * way to handle the error return here: - */ -PNG_FUNCTION(void /* PRIVATE */, -png_safe_error,(png_structp png_nonconst_ptr, png_const_charp error_message), - PNG_NORETURN) -{ - const png_const_structrp png_ptr = png_nonconst_ptr; - png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); - - /* An error is always logged here, overwriting anything (typically a warning) - * that is already there: - */ - if (image != NULL) - { - png_safecat(image->message, (sizeof image->message), 0, error_message); - image->warning_or_error |= PNG_IMAGE_ERROR; - - /* Retrieve the jmp_buf from within the png_control, making this work for - * C++ compilation too is pretty tricky: C++ wants a pointer to the first - * element of a jmp_buf, but C doesn't tell us the type of that. - */ - if (image->opaque != NULL && image->opaque->error_buf != NULL) - longjmp(png_control_jmp_buf(image->opaque), 1); - - /* Missing longjmp buffer, the following is to help debugging: */ - { - size_t pos = png_safecat(image->message, (sizeof image->message), 0, - "bad longjmp: "); - png_safecat(image->message, (sizeof image->message), pos, - error_message); - } - } - - /* Here on an internal programming error. */ - abort(); -} - -#ifdef PNG_WARNINGS_SUPPORTED -void /* PRIVATE */ -png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message) -{ - const png_const_structrp png_ptr = png_nonconst_ptr; - png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); - - /* A warning is only logged if there is no prior warning or error. */ - if (image->warning_or_error == 0) - { - png_safecat(image->message, (sizeof image->message), 0, warning_message); - image->warning_or_error |= PNG_IMAGE_WARNING; - } -} -#endif - -int /* PRIVATE */ -png_safe_execute(png_imagep image_in, int (*function)(png_voidp), png_voidp arg) -{ - volatile png_imagep image = image_in; - volatile int result; - volatile png_voidp saved_error_buf; - jmp_buf safe_jmpbuf; - - /* Safely execute function(arg) with png_error returning to this function. */ - saved_error_buf = image->opaque->error_buf; - result = setjmp(safe_jmpbuf) == 0; - - if (result) - { - - image->opaque->error_buf = safe_jmpbuf; - result = function(arg); - } - - image->opaque->error_buf = saved_error_buf; - - /* And do the cleanup prior to any failure return. */ - if (!result) - png_image_free(image); - - return result; -} -#endif /* SIMPLIFIED READ/WRITE */ -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pngget.c b/source/modules/juce_graphics/image_formats/pnglib/pngget.c deleted file mode 100644 index 80ab055dc..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pngget.c +++ /dev/null @@ -1,1177 +0,0 @@ - -/* pngget.c - retrieval of values from info struct - * - * Last changed in libpng 1.6.1 [March 28, 2013] - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - */ - -#include "pngpriv.h" - -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) - -png_uint_32 PNGAPI -png_get_valid(png_const_structrp png_ptr, png_const_inforp info_ptr, - png_uint_32 flag) -{ - if (png_ptr != NULL && info_ptr != NULL) - return(info_ptr->valid & flag); - - return(0); -} - -png_size_t PNGAPI -png_get_rowbytes(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return(info_ptr->rowbytes); - - return(0); -} - -#ifdef PNG_INFO_IMAGE_SUPPORTED -png_bytepp PNGAPI -png_get_rows(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return(info_ptr->row_pointers); - - return(0); -} -#endif - -#ifdef PNG_EASY_ACCESS_SUPPORTED -/* Easy access to info, added in libpng-0.99 */ -png_uint_32 PNGAPI -png_get_image_width(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->width; - - return (0); -} - -png_uint_32 PNGAPI -png_get_image_height(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->height; - - return (0); -} - -png_byte PNGAPI -png_get_bit_depth(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->bit_depth; - - return (0); -} - -png_byte PNGAPI -png_get_color_type(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->color_type; - - return (0); -} - -png_byte PNGAPI -png_get_filter_type(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->filter_type; - - return (0); -} - -png_byte PNGAPI -png_get_interlace_type(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->interlace_type; - - return (0); -} - -png_byte PNGAPI -png_get_compression_type(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->compression_type; - - return (0); -} - -png_uint_32 PNGAPI -png_get_x_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp - info_ptr) -{ -#ifdef PNG_pHYs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) - { - png_debug1(1, "in %s retrieval function", - "png_get_x_pixels_per_meter"); - - if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER) - return (info_ptr->x_pixels_per_unit); - } -#endif - - return (0); -} - -png_uint_32 PNGAPI -png_get_y_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp - info_ptr) -{ -#ifdef PNG_pHYs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) - { - png_debug1(1, "in %s retrieval function", - "png_get_y_pixels_per_meter"); - - if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER) - return (info_ptr->y_pixels_per_unit); - } -#endif - - return (0); -} - -png_uint_32 PNGAPI -png_get_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ -#ifdef PNG_pHYs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) - { - png_debug1(1, "in %s retrieval function", "png_get_pixels_per_meter"); - - if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER && - info_ptr->x_pixels_per_unit == info_ptr->y_pixels_per_unit) - return (info_ptr->x_pixels_per_unit); - } -#endif - - return (0); -} - -#ifdef PNG_FLOATING_POINT_SUPPORTED -float PNGAPI -png_get_pixel_aspect_ratio(png_const_structrp png_ptr, png_const_inforp - info_ptr) -{ -#ifdef PNG_READ_pHYs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) - { - png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio"); - - if (info_ptr->x_pixels_per_unit != 0) - return ((float)((float)info_ptr->y_pixels_per_unit - /(float)info_ptr->x_pixels_per_unit)); - } -#else - PNG_UNUSED(png_ptr) - PNG_UNUSED(info_ptr) -#endif - - return ((float)0.0); -} -#endif - -#ifdef PNG_FIXED_POINT_SUPPORTED -png_fixed_point PNGAPI -png_get_pixel_aspect_ratio_fixed(png_const_structrp png_ptr, - png_const_inforp info_ptr) -{ -#ifdef PNG_READ_pHYs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) - && info_ptr->x_pixels_per_unit > 0 && info_ptr->y_pixels_per_unit > 0 - && info_ptr->x_pixels_per_unit <= PNG_UINT_31_MAX - && info_ptr->y_pixels_per_unit <= PNG_UINT_31_MAX) - { - png_fixed_point res; - - png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio_fixed"); - - /* The following casts work because a PNG 4 byte integer only has a valid - * range of 0..2^31-1; otherwise the cast might overflow. - */ - if (png_muldiv(&res, (png_int_32)info_ptr->y_pixels_per_unit, PNG_FP_1, - (png_int_32)info_ptr->x_pixels_per_unit)) - return res; - } -#else - PNG_UNUSED(png_ptr) - PNG_UNUSED(info_ptr) -#endif - - return 0; -} -#endif - -png_int_32 PNGAPI -png_get_x_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ -#ifdef PNG_oFFs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) - { - png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns"); - - if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER) - return (info_ptr->x_offset); - } -#endif - - return (0); -} - -png_int_32 PNGAPI -png_get_y_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ -#ifdef PNG_oFFs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) - { - png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns"); - - if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER) - return (info_ptr->y_offset); - } -#endif - - return (0); -} - -png_int_32 PNGAPI -png_get_x_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ -#ifdef PNG_oFFs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) - { - png_debug1(1, "in %s retrieval function", "png_get_x_offset_pixels"); - - if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL) - return (info_ptr->x_offset); - } -#endif - - return (0); -} - -png_int_32 PNGAPI -png_get_y_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ -#ifdef PNG_oFFs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) - { - png_debug1(1, "in %s retrieval function", "png_get_y_offset_pixels"); - - if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL) - return (info_ptr->y_offset); - } -#endif - - return (0); -} - -#ifdef PNG_INCH_CONVERSIONS_SUPPORTED -static png_uint_32 -ppi_from_ppm(png_uint_32 ppm) -{ -#if 0 - /* The conversion is *(2.54/100), in binary (32 digits): - * .00000110100000001001110101001001 - */ - png_uint_32 t1001, t1101; - ppm >>= 1; /* .1 */ - t1001 = ppm + (ppm >> 3); /* .1001 */ - t1101 = t1001 + (ppm >> 1); /* .1101 */ - ppm >>= 20; /* .000000000000000000001 */ - t1101 += t1101 >> 15; /* .1101000000000001101 */ - t1001 >>= 11; /* .000000000001001 */ - t1001 += t1001 >> 12; /* .000000000001001000000001001 */ - ppm += t1001; /* .000000000001001000001001001 */ - ppm += t1101; /* .110100000001001110101001001 */ - return (ppm + 16) >> 5;/* .00000110100000001001110101001001 */ -#else - /* The argument is a PNG unsigned integer, so it is not permitted - * to be bigger than 2^31. - */ - png_fixed_point result; - if (ppm <= PNG_UINT_31_MAX && png_muldiv(&result, (png_int_32)ppm, 127, - 5000)) - return result; - - /* Overflow. */ - return 0; -#endif -} - -png_uint_32 PNGAPI -png_get_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ - return ppi_from_ppm(png_get_pixels_per_meter(png_ptr, info_ptr)); -} - -png_uint_32 PNGAPI -png_get_x_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ - return ppi_from_ppm(png_get_x_pixels_per_meter(png_ptr, info_ptr)); -} - -png_uint_32 PNGAPI -png_get_y_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ - return ppi_from_ppm(png_get_y_pixels_per_meter(png_ptr, info_ptr)); -} - -#ifdef PNG_FIXED_POINT_SUPPORTED -static png_fixed_point -png_fixed_inches_from_microns(png_const_structrp png_ptr, png_int_32 microns) -{ - /* Convert from metres * 1,000,000 to inches * 100,000, meters to - * inches is simply *(100/2.54), so we want *(10/2.54) == 500/127. - * Notice that this can overflow - a warning is output and 0 is - * returned. - */ - return png_muldiv_warn(png_ptr, microns, 500, 127); -} - -png_fixed_point PNGAPI -png_get_x_offset_inches_fixed(png_const_structrp png_ptr, - png_const_inforp info_ptr) -{ - return png_fixed_inches_from_microns(png_ptr, - png_get_x_offset_microns(png_ptr, info_ptr)); -} -#endif - -#ifdef PNG_FIXED_POINT_SUPPORTED -png_fixed_point PNGAPI -png_get_y_offset_inches_fixed(png_const_structrp png_ptr, - png_const_inforp info_ptr) -{ - return png_fixed_inches_from_microns(png_ptr, - png_get_y_offset_microns(png_ptr, info_ptr)); -} -#endif - -#ifdef PNG_FLOATING_POINT_SUPPORTED -float PNGAPI -png_get_x_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ - /* To avoid the overflow do the conversion directly in floating - * point. - */ - return (float)(png_get_x_offset_microns(png_ptr, info_ptr) * .00003937); -} -#endif - -#ifdef PNG_FLOATING_POINT_SUPPORTED -float PNGAPI -png_get_y_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ - /* To avoid the overflow do the conversion directly in floating - * point. - */ - return (float)(png_get_y_offset_microns(png_ptr, info_ptr) * .00003937); -} -#endif - -#ifdef PNG_pHYs_SUPPORTED -png_uint_32 PNGAPI -png_get_pHYs_dpi(png_const_structrp png_ptr, png_const_inforp info_ptr, - png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) -{ - png_uint_32 retval = 0; - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) - { - png_debug1(1, "in %s retrieval function", "pHYs"); - - if (res_x != NULL) - { - *res_x = info_ptr->x_pixels_per_unit; - retval |= PNG_INFO_pHYs; - } - - if (res_y != NULL) - { - *res_y = info_ptr->y_pixels_per_unit; - retval |= PNG_INFO_pHYs; - } - - if (unit_type != NULL) - { - *unit_type = (int)info_ptr->phys_unit_type; - retval |= PNG_INFO_pHYs; - - if (*unit_type == 1) - { - if (res_x != NULL) *res_x = (png_uint_32)(*res_x * .0254 + .50); - if (res_y != NULL) *res_y = (png_uint_32)(*res_y * .0254 + .50); - } - } - } - - return (retval); -} -#endif /* PNG_pHYs_SUPPORTED */ -#endif /* PNG_INCH_CONVERSIONS_SUPPORTED */ - -/* png_get_channels really belongs in here, too, but it's been around longer */ - -#endif /* PNG_EASY_ACCESS_SUPPORTED */ - - -png_byte PNGAPI -png_get_channels(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return(info_ptr->channels); - - return (0); -} - -#ifdef PNG_READ_SUPPORTED -png_const_bytep PNGAPI -png_get_signature(png_const_structrp png_ptr, png_const_inforp info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return(info_ptr->signature); - - return (NULL); -} -#endif - -#ifdef PNG_bKGD_SUPPORTED -png_uint_32 PNGAPI -png_get_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, - png_color_16p *background) -{ - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) - && background != NULL) - { - png_debug1(1, "in %s retrieval function", "bKGD"); - - *background = &(info_ptr->background); - return (PNG_INFO_bKGD); - } - - return (0); -} -#endif - -#ifdef PNG_cHRM_SUPPORTED -/* The XYZ APIs were added in 1.5.5 to take advantage of the code added at the - * same time to correct the rgb grayscale coefficient defaults obtained from the - * cHRM chunk in 1.5.4 - */ -# ifdef PNG_FLOATING_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_cHRM(png_const_structrp png_ptr, png_const_inforp info_ptr, - double *white_x, double *white_y, double *red_x, double *red_y, - double *green_x, double *green_y, double *blue_x, double *blue_y) -{ - /* Quiet API change: this code used to only return the end points if a cHRM - * chunk was present, but the end points can also come from iCCP or sRGB - * chunks, so in 1.6.0 the png_get_ APIs return the end points regardless and - * the png_set_ APIs merely check that set end points are mutually - * consistent. - */ - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS)) - { - png_debug1(1, "in %s retrieval function", "cHRM"); - - if (white_x != NULL) - *white_x = png_float(png_ptr, - info_ptr->colorspace.end_points_xy.whitex, "cHRM white X"); - if (white_y != NULL) - *white_y = png_float(png_ptr, - info_ptr->colorspace.end_points_xy.whitey, "cHRM white Y"); - if (red_x != NULL) - *red_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redx, - "cHRM red X"); - if (red_y != NULL) - *red_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redy, - "cHRM red Y"); - if (green_x != NULL) - *green_x = png_float(png_ptr, - info_ptr->colorspace.end_points_xy.greenx, "cHRM green X"); - if (green_y != NULL) - *green_y = png_float(png_ptr, - info_ptr->colorspace.end_points_xy.greeny, "cHRM green Y"); - if (blue_x != NULL) - *blue_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluex, - "cHRM blue X"); - if (blue_y != NULL) - *blue_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluey, - "cHRM blue Y"); - return (PNG_INFO_cHRM); - } - - return (0); -} - -png_uint_32 PNGAPI -png_get_cHRM_XYZ(png_const_structrp png_ptr, png_const_inforp info_ptr, - double *red_X, double *red_Y, double *red_Z, double *green_X, - double *green_Y, double *green_Z, double *blue_X, double *blue_Y, - double *blue_Z) -{ - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS)) - { - png_debug1(1, "in %s retrieval function", "cHRM_XYZ(float)"); - - if (red_X != NULL) - *red_X = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_X, - "cHRM red X"); - if (red_Y != NULL) - *red_Y = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Y, - "cHRM red Y"); - if (red_Z != NULL) - *red_Z = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Z, - "cHRM red Z"); - if (green_X != NULL) - *green_X = png_float(png_ptr, - info_ptr->colorspace.end_points_XYZ.green_X, "cHRM green X"); - if (green_Y != NULL) - *green_Y = png_float(png_ptr, - info_ptr->colorspace.end_points_XYZ.green_Y, "cHRM green Y"); - if (green_Z != NULL) - *green_Z = png_float(png_ptr, - info_ptr->colorspace.end_points_XYZ.green_Z, "cHRM green Z"); - if (blue_X != NULL) - *blue_X = png_float(png_ptr, - info_ptr->colorspace.end_points_XYZ.blue_X, "cHRM blue X"); - if (blue_Y != NULL) - *blue_Y = png_float(png_ptr, - info_ptr->colorspace.end_points_XYZ.blue_Y, "cHRM blue Y"); - if (blue_Z != NULL) - *blue_Z = png_float(png_ptr, - info_ptr->colorspace.end_points_XYZ.blue_Z, "cHRM blue Z"); - return (PNG_INFO_cHRM); - } - - return (0); -} -# endif - -# ifdef PNG_FIXED_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, - png_fixed_point *int_red_X, png_fixed_point *int_red_Y, - png_fixed_point *int_red_Z, png_fixed_point *int_green_X, - png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, - png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, - png_fixed_point *int_blue_Z) -{ - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS)) - { - png_debug1(1, "in %s retrieval function", "cHRM_XYZ"); - - if (int_red_X != NULL) - *int_red_X = info_ptr->colorspace.end_points_XYZ.red_X; - if (int_red_Y != NULL) - *int_red_Y = info_ptr->colorspace.end_points_XYZ.red_Y; - if (int_red_Z != NULL) - *int_red_Z = info_ptr->colorspace.end_points_XYZ.red_Z; - if (int_green_X != NULL) - *int_green_X = info_ptr->colorspace.end_points_XYZ.green_X; - if (int_green_Y != NULL) - *int_green_Y = info_ptr->colorspace.end_points_XYZ.green_Y; - if (int_green_Z != NULL) - *int_green_Z = info_ptr->colorspace.end_points_XYZ.green_Z; - if (int_blue_X != NULL) - *int_blue_X = info_ptr->colorspace.end_points_XYZ.blue_X; - if (int_blue_Y != NULL) - *int_blue_Y = info_ptr->colorspace.end_points_XYZ.blue_Y; - if (int_blue_Z != NULL) - *int_blue_Z = info_ptr->colorspace.end_points_XYZ.blue_Z; - return (PNG_INFO_cHRM); - } - - return (0); -} - -png_uint_32 PNGAPI -png_get_cHRM_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, - png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x, - png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y, - png_fixed_point *blue_x, png_fixed_point *blue_y) -{ - png_debug1(1, "in %s retrieval function", "cHRM"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS)) - { - if (white_x != NULL) - *white_x = info_ptr->colorspace.end_points_xy.whitex; - if (white_y != NULL) - *white_y = info_ptr->colorspace.end_points_xy.whitey; - if (red_x != NULL) - *red_x = info_ptr->colorspace.end_points_xy.redx; - if (red_y != NULL) - *red_y = info_ptr->colorspace.end_points_xy.redy; - if (green_x != NULL) - *green_x = info_ptr->colorspace.end_points_xy.greenx; - if (green_y != NULL) - *green_y = info_ptr->colorspace.end_points_xy.greeny; - if (blue_x != NULL) - *blue_x = info_ptr->colorspace.end_points_xy.bluex; - if (blue_y != NULL) - *blue_y = info_ptr->colorspace.end_points_xy.bluey; - return (PNG_INFO_cHRM); - } - - return (0); -} -# endif -#endif - -#ifdef PNG_gAMA_SUPPORTED -# ifdef PNG_FIXED_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_gAMA_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, - png_fixed_point *file_gamma) -{ - png_debug1(1, "in %s retrieval function", "gAMA"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) && - file_gamma != NULL) - { - *file_gamma = info_ptr->colorspace.gamma; - return (PNG_INFO_gAMA); - } - - return (0); -} -# endif - -# ifdef PNG_FLOATING_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_gAMA(png_const_structrp png_ptr, png_const_inforp info_ptr, - double *file_gamma) -{ - png_debug1(1, "in %s retrieval function", "gAMA(float)"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) && - file_gamma != NULL) - { - *file_gamma = png_float(png_ptr, info_ptr->colorspace.gamma, - "png_get_gAMA"); - return (PNG_INFO_gAMA); - } - - return (0); -} -# endif -#endif - -#ifdef PNG_sRGB_SUPPORTED -png_uint_32 PNGAPI -png_get_sRGB(png_const_structrp png_ptr, png_const_inforp info_ptr, - int *file_srgb_intent) -{ - png_debug1(1, "in %s retrieval function", "sRGB"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB) - && file_srgb_intent != NULL) - { - *file_srgb_intent = info_ptr->colorspace.rendering_intent; - return (PNG_INFO_sRGB); - } - - return (0); -} -#endif - -#ifdef PNG_iCCP_SUPPORTED -png_uint_32 PNGAPI -png_get_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, - png_charpp name, int *compression_type, - png_bytepp profile, png_uint_32 *proflen) -{ - png_debug1(1, "in %s retrieval function", "iCCP"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP) - && name != NULL && compression_type != NULL && profile != NULL && - proflen != NULL) - { - *name = info_ptr->iccp_name; - *profile = info_ptr->iccp_profile; - *proflen = png_get_uint_32(info_ptr->iccp_profile); - /* This is somewhat irrelevant since the profile data returned has - * actually been uncompressed. - */ - *compression_type = PNG_COMPRESSION_TYPE_BASE; - return (PNG_INFO_iCCP); - } - - return (0); -} -#endif - -#ifdef PNG_sPLT_SUPPORTED -int PNGAPI -png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr, - png_sPLT_tpp spalettes) -{ - if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL) - { - *spalettes = info_ptr->splt_palettes; - return info_ptr->splt_palettes_num; - } - - return (0); -} -#endif - -#ifdef PNG_hIST_SUPPORTED -png_uint_32 PNGAPI -png_get_hIST(png_const_structrp png_ptr, png_inforp info_ptr, - png_uint_16p *hist) -{ - png_debug1(1, "in %s retrieval function", "hIST"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) - && hist != NULL) - { - *hist = info_ptr->hist; - return (PNG_INFO_hIST); - } - - return (0); -} -#endif - -png_uint_32 PNGAPI -png_get_IHDR(png_const_structrp png_ptr, png_const_inforp info_ptr, - png_uint_32 *width, png_uint_32 *height, int *bit_depth, - int *color_type, int *interlace_type, int *compression_type, - int *filter_type) -{ - png_debug1(1, "in %s retrieval function", "IHDR"); - - if (png_ptr == NULL || info_ptr == NULL || width == NULL || - height == NULL || bit_depth == NULL || color_type == NULL) - return (0); - - *width = info_ptr->width; - *height = info_ptr->height; - *bit_depth = info_ptr->bit_depth; - *color_type = info_ptr->color_type; - - if (compression_type != NULL) - *compression_type = info_ptr->compression_type; - - if (filter_type != NULL) - *filter_type = info_ptr->filter_type; - - if (interlace_type != NULL) - *interlace_type = info_ptr->interlace_type; - - /* This is redundant if we can be sure that the info_ptr values were all - * assigned in png_set_IHDR(). We do the check anyhow in case an - * application has ignored our advice not to mess with the members - * of info_ptr directly. - */ - png_check_IHDR(png_ptr, info_ptr->width, info_ptr->height, - info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, - info_ptr->compression_type, info_ptr->filter_type); - - return (1); -} - -#ifdef PNG_oFFs_SUPPORTED -png_uint_32 PNGAPI -png_get_oFFs(png_const_structrp png_ptr, png_const_inforp info_ptr, - png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type) -{ - png_debug1(1, "in %s retrieval function", "oFFs"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) - && offset_x != NULL && offset_y != NULL && unit_type != NULL) - { - *offset_x = info_ptr->x_offset; - *offset_y = info_ptr->y_offset; - *unit_type = (int)info_ptr->offset_unit_type; - return (PNG_INFO_oFFs); - } - - return (0); -} -#endif - -#ifdef PNG_pCAL_SUPPORTED -png_uint_32 PNGAPI -png_get_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, - png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams, - png_charp *units, png_charpp *params) -{ - png_debug1(1, "in %s retrieval function", "pCAL"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) - && purpose != NULL && X0 != NULL && X1 != NULL && type != NULL && - nparams != NULL && units != NULL && params != NULL) - { - *purpose = info_ptr->pcal_purpose; - *X0 = info_ptr->pcal_X0; - *X1 = info_ptr->pcal_X1; - *type = (int)info_ptr->pcal_type; - *nparams = (int)info_ptr->pcal_nparams; - *units = info_ptr->pcal_units; - *params = info_ptr->pcal_params; - return (PNG_INFO_pCAL); - } - - return (0); -} -#endif - -#ifdef PNG_sCAL_SUPPORTED -# ifdef PNG_FIXED_POINT_SUPPORTED -# if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \ - defined(PNG_FLOATING_POINT_SUPPORTED) -png_uint_32 PNGAPI -png_get_sCAL_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, - int *unit, png_fixed_point *width, png_fixed_point *height) -{ - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_sCAL)) - { - *unit = info_ptr->scal_unit; - /*TODO: make this work without FP support; the API is currently eliminated - * if neither floating point APIs nor internal floating point arithmetic - * are enabled. - */ - *width = png_fixed(png_ptr, atof(info_ptr->scal_s_width), "sCAL width"); - *height = png_fixed(png_ptr, atof(info_ptr->scal_s_height), - "sCAL height"); - return (PNG_INFO_sCAL); - } - - return(0); -} -# endif /* FLOATING_ARITHMETIC */ -# endif /* FIXED_POINT */ -# ifdef PNG_FLOATING_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_sCAL(png_const_structrp png_ptr, png_const_inforp info_ptr, - int *unit, double *width, double *height) -{ - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_sCAL)) - { - *unit = info_ptr->scal_unit; - *width = atof(info_ptr->scal_s_width); - *height = atof(info_ptr->scal_s_height); - return (PNG_INFO_sCAL); - } - - return(0); -} -# endif /* FLOATING POINT */ -png_uint_32 PNGAPI -png_get_sCAL_s(png_const_structrp png_ptr, png_const_inforp info_ptr, - int *unit, png_charpp width, png_charpp height) -{ - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_sCAL)) - { - *unit = info_ptr->scal_unit; - *width = info_ptr->scal_s_width; - *height = info_ptr->scal_s_height; - return (PNG_INFO_sCAL); - } - - return(0); -} -#endif /* sCAL */ - -#ifdef PNG_pHYs_SUPPORTED -png_uint_32 PNGAPI -png_get_pHYs(png_const_structrp png_ptr, png_const_inforp info_ptr, - png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) -{ - png_uint_32 retval = 0; - - png_debug1(1, "in %s retrieval function", "pHYs"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_pHYs)) - { - if (res_x != NULL) - { - *res_x = info_ptr->x_pixels_per_unit; - retval |= PNG_INFO_pHYs; - } - - if (res_y != NULL) - { - *res_y = info_ptr->y_pixels_per_unit; - retval |= PNG_INFO_pHYs; - } - - if (unit_type != NULL) - { - *unit_type = (int)info_ptr->phys_unit_type; - retval |= PNG_INFO_pHYs; - } - } - - return (retval); -} -#endif /* pHYs */ - -png_uint_32 PNGAPI -png_get_PLTE(png_const_structrp png_ptr, png_inforp info_ptr, - png_colorp *palette, int *num_palette) -{ - png_debug1(1, "in %s retrieval function", "PLTE"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_PLTE) - && palette != NULL) - { - *palette = info_ptr->palette; - *num_palette = info_ptr->num_palette; - png_debug1(3, "num_palette = %d", *num_palette); - return (PNG_INFO_PLTE); - } - - return (0); -} - -#ifdef PNG_sBIT_SUPPORTED -png_uint_32 PNGAPI -png_get_sBIT(png_const_structrp png_ptr, png_inforp info_ptr, - png_color_8p *sig_bit) -{ - png_debug1(1, "in %s retrieval function", "sBIT"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) - && sig_bit != NULL) - { - *sig_bit = &(info_ptr->sig_bit); - return (PNG_INFO_sBIT); - } - - return (0); -} -#endif - -#ifdef PNG_TEXT_SUPPORTED -int PNGAPI -png_get_text(png_const_structrp png_ptr, png_inforp info_ptr, - png_textp *text_ptr, int *num_text) -{ - if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0) - { - png_debug1(1, "in 0x%lx retrieval function", - (unsigned long)png_ptr->chunk_name); - - if (text_ptr != NULL) - *text_ptr = info_ptr->text; - - if (num_text != NULL) - *num_text = info_ptr->num_text; - - return info_ptr->num_text; - } - - if (num_text != NULL) - *num_text = 0; - - return(0); -} -#endif - -#ifdef PNG_tIME_SUPPORTED -png_uint_32 PNGAPI -png_get_tIME(png_const_structrp png_ptr, png_inforp info_ptr, - png_timep *mod_time) -{ - png_debug1(1, "in %s retrieval function", "tIME"); - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) - && mod_time != NULL) - { - *mod_time = &(info_ptr->mod_time); - return (PNG_INFO_tIME); - } - - return (0); -} -#endif - -#ifdef PNG_tRNS_SUPPORTED -png_uint_32 PNGAPI -png_get_tRNS(png_const_structrp png_ptr, png_inforp info_ptr, - png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color) -{ - png_uint_32 retval = 0; - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) - { - png_debug1(1, "in %s retrieval function", "tRNS"); - - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - if (trans_alpha != NULL) - { - *trans_alpha = info_ptr->trans_alpha; - retval |= PNG_INFO_tRNS; - } - - if (trans_color != NULL) - *trans_color = &(info_ptr->trans_color); - } - - else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */ - { - if (trans_color != NULL) - { - *trans_color = &(info_ptr->trans_color); - retval |= PNG_INFO_tRNS; - } - - if (trans_alpha != NULL) - *trans_alpha = NULL; - } - - if (num_trans != NULL) - { - *num_trans = info_ptr->num_trans; - retval |= PNG_INFO_tRNS; - } - } - - return (retval); -} -#endif - -#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED -int PNGAPI -png_get_unknown_chunks(png_const_structrp png_ptr, png_inforp info_ptr, - png_unknown_chunkpp unknowns) -{ - if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL) - { - *unknowns = info_ptr->unknown_chunks; - return info_ptr->unknown_chunks_num; - } - - return (0); -} -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -png_byte PNGAPI -png_get_rgb_to_gray_status (png_const_structrp png_ptr) -{ - return (png_byte)(png_ptr ? png_ptr->rgb_to_gray_status : 0); -} -#endif - -#ifdef PNG_USER_CHUNKS_SUPPORTED -png_voidp PNGAPI -png_get_user_chunk_ptr(png_const_structrp png_ptr) -{ - return (png_ptr ? png_ptr->user_chunk_ptr : NULL); -} -#endif - -png_size_t PNGAPI -png_get_compression_buffer_size(png_const_structrp png_ptr) -{ - if (png_ptr == NULL) - return 0; - -# ifdef PNG_WRITE_SUPPORTED - if (png_ptr->mode & PNG_IS_READ_STRUCT) -# endif - { -# ifdef PNG_SEQUENTIAL_READ_SUPPORTED - return png_ptr->IDAT_read_size; -# else - return PNG_IDAT_READ_SIZE; -# endif - } - -# ifdef PNG_WRITE_SUPPORTED - else - return png_ptr->zbuffer_size; -# endif -} - -#ifdef PNG_SET_USER_LIMITS_SUPPORTED -/* These functions were added to libpng 1.2.6 and were enabled - * by default in libpng-1.4.0 */ -png_uint_32 PNGAPI -png_get_user_width_max (png_const_structrp png_ptr) -{ - return (png_ptr ? png_ptr->user_width_max : 0); -} - -png_uint_32 PNGAPI -png_get_user_height_max (png_const_structrp png_ptr) -{ - return (png_ptr ? png_ptr->user_height_max : 0); -} - -/* This function was added to libpng 1.4.0 */ -png_uint_32 PNGAPI -png_get_chunk_cache_max (png_const_structrp png_ptr) -{ - return (png_ptr ? png_ptr->user_chunk_cache_max : 0); -} - -/* This function was added to libpng 1.4.1 */ -png_alloc_size_t PNGAPI -png_get_chunk_malloc_max (png_const_structrp png_ptr) -{ - return (png_ptr ? png_ptr->user_chunk_malloc_max : 0); -} -#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ - -/* These functions were added to libpng 1.4.0 */ -#ifdef PNG_IO_STATE_SUPPORTED -png_uint_32 PNGAPI -png_get_io_state (png_const_structrp png_ptr) -{ - return png_ptr->io_state; -} - -png_uint_32 PNGAPI -png_get_io_chunk_type (png_const_structrp png_ptr) -{ - return png_ptr->chunk_name; -} -#endif /* ?PNG_IO_STATE_SUPPORTED */ - -#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED -# ifdef PNG_GET_PALETTE_MAX_SUPPORTED -int PNGAPI -png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return png_ptr->num_palette_max; - - return (-1); -} -# endif -#endif - -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pnginfo.h b/source/modules/juce_graphics/image_formats/pnglib/pnginfo.h deleted file mode 100644 index 898a40656..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pnginfo.h +++ /dev/null @@ -1,260 +0,0 @@ - -/* pnginfo.h - header file for PNG reference library - * - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * Last changed in libpng 1.6.1 [March 28, 2013] - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - */ - - /* png_info is a structure that holds the information in a PNG file so - * that the application can find out the characteristics of the image. - * If you are reading the file, this structure will tell you what is - * in the PNG file. If you are writing the file, fill in the information - * you want to put into the PNG file, using png_set_*() functions, then - * call png_write_info(). - * - * The names chosen should be very close to the PNG specification, so - * consult that document for information about the meaning of each field. - * - * With libpng < 0.95, it was only possible to directly set and read the - * the values in the png_info_struct, which meant that the contents and - * order of the values had to remain fixed. With libpng 0.95 and later, - * however, there are now functions that abstract the contents of - * png_info_struct from the application, so this makes it easier to use - * libpng with dynamic libraries, and even makes it possible to use - * libraries that don't have all of the libpng ancillary chunk-handing - * functionality. In libpng-1.5.0 this was moved into a separate private - * file that is not visible to applications. - * - * The following members may have allocated storage attached that should be - * cleaned up before the structure is discarded: palette, trans, text, - * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile, - * splt_palettes, scal_unit, row_pointers, and unknowns. By default, these - * are automatically freed when the info structure is deallocated, if they were - * allocated internally by libpng. This behavior can be changed by means - * of the png_data_freer() function. - * - * More allocation details: all the chunk-reading functions that - * change these members go through the corresponding png_set_* - * functions. A function to clear these members is available: see - * png_free_data(). The png_set_* functions do not depend on being - * able to point info structure members to any of the storage they are - * passed (they make their own copies), EXCEPT that the png_set_text - * functions use the same storage passed to them in the text_ptr or - * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns - * functions do not make their own copies. - */ -#ifndef PNGINFO_H -#define PNGINFO_H - -struct png_info_def -{ - /* The following are necessary for every PNG file */ - png_uint_32 width; /* width of image in pixels (from IHDR) */ - png_uint_32 height; /* height of image in pixels (from IHDR) */ - png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */ - png_size_t rowbytes; /* bytes needed to hold an untransformed row */ - png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */ - png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */ - png_uint_16 num_trans; /* number of transparent palette color (tRNS) */ - png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */ - png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */ - /* The following three should have been named *_method not *_type */ - png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */ - png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */ - png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ - - /* The following are set by png_set_IHDR, called from the application on - * write, but the are never actually used by the write code. - */ - png_byte channels; /* number of data channels per pixel (1, 2, 3, 4) */ - png_byte pixel_depth; /* number of bits per pixel */ - png_byte spare_byte; /* to align the data, and for future use */ - -#ifdef PNG_READ_SUPPORTED - /* This is never set during write */ - png_byte signature[8]; /* magic bytes read by libpng from start of file */ -#endif - - /* The rest of the data is optional. If you are reading, check the - * valid field to see if the information in these are valid. If you - * are writing, set the valid field to those chunks you want written, - * and initialize the appropriate fields below. - */ - -#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) - /* png_colorspace only contains 'flags' if neither GAMMA or COLORSPACE are - * defined. When COLORSPACE is switched on all the colorspace-defining - * chunks should be enabled, when GAMMA is switched on all the gamma-defining - * chunks should be enabled. If this is not done it becomes possible to read - * inconsistent PNG files and assign a probably incorrect interpretation to - * the information. (In other words, by carefully choosing which chunks to - * recognize the system configuration can select an interpretation for PNG - * files containing ambiguous data and this will result in inconsistent - * behavior between different libpng builds!) - */ - png_colorspace colorspace; -#endif - -#ifdef PNG_iCCP_SUPPORTED - /* iCCP chunk data. */ - png_charp iccp_name; /* profile name */ - png_bytep iccp_profile; /* International Color Consortium profile data */ - png_uint_32 iccp_proflen; /* ICC profile data length */ -#endif - -#ifdef PNG_TEXT_SUPPORTED - /* The tEXt, and zTXt chunks contain human-readable textual data in - * uncompressed, compressed, and optionally compressed forms, respectively. - * The data in "text" is an array of pointers to uncompressed, - * null-terminated C strings. Each chunk has a keyword that describes the - * textual data contained in that chunk. Keywords are not required to be - * unique, and the text string may be empty. Any number of text chunks may - * be in an image. - */ - int num_text; /* number of comments read or comments to write */ - int max_text; /* current size of text array */ - png_textp text; /* array of comments read or comments to write */ -#endif /* PNG_TEXT_SUPPORTED */ - -#ifdef PNG_tIME_SUPPORTED - /* The tIME chunk holds the last time the displayed image data was - * modified. See the png_time struct for the contents of this struct. - */ - png_time mod_time; -#endif - -#ifdef PNG_sBIT_SUPPORTED - /* The sBIT chunk specifies the number of significant high-order bits - * in the pixel data. Values are in the range [1, bit_depth], and are - * only specified for the channels in the pixel data. The contents of - * the low-order bits is not specified. Data is valid if - * (valid & PNG_INFO_sBIT) is non-zero. - */ - png_color_8 sig_bit; /* significant bits in color channels */ -#endif - -#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_EXPAND_SUPPORTED) || \ -defined(PNG_READ_BACKGROUND_SUPPORTED) - /* The tRNS chunk supplies transparency data for paletted images and - * other image types that don't need a full alpha channel. There are - * "num_trans" transparency values for a paletted image, stored in the - * same order as the palette colors, starting from index 0. Values - * for the data are in the range [0, 255], ranging from fully transparent - * to fully opaque, respectively. For non-paletted images, there is a - * single color specified that should be treated as fully transparent. - * Data is valid if (valid & PNG_INFO_tRNS) is non-zero. - */ - png_bytep trans_alpha; /* alpha values for paletted image */ - png_color_16 trans_color; /* transparent color for non-palette image */ -#endif - -#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - /* The bKGD chunk gives the suggested image background color if the - * display program does not have its own background color and the image - * is needs to composited onto a background before display. The colors - * in "background" are normally in the same color space/depth as the - * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero. - */ - png_color_16 background; -#endif - -#ifdef PNG_oFFs_SUPPORTED - /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards - * and downwards from the top-left corner of the display, page, or other - * application-specific co-ordinate space. See the PNG_OFFSET_ defines - * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero. - */ - png_int_32 x_offset; /* x offset on page */ - png_int_32 y_offset; /* y offset on page */ - png_byte offset_unit_type; /* offset units type */ -#endif - -#ifdef PNG_pHYs_SUPPORTED - /* The pHYs chunk gives the physical pixel density of the image for - * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_ - * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero. - */ - png_uint_32 x_pixels_per_unit; /* horizontal pixel density */ - png_uint_32 y_pixels_per_unit; /* vertical pixel density */ - png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */ -#endif - -#ifdef PNG_hIST_SUPPORTED - /* The hIST chunk contains the relative frequency or importance of the - * various palette entries, so that a viewer can intelligently select a - * reduced-color palette, if required. Data is an array of "num_palette" - * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST) - * is non-zero. - */ - png_uint_16p hist; -#endif - -#ifdef PNG_pCAL_SUPPORTED - /* The pCAL chunk describes a transformation between the stored pixel - * values and original physical data values used to create the image. - * The integer range [0, 2^bit_depth - 1] maps to the floating-point - * range given by [pcal_X0, pcal_X1], and are further transformed by a - * (possibly non-linear) transformation function given by "pcal_type" - * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_ - * defines below, and the PNG-Group's PNG extensions document for a - * complete description of the transformations and how they should be - * implemented, and for a description of the ASCII parameter strings. - * Data values are valid if (valid & PNG_INFO_pCAL) non-zero. - */ - png_charp pcal_purpose; /* pCAL chunk description string */ - png_int_32 pcal_X0; /* minimum value */ - png_int_32 pcal_X1; /* maximum value */ - png_charp pcal_units; /* Latin-1 string giving physical units */ - png_charpp pcal_params; /* ASCII strings containing parameter values */ - png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */ - png_byte pcal_nparams; /* number of parameters given in pcal_params */ -#endif - -/* New members added in libpng-1.0.6 */ - png_uint_32 free_me; /* flags items libpng is responsible for freeing */ - -#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED - /* Storage for unknown chunks that the library doesn't recognize. */ - png_unknown_chunkp unknown_chunks; - - /* The type of this field is limited by the type of - * png_struct::user_chunk_cache_max, else overflow can occur. - */ - int unknown_chunks_num; -#endif - -#ifdef PNG_sPLT_SUPPORTED - /* Data on sPLT chunks (there may be more than one). */ - png_sPLT_tp splt_palettes; - int splt_palettes_num; /* Match type returned by png_get API */ -#endif - -#ifdef PNG_sCAL_SUPPORTED - /* The sCAL chunk describes the actual physical dimensions of the - * subject matter of the graphic. The chunk contains a unit specification - * a byte value, and two ASCII strings representing floating-point - * values. The values are width and height corresponsing to one pixel - * in the image. Data values are valid if (valid & PNG_INFO_sCAL) is - * non-zero. - */ - png_byte scal_unit; /* unit of physical scale */ - png_charp scal_s_width; /* string containing height */ - png_charp scal_s_height; /* string containing width */ -#endif - -#ifdef PNG_INFO_IMAGE_SUPPORTED - /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS) - non-zero */ - /* Data valid if (valid & PNG_INFO_IDAT) non-zero */ - png_bytepp row_pointers; /* the image bits */ -#endif - -}; -#endif /* PNGINFO_H */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pngmem.c b/source/modules/juce_graphics/image_formats/pnglib/pngmem.c deleted file mode 100644 index 43e294850..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pngmem.c +++ /dev/null @@ -1,277 +0,0 @@ - -/* pngmem.c - stub functions for memory allocation - * - * Last changed in libpng 1.6.0 [February 14, 2013] - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file provides a location for all memory allocation. Users who - * need special memory handling are expected to supply replacement - * functions for png_malloc() and png_free(), and to use - * png_create_read_struct_2() and png_create_write_struct_2() to - * identify the replacement functions. - */ - -#include "pngpriv.h" - -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -/* Free a png_struct */ -void /* PRIVATE */ -png_destroy_png_struct(png_structrp png_ptr) -{ - if (png_ptr != NULL) - { - /* png_free might call png_error and may certainly call - * png_get_mem_ptr, so fake a temporary png_struct to support this. - */ - png_struct dummy_struct = *png_ptr; - memset(png_ptr, 0, (sizeof *png_ptr)); - png_free(&dummy_struct, png_ptr); - -# ifdef PNG_SETJMP_SUPPORTED - /* We may have a jmp_buf left to deallocate. */ - png_free_jmpbuf(&dummy_struct); -# endif - } -} - -/* Allocate memory. For reasonable files, size should never exceed - * 64K. However, zlib may allocate more then 64K if you don't tell - * it not to. See zconf.h and png.h for more information. zlib does - * need to allocate exactly 64K, so whatever you call here must - * have the ability to do that. - */ -PNG_FUNCTION(png_voidp,PNGAPI -png_calloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) -{ - png_voidp ret; - - ret = png_malloc(png_ptr, size); - - if (ret != NULL) - memset(ret, 0, size); - - return ret; -} - -/* png_malloc_base, an internal function added at libpng 1.6.0, does the work of - * allocating memory, taking into account limits and PNG_USER_MEM_SUPPORTED. - * Checking and error handling must happen outside this routine; it returns NULL - * if the allocation cannot be done (for any reason.) - */ -PNG_FUNCTION(png_voidp /* PRIVATE */, -png_malloc_base,(png_const_structrp, png_alloc_size_t size), - PNG_ALLOCATED) -{ - /* Moved to png_malloc_base from png_malloc_default in 1.6.0; the DOS - * allocators have also been removed in 1.6.0, so any 16-bit system now has - * to implement a user memory handler. This checks to be sure it isn't - * called with big numbers. - */ -#ifdef PNG_USER_MEM_SUPPORTED - PNG_UNUSED(png_ptr) -#endif - if (size > 0 && size <= PNG_SIZE_MAX -# ifdef PNG_MAX_MALLOC_64K - && size <= 65536U -# endif - ) - { -#ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr != NULL && png_ptr->malloc_fn != NULL) - return png_ptr->malloc_fn(png_constcast(png_structrp,png_ptr), size); - - else -#endif - return malloc((size_t)size); /* checked for truncation above */ - } - - else - return NULL; -} - -/* This is really here only to work round a spurious warning in GCC 4.6 and 4.7 - * that arises because of the checks in png_realloc_array that are repeated in - * png_malloc_array. - */ -static png_voidp -png_malloc_array_checked(png_const_structrp png_ptr, int nelements, - size_t element_size) -{ - png_alloc_size_t req = nelements; /* known to be > 0 */ - - if (req <= PNG_SIZE_MAX/element_size) - return png_malloc_base(png_ptr, req * element_size); - - /* The failure case when the request is too large */ - return NULL; -} - -PNG_FUNCTION(png_voidp /* PRIVATE */, -png_malloc_array,(png_const_structrp png_ptr, int nelements, - size_t element_size),PNG_ALLOCATED) -{ - if (nelements <= 0 || element_size == 0) - png_error(png_ptr, "internal error: array alloc"); - - return png_malloc_array_checked(png_ptr, nelements, element_size); -} - -PNG_FUNCTION(png_voidp /* PRIVATE */, -png_realloc_array,(png_const_structrp png_ptr, png_const_voidp old_array, - int old_elements, int add_elements, size_t element_size),PNG_ALLOCATED) -{ - /* These are internal errors: */ - if (add_elements <= 0 || element_size == 0 || old_elements < 0 || - (old_array == NULL && old_elements > 0)) - png_error(png_ptr, "internal error: array realloc"); - - /* Check for overflow on the elements count (so the caller does not have to - * check.) - */ - if (add_elements <= INT_MAX - old_elements) - { - png_voidp new_array = png_malloc_array_checked(png_ptr, - old_elements+add_elements, element_size); - - if (new_array != NULL) - { - /* Because png_malloc_array worked the size calculations below cannot - * overflow. - */ - if (old_elements > 0) - memcpy(new_array, old_array, element_size*(unsigned)old_elements); - - memset((char*)new_array + element_size*(unsigned)old_elements, 0, - element_size*(unsigned)add_elements); - - return new_array; - } - } - - return NULL; /* error */ -} - -/* Various functions that have different error handling are derived from this. - * png_malloc always exists, but if PNG_USER_MEM_SUPPORTED is defined a separate - * function png_malloc_default is also provided. - */ -PNG_FUNCTION(png_voidp,PNGAPI -png_malloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) -{ - png_voidp ret; - - if (png_ptr == NULL) - return NULL; - - ret = png_malloc_base(png_ptr, size); - - if (ret == NULL) - png_error(png_ptr, "Out of memory"); /* 'm' means png_malloc */ - - return ret; -} - -#ifdef PNG_USER_MEM_SUPPORTED -PNG_FUNCTION(png_voidp,PNGAPI -png_malloc_default,(png_const_structrp png_ptr, png_alloc_size_t size), - PNG_ALLOCATED PNG_DEPRECATED) -{ - png_voidp ret; - - if (png_ptr == NULL) - return NULL; - - /* Passing 'NULL' here bypasses the application provided memory handler. */ - ret = png_malloc_base(NULL/*use malloc*/, size); - - if (ret == NULL) - png_error(png_ptr, "Out of Memory"); /* 'M' means png_malloc_default */ - - return ret; -} -#endif /* PNG_USER_MEM_SUPPORTED */ - -/* This function was added at libpng version 1.2.3. The png_malloc_warn() - * function will issue a png_warning and return NULL instead of issuing a - * png_error, if it fails to allocate the requested memory. - */ -PNG_FUNCTION(png_voidp,PNGAPI -png_malloc_warn,(png_const_structrp png_ptr, png_alloc_size_t size), - PNG_ALLOCATED) -{ - if (png_ptr != NULL) - { - png_voidp ret = png_malloc_base(png_ptr, size); - - if (ret != NULL) - return ret; - - png_warning(png_ptr, "Out of memory"); - } - - return NULL; -} - -/* Free a pointer allocated by png_malloc(). If ptr is NULL, return - * without taking any action. - */ -void PNGAPI -png_free(png_const_structrp png_ptr, png_voidp ptr) -{ - if (png_ptr == NULL || ptr == NULL) - return; - -#ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr->free_fn != NULL) - png_ptr->free_fn(png_constcast(png_structrp,png_ptr), ptr); - - else - png_free_default(png_ptr, ptr); -} - -PNG_FUNCTION(void,PNGAPI -png_free_default,(png_const_structrp png_ptr, png_voidp ptr),PNG_DEPRECATED) -{ - if (png_ptr == NULL || ptr == NULL) - return; -#endif /* PNG_USER_MEM_SUPPORTED */ - - free(ptr); -} - -#ifdef PNG_USER_MEM_SUPPORTED -/* This function is called when the application wants to use another method - * of allocating and freeing memory. - */ -void PNGAPI -png_set_mem_fn(png_structrp png_ptr, png_voidp mem_ptr, png_malloc_ptr - malloc_fn, png_free_ptr free_fn) -{ - if (png_ptr != NULL) - { - png_ptr->mem_ptr = mem_ptr; - png_ptr->malloc_fn = malloc_fn; - png_ptr->free_fn = free_fn; - } -} - -/* This function returns a pointer to the mem_ptr associated with the user - * functions. The application should free any memory associated with this - * pointer before png_write_destroy and png_read_destroy are called. - */ -png_voidp PNGAPI -png_get_mem_ptr(png_const_structrp png_ptr) -{ - if (png_ptr == NULL) - return NULL; - - return png_ptr->mem_ptr; -} -#endif /* PNG_USER_MEM_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pngpread.c b/source/modules/juce_graphics/image_formats/pnglib/pngpread.c deleted file mode 100644 index a133331ff..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pngpread.c +++ /dev/null @@ -1,1291 +0,0 @@ - -/* pngpread.c - read a png file in push mode - * - * Last changed in libpng 1.6.0 [February 14, 2013] - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - */ - -#include "pngpriv.h" - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED - -/* Push model modes */ -#define PNG_READ_SIG_MODE 0 -#define PNG_READ_CHUNK_MODE 1 -#define PNG_READ_IDAT_MODE 2 -#define PNG_SKIP_MODE 3 -#define PNG_READ_tEXt_MODE 4 -#define PNG_READ_zTXt_MODE 5 -#define PNG_READ_DONE_MODE 6 -#define PNG_READ_iTXt_MODE 7 -#define PNG_ERROR_MODE 8 - -void PNGAPI -png_process_data(png_structrp png_ptr, png_inforp info_ptr, - png_bytep buffer, png_size_t buffer_size) -{ - if (png_ptr == NULL || info_ptr == NULL) - return; - - png_push_restore_buffer(png_ptr, buffer, buffer_size); - - while (png_ptr->buffer_size) - { - png_process_some_data(png_ptr, info_ptr); - } -} - -png_size_t PNGAPI -png_process_data_pause(png_structrp png_ptr, int save) -{ - if (png_ptr != NULL) - { - /* It's easiest for the caller if we do the save, then the caller doesn't - * have to supply the same data again: - */ - if (save) - png_push_save_buffer(png_ptr); - else - { - /* This includes any pending saved bytes: */ - png_size_t remaining = png_ptr->buffer_size; - png_ptr->buffer_size = 0; - - /* So subtract the saved buffer size, unless all the data - * is actually 'saved', in which case we just return 0 - */ - if (png_ptr->save_buffer_size < remaining) - return remaining - png_ptr->save_buffer_size; - } - } - - return 0; -} - -png_uint_32 PNGAPI -png_process_data_skip(png_structrp png_ptr) -{ - png_uint_32 remaining = 0; - - if (png_ptr != NULL && png_ptr->process_mode == PNG_SKIP_MODE && - png_ptr->skip_length > 0) - { - /* At the end of png_process_data the buffer size must be 0 (see the loop - * above) so we can detect a broken call here: - */ - if (png_ptr->buffer_size != 0) - png_error(png_ptr, - "png_process_data_skip called inside png_process_data"); - - /* If is impossible for there to be a saved buffer at this point - - * otherwise we could not be in SKIP mode. This will also happen if - * png_process_skip is called inside png_process_data (but only very - * rarely.) - */ - if (png_ptr->save_buffer_size != 0) - png_error(png_ptr, "png_process_data_skip called with saved data"); - - remaining = png_ptr->skip_length; - png_ptr->skip_length = 0; - png_ptr->process_mode = PNG_READ_CHUNK_MODE; - } - - return remaining; -} - -/* What we do with the incoming data depends on what we were previously - * doing before we ran out of data... - */ -void /* PRIVATE */ -png_process_some_data(png_structrp png_ptr, png_inforp info_ptr) -{ - if (png_ptr == NULL) - return; - - switch (png_ptr->process_mode) - { - case PNG_READ_SIG_MODE: - { - png_push_read_sig(png_ptr, info_ptr); - break; - } - - case PNG_READ_CHUNK_MODE: - { - png_push_read_chunk(png_ptr, info_ptr); - break; - } - - case PNG_READ_IDAT_MODE: - { - png_push_read_IDAT(png_ptr); - break; - } - - case PNG_SKIP_MODE: - { - png_push_crc_finish(png_ptr); - break; - } - - default: - { - png_ptr->buffer_size = 0; - break; - } - } -} - -/* Read any remaining signature bytes from the stream and compare them with - * the correct PNG signature. It is possible that this routine is called - * with bytes already read from the signature, either because they have been - * checked by the calling application, or because of multiple calls to this - * routine. - */ -void /* PRIVATE */ -png_push_read_sig(png_structrp png_ptr, png_inforp info_ptr) -{ - png_size_t num_checked = png_ptr->sig_bytes, - num_to_check = 8 - num_checked; - - if (png_ptr->buffer_size < num_to_check) - { - num_to_check = png_ptr->buffer_size; - } - - png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]), - num_to_check); - png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes + num_to_check); - - if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) - { - if (num_checked < 4 && - png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) - png_error(png_ptr, "Not a PNG file"); - - else - png_error(png_ptr, "PNG file corrupted by ASCII conversion"); - } - else - { - if (png_ptr->sig_bytes >= 8) - { - png_ptr->process_mode = PNG_READ_CHUNK_MODE; - } - } -} - -void /* PRIVATE */ -png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) -{ - png_uint_32 chunk_name; -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - int keep; /* unknown handling method */ -#endif - - /* First we make sure we have enough data for the 4 byte chunk name - * and the 4 byte chunk length before proceeding with decoding the - * chunk data. To fully decode each of these chunks, we also make - * sure we have enough data in the buffer for the 4 byte CRC at the - * end of every chunk (except IDAT, which is handled separately). - */ - if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) - { - png_byte chunk_length[4]; - png_byte chunk_tag[4]; - - if (png_ptr->buffer_size < 8) - { - png_push_save_buffer(png_ptr); - return; - } - - png_push_fill_buffer(png_ptr, chunk_length, 4); - png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); - png_reset_crc(png_ptr); - png_crc_read(png_ptr, chunk_tag, 4); - png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag); - png_check_chunk_name(png_ptr, png_ptr->chunk_name); - png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; - } - - chunk_name = png_ptr->chunk_name; - - if (chunk_name == png_IDAT) - { - if (png_ptr->mode & PNG_AFTER_IDAT) - png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; - - /* If we reach an IDAT chunk, this means we have read all of the - * header chunks, and we can start reading the image (or if this - * is called after the image has been read - we have an error). - */ - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before IDAT"); - - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) - png_error(png_ptr, "Missing PLTE before IDAT"); - - png_ptr->mode |= PNG_HAVE_IDAT; - - if (!(png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) - if (png_ptr->push_length == 0) - return; - - if (png_ptr->mode & PNG_AFTER_IDAT) - png_benign_error(png_ptr, "Too many IDATs found"); - } - - if (chunk_name == png_IHDR) - { - if (png_ptr->push_length != 13) - png_error(png_ptr, "Invalid IHDR length"); - - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); - } - - else if (chunk_name == png_IEND) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); - - png_ptr->process_mode = PNG_READ_DONE_MODE; - png_push_have_end(png_ptr, info_ptr); - } - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, keep); - - if (chunk_name == png_PLTE) - png_ptr->mode |= PNG_HAVE_PLTE; - } - -#endif - else if (chunk_name == png_PLTE) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length); - } - - else if (chunk_name == png_IDAT) - { - png_ptr->idat_size = png_ptr->push_length; - png_ptr->process_mode = PNG_READ_IDAT_MODE; - png_push_have_info(png_ptr, info_ptr); - png_ptr->zstream.avail_out = - (uInt) PNG_ROWBYTES(png_ptr->pixel_depth, - png_ptr->iwidth) + 1; - png_ptr->zstream.next_out = png_ptr->row_buf; - return; - } - -#ifdef PNG_READ_gAMA_SUPPORTED - else if (png_ptr->chunk_name == png_gAMA) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_sBIT_SUPPORTED - else if (png_ptr->chunk_name == png_sBIT) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_cHRM_SUPPORTED - else if (png_ptr->chunk_name == png_cHRM) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_sRGB_SUPPORTED - else if (chunk_name == png_sRGB) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_iCCP_SUPPORTED - else if (png_ptr->chunk_name == png_iCCP) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_sPLT_SUPPORTED - else if (chunk_name == png_sPLT) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_tRNS_SUPPORTED - else if (chunk_name == png_tRNS) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_bKGD_SUPPORTED - else if (chunk_name == png_bKGD) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_hIST_SUPPORTED - else if (chunk_name == png_hIST) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_pHYs_SUPPORTED - else if (chunk_name == png_pHYs) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_oFFs_SUPPORTED - else if (chunk_name == png_oFFs) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length); - } -#endif - -#ifdef PNG_READ_pCAL_SUPPORTED - else if (chunk_name == png_pCAL) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_sCAL_SUPPORTED - else if (chunk_name == png_sCAL) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_tIME_SUPPORTED - else if (chunk_name == png_tIME) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_tEXt_SUPPORTED - else if (chunk_name == png_tEXt) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_zTXt_SUPPORTED - else if (chunk_name == png_zTXt) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#ifdef PNG_READ_iTXt_SUPPORTED - else if (chunk_name == png_iTXt) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif - else - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, - PNG_HANDLE_CHUNK_AS_DEFAULT); - } - - png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; -} - -void /* PRIVATE */ -png_push_crc_skip(png_structrp png_ptr, png_uint_32 skip) -{ - png_ptr->process_mode = PNG_SKIP_MODE; - png_ptr->skip_length = skip; -} - -void /* PRIVATE */ -png_push_crc_finish(png_structrp png_ptr) -{ - if (png_ptr->skip_length && png_ptr->save_buffer_size) - { - png_size_t save_size = png_ptr->save_buffer_size; - png_uint_32 skip_length = png_ptr->skip_length; - - /* We want the smaller of 'skip_length' and 'save_buffer_size', but - * they are of different types and we don't know which variable has the - * fewest bits. Carefully select the smaller and cast it to the type of - * the larger - this cannot overflow. Do not cast in the following test - * - it will break on either 16 or 64 bit platforms. - */ - if (skip_length < save_size) - save_size = (png_size_t)skip_length; - - else - skip_length = (png_uint_32)save_size; - - png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); - - png_ptr->skip_length -= skip_length; - png_ptr->buffer_size -= save_size; - png_ptr->save_buffer_size -= save_size; - png_ptr->save_buffer_ptr += save_size; - } - if (png_ptr->skip_length && png_ptr->current_buffer_size) - { - png_size_t save_size = png_ptr->current_buffer_size; - png_uint_32 skip_length = png_ptr->skip_length; - - /* We want the smaller of 'skip_length' and 'current_buffer_size', here, - * the same problem exists as above and the same solution. - */ - if (skip_length < save_size) - save_size = (png_size_t)skip_length; - - else - skip_length = (png_uint_32)save_size; - - png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); - - png_ptr->skip_length -= skip_length; - png_ptr->buffer_size -= save_size; - png_ptr->current_buffer_size -= save_size; - png_ptr->current_buffer_ptr += save_size; - } - if (!png_ptr->skip_length) - { - if (png_ptr->buffer_size < 4) - { - png_push_save_buffer(png_ptr); - return; - } - - png_crc_finish(png_ptr, 0); - png_ptr->process_mode = PNG_READ_CHUNK_MODE; - } -} - -void PNGCBAPI -png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) -{ - png_bytep ptr; - - if (png_ptr == NULL) - return; - - ptr = buffer; - if (png_ptr->save_buffer_size) - { - png_size_t save_size; - - if (length < png_ptr->save_buffer_size) - save_size = length; - - else - save_size = png_ptr->save_buffer_size; - - memcpy(ptr, png_ptr->save_buffer_ptr, save_size); - length -= save_size; - ptr += save_size; - png_ptr->buffer_size -= save_size; - png_ptr->save_buffer_size -= save_size; - png_ptr->save_buffer_ptr += save_size; - } - if (length && png_ptr->current_buffer_size) - { - png_size_t save_size; - - if (length < png_ptr->current_buffer_size) - save_size = length; - - else - save_size = png_ptr->current_buffer_size; - - memcpy(ptr, png_ptr->current_buffer_ptr, save_size); - png_ptr->buffer_size -= save_size; - png_ptr->current_buffer_size -= save_size; - png_ptr->current_buffer_ptr += save_size; - } -} - -void /* PRIVATE */ -png_push_save_buffer(png_structrp png_ptr) -{ - if (png_ptr->save_buffer_size) - { - if (png_ptr->save_buffer_ptr != png_ptr->save_buffer) - { - png_size_t i, istop; - png_bytep sp; - png_bytep dp; - - istop = png_ptr->save_buffer_size; - for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer; - i < istop; i++, sp++, dp++) - { - *dp = *sp; - } - } - } - if (png_ptr->save_buffer_size + png_ptr->current_buffer_size > - png_ptr->save_buffer_max) - { - png_size_t new_max; - png_bytep old_buffer; - - if (png_ptr->save_buffer_size > PNG_SIZE_MAX - - (png_ptr->current_buffer_size + 256)) - { - png_error(png_ptr, "Potential overflow of save_buffer"); - } - - new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256; - old_buffer = png_ptr->save_buffer; - png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr, - (png_size_t)new_max); - - if (png_ptr->save_buffer == NULL) - { - png_free(png_ptr, old_buffer); - png_error(png_ptr, "Insufficient memory for save_buffer"); - } - - memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); - png_free(png_ptr, old_buffer); - png_ptr->save_buffer_max = new_max; - } - if (png_ptr->current_buffer_size) - { - memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size, - png_ptr->current_buffer_ptr, png_ptr->current_buffer_size); - png_ptr->save_buffer_size += png_ptr->current_buffer_size; - png_ptr->current_buffer_size = 0; - } - png_ptr->save_buffer_ptr = png_ptr->save_buffer; - png_ptr->buffer_size = 0; -} - -void /* PRIVATE */ -png_push_restore_buffer(png_structrp png_ptr, png_bytep buffer, - png_size_t buffer_length) -{ - png_ptr->current_buffer = buffer; - png_ptr->current_buffer_size = buffer_length; - png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size; - png_ptr->current_buffer_ptr = png_ptr->current_buffer; -} - -void /* PRIVATE */ -png_push_read_IDAT(png_structrp png_ptr) -{ - if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) - { - png_byte chunk_length[4]; - png_byte chunk_tag[4]; - - /* TODO: this code can be commoned up with the same code in push_read */ - if (png_ptr->buffer_size < 8) - { - png_push_save_buffer(png_ptr); - return; - } - - png_push_fill_buffer(png_ptr, chunk_length, 4); - png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); - png_reset_crc(png_ptr); - png_crc_read(png_ptr, chunk_tag, 4); - png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag); - png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; - - if (png_ptr->chunk_name != png_IDAT) - { - png_ptr->process_mode = PNG_READ_CHUNK_MODE; - - if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) - png_error(png_ptr, "Not enough compressed data"); - - return; - } - - png_ptr->idat_size = png_ptr->push_length; - } - - if (png_ptr->idat_size && png_ptr->save_buffer_size) - { - png_size_t save_size = png_ptr->save_buffer_size; - png_uint_32 idat_size = png_ptr->idat_size; - - /* We want the smaller of 'idat_size' and 'current_buffer_size', but they - * are of different types and we don't know which variable has the fewest - * bits. Carefully select the smaller and cast it to the type of the - * larger - this cannot overflow. Do not cast in the following test - it - * will break on either 16 or 64 bit platforms. - */ - if (idat_size < save_size) - save_size = (png_size_t)idat_size; - - else - idat_size = (png_uint_32)save_size; - - png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); - - png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size); - - png_ptr->idat_size -= idat_size; - png_ptr->buffer_size -= save_size; - png_ptr->save_buffer_size -= save_size; - png_ptr->save_buffer_ptr += save_size; - } - - if (png_ptr->idat_size && png_ptr->current_buffer_size) - { - png_size_t save_size = png_ptr->current_buffer_size; - png_uint_32 idat_size = png_ptr->idat_size; - - /* We want the smaller of 'idat_size' and 'current_buffer_size', but they - * are of different types and we don't know which variable has the fewest - * bits. Carefully select the smaller and cast it to the type of the - * larger - this cannot overflow. - */ - if (idat_size < save_size) - save_size = (png_size_t)idat_size; - - else - idat_size = (png_uint_32)save_size; - - png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); - - png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size); - - png_ptr->idat_size -= idat_size; - png_ptr->buffer_size -= save_size; - png_ptr->current_buffer_size -= save_size; - png_ptr->current_buffer_ptr += save_size; - } - if (!png_ptr->idat_size) - { - if (png_ptr->buffer_size < 4) - { - png_push_save_buffer(png_ptr); - return; - } - - png_crc_finish(png_ptr, 0); - png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; - png_ptr->mode |= PNG_AFTER_IDAT; - png_ptr->zowner = 0; - } -} - -void /* PRIVATE */ -png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer, - png_size_t buffer_length) -{ - /* The caller checks for a non-zero buffer length. */ - if (!(buffer_length > 0) || buffer == NULL) - png_error(png_ptr, "No IDAT data (internal error)"); - - /* This routine must process all the data it has been given - * before returning, calling the row callback as required to - * handle the uncompressed results. - */ - png_ptr->zstream.next_in = buffer; - /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */ - png_ptr->zstream.avail_in = (uInt)buffer_length; - - /* Keep going until the decompressed data is all processed - * or the stream marked as finished. - */ - while (png_ptr->zstream.avail_in > 0 && - !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) - { - int ret; - - /* We have data for zlib, but we must check that zlib - * has someplace to put the results. It doesn't matter - * if we don't expect any results -- it may be the input - * data is just the LZ end code. - */ - if (!(png_ptr->zstream.avail_out > 0)) - { - /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */ - png_ptr->zstream.avail_out = (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth, - png_ptr->iwidth) + 1); - - png_ptr->zstream.next_out = png_ptr->row_buf; - } - - /* Using Z_SYNC_FLUSH here means that an unterminated - * LZ stream (a stream with a missing end code) can still - * be handled, otherwise (Z_NO_FLUSH) a future zlib - * implementation might defer output and therefore - * change the current behavior (see comments in inflate.c - * for why this doesn't happen at present with zlib 1.2.5). - */ - ret = inflate(&png_ptr->zstream, Z_SYNC_FLUSH); - - /* Check for any failure before proceeding. */ - if (ret != Z_OK && ret != Z_STREAM_END) - { - /* Terminate the decompression. */ - png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; - png_ptr->zowner = 0; - - /* This may be a truncated stream (missing or - * damaged end code). Treat that as a warning. - */ - if (png_ptr->row_number >= png_ptr->num_rows || - png_ptr->pass > 6) - png_warning(png_ptr, "Truncated compressed data in IDAT"); - - else - png_error(png_ptr, "Decompression error in IDAT"); - - /* Skip the check on unprocessed input */ - return; - } - - /* Did inflate output any data? */ - if (png_ptr->zstream.next_out != png_ptr->row_buf) - { - /* Is this unexpected data after the last row? - * If it is, artificially terminate the LZ output - * here. - */ - if (png_ptr->row_number >= png_ptr->num_rows || - png_ptr->pass > 6) - { - /* Extra data. */ - png_warning(png_ptr, "Extra compressed data in IDAT"); - png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; - png_ptr->zowner = 0; - - /* Do no more processing; skip the unprocessed - * input check below. - */ - return; - } - - /* Do we have a complete row? */ - if (png_ptr->zstream.avail_out == 0) - png_push_process_row(png_ptr); - } - - /* And check for the end of the stream. */ - if (ret == Z_STREAM_END) - png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; - } - - /* All the data should have been processed, if anything - * is left at this point we have bytes of IDAT data - * after the zlib end code. - */ - if (png_ptr->zstream.avail_in > 0) - png_warning(png_ptr, "Extra compression data in IDAT"); -} - -void /* PRIVATE */ -png_push_process_row(png_structrp png_ptr) -{ - /* 1.5.6: row_info moved out of png_struct to a local here. */ - png_row_info row_info; - - row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */ - row_info.color_type = png_ptr->color_type; - row_info.bit_depth = png_ptr->bit_depth; - row_info.channels = png_ptr->channels; - row_info.pixel_depth = png_ptr->pixel_depth; - row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); - - if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE) - { - if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST) - png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1, - png_ptr->prev_row + 1, png_ptr->row_buf[0]); - else - png_error(png_ptr, "bad adaptive filter value"); - } - - /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before - * 1.5.6, while the buffer really is this big in current versions of libpng - * it may not be in the future, so this was changed just to copy the - * interlaced row count: - */ - memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); - -#ifdef PNG_READ_TRANSFORMS_SUPPORTED - if (png_ptr->transformations) - png_do_read_transformations(png_ptr, &row_info); -#endif - - /* The transformed pixel depth should match the depth now in row_info. */ - if (png_ptr->transformed_pixel_depth == 0) - { - png_ptr->transformed_pixel_depth = row_info.pixel_depth; - if (row_info.pixel_depth > png_ptr->maximum_pixel_depth) - png_error(png_ptr, "progressive row overflow"); - } - - else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth) - png_error(png_ptr, "internal progressive row size calculation error"); - - -#ifdef PNG_READ_INTERLACING_SUPPORTED - /* Blow up interlaced rows to full size */ - if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) - { - if (png_ptr->pass < 6) - png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass, - png_ptr->transformations); - - switch (png_ptr->pass) - { - case 0: - { - int i; - for (i = 0; i < 8 && png_ptr->pass == 0; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); /* Updates png_ptr->pass */ - } - - if (png_ptr->pass == 2) /* Pass 1 might be empty */ - { - for (i = 0; i < 4 && png_ptr->pass == 2; i++) - { - png_push_have_row(png_ptr, NULL); - png_read_push_finish_row(png_ptr); - } - } - - if (png_ptr->pass == 4 && png_ptr->height <= 4) - { - for (i = 0; i < 2 && png_ptr->pass == 4; i++) - { - png_push_have_row(png_ptr, NULL); - png_read_push_finish_row(png_ptr); - } - } - - if (png_ptr->pass == 6 && png_ptr->height <= 4) - { - png_push_have_row(png_ptr, NULL); - png_read_push_finish_row(png_ptr); - } - - break; - } - - case 1: - { - int i; - for (i = 0; i < 8 && png_ptr->pass == 1; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } - - if (png_ptr->pass == 2) /* Skip top 4 generated rows */ - { - for (i = 0; i < 4 && png_ptr->pass == 2; i++) - { - png_push_have_row(png_ptr, NULL); - png_read_push_finish_row(png_ptr); - } - } - - break; - } - - case 2: - { - int i; - - for (i = 0; i < 4 && png_ptr->pass == 2; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } - - for (i = 0; i < 4 && png_ptr->pass == 2; i++) - { - png_push_have_row(png_ptr, NULL); - png_read_push_finish_row(png_ptr); - } - - if (png_ptr->pass == 4) /* Pass 3 might be empty */ - { - for (i = 0; i < 2 && png_ptr->pass == 4; i++) - { - png_push_have_row(png_ptr, NULL); - png_read_push_finish_row(png_ptr); - } - } - - break; - } - - case 3: - { - int i; - - for (i = 0; i < 4 && png_ptr->pass == 3; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } - - if (png_ptr->pass == 4) /* Skip top two generated rows */ - { - for (i = 0; i < 2 && png_ptr->pass == 4; i++) - { - png_push_have_row(png_ptr, NULL); - png_read_push_finish_row(png_ptr); - } - } - - break; - } - - case 4: - { - int i; - - for (i = 0; i < 2 && png_ptr->pass == 4; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } - - for (i = 0; i < 2 && png_ptr->pass == 4; i++) - { - png_push_have_row(png_ptr, NULL); - png_read_push_finish_row(png_ptr); - } - - if (png_ptr->pass == 6) /* Pass 5 might be empty */ - { - png_push_have_row(png_ptr, NULL); - png_read_push_finish_row(png_ptr); - } - - break; - } - - case 5: - { - int i; - - for (i = 0; i < 2 && png_ptr->pass == 5; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } - - if (png_ptr->pass == 6) /* Skip top generated row */ - { - png_push_have_row(png_ptr, NULL); - png_read_push_finish_row(png_ptr); - } - - break; - } - - default: - case 6: - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - - if (png_ptr->pass != 6) - break; - - png_push_have_row(png_ptr, NULL); - png_read_push_finish_row(png_ptr); - } - } - } - else -#endif - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } -} - -void /* PRIVATE */ -png_read_push_finish_row(png_structrp png_ptr) -{ -#ifdef PNG_READ_INTERLACING_SUPPORTED - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - static PNG_CONST png_byte png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - static PNG_CONST png_byte png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - static PNG_CONST png_byte png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - static PNG_CONST png_byte png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; - - /* Height of interlace block. This is not currently used - if you need - * it, uncomment it here and in png.h - static PNG_CONST png_byte png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; - */ -#endif - - png_ptr->row_number++; - if (png_ptr->row_number < png_ptr->num_rows) - return; - -#ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced) - { - png_ptr->row_number = 0; - memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); - - do - { - png_ptr->pass++; - if ((png_ptr->pass == 1 && png_ptr->width < 5) || - (png_ptr->pass == 3 && png_ptr->width < 3) || - (png_ptr->pass == 5 && png_ptr->width < 2)) - png_ptr->pass++; - - if (png_ptr->pass > 7) - png_ptr->pass--; - - if (png_ptr->pass >= 7) - break; - - png_ptr->iwidth = (png_ptr->width + - png_pass_inc[png_ptr->pass] - 1 - - png_pass_start[png_ptr->pass]) / - png_pass_inc[png_ptr->pass]; - - if (png_ptr->transformations & PNG_INTERLACE) - break; - - png_ptr->num_rows = (png_ptr->height + - png_pass_yinc[png_ptr->pass] - 1 - - png_pass_ystart[png_ptr->pass]) / - png_pass_yinc[png_ptr->pass]; - - } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0); - } -#endif /* PNG_READ_INTERLACING_SUPPORTED */ -} - -void /* PRIVATE */ -png_push_have_info(png_structrp png_ptr, png_inforp info_ptr) -{ - if (png_ptr->info_fn != NULL) - (*(png_ptr->info_fn))(png_ptr, info_ptr); -} - -void /* PRIVATE */ -png_push_have_end(png_structrp png_ptr, png_inforp info_ptr) -{ - if (png_ptr->end_fn != NULL) - (*(png_ptr->end_fn))(png_ptr, info_ptr); -} - -void /* PRIVATE */ -png_push_have_row(png_structrp png_ptr, png_bytep row) -{ - if (png_ptr->row_fn != NULL) - (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number, - (int)png_ptr->pass); -} - -#ifdef PNG_READ_INTERLACING_SUPPORTED -void PNGAPI -png_progressive_combine_row(png_const_structrp png_ptr, png_bytep old_row, - png_const_bytep new_row) -{ - if (png_ptr == NULL) - return; - - /* new_row is a flag here - if it is NULL then the app callback was called - * from an empty row (see the calls to png_struct::row_fn below), otherwise - * it must be png_ptr->row_buf+1 - */ - if (new_row != NULL) - png_combine_row(png_ptr, old_row, 1/*display*/); -} -#endif /* PNG_READ_INTERLACING_SUPPORTED */ - -void PNGAPI -png_set_progressive_read_fn(png_structrp png_ptr, png_voidp progressive_ptr, - png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, - png_progressive_end_ptr end_fn) -{ - if (png_ptr == NULL) - return; - - png_ptr->info_fn = info_fn; - png_ptr->row_fn = row_fn; - png_ptr->end_fn = end_fn; - - png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer); -} - -png_voidp PNGAPI -png_get_progressive_ptr(png_const_structrp png_ptr) -{ - if (png_ptr == NULL) - return (NULL); - - return png_ptr->io_ptr; -} -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pngpriv.h b/source/modules/juce_graphics/image_formats/pnglib/pngpriv.h deleted file mode 100644 index a93a87713..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pngpriv.h +++ /dev/null @@ -1,1904 +0,0 @@ - -/* pngpriv.h - private declarations for use inside libpng - * - * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * Last changed in libpng 1.6.1 [March 28, 2013] - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - */ - -/* The symbols declared in this file (including the functions declared - * as extern) are PRIVATE. They are not part of the libpng public - * interface, and are not recommended for use by regular applications. - * Some of them may become public in the future; others may stay private, - * change in an incompatible way, or even disappear. - * Although the libpng users are not forbidden to include this header, - * they should be well aware of the issues that may arise from doing so. - */ - -#ifndef PNGPRIV_H -#define PNGPRIV_H - -/* Feature Test Macros. The following are defined here to ensure that correctly - * implemented libraries reveal the APIs libpng needs to build and hide those - * that are not needed and potentially damaging to the compilation. - * - * Feature Test Macros must be defined before any system header is included (see - * POSIX 1003.1 2.8.2 "POSIX Symbols." - * - * These macros only have an effect if the operating system supports either - * POSIX 1003.1 or C99, or both. On other operating systems (particularly - * Windows/Visual Studio) there is no effect; the OS specific tests below are - * still required (as of 2011-05-02.) - */ -#define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */ - -#ifndef PNG_VERSION_INFO_ONLY -/* Standard library headers not required by png.h: */ -# include -# include -#endif - -#define PNGLIB_BUILD /*libpng is being built, not used*/ - -/* If HAVE_CONFIG_H is defined during the build then the build system must - * provide an appropriate "config.h" file on the include path. The header file - * must provide definitions as required below (search for "HAVE_CONFIG_H"); - * see configure.ac for more details of the requirements. The macro - * "PNG_NO_CONFIG_H" is provided for maintainers to test for dependencies on - * 'configure'; define this macro to prevent the configure build including the - * configure generated config.h. Libpng is expected to compile without *any* - * special build system support on a reasonably ANSI-C compliant system. - */ -#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) -# include - - /* Pick up the definition of 'restrict' from config.h if it was read: */ -# define PNG_RESTRICT restrict -#endif - -/* To support symbol prefixing it is necessary to know *before* including png.h - * whether the fixed point (and maybe other) APIs are exported, because if they - * are not internal definitions may be required. This is handled below just - * before png.h is included, but load the configuration now if it is available. - */ -#ifndef PNGLCONF_H -# include "pnglibconf.h" -#endif - -/* Local renames may change non-exported API functions from png.h */ -#if defined(PNG_PREFIX) && !defined(PNGPREFIX_H) -# include "pngprefix.h" -#endif - -#ifdef PNG_USER_CONFIG -# include "pngusr.h" - /* These should have been defined in pngusr.h */ -# ifndef PNG_USER_PRIVATEBUILD -# define PNG_USER_PRIVATEBUILD "Custom libpng build" -# endif -# ifndef PNG_USER_DLLFNAME_POSTFIX -# define PNG_USER_DLLFNAME_POSTFIX "Cb" -# endif -#endif - -/* Is this a build of a DLL where compilation of the object modules requires - * different preprocessor settings to those required for a simple library? If - * so PNG_BUILD_DLL must be set. - * - * If libpng is used inside a DLL but that DLL does not export the libpng APIs - * PNG_BUILD_DLL must not be set. To avoid the code below kicking in build a - * static library of libpng then link the DLL against that. - */ -#ifndef PNG_BUILD_DLL -# ifdef DLL_EXPORT - /* This is set by libtool when files are compiled for a DLL; libtool - * always compiles twice, even on systems where it isn't necessary. Set - * PNG_BUILD_DLL in case it is necessary: - */ -# define PNG_BUILD_DLL -# else -# ifdef _WINDLL - /* This is set by the Microsoft Visual Studio IDE in projects that - * build a DLL. It can't easily be removed from those projects (it - * isn't visible in the Visual Studio UI) so it is a fairly reliable - * indication that PNG_IMPEXP needs to be set to the DLL export - * attributes. - */ -# define PNG_BUILD_DLL -# else -# ifdef __DLL__ - /* This is set by the Borland C system when compiling for a DLL - * (as above.) - */ -# define PNG_BUILD_DLL -# else - /* Add additional compiler cases here. */ -# endif -# endif -# endif -#endif /* Setting PNG_BUILD_DLL if required */ - -/* See pngconf.h for more details: the builder of the library may set this on - * the command line to the right thing for the specific compilation system or it - * may be automagically set above (at present we know of no system where it does - * need to be set on the command line.) - * - * PNG_IMPEXP must be set here when building the library to prevent pngconf.h - * setting it to the "import" setting for a DLL build. - */ -#ifndef PNG_IMPEXP -# ifdef PNG_BUILD_DLL -# define PNG_IMPEXP PNG_DLL_EXPORT -# else - /* Not building a DLL, or the DLL doesn't require specific export - * definitions. - */ -# define PNG_IMPEXP -# endif -#endif - -/* No warnings for private or deprecated functions in the build: */ -#ifndef PNG_DEPRECATED -# define PNG_DEPRECATED -#endif -#ifndef PNG_PRIVATE -# define PNG_PRIVATE -#endif - -/* Symbol preprocessing support. - * - * To enable listing global, but internal, symbols the following macros should - * always be used to declare an extern data or function object in this file. - */ -#ifndef PNG_INTERNAL_DATA -# define PNG_INTERNAL_DATA(type, name, array) extern type name array -#endif - -#ifndef PNG_INTERNAL_FUNCTION -# define PNG_INTERNAL_FUNCTION(type, name, args, attributes)\ - extern PNG_FUNCTION(type, name, args, PNG_EMPTY attributes) -#endif - -/* If floating or fixed point APIs are disabled they may still be compiled - * internally. To handle this make sure they are declared as the appropriate - * internal extern function (otherwise the symbol prefixing stuff won't work and - * the functions will be used without definitions.) - * - * NOTE: although all the API functions are declared here they are not all - * actually built! Because the declarations are still made it is necessary to - * fake out types that they depend on. - */ -#ifndef PNG_FP_EXPORT -# ifndef PNG_FLOATING_POINT_SUPPORTED -# define PNG_FP_EXPORT(ordinal, type, name, args)\ - PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY); -# ifndef PNG_VERSION_INFO_ONLY - typedef struct png_incomplete png_double; - typedef png_double* png_doublep; - typedef const png_double* png_const_doublep; - typedef png_double** png_doublepp; -# endif -# endif -#endif -#ifndef PNG_FIXED_EXPORT -# ifndef PNG_FIXED_POINT_SUPPORTED -# define PNG_FIXED_EXPORT(ordinal, type, name, args)\ - PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY); -# endif -#endif - -#include "png.h" - -/* pngconf.h does not set PNG_DLL_EXPORT unless it is required, so: */ -#ifndef PNG_DLL_EXPORT -# define PNG_DLL_EXPORT -#endif - -/* SECURITY and SAFETY: - * - * By default libpng is built without any internal limits on image size, - * individual heap (png_malloc) allocations or the total amount of memory used. - * If PNG_SAFE_LIMITS_SUPPORTED is defined, however, the limits below are used - * (unless individually overridden). These limits are believed to be fairly - * safe, but builders of secure systems should verify the values against the - * real system capabilities. - */ -#ifdef PNG_SAFE_LIMITS_SUPPORTED - /* 'safe' limits */ -# ifndef PNG_USER_WIDTH_MAX -# define PNG_USER_WIDTH_MAX 1000000 -# endif -# ifndef PNG_USER_HEIGHT_MAX -# define PNG_USER_HEIGHT_MAX 1000000 -# endif -# ifndef PNG_USER_CHUNK_CACHE_MAX -# define PNG_USER_CHUNK_CACHE_MAX 128 -# endif -# ifndef PNG_USER_CHUNK_MALLOC_MAX -# define PNG_USER_CHUNK_MALLOC_MAX 8000000 -# endif -#else - /* values for no limits */ -# ifndef PNG_USER_WIDTH_MAX -# define PNG_USER_WIDTH_MAX 0x7fffffff -# endif -# ifndef PNG_USER_HEIGHT_MAX -# define PNG_USER_HEIGHT_MAX 0x7fffffff -# endif -# ifndef PNG_USER_CHUNK_CACHE_MAX -# define PNG_USER_CHUNK_CACHE_MAX 0 -# endif -# ifndef PNG_USER_CHUNK_MALLOC_MAX -# define PNG_USER_CHUNK_MALLOC_MAX 0 -# endif -#endif - -/* Moved to pngpriv.h at libpng-1.5.0 */ -/* NOTE: some of these may have been used in external applications as - * these definitions were exposed in pngconf.h prior to 1.5. - */ - -/* If you are running on a machine where you cannot allocate more - * than 64K of memory at once, uncomment this. While libpng will not - * normally need that much memory in a chunk (unless you load up a very - * large file), zlib needs to know how big of a chunk it can use, and - * libpng thus makes sure to check any memory allocation to verify it - * will fit into memory. - * - * zlib provides 'MAXSEG_64K' which, if defined, indicates the - * same limit and pngconf.h (already included) sets the limit - * if certain operating systems are detected. - */ -#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) -# define PNG_MAX_MALLOC_64K -#endif - -#ifndef PNG_UNUSED -/* Unused formal parameter warnings are silenced using the following macro - * which is expected to have no bad effects on performance (optimizing - * compilers will probably remove it entirely). Note that if you replace - * it with something other than whitespace, you must include the terminating - * semicolon. - */ -# define PNG_UNUSED(param) (void)param; -#endif - -/* Just a little check that someone hasn't tried to define something - * contradictory. - */ -#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K) -# undef PNG_ZBUF_SIZE -# define PNG_ZBUF_SIZE 65536L -#endif - -/* If warnings or errors are turned off the code is disabled or redirected here. - * From 1.5.4 functions have been added to allow very limited formatting of - * error and warning messages - this code will also be disabled here. - */ -#ifdef PNG_WARNINGS_SUPPORTED -# define PNG_WARNING_PARAMETERS(p) png_warning_parameters p; -#else -# define png_warning(s1,s2) ((void)(s1)) -# define png_chunk_warning(s1,s2) ((void)(s1)) -# define png_warning_parameter(p,number,string) ((void)0) -# define png_warning_parameter_unsigned(p,number,format,value) ((void)0) -# define png_warning_parameter_signed(p,number,format,value) ((void)0) -# define png_formatted_warning(pp,p,message) ((void)(pp)) -# define PNG_WARNING_PARAMETERS(p) -#endif -#ifndef PNG_ERROR_TEXT_SUPPORTED -# define png_error(s1,s2) png_err(s1) -# define png_chunk_error(s1,s2) png_err(s1) -# define png_fixed_error(s1,s2) png_err(s1) -#endif - -/* C allows up-casts from (void*) to any pointer and (const void*) to any - * pointer to a const object. C++ regards this as a type error and requires an - * explicit, static, cast and provides the static_cast<> rune to ensure that - * const is not cast away. - */ -#ifdef __cplusplus -# define png_voidcast(type, value) static_cast(value) -# define png_constcast(type, value) const_cast(value) -# define png_aligncast(type, value) \ - static_cast(static_cast(value)) -# define png_aligncastconst(type, value) \ - static_cast(static_cast(value)) -#else -# define png_voidcast(type, value) (value) -# define png_constcast(type, value) ((type)(value)) -# define png_aligncast(type, value) ((void*)(value)) -# define png_aligncastconst(type, value) ((const void*)(value)) -#endif /* __cplusplus */ - -/* Some fixed point APIs are still required even if not exported because - * they get used by the corresponding floating point APIs. This magic - * deals with this: - */ -#ifdef PNG_FIXED_POINT_SUPPORTED -# define PNGFAPI PNGAPI -#else -# define PNGFAPI /* PRIVATE */ -#endif - -#ifndef PNG_VERSION_INFO_ONLY -/* Other defines specific to compilers can go here. Try to keep - * them inside an appropriate ifdef/endif pair for portability. - */ -#if defined(PNG_FLOATING_POINT_SUPPORTED) ||\ - defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) - /* png.c requires the following ANSI-C constants if the conversion of - * floating point to ASCII is implemented therein: - * - * DBL_DIG Maximum number of decimal digits (can be set to any constant) - * DBL_MIN Smallest normalized fp number (can be set to an arbitrary value) - * DBL_MAX Maximum floating point number (can be set to an arbitrary value) - */ -# include - -# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \ - defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC) - /* We need to check that hasn't already been included earlier - * as it seems it doesn't agree with , yet we should really use - * if possible. - */ -# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__) -# include -# endif -# else -# include -# endif -# if defined(_AMIGA) && defined(__SASC) && defined(_M68881) - /* Amiga SAS/C: We must include builtin FPU functions when compiling using - * MATH=68881 - */ -# include -# endif -#endif - -/* This provides the non-ANSI (far) memory allocation routines. */ -#if defined(__TURBOC__) && defined(__MSDOS__) -# include -# include -#endif - -#if defined(WIN32) || defined(_Windows) || defined(_WINDOWS) || \ - defined(_WIN32) || defined(__WIN32__) -# include /* defines _WINDOWS_ macro */ -#endif -#endif /* PNG_VERSION_INFO_ONLY */ - -/* Moved here around 1.5.0beta36 from pngconf.h */ -/* Users may want to use these so they are not private. Any library - * functions that are passed far data must be model-independent. - */ - -/* Memory model/platform independent fns */ -#ifndef PNG_ABORT -# ifdef _WINDOWS_ -# define PNG_ABORT() ExitProcess(0) -# else -# define PNG_ABORT() abort() -# endif -#endif - -/* These macros may need to be architecture dependent. */ -#define PNG_ALIGN_NONE 0 /* do not use data alignment */ -#define PNG_ALIGN_ALWAYS 1 /* assume unaligned accesses are OK */ -#ifdef offsetof -# define PNG_ALIGN_OFFSET 2 /* use offsetof to determine alignment */ -#else -# define PNG_ALIGN_OFFSET -1 /* prevent the use of this */ -#endif -#define PNG_ALIGN_SIZE 3 /* use sizeof to determine alignment */ - -#ifndef PNG_ALIGN_TYPE - /* Default to using aligned access optimizations and requiring alignment to a - * multiple of the data type size. Override in a compiler specific fashion - * if necessary by inserting tests here: - */ -# define PNG_ALIGN_TYPE PNG_ALIGN_SIZE -#endif - -#if PNG_ALIGN_TYPE == PNG_ALIGN_SIZE - /* This is used because in some compiler implementations non-aligned - * structure members are supported, so the offsetof approach below fails. - * Set PNG_ALIGN_SIZE=0 for compiler combinations where unaligned access - * is good for performance. Do not do this unless you have tested the result - * and understand it. - */ -# define png_alignof(type) (sizeof (type)) -#else -# if PNG_ALIGN_TYPE == PNG_ALIGN_OFFSET -# define png_alignof(type) offsetof(struct{char c; type t;}, t) -# else -# if PNG_ALIGN_TYPE == PNG_ALIGN_ALWAYS -# define png_alignof(type) (1) -# endif - /* Else leave png_alignof undefined to prevent use thereof */ -# endif -#endif - -/* This implicitly assumes alignment is always to a power of 2. */ -#ifdef png_alignof -# define png_isaligned(ptr, type)\ - ((((const char*)ptr-(const char*)0) & (png_alignof(type)-1)) == 0) -#else -# define png_isaligned(ptr, type) 0 -#endif - -/* End of memory model/platform independent support */ -/* End of 1.5.0beta36 move from pngconf.h */ - -/* CONSTANTS and UTILITY MACROS - * These are used internally by libpng and not exposed in the API - */ - -/* Various modes of operation. Note that after an init, mode is set to - * zero automatically when the structure is created. Three of these - * are defined in png.h because they need to be visible to applications - * that call png_set_unknown_chunk(). - */ -/* #define PNG_HAVE_IHDR 0x01 (defined in png.h) */ -/* #define PNG_HAVE_PLTE 0x02 (defined in png.h) */ -#define PNG_HAVE_IDAT 0x04 -/* #define PNG_AFTER_IDAT 0x08 (defined in png.h) */ -#define PNG_HAVE_IEND 0x10 - /* 0x20 (unused) */ - /* 0x40 (unused) */ - /* 0x80 (unused) */ -#define PNG_HAVE_CHUNK_HEADER 0x100 -#define PNG_WROTE_tIME 0x200 -#define PNG_WROTE_INFO_BEFORE_PLTE 0x400 -#define PNG_BACKGROUND_IS_GRAY 0x800 -#define PNG_HAVE_PNG_SIGNATURE 0x1000 -#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */ - /* 0x4000 (unused) */ -#define PNG_IS_READ_STRUCT 0x8000 /* Else is a write struct */ - -/* Flags for the transformations the PNG library does on the image data */ -#define PNG_BGR 0x0001 -#define PNG_INTERLACE 0x0002 -#define PNG_PACK 0x0004 -#define PNG_SHIFT 0x0008 -#define PNG_SWAP_BYTES 0x0010 -#define PNG_INVERT_MONO 0x0020 -#define PNG_QUANTIZE 0x0040 -#define PNG_COMPOSE 0x0080 /* Was PNG_BACKGROUND */ -#define PNG_BACKGROUND_EXPAND 0x0100 -#define PNG_EXPAND_16 0x0200 /* Added to libpng 1.5.2 */ -#define PNG_16_TO_8 0x0400 /* Becomes 'chop' in 1.5.4 */ -#define PNG_RGBA 0x0800 -#define PNG_EXPAND 0x1000 -#define PNG_GAMMA 0x2000 -#define PNG_GRAY_TO_RGB 0x4000 -#define PNG_FILLER 0x8000 -#define PNG_PACKSWAP 0x10000 -#define PNG_SWAP_ALPHA 0x20000 -#define PNG_STRIP_ALPHA 0x40000 -#define PNG_INVERT_ALPHA 0x80000 -#define PNG_USER_TRANSFORM 0x100000 -#define PNG_RGB_TO_GRAY_ERR 0x200000 -#define PNG_RGB_TO_GRAY_WARN 0x400000 -#define PNG_RGB_TO_GRAY 0x600000 /* two bits, RGB_TO_GRAY_ERR|WARN */ -#define PNG_ENCODE_ALPHA 0x800000 /* Added to libpng-1.5.4 */ -#define PNG_ADD_ALPHA 0x1000000 /* Added to libpng-1.2.7 */ -#define PNG_EXPAND_tRNS 0x2000000 /* Added to libpng-1.2.9 */ -#define PNG_SCALE_16_TO_8 0x4000000 /* Added to libpng-1.5.4 */ - /* 0x8000000 unused */ - /* 0x10000000 unused */ - /* 0x20000000 unused */ - /* 0x40000000 unused */ -/* Flags for png_create_struct */ -#define PNG_STRUCT_PNG 0x0001 -#define PNG_STRUCT_INFO 0x0002 - -/* Scaling factor for filter heuristic weighting calculations */ -#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT)) -#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT)) - -/* Flags for the png_ptr->flags rather than declaring a byte for each one */ -#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001 -#define PNG_FLAG_ZSTREAM_INITIALIZED 0x0002 /* Added to libpng-1.6.0 */ - /* 0x0004 unused */ -#define PNG_FLAG_ZSTREAM_ENDED 0x0008 /* Added to libpng-1.6.0 */ - /* 0x0010 unused */ - /* 0x0020 unused */ -#define PNG_FLAG_ROW_INIT 0x0040 -#define PNG_FLAG_FILLER_AFTER 0x0080 -#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100 -#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200 -#define PNG_FLAG_CRC_CRITICAL_USE 0x0400 -#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 -#define PNG_FLAG_ASSUME_sRGB 0x1000 /* Added to libpng-1.5.4 */ -#define PNG_FLAG_OPTIMIZE_ALPHA 0x2000 /* Added to libpng-1.5.4 */ -#define PNG_FLAG_DETECT_UNINITIALIZED 0x4000 /* Added to libpng-1.5.4 */ -/* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000 */ -/* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000 */ -#define PNG_FLAG_LIBRARY_MISMATCH 0x20000 -#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000 -#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000 -#define PNG_FLAG_BENIGN_ERRORS_WARN 0x100000 /* Added to libpng-1.4.0 */ -#define PNG_FLAG_APP_WARNINGS_WARN 0x200000 /* Added to libpng-1.6.0 */ -#define PNG_FLAG_APP_ERRORS_WARN 0x400000 /* Added to libpng-1.6.0 */ - /* 0x800000 unused */ - /* 0x1000000 unused */ - /* 0x2000000 unused */ - /* 0x4000000 unused */ - /* 0x8000000 unused */ - /* 0x10000000 unused */ - /* 0x20000000 unused */ - /* 0x40000000 unused */ - -#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ - PNG_FLAG_CRC_ANCILLARY_NOWARN) - -#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \ - PNG_FLAG_CRC_CRITICAL_IGNORE) - -#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \ - PNG_FLAG_CRC_CRITICAL_MASK) - -/* Save typing and make code easier to understand */ - -#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ - abs((int)((c1).green) - (int)((c2).green)) + \ - abs((int)((c1).blue) - (int)((c2).blue))) - -/* Added to libpng-1.6.0: scale a 16-bit value in the range 0..65535 to 0..255 - * by dividing by 257 *with rounding*. This macro is exact for the given range. - * See the discourse in pngrtran.c png_do_scale_16_to_8. The values in the - * macro were established by experiment (modifying the added value). The macro - * has a second variant that takes a value already scaled by 255 and divides by - * 65535 - this has a maximum error of .502. Over the range 0..65535*65535 it - * only gives off-by-one errors and only for 0.5% (1 in 200) of the values. - */ -#define PNG_DIV65535(v24) (((v24) + 32895) >> 16) -#define PNG_DIV257(v16) PNG_DIV65535((png_uint_32)(v16) * 255) - -/* Added to libpng-1.2.6 JB */ -#define PNG_ROWBYTES(pixel_bits, width) \ - ((pixel_bits) >= 8 ? \ - ((png_size_t)(width) * (((png_size_t)(pixel_bits)) >> 3)) : \ - (( ((png_size_t)(width) * ((png_size_t)(pixel_bits))) + 7) >> 3) ) - -/* PNG_OUT_OF_RANGE returns true if value is outside the range - * ideal-delta..ideal+delta. Each argument is evaluated twice. - * "ideal" and "delta" should be constants, normally simple - * integers, "value" a variable. Added to libpng-1.2.6 JB - */ -#define PNG_OUT_OF_RANGE(value, ideal, delta) \ - ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) ) - -/* Conversions between fixed and floating point, only defined if - * required (to make sure the code doesn't accidentally use float - * when it is supposedly disabled.) - */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -/* The floating point conversion can't overflow, though it can and - * does lose accuracy relative to the original fixed point value. - * In practice this doesn't matter because png_fixed_point only - * stores numbers with very low precision. The png_ptr and s - * arguments are unused by default but are there in case error - * checking becomes a requirement. - */ -#define png_float(png_ptr, fixed, s) (.00001 * (fixed)) - -/* The fixed point conversion performs range checking and evaluates - * its argument multiple times, so must be used with care. The - * range checking uses the PNG specification values for a signed - * 32 bit fixed point value except that the values are deliberately - * rounded-to-zero to an integral value - 21474 (21474.83 is roughly - * (2^31-1) * 100000). 's' is a string that describes the value being - * converted. - * - * NOTE: this macro will raise a png_error if the range check fails, - * therefore it is normally only appropriate to use this on values - * that come from API calls or other sources where an out of range - * error indicates a programming error, not a data error! - * - * NOTE: by default this is off - the macro is not used - because the - * function call saves a lot of code. - */ -#ifdef PNG_FIXED_POINT_MACRO_SUPPORTED -#define png_fixed(png_ptr, fp, s) ((fp) <= 21474 && (fp) >= -21474 ?\ - ((png_fixed_point)(100000 * (fp))) : (png_fixed_error(png_ptr, s),0)) -#endif -/* else the corresponding function is defined below, inside the scope of the - * cplusplus test. - */ -#endif - -/* Constants for known chunk types. If you need to add a chunk, define the name - * here. For historical reasons these constants have the form png_; i.e. - * the prefix is lower case. Please use decimal values as the parameters to - * match the ISO PNG specification and to avoid relying on the C locale - * interpretation of character values. - * - * Prior to 1.5.6 these constants were strings, as of 1.5.6 png_uint_32 values - * are computed and a new macro (PNG_STRING_FROM_CHUNK) added to allow a string - * to be generated if required. - * - * PNG_32b correctly produces a value shifted by up to 24 bits, even on - * architectures where (int) is only 16 bits. - */ -#define PNG_32b(b,s) ((png_uint_32)(b) << (s)) -#define PNG_CHUNK(b1,b2,b3,b4) \ - (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0)) - -#define png_IHDR PNG_CHUNK( 73, 72, 68, 82) -#define png_IDAT PNG_CHUNK( 73, 68, 65, 84) -#define png_IEND PNG_CHUNK( 73, 69, 78, 68) -#define png_PLTE PNG_CHUNK( 80, 76, 84, 69) -#define png_bKGD PNG_CHUNK( 98, 75, 71, 68) -#define png_cHRM PNG_CHUNK( 99, 72, 82, 77) -#define png_gAMA PNG_CHUNK(103, 65, 77, 65) -#define png_hIST PNG_CHUNK(104, 73, 83, 84) -#define png_iCCP PNG_CHUNK(105, 67, 67, 80) -#define png_iTXt PNG_CHUNK(105, 84, 88, 116) -#define png_oFFs PNG_CHUNK(111, 70, 70, 115) -#define png_pCAL PNG_CHUNK(112, 67, 65, 76) -#define png_sCAL PNG_CHUNK(115, 67, 65, 76) -#define png_pHYs PNG_CHUNK(112, 72, 89, 115) -#define png_sBIT PNG_CHUNK(115, 66, 73, 84) -#define png_sPLT PNG_CHUNK(115, 80, 76, 84) -#define png_sRGB PNG_CHUNK(115, 82, 71, 66) -#define png_sTER PNG_CHUNK(115, 84, 69, 82) -#define png_tEXt PNG_CHUNK(116, 69, 88, 116) -#define png_tIME PNG_CHUNK(116, 73, 77, 69) -#define png_tRNS PNG_CHUNK(116, 82, 78, 83) -#define png_zTXt PNG_CHUNK(122, 84, 88, 116) - -/* The following will work on (signed char*) strings, whereas the get_uint_32 - * macro will fail on top-bit-set values because of the sign extension. - */ -#define PNG_CHUNK_FROM_STRING(s)\ - PNG_CHUNK(0xff&(s)[0], 0xff&(s)[1], 0xff&(s)[2], 0xff&(s)[3]) - -/* This uses (char), not (png_byte) to avoid warnings on systems where (char) is - * signed and the argument is a (char[]) This macro will fail miserably on - * systems where (char) is more than 8 bits. - */ -#define PNG_STRING_FROM_CHUNK(s,c)\ - (void)(((char*)(s))[0]=(char)((c)>>24), ((char*)(s))[1]=(char)((c)>>16),\ - ((char*)(s))[2]=(char)((c)>>8), ((char*)(s))[3]=(char)((c))) - -/* Do the same but terminate with a null character. */ -#define PNG_CSTRING_FROM_CHUNK(s,c)\ - (void)(PNG_STRING_FROM_CHUNK(s,c), ((char*)(s))[4] = 0) - -/* Test on flag values as defined in the spec (section 5.4): */ -#define PNG_CHUNK_ANCILLIARY(c) (1 & ((c) >> 29)) -#define PNG_CHUNK_CRITICAL(c) (!PNG_CHUNK_ANCILLIARY(c)) -#define PNG_CHUNK_PRIVATE(c) (1 & ((c) >> 21)) -#define PNG_CHUNK_RESERVED(c) (1 & ((c) >> 13)) -#define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >> 5)) - -/* Gamma values (new at libpng-1.5.4): */ -#define PNG_GAMMA_MAC_OLD 151724 /* Assume '1.8' is really 2.2/1.45! */ -#define PNG_GAMMA_MAC_INVERSE 65909 -#define PNG_GAMMA_sRGB_INVERSE 45455 - -/* Almost everything below is C specific; the #defines above can be used in - * non-C code (so long as it is C-preprocessed) the rest of this stuff cannot. - */ -#ifndef PNG_VERSION_INFO_ONLY - -#include "pngstruct.h" -#include "pnginfo.h" - -/* This is used for 16 bit gamma tables -- only the top level pointers are - * const; this could be changed: - */ -typedef const png_uint_16p * png_const_uint_16pp; - -/* Added to libpng-1.5.7: sRGB conversion tables */ -#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ - defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) -#ifdef PNG_SIMPLIFIED_READ_SUPPORTED -PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_table, [256]); - /* Convert from an sRGB encoded value 0..255 to a 16-bit linear value, - * 0..65535. This table gives the closest 16-bit answers (no errors). - */ -#endif - -PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_base, [512]); -PNG_INTERNAL_DATA(const png_byte, png_sRGB_delta, [512]); - -#define PNG_sRGB_FROM_LINEAR(linear) ((png_byte)((png_sRGB_base[(linear)>>15] +\ - ((((linear)&0x7fff)*png_sRGB_delta[(linear)>>15])>>12)) >> 8)) - /* Given a value 'linear' in the range 0..255*65535 calculate the 8-bit sRGB - * encoded value with maximum error 0.646365. Note that the input is not a - * 16-bit value; it has been multiplied by 255! */ -#endif /* PNG_SIMPLIFIED_READ/WRITE */ - - -/* Internal functions; these are not exported from a DLL however because they - * are used within several of the C source files they have to be C extern. - * - * All of these functions must be declared with PNG_INTERNAL_FUNCTION. - */ - -/* Zlib support */ -#define PNG_UNEXPECTED_ZLIB_RETURN (-7) -PNG_INTERNAL_FUNCTION(void, png_zstream_error,(png_structrp png_ptr, int ret), - PNG_EMPTY); - /* Used by the zlib handling functions to ensure that z_stream::msg is always - * set before they return. - */ - -#ifdef PNG_WRITE_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr, - png_compression_bufferp *list),PNG_EMPTY); - /* Free the buffer list used by the compressed write code. */ -#endif - -#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ - !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ - (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \ - defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \ - defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \ - (defined(PNG_sCAL_SUPPORTED) && \ - defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)) -PNG_INTERNAL_FUNCTION(png_fixed_point,png_fixed,(png_const_structrp png_ptr, - double fp, png_const_charp text),PNG_EMPTY); -#endif - -/* Check the user version string for compatibility, returns false if the version - * numbers aren't compatible. - */ -PNG_INTERNAL_FUNCTION(int,png_user_version_check,(png_structrp png_ptr, - png_const_charp user_png_ver),PNG_EMPTY); - -/* Internal base allocator - no messages, NULL on failure to allocate. This - * does, however, call the application provided allocator and that could call - * png_error (although that would be a bug in the application implementation.) - */ -PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_base,(png_const_structrp png_ptr, - png_alloc_size_t size),PNG_ALLOCATED); - -#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\ - defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) -/* Internal array allocator, outputs no error or warning messages on failure, - * just returns NULL. - */ -PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_array,(png_const_structrp png_ptr, - int nelements, size_t element_size),PNG_ALLOCATED); - -/* The same but an existing array is extended by add_elements. This function - * also memsets the new elements to 0 and copies the old elements. The old - * array is not freed or altered. - */ -PNG_INTERNAL_FUNCTION(png_voidp,png_realloc_array,(png_const_structrp png_ptr, - png_const_voidp array, int old_elements, int add_elements, - size_t element_size),PNG_ALLOCATED); -#endif /* text, sPLT or unknown chunks */ - -/* Magic to create a struct when there is no struct to call the user supplied - * memory allocators. Because error handling has not been set up the memory - * handlers can't safely call png_error, but this is an obscure and undocumented - * restriction so libpng has to assume that the 'free' handler, at least, might - * call png_error. - */ -PNG_INTERNAL_FUNCTION(png_structp,png_create_png_struct, - (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, - png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, - png_free_ptr free_fn),PNG_ALLOCATED); - -/* Free memory from internal libpng struct */ -PNG_INTERNAL_FUNCTION(void,png_destroy_png_struct,(png_structrp png_ptr), - PNG_EMPTY); - -/* Free an allocated jmp_buf (always succeeds) */ -PNG_INTERNAL_FUNCTION(void,png_free_jmpbuf,(png_structrp png_ptr),PNG_EMPTY); - -/* Function to allocate memory for zlib. PNGAPI is disallowed. */ -PNG_INTERNAL_FUNCTION(voidpf,png_zalloc,(voidpf png_ptr, uInt items, uInt size), - PNG_ALLOCATED); - -/* Function to free memory for zlib. PNGAPI is disallowed. */ -PNG_INTERNAL_FUNCTION(void,png_zfree,(voidpf png_ptr, voidpf ptr),PNG_EMPTY); - -/* Next four functions are used internally as callbacks. PNGCBAPI is required - * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3, changed to - * PNGCBAPI at 1.5.0 - */ - -PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_read_data,(png_structp png_ptr, - png_bytep data, png_size_t length),PNG_EMPTY); - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_push_fill_buffer,(png_structp png_ptr, - png_bytep buffer, png_size_t length),PNG_EMPTY); -#endif - -PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_write_data,(png_structp png_ptr, - png_bytep data, png_size_t length),PNG_EMPTY); - -#ifdef PNG_WRITE_FLUSH_SUPPORTED -# ifdef PNG_STDIO_SUPPORTED -PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_flush,(png_structp png_ptr), - PNG_EMPTY); -# endif -#endif - -/* Reset the CRC variable */ -PNG_INTERNAL_FUNCTION(void,png_reset_crc,(png_structrp png_ptr),PNG_EMPTY); - -/* Write the "data" buffer to whatever output you are using */ -PNG_INTERNAL_FUNCTION(void,png_write_data,(png_structrp png_ptr, - png_const_bytep data, png_size_t length),PNG_EMPTY); - -/* Read and check the PNG file signature */ -PNG_INTERNAL_FUNCTION(void,png_read_sig,(png_structrp png_ptr, - png_inforp info_ptr),PNG_EMPTY); - -/* Read the chunk header (length + type name) */ -PNG_INTERNAL_FUNCTION(png_uint_32,png_read_chunk_header,(png_structrp png_ptr), - PNG_EMPTY); - -/* Read data from whatever input you are using into the "data" buffer */ -PNG_INTERNAL_FUNCTION(void,png_read_data,(png_structrp png_ptr, png_bytep data, - png_size_t length),PNG_EMPTY); - -/* Read bytes into buf, and update png_ptr->crc */ -PNG_INTERNAL_FUNCTION(void,png_crc_read,(png_structrp png_ptr, png_bytep buf, - png_uint_32 length),PNG_EMPTY); - -/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ -PNG_INTERNAL_FUNCTION(int,png_crc_finish,(png_structrp png_ptr, - png_uint_32 skip),PNG_EMPTY); - -/* Read the CRC from the file and compare it to the libpng calculated CRC */ -PNG_INTERNAL_FUNCTION(int,png_crc_error,(png_structrp png_ptr),PNG_EMPTY); - -/* Calculate the CRC over a section of data. Note that we are only - * passing a maximum of 64K on systems that have this as a memory limit, - * since this is the maximum buffer size we can specify. - */ -PNG_INTERNAL_FUNCTION(void,png_calculate_crc,(png_structrp png_ptr, - png_const_bytep ptr, png_size_t length),PNG_EMPTY); - -#ifdef PNG_WRITE_FLUSH_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_flush,(png_structrp png_ptr),PNG_EMPTY); -#endif - -/* Write various chunks */ - -/* Write the IHDR chunk, and update the png_struct with the necessary - * information. - */ -PNG_INTERNAL_FUNCTION(void,png_write_IHDR,(png_structrp png_ptr, - png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, - int compression_method, int filter_method, int interlace_method),PNG_EMPTY); - -PNG_INTERNAL_FUNCTION(void,png_write_PLTE,(png_structrp png_ptr, - png_const_colorp palette, png_uint_32 num_pal),PNG_EMPTY); - -PNG_INTERNAL_FUNCTION(void,png_compress_IDAT,(png_structrp png_ptr, - png_const_bytep row_data, png_alloc_size_t row_data_length, int flush), - PNG_EMPTY); - -PNG_INTERNAL_FUNCTION(void,png_write_IEND,(png_structrp png_ptr),PNG_EMPTY); - -#ifdef PNG_WRITE_gAMA_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_gAMA_fixed,(png_structrp png_ptr, - png_fixed_point file_gamma),PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_sBIT_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_sBIT,(png_structrp png_ptr, - png_const_color_8p sbit, int color_type),PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_cHRM_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_cHRM_fixed,(png_structrp png_ptr, - const png_xy *xy), PNG_EMPTY); - /* The xy value must have been previously validated */ -#endif - -#ifdef PNG_WRITE_sRGB_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr, - int intent),PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_iCCP_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_iCCP,(png_structrp png_ptr, - png_const_charp name, png_const_bytep profile), PNG_EMPTY); - /* The profile must have been previously validated for correctness, the - * length comes from the first four bytes. Only the base, deflate, - * compression is supported. - */ -#endif - -#ifdef PNG_WRITE_sPLT_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_sPLT,(png_structrp png_ptr, - png_const_sPLT_tp palette),PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_tRNS_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_tRNS,(png_structrp png_ptr, - png_const_bytep trans, png_const_color_16p values, int number, - int color_type),PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_bKGD_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_bKGD,(png_structrp png_ptr, - png_const_color_16p values, int color_type),PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_hIST_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_hIST,(png_structrp png_ptr, - png_const_uint_16p hist, int num_hist),PNG_EMPTY); -#endif - -/* Chunks that have keywords */ -#ifdef PNG_WRITE_tEXt_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_tEXt,(png_structrp png_ptr, - png_const_charp key, png_const_charp text, png_size_t text_len),PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_zTXt_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_zTXt,(png_structrp png_ptr, png_const_charp - key, png_const_charp text, png_size_t text_len, int compression),PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_iTXt_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_iTXt,(png_structrp png_ptr, - int compression, png_const_charp key, png_const_charp lang, - png_const_charp lang_key, png_const_charp text),PNG_EMPTY); -#endif - -#ifdef PNG_TEXT_SUPPORTED /* Added at version 1.0.14 and 1.2.4 */ -PNG_INTERNAL_FUNCTION(int,png_set_text_2,(png_const_structrp png_ptr, - png_inforp info_ptr, png_const_textp text_ptr, int num_text),PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_oFFs_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_oFFs,(png_structrp png_ptr, - png_int_32 x_offset, png_int_32 y_offset, int unit_type),PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_pCAL_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_pCAL,(png_structrp png_ptr, - png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, - png_const_charp units, png_charpp params),PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_pHYs_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_pHYs,(png_structrp png_ptr, - png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, - int unit_type),PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_tIME_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_tIME,(png_structrp png_ptr, - png_const_timep mod_time),PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_sCAL_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr, - int unit, png_const_charp width, png_const_charp height),PNG_EMPTY); -#endif - -/* Called when finished processing a row of data */ -PNG_INTERNAL_FUNCTION(void,png_write_finish_row,(png_structrp png_ptr), - PNG_EMPTY); - -/* Internal use only. Called before first row of data */ -PNG_INTERNAL_FUNCTION(void,png_write_start_row,(png_structrp png_ptr), - PNG_EMPTY); - -/* Combine a row of data, dealing with alpha, etc. if requested. 'row' is an - * array of png_ptr->width pixels. If the image is not interlaced or this - * is the final pass this just does a memcpy, otherwise the "display" flag - * is used to determine whether to copy pixels that are not in the current pass. - * - * Because 'png_do_read_interlace' (below) replicates pixels this allows this - * function to achieve the documented 'blocky' appearance during interlaced read - * if display is 1 and the 'sparkle' appearance, where existing pixels in 'row' - * are not changed if they are not in the current pass, when display is 0. - * - * 'display' must be 0 or 1, otherwise the memcpy will be done regardless. - * - * The API always reads from the png_struct row buffer and always assumes that - * it is full width (png_do_read_interlace has already been called.) - * - * This function is only ever used to write to row buffers provided by the - * caller of the relevant libpng API and the row must have already been - * transformed by the read transformations. - * - * The PNG_USE_COMPILE_TIME_MASKS option causes generation of pre-computed - * bitmasks for use within the code, otherwise runtime generated masks are used. - * The default is compile time masks. - */ -#ifndef PNG_USE_COMPILE_TIME_MASKS -# define PNG_USE_COMPILE_TIME_MASKS 1 -#endif -PNG_INTERNAL_FUNCTION(void,png_combine_row,(png_const_structrp png_ptr, - png_bytep row, int display),PNG_EMPTY); - -#ifdef PNG_READ_INTERLACING_SUPPORTED -/* Expand an interlaced row: the 'row_info' describes the pass data that has - * been read in and must correspond to the pixels in 'row', the pixels are - * expanded (moved apart) in 'row' to match the final layout, when doing this - * the pixels are *replicated* to the intervening space. This is essential for - * the correct operation of png_combine_row, above. - */ -PNG_INTERNAL_FUNCTION(void,png_do_read_interlace,(png_row_infop row_info, - png_bytep row, int pass, png_uint_32 transformations),PNG_EMPTY); -#endif - -/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ - -#ifdef PNG_WRITE_INTERLACING_SUPPORTED -/* Grab pixels out of a row for an interlaced pass */ -PNG_INTERNAL_FUNCTION(void,png_do_write_interlace,(png_row_infop row_info, - png_bytep row, int pass),PNG_EMPTY); -#endif - -/* Unfilter a row: check the filter value before calling this, there is no point - * calling it for PNG_FILTER_VALUE_NONE. - */ -PNG_INTERNAL_FUNCTION(void,png_read_filter_row,(png_structrp pp, png_row_infop - row_info, png_bytep row, png_const_bytep prev_row, int filter),PNG_EMPTY); - -PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_neon,(png_row_infop row_info, - png_bytep row, png_const_bytep prev_row),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_neon,(png_row_infop - row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_neon,(png_row_infop - row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_neon,(png_row_infop - row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_neon,(png_row_infop - row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_neon,(png_row_infop - row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_neon,(png_row_infop - row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); - -/* Choose the best filter to use and filter the row data */ -PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr, - png_row_infop row_info),PNG_EMPTY); - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_read_IDAT_data,(png_structrp png_ptr, - png_bytep output, png_alloc_size_t avail_out),PNG_EMPTY); - /* Read 'avail_out' bytes of data from the IDAT stream. If the output buffer - * is NULL the function checks, instead, for the end of the stream. In this - * case a benign error will be issued if the stream end is not found or if - * extra data has to be consumed. - */ -PNG_INTERNAL_FUNCTION(void,png_read_finish_IDAT,(png_structrp png_ptr), - PNG_EMPTY); - /* This cleans up when the IDAT LZ stream does not end when the last image - * byte is read; there is still some pending input. - */ - -PNG_INTERNAL_FUNCTION(void,png_read_finish_row,(png_structrp png_ptr), - PNG_EMPTY); - /* Finish a row while reading, dealing with interlacing passes, etc. */ -#endif - -/* Initialize the row buffers, etc. */ -PNG_INTERNAL_FUNCTION(void,png_read_start_row,(png_structrp png_ptr),PNG_EMPTY); - -#ifdef PNG_READ_TRANSFORMS_SUPPORTED -/* Optional call to update the users info structure */ -PNG_INTERNAL_FUNCTION(void,png_read_transform_info,(png_structrp png_ptr, - png_inforp info_ptr),PNG_EMPTY); -#endif - -/* These are the functions that do the transformations */ -#ifdef PNG_READ_FILLER_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_read_filler,(png_row_infop row_info, - png_bytep row, png_uint_32 filler, png_uint_32 flags),PNG_EMPTY); -#endif - -#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_read_swap_alpha,(png_row_infop row_info, - png_bytep row),PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_write_swap_alpha,(png_row_infop row_info, - png_bytep row),PNG_EMPTY); -#endif - -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_read_invert_alpha,(png_row_infop row_info, - png_bytep row),PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_write_invert_alpha,(png_row_infop row_info, - png_bytep row),PNG_EMPTY); -#endif - -#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ - defined(PNG_READ_STRIP_ALPHA_SUPPORTED) -PNG_INTERNAL_FUNCTION(void,png_do_strip_channel,(png_row_infop row_info, - png_bytep row, int at_start),PNG_EMPTY); -#endif - -#ifdef PNG_16BIT_SUPPORTED -#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) -PNG_INTERNAL_FUNCTION(void,png_do_swap,(png_row_infop row_info, - png_bytep row),PNG_EMPTY); -#endif -#endif - -#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ - defined(PNG_WRITE_PACKSWAP_SUPPORTED) -PNG_INTERNAL_FUNCTION(void,png_do_packswap,(png_row_infop row_info, - png_bytep row),PNG_EMPTY); -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -PNG_INTERNAL_FUNCTION(int,png_do_rgb_to_gray,(png_structrp png_ptr, - png_row_infop row_info, png_bytep row),PNG_EMPTY); -#endif - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_gray_to_rgb,(png_row_infop row_info, - png_bytep row),PNG_EMPTY); -#endif - -#ifdef PNG_READ_PACK_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_unpack,(png_row_infop row_info, - png_bytep row),PNG_EMPTY); -#endif - -#ifdef PNG_READ_SHIFT_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_unshift,(png_row_infop row_info, - png_bytep row, png_const_color_8p sig_bits),PNG_EMPTY); -#endif - -#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) -PNG_INTERNAL_FUNCTION(void,png_do_invert,(png_row_infop row_info, - png_bytep row),PNG_EMPTY); -#endif - -#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_scale_16_to_8,(png_row_infop row_info, - png_bytep row),PNG_EMPTY); -#endif - -#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_chop,(png_row_infop row_info, - png_bytep row),PNG_EMPTY); -#endif - -#ifdef PNG_READ_QUANTIZE_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_quantize,(png_row_infop row_info, - png_bytep row, png_const_bytep palette_lookup, - png_const_bytep quantize_lookup),PNG_EMPTY); - -# ifdef PNG_CORRECT_PALETTE_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_correct_palette,(png_structrp png_ptr, - png_colorp palette, int num_palette),PNG_EMPTY); -# endif -#endif - -#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) -PNG_INTERNAL_FUNCTION(void,png_do_bgr,(png_row_infop row_info, - png_bytep row),PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_PACK_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_pack,(png_row_infop row_info, - png_bytep row, png_uint_32 bit_depth),PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_SHIFT_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_shift,(png_row_infop row_info, - png_bytep row, png_const_color_8p bit_depth),PNG_EMPTY); -#endif - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ - defined(PNG_READ_ALPHA_MODE_SUPPORTED) -PNG_INTERNAL_FUNCTION(void,png_do_compose,(png_row_infop row_info, - png_bytep row, png_structrp png_ptr),PNG_EMPTY); -#endif - -#ifdef PNG_READ_GAMMA_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_gamma,(png_row_infop row_info, - png_bytep row, png_structrp png_ptr),PNG_EMPTY); -#endif - -#ifdef PNG_READ_ALPHA_MODE_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_encode_alpha,(png_row_infop row_info, - png_bytep row, png_structrp png_ptr),PNG_EMPTY); -#endif - -#ifdef PNG_READ_EXPAND_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_expand_palette,(png_row_infop row_info, - png_bytep row, png_const_colorp palette, png_const_bytep trans, - int num_trans),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_do_expand,(png_row_infop row_info, - png_bytep row, png_const_color_16p trans_color),PNG_EMPTY); -#endif - -#ifdef PNG_READ_EXPAND_16_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_expand_16,(png_row_infop row_info, - png_bytep row),PNG_EMPTY); -#endif - -/* The following decodes the appropriate chunks, and does error correction, - * then calls the appropriate callback for the chunk if it is valid. - */ - -/* Decode the IHDR chunk */ -PNG_INTERNAL_FUNCTION(void,png_handle_IHDR,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_handle_PLTE,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_handle_IEND,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); - -#ifdef PNG_READ_bKGD_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_bKGD,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -#endif - -#ifdef PNG_READ_cHRM_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_cHRM,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -#endif - -#ifdef PNG_READ_gAMA_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_gAMA,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -#endif - -#ifdef PNG_READ_hIST_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_hIST,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -#endif - -#ifdef PNG_READ_iCCP_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_iCCP,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -#endif /* PNG_READ_iCCP_SUPPORTED */ - -#ifdef PNG_READ_iTXt_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_iTXt,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -#endif - -#ifdef PNG_READ_oFFs_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_oFFs,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -#endif - -#ifdef PNG_READ_pCAL_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_pCAL,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -#endif - -#ifdef PNG_READ_pHYs_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_pHYs,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -#endif - -#ifdef PNG_READ_sBIT_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_sBIT,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -#endif - -#ifdef PNG_READ_sCAL_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_sCAL,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -#endif - -#ifdef PNG_READ_sPLT_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_sPLT,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -#endif /* PNG_READ_sPLT_SUPPORTED */ - -#ifdef PNG_READ_sRGB_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_sRGB,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -#endif - -#ifdef PNG_READ_tEXt_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_tEXt,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -#endif - -#ifdef PNG_READ_tIME_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_tIME,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -#endif - -#ifdef PNG_READ_tRNS_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_tRNS,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -#endif - -#ifdef PNG_READ_zTXt_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_zTXt,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -#endif - -PNG_INTERNAL_FUNCTION(void,png_check_chunk_name,(png_structrp png_ptr, - png_uint_32 chunk_name),PNG_EMPTY); - -#ifdef PNG_READ_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_handle_unknown,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length, int keep),PNG_EMPTY); - /* This is the function that gets called for unknown chunks. The 'keep' - * argument is either non-zero for a known chunk that has been set to be - * handled as unknown or zero for an unknown chunk. By default the function - * just skips the chunk or errors out if it is critical. - */ - -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED -#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED -PNG_INTERNAL_FUNCTION(int,png_chunk_unknown_handling, - (png_const_structrp png_ptr, png_uint_32 chunk_name),PNG_EMPTY); - /* Exactly as the API png_handle_as_unknown() except that the argument is a - * 32-bit chunk name, not a string. - */ -#endif -#endif /* PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED */ - -/* Handle the transformations for reading and writing */ -#ifdef PNG_READ_TRANSFORMS_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_read_transformations,(png_structrp png_ptr, - png_row_infop row_info),PNG_EMPTY); -#endif -#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_write_transformations,(png_structrp png_ptr, - png_row_infop row_info),PNG_EMPTY); -#endif - -#ifdef PNG_READ_TRANSFORMS_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_init_read_transformations,(png_structrp png_ptr), - PNG_EMPTY); -#endif - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_push_read_chunk,(png_structrp png_ptr, - png_inforp info_ptr),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_push_read_sig,(png_structrp png_ptr, - png_inforp info_ptr),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_push_check_crc,(png_structrp png_ptr),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_push_crc_skip,(png_structrp png_ptr, - png_uint_32 length),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_push_crc_finish,(png_structrp png_ptr), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_push_save_buffer,(png_structrp png_ptr), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_push_restore_buffer,(png_structrp png_ptr, - png_bytep buffer, png_size_t buffer_length),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_push_read_IDAT,(png_structrp png_ptr),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_process_IDAT_data,(png_structrp png_ptr, - png_bytep buffer, png_size_t buffer_length),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_push_process_row,(png_structrp png_ptr), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_push_handle_unknown,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_push_have_info,(png_structrp png_ptr, - png_inforp info_ptr),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_push_have_end,(png_structrp png_ptr, - png_inforp info_ptr),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_push_have_row,(png_structrp png_ptr, - png_bytep row),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_push_read_end,(png_structrp png_ptr, - png_inforp info_ptr),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_process_some_data,(png_structrp png_ptr, - png_inforp info_ptr),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_read_push_finish_row,(png_structrp png_ptr), - PNG_EMPTY); -# ifdef PNG_READ_tEXt_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_push_handle_tEXt,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_push_read_tEXt,(png_structrp png_ptr, - png_inforp info_ptr),PNG_EMPTY); -# endif -# ifdef PNG_READ_zTXt_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_push_handle_zTXt,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_push_read_zTXt,(png_structrp png_ptr, - png_inforp info_ptr),PNG_EMPTY); -# endif -# ifdef PNG_READ_iTXt_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_push_handle_iTXt,(png_structrp png_ptr, - png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_push_read_iTXt,(png_structrp png_ptr, - png_inforp info_ptr),PNG_EMPTY); -# endif - -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ - -#ifdef PNG_MNG_FEATURES_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_do_read_intrapixel,(png_row_infop row_info, - png_bytep row),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_do_write_intrapixel,(png_row_infop row_info, - png_bytep row),PNG_EMPTY); -#endif - -/* Added at libpng version 1.6.0 */ -#ifdef PNG_GAMMA_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_colorspace_set_gamma,(png_const_structrp png_ptr, - png_colorspacerp colorspace, png_fixed_point gAMA), PNG_EMPTY); - /* Set the colorspace gamma with a value provided by the application or by - * the gAMA chunk on read. The value will override anything set by an ICC - * profile. - */ - -PNG_INTERNAL_FUNCTION(void,png_colorspace_sync_info,(png_const_structrp png_ptr, - png_inforp info_ptr), PNG_EMPTY); - /* Synchronize the info 'valid' flags with the colorspace */ - -PNG_INTERNAL_FUNCTION(void,png_colorspace_sync,(png_const_structrp png_ptr, - png_inforp info_ptr), PNG_EMPTY); - /* Copy the png_struct colorspace to the info_struct and call the above to - * synchronize the flags. Checks for NULL info_ptr and does nothing. - */ -#endif - -/* Added at libpng version 1.4.0 */ -#ifdef PNG_COLORSPACE_SUPPORTED -/* These internal functions are for maintaining the colorspace structure within - * a png_info or png_struct (or, indeed, both). - */ -PNG_INTERNAL_FUNCTION(int,png_colorspace_set_chromaticities, - (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_xy *xy, - int preferred), PNG_EMPTY); - -PNG_INTERNAL_FUNCTION(int,png_colorspace_set_endpoints, - (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_XYZ *XYZ, - int preferred), PNG_EMPTY); - -#ifdef PNG_sRGB_SUPPORTED -PNG_INTERNAL_FUNCTION(int,png_colorspace_set_sRGB,(png_const_structrp png_ptr, - png_colorspacerp colorspace, int intent), PNG_EMPTY); - /* This does set the colorspace gAMA and cHRM values too, but doesn't set the - * flags to write them, if it returns false there was a problem and an error - * message has already been output (but the colorspace may still need to be - * synced to record the invalid flag). - */ -#endif /* sRGB */ - -#ifdef PNG_iCCP_SUPPORTED -PNG_INTERNAL_FUNCTION(int,png_colorspace_set_ICC,(png_const_structrp png_ptr, - png_colorspacerp colorspace, png_const_charp name, - png_uint_32 profile_length, png_const_bytep profile, int color_type), - PNG_EMPTY); - /* The 'name' is used for information only */ - -/* Routines for checking parts of an ICC profile. */ -PNG_INTERNAL_FUNCTION(int,png_icc_check_length,(png_const_structrp png_ptr, - png_colorspacerp colorspace, png_const_charp name, - png_uint_32 profile_length), PNG_EMPTY); -PNG_INTERNAL_FUNCTION(int,png_icc_check_header,(png_const_structrp png_ptr, - png_colorspacerp colorspace, png_const_charp name, - png_uint_32 profile_length, - png_const_bytep profile /* first 132 bytes only */, int color_type), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(int,png_icc_check_tag_table,(png_const_structrp png_ptr, - png_colorspacerp colorspace, png_const_charp name, - png_uint_32 profile_length, - png_const_bytep profile /* header plus whole tag table */), PNG_EMPTY); -#ifdef PNG_sRGB_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_icc_set_sRGB,( - png_const_structrp png_ptr, png_colorspacerp colorspace, - png_const_bytep profile, uLong adler), PNG_EMPTY); - /* 'adler' is the Adler32 checksum of the uncompressed profile data. It may - * be zero to indicate that it is not available. It is used, if provided, - * as a fast check on the profile when checking to see if it is sRGB. - */ -#endif -#endif /* iCCP */ - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_colorspace_set_rgb_coefficients, - (png_structrp png_ptr), PNG_EMPTY); - /* Set the rgb_to_gray coefficients from the colorspace Y values */ -#endif /* READ_RGB_TO_GRAY */ -#endif /* COLORSPACE */ - -/* Added at libpng version 1.4.0 */ -PNG_INTERNAL_FUNCTION(void,png_check_IHDR,(png_const_structrp png_ptr, - png_uint_32 width, png_uint_32 height, int bit_depth, - int color_type, int interlace_type, int compression_type, - int filter_type),PNG_EMPTY); - -/* Added at libpng version 1.5.10 */ -#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ - defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) -PNG_INTERNAL_FUNCTION(void,png_do_check_palette_indexes, - (png_structrp png_ptr, png_row_infop row_info),PNG_EMPTY); -#endif - -#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) -PNG_INTERNAL_FUNCTION(void,png_fixed_error,(png_const_structrp png_ptr, - png_const_charp name),PNG_NORETURN); -#endif - -/* Puts 'string' into 'buffer' at buffer[pos], taking care never to overwrite - * the end. Always leaves the buffer nul terminated. Never errors out (and - * there is no error code.) - */ -PNG_INTERNAL_FUNCTION(size_t,png_safecat,(png_charp buffer, size_t bufsize, - size_t pos, png_const_charp string),PNG_EMPTY); - -/* Various internal functions to handle formatted warning messages, currently - * only implemented for warnings. - */ -#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED) -/* Utility to dump an unsigned value into a buffer, given a start pointer and - * and end pointer (which should point just *beyond* the end of the buffer!) - * Returns the pointer to the start of the formatted string. This utility only - * does unsigned values. - */ -PNG_INTERNAL_FUNCTION(png_charp,png_format_number,(png_const_charp start, - png_charp end, int format, png_alloc_size_t number),PNG_EMPTY); - -/* Convenience macro that takes an array: */ -#define PNG_FORMAT_NUMBER(buffer,format,number) \ - png_format_number(buffer, buffer + (sizeof buffer), format, number) - -/* Suggested size for a number buffer (enough for 64 bits and a sign!) */ -#define PNG_NUMBER_BUFFER_SIZE 24 - -/* These are the integer formats currently supported, the name is formed from - * the standard printf(3) format string. - */ -#define PNG_NUMBER_FORMAT_u 1 /* chose unsigned API! */ -#define PNG_NUMBER_FORMAT_02u 2 -#define PNG_NUMBER_FORMAT_d 1 /* chose signed API! */ -#define PNG_NUMBER_FORMAT_02d 2 -#define PNG_NUMBER_FORMAT_x 3 -#define PNG_NUMBER_FORMAT_02x 4 -#define PNG_NUMBER_FORMAT_fixed 5 /* choose the signed API */ -#endif - -#ifdef PNG_WARNINGS_SUPPORTED -/* New defines and members adding in libpng-1.5.4 */ -# define PNG_WARNING_PARAMETER_SIZE 32 -# define PNG_WARNING_PARAMETER_COUNT 8 /* Maximum 9; see pngerror.c */ - -/* An l-value of this type has to be passed to the APIs below to cache the - * values of the parameters to a formatted warning message. - */ -typedef char png_warning_parameters[PNG_WARNING_PARAMETER_COUNT][ - PNG_WARNING_PARAMETER_SIZE]; - -PNG_INTERNAL_FUNCTION(void,png_warning_parameter,(png_warning_parameters p, - int number, png_const_charp string),PNG_EMPTY); - /* Parameters are limited in size to PNG_WARNING_PARAMETER_SIZE characters, - * including the trailing '\0'. - */ -PNG_INTERNAL_FUNCTION(void,png_warning_parameter_unsigned, - (png_warning_parameters p, int number, int format, png_alloc_size_t value), - PNG_EMPTY); - /* Use png_alloc_size_t because it is an unsigned type as big as any we - * need to output. Use the following for a signed value. - */ -PNG_INTERNAL_FUNCTION(void,png_warning_parameter_signed, - (png_warning_parameters p, int number, int format, png_int_32 value), - PNG_EMPTY); - -PNG_INTERNAL_FUNCTION(void,png_formatted_warning,(png_const_structrp png_ptr, - png_warning_parameters p, png_const_charp message),PNG_EMPTY); - /* 'message' follows the X/Open approach of using @1, @2 to insert - * parameters previously supplied using the above functions. Errors in - * specifying the parameters will simply result in garbage substitutions. - */ -#endif - -#ifdef PNG_BENIGN_ERRORS_SUPPORTED -/* Application errors (new in 1.6); use these functions (declared below) for - * errors in the parameters or order of API function calls on read. The - * 'warning' should be used for an error that can be handled completely; the - * 'error' for one which can be handled safely but which may lose application - * information or settings. - * - * By default these both result in a png_error call prior to release, while in a - * released version the 'warning' is just a warning. However if the application - * explicitly disables benign errors (explicitly permitting the code to lose - * information) they both turn into warnings. - * - * If benign errors aren't supported they end up as the corresponding base call - * (png_warning or png_error.) - */ -PNG_INTERNAL_FUNCTION(void,png_app_warning,(png_const_structrp png_ptr, - png_const_charp message),PNG_EMPTY); - /* The application provided invalid parameters to an API function or called - * an API function at the wrong time, libpng can completely recover. - */ - -PNG_INTERNAL_FUNCTION(void,png_app_error,(png_const_structrp png_ptr, - png_const_charp message),PNG_EMPTY); - /* As above but libpng will ignore the call, or attempt some other partial - * recovery from the error. - */ -#else -# define png_app_warning(pp,s) png_warning(pp,s) -# define png_app_error(pp,s) png_error(pp,s) -#endif - -PNG_INTERNAL_FUNCTION(void,png_chunk_report,(png_const_structrp png_ptr, - png_const_charp message, int error),PNG_EMPTY); - /* Report a recoverable issue in chunk data. On read this is used to report - * a problem found while reading a particular chunk and the - * png_chunk_benign_error or png_chunk_warning function is used as - * appropriate. On write this is used to report an error that comes from - * data set via an application call to a png_set_ API and png_app_error or - * png_app_warning is used as appropriate. - * - * The 'error' parameter must have one of the following values: - */ -#define PNG_CHUNK_WARNING 0 /* never an error */ -#define PNG_CHUNK_WRITE_ERROR 1 /* an error only on write */ -#define PNG_CHUNK_ERROR 2 /* always an error */ - -/* ASCII to FP interfaces, currently only implemented if sCAL - * support is required. - */ -#if defined(PNG_sCAL_SUPPORTED) -/* MAX_DIGITS is actually the maximum number of characters in an sCAL - * width or height, derived from the precision (number of significant - * digits - a build time settable option) and assumptions about the - * maximum ridiculous exponent. - */ -#define PNG_sCAL_MAX_DIGITS (PNG_sCAL_PRECISION+1/*.*/+1/*E*/+10/*exponent*/) - -#ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_ascii_from_fp,(png_const_structrp png_ptr, - png_charp ascii, png_size_t size, double fp, unsigned int precision), - PNG_EMPTY); -#endif /* FLOATING_POINT */ - -#ifdef PNG_FIXED_POINT_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr, - png_charp ascii, png_size_t size, png_fixed_point fp),PNG_EMPTY); -#endif /* FIXED_POINT */ -#endif /* sCAL */ - -#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) -/* An internal API to validate the format of a floating point number. - * The result is the index of the next character. If the number is - * not valid it will be the index of a character in the supposed number. - * - * The format of a number is defined in the PNG extensions specification - * and this API is strictly conformant to that spec, not anyone elses! - * - * The format as a regular expression is: - * - * [+-]?[0-9]+.?([Ee][+-]?[0-9]+)? - * - * or: - * - * [+-]?.[0-9]+(.[0-9]+)?([Ee][+-]?[0-9]+)? - * - * The complexity is that either integer or fraction must be present and the - * fraction is permitted to have no digits only if the integer is present. - * - * NOTE: The dangling E problem. - * There is a PNG valid floating point number in the following: - * - * PNG floating point numbers are not greedy. - * - * Working this out requires *TWO* character lookahead (because of the - * sign), the parser does not do this - it will fail at the 'r' - this - * doesn't matter for PNG sCAL chunk values, but it requires more care - * if the value were ever to be embedded in something more complex. Use - * ANSI-C strtod if you need the lookahead. - */ -/* State table for the parser. */ -#define PNG_FP_INTEGER 0 /* before or in integer */ -#define PNG_FP_FRACTION 1 /* before or in fraction */ -#define PNG_FP_EXPONENT 2 /* before or in exponent */ -#define PNG_FP_STATE 3 /* mask for the above */ -#define PNG_FP_SAW_SIGN 4 /* Saw +/- in current state */ -#define PNG_FP_SAW_DIGIT 8 /* Saw a digit in current state */ -#define PNG_FP_SAW_DOT 16 /* Saw a dot in current state */ -#define PNG_FP_SAW_E 32 /* Saw an E (or e) in current state */ -#define PNG_FP_SAW_ANY 60 /* Saw any of the above 4 */ - -/* These three values don't affect the parser. They are set but not used. - */ -#define PNG_FP_WAS_VALID 64 /* Preceding substring is a valid fp number */ -#define PNG_FP_NEGATIVE 128 /* A negative number, including "-0" */ -#define PNG_FP_NONZERO 256 /* A non-zero value */ -#define PNG_FP_STICKY 448 /* The above three flags */ - -/* This is available for the caller to store in 'state' if required. Do not - * call the parser after setting it (the parser sometimes clears it.) - */ -#define PNG_FP_INVALID 512 /* Available for callers as a distinct value */ - -/* Result codes for the parser (boolean - true meants ok, false means - * not ok yet.) - */ -#define PNG_FP_MAYBE 0 /* The number may be valid in the future */ -#define PNG_FP_OK 1 /* The number is valid */ - -/* Tests on the sticky non-zero and negative flags. To pass these checks - * the state must also indicate that the whole number is valid - this is - * achieved by testing PNG_FP_SAW_DIGIT (see the implementation for why this - * is equivalent to PNG_FP_OK above.) - */ -#define PNG_FP_NZ_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NEGATIVE | PNG_FP_NONZERO) - /* NZ_MASK: the string is valid and a non-zero negative value */ -#define PNG_FP_Z_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NONZERO) - /* Z MASK: the string is valid and a non-zero value. */ - /* PNG_FP_SAW_DIGIT: the string is valid. */ -#define PNG_FP_IS_ZERO(state) (((state) & PNG_FP_Z_MASK) == PNG_FP_SAW_DIGIT) -#define PNG_FP_IS_POSITIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_Z_MASK) -#define PNG_FP_IS_NEGATIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_NZ_MASK) - -/* The actual parser. This can be called repeatedly. It updates - * the index into the string and the state variable (which must - * be initialized to 0). It returns a result code, as above. There - * is no point calling the parser any more if it fails to advance to - * the end of the string - it is stuck on an invalid character (or - * terminated by '\0'). - * - * Note that the pointer will consume an E or even an E+ and then leave - * a 'maybe' state even though a preceding integer.fraction is valid. - * The PNG_FP_WAS_VALID flag indicates that a preceding substring was - * a valid number. It's possible to recover from this by calling - * the parser again (from the start, with state 0) but with a string - * that omits the last character (i.e. set the size to the index of - * the problem character.) This has not been tested within libpng. - */ -PNG_INTERNAL_FUNCTION(int,png_check_fp_number,(png_const_charp string, - png_size_t size, int *statep, png_size_tp whereami),PNG_EMPTY); - -/* This is the same but it checks a complete string and returns true - * only if it just contains a floating point number. As of 1.5.4 this - * function also returns the state at the end of parsing the number if - * it was valid (otherwise it returns 0.) This can be used for testing - * for negative or zero values using the sticky flag. - */ -PNG_INTERNAL_FUNCTION(int,png_check_fp_string,(png_const_charp string, - png_size_t size),PNG_EMPTY); -#endif /* pCAL || sCAL */ - -#if defined(PNG_READ_GAMMA_SUPPORTED) ||\ - defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED) -/* Added at libpng version 1.5.0 */ -/* This is a utility to provide a*times/div (rounded) and indicate - * if there is an overflow. The result is a boolean - false (0) - * for overflow, true (1) if no overflow, in which case *res - * holds the result. - */ -PNG_INTERNAL_FUNCTION(int,png_muldiv,(png_fixed_point_p res, png_fixed_point a, - png_int_32 multiplied_by, png_int_32 divided_by),PNG_EMPTY); -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED) -/* Same deal, but issue a warning on overflow and return 0. */ -PNG_INTERNAL_FUNCTION(png_fixed_point,png_muldiv_warn, - (png_const_structrp png_ptr, png_fixed_point a, png_int_32 multiplied_by, - png_int_32 divided_by),PNG_EMPTY); -#endif - -#ifdef PNG_GAMMA_SUPPORTED -/* Calculate a reciprocal - used for gamma values. This returns - * 0 if the argument is 0 in order to maintain an undefined value; - * there are no warnings. - */ -PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal,(png_fixed_point a), - PNG_EMPTY); - -#ifdef PNG_READ_GAMMA_SUPPORTED -/* The same but gives a reciprocal of the product of two fixed point - * values. Accuracy is suitable for gamma calculations but this is - * not exact - use png_muldiv for that. Only required at present on read. - */ -PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal2,(png_fixed_point a, - png_fixed_point b),PNG_EMPTY); -#endif - -/* Return true if the gamma value is significantly different from 1.0 */ -PNG_INTERNAL_FUNCTION(int,png_gamma_significant,(png_fixed_point gamma_value), - PNG_EMPTY); -#endif - -#ifdef PNG_READ_GAMMA_SUPPORTED -/* Internal fixed point gamma correction. These APIs are called as - * required to convert single values - they don't need to be fast, - * they are not used when processing image pixel values. - * - * While the input is an 'unsigned' value it must actually be the - * correct bit value - 0..255 or 0..65535 as required. - */ -PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_correct,(png_structrp png_ptr, - unsigned int value, png_fixed_point gamma_value),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_16bit_correct,(unsigned int value, - png_fixed_point gamma_value),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(png_byte,png_gamma_8bit_correct,(unsigned int value, - png_fixed_point gamma_value),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_destroy_gamma_table,(png_structrp png_ptr), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_build_gamma_table,(png_structrp png_ptr, - int bit_depth),PNG_EMPTY); -#endif - -/* SIMPLIFIED READ/WRITE SUPPORT */ -#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ - defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) -/* The internal structure that png_image::opaque points to. */ -typedef struct png_control -{ - png_structp png_ptr; - png_infop info_ptr; - png_voidp error_buf; /* Always a jmp_buf at present. */ - - png_const_bytep memory; /* Memory buffer. */ - png_size_t size; /* Size of the memory buffer. */ - - unsigned int for_write :1; /* Otherwise it is a read structure */ - unsigned int owned_file :1; /* We own the file in io_ptr */ -} png_control; - -/* Return the pointer to the jmp_buf from a png_control: necessary because C - * does not reveal the type of the elements of jmp_buf. - */ -#ifdef __cplusplus -# define png_control_jmp_buf(pc) (((jmp_buf*)((pc)->error_buf))[0]) -#else -# define png_control_jmp_buf(pc) ((pc)->error_buf) -#endif - -/* Utility to safely execute a piece of libpng code catching and logging any - * errors that might occur. Returns true on success, false on failure (either - * of the function or as a result of a png_error.) - */ -PNG_INTERNAL_FUNCTION(void,png_safe_error,(png_structp png_ptr, - png_const_charp error_message),PNG_NORETURN); - -#ifdef PNG_WARNINGS_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_safe_warning,(png_structp png_ptr, - png_const_charp warning_message),PNG_EMPTY); -#else -# define png_safe_warning 0/*dummy argument*/ -#endif - -PNG_INTERNAL_FUNCTION(int,png_safe_execute,(png_imagep image, - int (*function)(png_voidp), png_voidp arg),PNG_EMPTY); - -/* Utility to log an error; this also cleans up the png_image; the function - * always returns 0 (false). - */ -PNG_INTERNAL_FUNCTION(int,png_image_error,(png_imagep image, - png_const_charp error_message),PNG_EMPTY); - -#ifndef PNG_SIMPLIFIED_READ_SUPPORTED -/* png_image_free is used by the write code but not exported */ -PNG_INTERNAL_FUNCTION(void, png_image_free, (png_imagep image), PNG_EMPTY); -#endif /* !SIMPLIFIED_READ */ - -#endif /* SIMPLIFIED READ/WRITE */ - -#ifdef PNG_FILTER_OPTIMIZATIONS -PNG_INTERNAL_FUNCTION(void, PNG_FILTER_OPTIMIZATIONS, (png_structp png_ptr, - unsigned int bpp), PNG_EMPTY); - /* This is the initialization function for hardware specific optimizations, - * one implementation (for ARM NEON machines) is contained in - * arm/filter_neon.c. It need not be defined - the generic code will be used - * if not. - */ -#endif - -/* Maintainer: Put new private prototypes here ^ */ - -//#include "pngdebug.h" - -#endif /* PNG_VERSION_INFO_ONLY */ -#endif /* PNGPRIV_H */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pngread.c b/source/modules/juce_graphics/image_formats/pnglib/pngread.c deleted file mode 100644 index f7bde9620..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pngread.c +++ /dev/null @@ -1,4000 +0,0 @@ - -/* pngread.c - read a PNG file - * - * Last changed in libpng 1.6.1 [March 28, 2013] - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file contains routines that an application calls directly to - * read a PNG file or stream. - */ - -#include "pngpriv.h" -#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) -# include -#endif - -#ifdef PNG_READ_SUPPORTED - -/* Create a PNG structure for reading, and allocate any memory needed. */ -PNG_FUNCTION(png_structp,PNGAPI -png_create_read_struct,(png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) -{ -#ifndef PNG_USER_MEM_SUPPORTED - png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr, - error_fn, warn_fn, NULL, NULL, NULL); -#else - return png_create_read_struct_2(user_png_ver, error_ptr, error_fn, - warn_fn, NULL, NULL, NULL); -} - -/* Alternate create PNG structure for reading, and allocate any memory - * needed. - */ -PNG_FUNCTION(png_structp,PNGAPI -png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, - png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) -{ - png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr, - error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); -#endif /* PNG_USER_MEM_SUPPORTED */ - - if (png_ptr != NULL) - { - png_ptr->mode = PNG_IS_READ_STRUCT; - - /* Added in libpng-1.6.0; this can be used to detect a read structure if - * required (it will be zero in a write structure.) - */ -# ifdef PNG_SEQUENTIAL_READ_SUPPORTED - png_ptr->IDAT_read_size = PNG_IDAT_READ_SIZE; -# endif - -# ifdef PNG_BENIGN_READ_ERRORS_SUPPORTED - png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; - - /* In stable builds only warn if an application error can be completely - * handled. - */ -# if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC - png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; -# endif -# endif - - /* TODO: delay this, it can be done in png_init_io (if the app doesn't - * do it itself) avoiding setting the default function if it is not - * required. - */ - png_set_read_fn(png_ptr, NULL, NULL); - } - - return png_ptr; -} - - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -/* Read the information before the actual image data. This has been - * changed in v0.90 to allow reading a file that already has the magic - * bytes read from the stream. You can tell libpng how many bytes have - * been read from the beginning of the stream (up to the maximum of 8) - * via png_set_sig_bytes(), and we will only check the remaining bytes - * here. The application can then have access to the signature bytes we - * read if it is determined that this isn't a valid PNG file. - */ -void PNGAPI -png_read_info(png_structrp png_ptr, png_inforp info_ptr) -{ -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - int keep; -#endif - - png_debug(1, "in png_read_info"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - /* Read and check the PNG file signature. */ - png_read_sig(png_ptr, info_ptr); - - for (;;) - { - png_uint_32 length = png_read_chunk_header(png_ptr); - png_uint_32 chunk_name = png_ptr->chunk_name; - - /* IDAT logic needs to happen here to simplify getting the two flags - * right. - */ - if (chunk_name == png_IDAT) - { - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "Missing IHDR before IDAT"); - - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) - png_chunk_error(png_ptr, "Missing PLTE before IDAT"); - - else if (png_ptr->mode & PNG_AFTER_IDAT) - png_chunk_benign_error(png_ptr, "Too many IDATs found"); - - png_ptr->mode |= PNG_HAVE_IDAT; - } - - else if (png_ptr->mode & PNG_HAVE_IDAT) - png_ptr->mode |= PNG_AFTER_IDAT; - - /* This should be a binary subdivision search or a hash for - * matching the chunk name rather than a linear search. - */ - if (chunk_name == png_IHDR) - png_handle_IHDR(png_ptr, info_ptr, length); - - else if (chunk_name == png_IEND) - png_handle_IEND(png_ptr, info_ptr, length); - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) - { - png_handle_unknown(png_ptr, info_ptr, length, keep); - - if (chunk_name == png_PLTE) - png_ptr->mode |= PNG_HAVE_PLTE; - - else if (chunk_name == png_IDAT) - { - png_ptr->idat_size = 0; /* It has been consumed */ - break; - } - } -#endif - else if (chunk_name == png_PLTE) - png_handle_PLTE(png_ptr, info_ptr, length); - - else if (chunk_name == png_IDAT) - { - png_ptr->idat_size = length; - break; - } - -#ifdef PNG_READ_bKGD_SUPPORTED - else if (chunk_name == png_bKGD) - png_handle_bKGD(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_cHRM_SUPPORTED - else if (chunk_name == png_cHRM) - png_handle_cHRM(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_gAMA_SUPPORTED - else if (chunk_name == png_gAMA) - png_handle_gAMA(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_hIST_SUPPORTED - else if (chunk_name == png_hIST) - png_handle_hIST(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_oFFs_SUPPORTED - else if (chunk_name == png_oFFs) - png_handle_oFFs(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_pCAL_SUPPORTED - else if (chunk_name == png_pCAL) - png_handle_pCAL(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_sCAL_SUPPORTED - else if (chunk_name == png_sCAL) - png_handle_sCAL(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_pHYs_SUPPORTED - else if (chunk_name == png_pHYs) - png_handle_pHYs(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_sBIT_SUPPORTED - else if (chunk_name == png_sBIT) - png_handle_sBIT(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_sRGB_SUPPORTED - else if (chunk_name == png_sRGB) - png_handle_sRGB(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_iCCP_SUPPORTED - else if (chunk_name == png_iCCP) - png_handle_iCCP(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_sPLT_SUPPORTED - else if (chunk_name == png_sPLT) - png_handle_sPLT(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_tEXt_SUPPORTED - else if (chunk_name == png_tEXt) - png_handle_tEXt(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_tIME_SUPPORTED - else if (chunk_name == png_tIME) - png_handle_tIME(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_tRNS_SUPPORTED - else if (chunk_name == png_tRNS) - png_handle_tRNS(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_zTXt_SUPPORTED - else if (chunk_name == png_zTXt) - png_handle_zTXt(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_iTXt_SUPPORTED - else if (chunk_name == png_iTXt) - png_handle_iTXt(png_ptr, info_ptr, length); -#endif - - else - png_handle_unknown(png_ptr, info_ptr, length, - PNG_HANDLE_CHUNK_AS_DEFAULT); - } -} -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ - -/* Optional call to update the users info_ptr structure */ -void PNGAPI -png_read_update_info(png_structrp png_ptr, png_inforp info_ptr) -{ - png_debug(1, "in png_read_update_info"); - - if (png_ptr != NULL) - { - if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) - { - png_read_start_row(png_ptr); - -# ifdef PNG_READ_TRANSFORMS_SUPPORTED - png_read_transform_info(png_ptr, info_ptr); -# else - PNG_UNUSED(info_ptr) -# endif - } - - /* New in 1.6.0 this avoids the bug of doing the initializations twice */ - else - png_app_error(png_ptr, - "png_read_update_info/png_start_read_image: duplicate call"); - } -} - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -/* Initialize palette, background, etc, after transformations - * are set, but before any reading takes place. This allows - * the user to obtain a gamma-corrected palette, for example. - * If the user doesn't call this, we will do it ourselves. - */ -void PNGAPI -png_start_read_image(png_structrp png_ptr) -{ - png_debug(1, "in png_start_read_image"); - - if (png_ptr != NULL) - { - if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) - png_read_start_row(png_ptr); - - /* New in 1.6.0 this avoids the bug of doing the initializations twice */ - else - png_app_error(png_ptr, - "png_start_read_image/png_read_update_info: duplicate call"); - } -} -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -void PNGAPI -png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) -{ - png_row_info row_info; - - if (png_ptr == NULL) - return; - - png_debug2(1, "in png_read_row (row %lu, pass %d)", - (unsigned long)png_ptr->row_number, png_ptr->pass); - - /* png_read_start_row sets the information (in particular iwidth) for this - * interlace pass. - */ - if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) - png_read_start_row(png_ptr); - - /* 1.5.6: row_info moved out of png_struct to a local here. */ - row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */ - row_info.color_type = png_ptr->color_type; - row_info.bit_depth = png_ptr->bit_depth; - row_info.channels = png_ptr->channels; - row_info.pixel_depth = png_ptr->pixel_depth; - row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); - - if (png_ptr->row_number == 0 && png_ptr->pass == 0) - { - /* Check for transforms that have been set but were defined out */ -#if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED) - if (png_ptr->transformations & PNG_INVERT_MONO) - png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined"); -#endif - -#if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED) - if (png_ptr->transformations & PNG_FILLER) - png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined"); -#endif - -#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ - !defined(PNG_READ_PACKSWAP_SUPPORTED) - if (png_ptr->transformations & PNG_PACKSWAP) - png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined"); -#endif - -#if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED) - if (png_ptr->transformations & PNG_PACK) - png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined"); -#endif - -#if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) - if (png_ptr->transformations & PNG_SHIFT) - png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined"); -#endif - -#if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED) - if (png_ptr->transformations & PNG_BGR) - png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined"); -#endif - -#if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED) - if (png_ptr->transformations & PNG_SWAP_BYTES) - png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined"); -#endif - } - -#ifdef PNG_READ_INTERLACING_SUPPORTED - /* If interlaced and we do not need a new row, combine row and return. - * Notice that the pixels we have from previous rows have been transformed - * already; we can only combine like with like (transformed or - * untransformed) and, because of the libpng API for interlaced images, this - * means we must transform before de-interlacing. - */ - if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) - { - switch (png_ptr->pass) - { - case 0: - if (png_ptr->row_number & 0x07) - { - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, 1/*display*/); - png_read_finish_row(png_ptr); - return; - } - break; - - case 1: - if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) - { - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, 1/*display*/); - - png_read_finish_row(png_ptr); - return; - } - break; - - case 2: - if ((png_ptr->row_number & 0x07) != 4) - { - if (dsp_row != NULL && (png_ptr->row_number & 4)) - png_combine_row(png_ptr, dsp_row, 1/*display*/); - - png_read_finish_row(png_ptr); - return; - } - break; - - case 3: - if ((png_ptr->row_number & 3) || png_ptr->width < 3) - { - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, 1/*display*/); - - png_read_finish_row(png_ptr); - return; - } - break; - - case 4: - if ((png_ptr->row_number & 3) != 2) - { - if (dsp_row != NULL && (png_ptr->row_number & 2)) - png_combine_row(png_ptr, dsp_row, 1/*display*/); - - png_read_finish_row(png_ptr); - return; - } - break; - - case 5: - if ((png_ptr->row_number & 1) || png_ptr->width < 2) - { - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, 1/*display*/); - - png_read_finish_row(png_ptr); - return; - } - break; - - default: - case 6: - if (!(png_ptr->row_number & 1)) - { - png_read_finish_row(png_ptr); - return; - } - break; - } - } -#endif - - if (!(png_ptr->mode & PNG_HAVE_IDAT)) - png_error(png_ptr, "Invalid attempt to read row data"); - - /* Fill the row with IDAT data: */ - png_read_IDAT_data(png_ptr, png_ptr->row_buf, row_info.rowbytes + 1); - - if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE) - { - if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST) - png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1, - png_ptr->prev_row + 1, png_ptr->row_buf[0]); - else - png_error(png_ptr, "bad adaptive filter value"); - } - - /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before - * 1.5.6, while the buffer really is this big in current versions of libpng - * it may not be in the future, so this was changed just to copy the - * interlaced count: - */ - memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); - -#ifdef PNG_MNG_FEATURES_SUPPORTED - if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && - (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) - { - /* Intrapixel differencing */ - png_do_read_intrapixel(&row_info, png_ptr->row_buf + 1); - } -#endif - - -#ifdef PNG_READ_TRANSFORMS_SUPPORTED - if (png_ptr->transformations) - png_do_read_transformations(png_ptr, &row_info); -#endif - - /* The transformed pixel depth should match the depth now in row_info. */ - if (png_ptr->transformed_pixel_depth == 0) - { - png_ptr->transformed_pixel_depth = row_info.pixel_depth; - if (row_info.pixel_depth > png_ptr->maximum_pixel_depth) - png_error(png_ptr, "sequential row overflow"); - } - - else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth) - png_error(png_ptr, "internal sequential row size calculation error"); - -#ifdef PNG_READ_INTERLACING_SUPPORTED - /* Blow up interlaced rows to full size */ - if (png_ptr->interlaced && - (png_ptr->transformations & PNG_INTERLACE)) - { - if (png_ptr->pass < 6) - png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass, - png_ptr->transformations); - - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, 1/*display*/); - - if (row != NULL) - png_combine_row(png_ptr, row, 0/*row*/); - } - - else -#endif - { - if (row != NULL) - png_combine_row(png_ptr, row, -1/*ignored*/); - - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, -1/*ignored*/); - } - png_read_finish_row(png_ptr); - - if (png_ptr->read_row_fn != NULL) - (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); - -} -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -/* Read one or more rows of image data. If the image is interlaced, - * and png_set_interlace_handling() has been called, the rows need to - * contain the contents of the rows from the previous pass. If the - * image has alpha or transparency, and png_handle_alpha()[*] has been - * called, the rows contents must be initialized to the contents of the - * screen. - * - * "row" holds the actual image, and pixels are placed in it - * as they arrive. If the image is displayed after each pass, it will - * appear to "sparkle" in. "display_row" can be used to display a - * "chunky" progressive image, with finer detail added as it becomes - * available. If you do not want this "chunky" display, you may pass - * NULL for display_row. If you do not want the sparkle display, and - * you have not called png_handle_alpha(), you may pass NULL for rows. - * If you have called png_handle_alpha(), and the image has either an - * alpha channel or a transparency chunk, you must provide a buffer for - * rows. In this case, you do not have to provide a display_row buffer - * also, but you may. If the image is not interlaced, or if you have - * not called png_set_interlace_handling(), the display_row buffer will - * be ignored, so pass NULL to it. - * - * [*] png_handle_alpha() does not exist yet, as of this version of libpng - */ - -void PNGAPI -png_read_rows(png_structrp png_ptr, png_bytepp row, - png_bytepp display_row, png_uint_32 num_rows) -{ - png_uint_32 i; - png_bytepp rp; - png_bytepp dp; - - png_debug(1, "in png_read_rows"); - - if (png_ptr == NULL) - return; - - rp = row; - dp = display_row; - if (rp != NULL && dp != NULL) - for (i = 0; i < num_rows; i++) - { - png_bytep rptr = *rp++; - png_bytep dptr = *dp++; - - png_read_row(png_ptr, rptr, dptr); - } - - else if (rp != NULL) - for (i = 0; i < num_rows; i++) - { - png_bytep rptr = *rp; - png_read_row(png_ptr, rptr, NULL); - rp++; - } - - else if (dp != NULL) - for (i = 0; i < num_rows; i++) - { - png_bytep dptr = *dp; - png_read_row(png_ptr, NULL, dptr); - dp++; - } -} -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -/* Read the entire image. If the image has an alpha channel or a tRNS - * chunk, and you have called png_handle_alpha()[*], you will need to - * initialize the image to the current image that PNG will be overlaying. - * We set the num_rows again here, in case it was incorrectly set in - * png_read_start_row() by a call to png_read_update_info() or - * png_start_read_image() if png_set_interlace_handling() wasn't called - * prior to either of these functions like it should have been. You can - * only call this function once. If you desire to have an image for - * each pass of a interlaced image, use png_read_rows() instead. - * - * [*] png_handle_alpha() does not exist yet, as of this version of libpng - */ -void PNGAPI -png_read_image(png_structrp png_ptr, png_bytepp image) -{ - png_uint_32 i, image_height; - int pass, j; - png_bytepp rp; - - png_debug(1, "in png_read_image"); - - if (png_ptr == NULL) - return; - -#ifdef PNG_READ_INTERLACING_SUPPORTED - if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) - { - pass = png_set_interlace_handling(png_ptr); - /* And make sure transforms are initialized. */ - png_start_read_image(png_ptr); - } - else - { - if (png_ptr->interlaced && !(png_ptr->transformations & PNG_INTERLACE)) - { - /* Caller called png_start_read_image or png_read_update_info without - * first turning on the PNG_INTERLACE transform. We can fix this here, - * but the caller should do it! - */ - png_warning(png_ptr, "Interlace handling should be turned on when " - "using png_read_image"); - /* Make sure this is set correctly */ - png_ptr->num_rows = png_ptr->height; - } - - /* Obtain the pass number, which also turns on the PNG_INTERLACE flag in - * the above error case. - */ - pass = png_set_interlace_handling(png_ptr); - } -#else - if (png_ptr->interlaced) - png_error(png_ptr, - "Cannot read interlaced image -- interlace handler disabled"); - - pass = 1; -#endif - - image_height=png_ptr->height; - - for (j = 0; j < pass; j++) - { - rp = image; - for (i = 0; i < image_height; i++) - { - png_read_row(png_ptr, *rp, NULL); - rp++; - } - } -} -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -/* Read the end of the PNG file. Will not read past the end of the - * file, will verify the end is accurate, and will read any comments - * or time information at the end of the file, if info is not NULL. - */ -void PNGAPI -png_read_end(png_structrp png_ptr, png_inforp info_ptr) -{ -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - int keep; -#endif - - png_debug(1, "in png_read_end"); - - if (png_ptr == NULL) - return; - - /* If png_read_end is called in the middle of reading the rows there may - * still be pending IDAT data and an owned zstream. Deal with this here. - */ -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - if (!png_chunk_unknown_handling(png_ptr, png_IDAT)) -#endif - png_read_finish_IDAT(png_ptr); - -#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED - /* Report invalid palette index; added at libng-1.5.10 */ - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - png_ptr->num_palette_max > png_ptr->num_palette) - png_benign_error(png_ptr, "Read palette index exceeding num_palette"); -#endif - - do - { - png_uint_32 length = png_read_chunk_header(png_ptr); - png_uint_32 chunk_name = png_ptr->chunk_name; - - if (chunk_name == png_IHDR) - png_handle_IHDR(png_ptr, info_ptr, length); - - else if (chunk_name == png_IEND) - png_handle_IEND(png_ptr, info_ptr, length); - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) - { - if (chunk_name == png_IDAT) - { - if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) - png_benign_error(png_ptr, "Too many IDATs found"); - } - png_handle_unknown(png_ptr, info_ptr, length, keep); - if (chunk_name == png_PLTE) - png_ptr->mode |= PNG_HAVE_PLTE; - } -#endif - - else if (chunk_name == png_IDAT) - { - /* Zero length IDATs are legal after the last IDAT has been - * read, but not after other chunks have been read. - */ - if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) - png_benign_error(png_ptr, "Too many IDATs found"); - - png_crc_finish(png_ptr, length); - } - else if (chunk_name == png_PLTE) - png_handle_PLTE(png_ptr, info_ptr, length); - -#ifdef PNG_READ_bKGD_SUPPORTED - else if (chunk_name == png_bKGD) - png_handle_bKGD(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_cHRM_SUPPORTED - else if (chunk_name == png_cHRM) - png_handle_cHRM(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_gAMA_SUPPORTED - else if (chunk_name == png_gAMA) - png_handle_gAMA(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_hIST_SUPPORTED - else if (chunk_name == png_hIST) - png_handle_hIST(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_oFFs_SUPPORTED - else if (chunk_name == png_oFFs) - png_handle_oFFs(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_pCAL_SUPPORTED - else if (chunk_name == png_pCAL) - png_handle_pCAL(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_sCAL_SUPPORTED - else if (chunk_name == png_sCAL) - png_handle_sCAL(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_pHYs_SUPPORTED - else if (chunk_name == png_pHYs) - png_handle_pHYs(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_sBIT_SUPPORTED - else if (chunk_name == png_sBIT) - png_handle_sBIT(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_sRGB_SUPPORTED - else if (chunk_name == png_sRGB) - png_handle_sRGB(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_iCCP_SUPPORTED - else if (chunk_name == png_iCCP) - png_handle_iCCP(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_sPLT_SUPPORTED - else if (chunk_name == png_sPLT) - png_handle_sPLT(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_tEXt_SUPPORTED - else if (chunk_name == png_tEXt) - png_handle_tEXt(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_tIME_SUPPORTED - else if (chunk_name == png_tIME) - png_handle_tIME(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_tRNS_SUPPORTED - else if (chunk_name == png_tRNS) - png_handle_tRNS(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_zTXt_SUPPORTED - else if (chunk_name == png_zTXt) - png_handle_zTXt(png_ptr, info_ptr, length); -#endif - -#ifdef PNG_READ_iTXt_SUPPORTED - else if (chunk_name == png_iTXt) - png_handle_iTXt(png_ptr, info_ptr, length); -#endif - - else - png_handle_unknown(png_ptr, info_ptr, length, - PNG_HANDLE_CHUNK_AS_DEFAULT); - } while (!(png_ptr->mode & PNG_HAVE_IEND)); -} -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ - -/* Free all memory used in the read struct */ -static void -png_read_destroy(png_structrp png_ptr) -{ - png_debug(1, "in png_read_destroy"); - -#ifdef PNG_READ_GAMMA_SUPPORTED - png_destroy_gamma_table(png_ptr); -#endif - - png_free(png_ptr, png_ptr->big_row_buf); - png_free(png_ptr, png_ptr->big_prev_row); - png_free(png_ptr, png_ptr->read_buffer); - -#ifdef PNG_READ_QUANTIZE_SUPPORTED - png_free(png_ptr, png_ptr->palette_lookup); - png_free(png_ptr, png_ptr->quantize_index); -#endif - - if (png_ptr->free_me & PNG_FREE_PLTE) - png_zfree(png_ptr, png_ptr->palette); - png_ptr->free_me &= ~PNG_FREE_PLTE; - -#if defined(PNG_tRNS_SUPPORTED) || \ - defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->free_me & PNG_FREE_TRNS) - png_free(png_ptr, png_ptr->trans_alpha); - png_ptr->free_me &= ~PNG_FREE_TRNS; -#endif - - inflateEnd(&png_ptr->zstream); - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED - png_free(png_ptr, png_ptr->save_buffer); -#endif - -#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) &&\ - defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) - png_free(png_ptr, png_ptr->unknown_chunk.data); -#endif - -#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED - png_free(png_ptr, png_ptr->chunk_list); -#endif - - /* NOTE: the 'setjmp' buffer may still be allocated and the memory and error - * callbacks are still set at this point. They are required to complete the - * destruction of the png_struct itself. - */ -} - -/* Free all memory used by the read */ -void PNGAPI -png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, - png_infopp end_info_ptr_ptr) -{ - png_structrp png_ptr = NULL; - - png_debug(1, "in png_destroy_read_struct"); - - if (png_ptr_ptr != NULL) - png_ptr = *png_ptr_ptr; - - if (png_ptr == NULL) - return; - - /* libpng 1.6.0: use the API to destroy info structs to ensure consistent - * behavior. Prior to 1.6.0 libpng did extra 'info' destruction in this API. - * The extra was, apparently, unnecessary yet this hides memory leak bugs. - */ - png_destroy_info_struct(png_ptr, end_info_ptr_ptr); - png_destroy_info_struct(png_ptr, info_ptr_ptr); - - *png_ptr_ptr = NULL; - png_read_destroy(png_ptr); - png_destroy_png_struct(png_ptr); -} - -void PNGAPI -png_set_read_status_fn(png_structrp png_ptr, png_read_status_ptr read_row_fn) -{ - if (png_ptr == NULL) - return; - - png_ptr->read_row_fn = read_row_fn; -} - - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -#ifdef PNG_INFO_IMAGE_SUPPORTED -void PNGAPI -png_read_png(png_structrp png_ptr, png_inforp info_ptr, - int transforms, - voidp params) -{ - int row; - - if (png_ptr == NULL || info_ptr == NULL) - return; - - /* png_read_info() gives us all of the information from the - * PNG file before the first IDAT (image data chunk). - */ - png_read_info(png_ptr, info_ptr); - if (info_ptr->height > PNG_UINT_32_MAX/(sizeof (png_bytep))) - png_error(png_ptr, "Image is too high to process with png_read_png()"); - - /* -------------- image transformations start here ------------------- */ - -#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED - /* Tell libpng to strip 16-bit/color files down to 8 bits per color. - */ - if (transforms & PNG_TRANSFORM_SCALE_16) - { - /* Added at libpng-1.5.4. "strip_16" produces the same result that it - * did in earlier versions, while "scale_16" is now more accurate. - */ - png_set_scale_16(png_ptr); - } -#endif - -#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED - /* If both SCALE and STRIP are required pngrtran will effectively cancel the - * latter by doing SCALE first. This is ok and allows apps not to check for - * which is supported to get the right answer. - */ - if (transforms & PNG_TRANSFORM_STRIP_16) - png_set_strip_16(png_ptr); -#endif - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - /* Strip alpha bytes from the input data without combining with - * the background (not recommended). - */ - if (transforms & PNG_TRANSFORM_STRIP_ALPHA) - png_set_strip_alpha(png_ptr); -#endif - -#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) - /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single - * byte into separate bytes (useful for paletted and grayscale images). - */ - if (transforms & PNG_TRANSFORM_PACKING) - png_set_packing(png_ptr); -#endif - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - /* Change the order of packed pixels to least significant bit first - * (not useful if you are using png_set_packing). - */ - if (transforms & PNG_TRANSFORM_PACKSWAP) - png_set_packswap(png_ptr); -#endif - -#ifdef PNG_READ_EXPAND_SUPPORTED - /* Expand paletted colors into true RGB triplets - * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel - * Expand paletted or RGB images with transparency to full alpha - * channels so the data will be available as RGBA quartets. - */ - if (transforms & PNG_TRANSFORM_EXPAND) - if ((png_ptr->bit_depth < 8) || - (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) || - (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) - png_set_expand(png_ptr); -#endif - - /* We don't handle background color or gamma transformation or quantizing. - */ - -#ifdef PNG_READ_INVERT_SUPPORTED - /* Invert monochrome files to have 0 as white and 1 as black - */ - if (transforms & PNG_TRANSFORM_INVERT_MONO) - png_set_invert_mono(png_ptr); -#endif - -#ifdef PNG_READ_SHIFT_SUPPORTED - /* If you want to shift the pixel values from the range [0,255] or - * [0,65535] to the original [0,7] or [0,31], or whatever range the - * colors were originally in: - */ - if ((transforms & PNG_TRANSFORM_SHIFT) - && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) - { - png_color_8p sig_bit = 0; - - png_get_sBIT(png_ptr, info_ptr, &sig_bit); - png_set_shift(png_ptr, sig_bit); - } -#endif - -#ifdef PNG_READ_BGR_SUPPORTED - /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ - if (transforms & PNG_TRANSFORM_BGR) - png_set_bgr(png_ptr); -#endif - -#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED - /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ - if (transforms & PNG_TRANSFORM_SWAP_ALPHA) - png_set_swap_alpha(png_ptr); -#endif - -#ifdef PNG_READ_SWAP_SUPPORTED - /* Swap bytes of 16-bit files to least significant byte first */ - if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) - png_set_swap(png_ptr); -#endif - -/* Added at libpng-1.2.41 */ -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED - /* Invert the alpha channel from opacity to transparency */ - if (transforms & PNG_TRANSFORM_INVERT_ALPHA) - png_set_invert_alpha(png_ptr); -#endif - -/* Added at libpng-1.2.41 */ -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - /* Expand grayscale image to RGB */ - if (transforms & PNG_TRANSFORM_GRAY_TO_RGB) - png_set_gray_to_rgb(png_ptr); -#endif - -/* Added at libpng-1.5.4 */ -#ifdef PNG_READ_EXPAND_16_SUPPORTED - if (transforms & PNG_TRANSFORM_EXPAND_16) - png_set_expand_16(png_ptr); -#endif - - /* We don't handle adding filler bytes */ - - /* We use png_read_image and rely on that for interlace handling, but we also - * call png_read_update_info therefore must turn on interlace handling now: - */ - (void)png_set_interlace_handling(png_ptr); - - /* Optional call to gamma correct and add the background to the palette - * and update info structure. REQUIRED if you are expecting libpng to - * update the palette for you (i.e., you selected such a transform above). - */ - png_read_update_info(png_ptr, info_ptr); - - /* -------------- image transformations end here ------------------- */ - - png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); - if (info_ptr->row_pointers == NULL) - { - png_uint_32 iptr; - - info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, - info_ptr->height * (sizeof (png_bytep))); - for (iptr=0; iptrheight; iptr++) - info_ptr->row_pointers[iptr] = NULL; - - info_ptr->free_me |= PNG_FREE_ROWS; - - for (row = 0; row < (int)info_ptr->height; row++) - info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr, - png_get_rowbytes(png_ptr, info_ptr)); - } - - png_read_image(png_ptr, info_ptr->row_pointers); - info_ptr->valid |= PNG_INFO_IDAT; - - /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ - png_read_end(png_ptr, info_ptr); - - PNG_UNUSED(transforms) /* Quiet compiler warnings */ - PNG_UNUSED(params) - -} -#endif /* PNG_INFO_IMAGE_SUPPORTED */ -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ - -#ifdef PNG_SIMPLIFIED_READ_SUPPORTED -/* SIMPLIFIED READ - * - * This code currently relies on the sequential reader, though it could easily - * be made to work with the progressive one. - */ -/* Arguments to png_image_finish_read: */ - -/* Encoding of PNG data (used by the color-map code) */ -/* TODO: change these, dang, ANSI-C reserves the 'E' namespace. */ -# define E_NOTSET 0 /* File encoding not yet known */ -# define E_sRGB 1 /* 8-bit encoded to sRGB gamma */ -# define E_LINEAR 2 /* 16-bit linear: not encoded, NOT pre-multiplied! */ -# define E_FILE 3 /* 8-bit encoded to file gamma, not sRGB or linear */ -# define E_LINEAR8 4 /* 8-bit linear: only from a file value */ - -/* Color-map processing: after libpng has run on the PNG image further - * processing may be needed to conver the data to color-map indicies. - */ -#define PNG_CMAP_NONE 0 -#define PNG_CMAP_GA 1 /* Process GA data to a color-map with alpha */ -#define PNG_CMAP_TRANS 2 /* Process GA data to a background index */ -#define PNG_CMAP_RGB 3 /* Process RGB data */ -#define PNG_CMAP_RGB_ALPHA 4 /* Process RGBA data */ - -/* The following document where the background is for each processing case. */ -#define PNG_CMAP_NONE_BACKGROUND 256 -#define PNG_CMAP_GA_BACKGROUND 231 -#define PNG_CMAP_TRANS_BACKGROUND 254 -#define PNG_CMAP_RGB_BACKGROUND 256 -#define PNG_CMAP_RGB_ALPHA_BACKGROUND 216 - -typedef struct -{ - /* Arguments: */ - png_imagep image; - png_voidp buffer; - png_int_32 row_stride; - png_voidp colormap; - png_const_colorp background; - /* Local variables: */ - png_voidp local_row; - png_voidp first_row; - ptrdiff_t row_bytes; /* step between rows */ - int file_encoding; /* E_ values above */ - png_fixed_point gamma_to_linear; /* For E_FILE, reciprocal of gamma */ - int colormap_processing; /* PNG_CMAP_ values above */ -} png_image_read_control; - -/* Do all the *safe* initialization - 'safe' means that png_error won't be - * called, so setting up the jmp_buf is not required. This means that anything - * called from here must *not* call png_malloc - it has to call png_malloc_warn - * instead so that control is returned safely back to this routine. - */ -static int -png_image_read_init(png_imagep image) -{ - if (image->opaque == NULL) - { - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, image, - png_safe_error, png_safe_warning); - - /* And set the rest of the structure to NULL to ensure that the various - * fields are consistent. - */ - memset(image, 0, (sizeof *image)); - image->version = PNG_IMAGE_VERSION; - - if (png_ptr != NULL) - { - png_infop info_ptr = png_create_info_struct(png_ptr); - - if (info_ptr != NULL) - { - png_controlp control = png_voidcast(png_controlp, - png_malloc_warn(png_ptr, (sizeof *control))); - - if (control != NULL) - { - memset(control, 0, (sizeof *control)); - - control->png_ptr = png_ptr; - control->info_ptr = info_ptr; - control->for_write = 0; - - image->opaque = control; - return 1; - } - - /* Error clean up */ - png_destroy_info_struct(png_ptr, &info_ptr); - } - - png_destroy_read_struct(&png_ptr, NULL, NULL); - } - - return png_image_error(image, "png_image_read: out of memory"); - } - - return png_image_error(image, "png_image_read: opaque pointer not NULL"); -} - -/* Utility to find the base format of a PNG file from a png_struct. */ -static png_uint_32 -png_image_format(png_structrp png_ptr) -{ - png_uint_32 format = 0; - - if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) - format |= PNG_FORMAT_FLAG_COLOR; - - if (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) - format |= PNG_FORMAT_FLAG_ALPHA; - - /* Use png_ptr here, not info_ptr, because by examination png_handle_tRNS - * sets the png_struct fields; that's all we are interested in here. The - * precise interaction with an app call to png_set_tRNS and PNG file reading - * is unclear. - */ - else if (png_ptr->num_trans > 0) - format |= PNG_FORMAT_FLAG_ALPHA; - - if (png_ptr->bit_depth == 16) - format |= PNG_FORMAT_FLAG_LINEAR; - - if (png_ptr->color_type & PNG_COLOR_MASK_PALETTE) - format |= PNG_FORMAT_FLAG_COLORMAP; - - return format; -} - -/* Is the given gamma significantly different from sRGB? The test is the same - * one used in pngrtran.c when deciding whether to do gamma correction. The - * arithmetic optimizes the division by using the fact that the inverse of the - * file sRGB gamma is 2.2 - */ -static int -png_gamma_not_sRGB(png_fixed_point g) -{ - if (g < PNG_FP_1) - { - /* An uninitialized gamma is assumed to be sRGB for the simplified API. */ - if (g == 0) - return 0; - - return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */); - } - - return 1; -} - -/* Do the main body of a 'png_image_begin_read' function; read the PNG file - * header and fill in all the information. This is executed in a safe context, - * unlike the init routine above. - */ -static int -png_image_read_header(png_voidp argument) -{ - png_imagep image = png_voidcast(png_imagep, argument); - png_structrp png_ptr = image->opaque->png_ptr; - png_inforp info_ptr = image->opaque->info_ptr; - - png_set_benign_errors(png_ptr, 1/*warn*/); - png_read_info(png_ptr, info_ptr); - - /* Do this the fast way; just read directly out of png_struct. */ - image->width = png_ptr->width; - image->height = png_ptr->height; - - { - png_uint_32 format = png_image_format(png_ptr); - - image->format = format; - -#ifdef PNG_COLORSPACE_SUPPORTED - /* Does the colorspace match sRGB? If there is no color endpoint - * (colorant) information assume yes, otherwise require the - * 'ENDPOINTS_MATCHE_sRGB' colorspace flag to have been set. If the - * colorspace has been determined to be invalid ignore it. - */ - if ((format & PNG_FORMAT_FLAG_COLOR) != 0 && ((png_ptr->colorspace.flags - & (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB| - PNG_COLORSPACE_INVALID)) == PNG_COLORSPACE_HAVE_ENDPOINTS)) - image->flags |= PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB; -#endif - } - - /* We need the maximum number of entries regardless of the format the - * application sets here. - */ - { - png_uint_32 cmap_entries; - - switch (png_ptr->color_type) - { - case PNG_COLOR_TYPE_GRAY: - cmap_entries = 1U << png_ptr->bit_depth; - break; - - case PNG_COLOR_TYPE_PALETTE: - cmap_entries = png_ptr->num_palette; - break; - - default: - cmap_entries = 256; - break; - } - - if (cmap_entries > 256) - cmap_entries = 256; - - image->colormap_entries = cmap_entries; - } - - return 1; -} - -#ifdef PNG_STDIO_SUPPORTED -int PNGAPI -png_image_begin_read_from_stdio(png_imagep image, FILE* file) -{ - if (image != NULL && image->version == PNG_IMAGE_VERSION) - { - if (file != NULL) - { - if (png_image_read_init(image)) - { - /* This is slightly evil, but png_init_io doesn't do anything other - * than this and we haven't changed the standard IO functions so - * this saves a 'safe' function. - */ - image->opaque->png_ptr->io_ptr = file; - return png_safe_execute(image, png_image_read_header, image); - } - } - - else - return png_image_error(image, - "png_image_begin_read_from_stdio: invalid argument"); - } - - else if (image != NULL) - return png_image_error(image, - "png_image_begin_read_from_stdio: incorrect PNG_IMAGE_VERSION"); - - return 0; -} - -int PNGAPI -png_image_begin_read_from_file(png_imagep image, const char *file_name) -{ - if (image != NULL && image->version == PNG_IMAGE_VERSION) - { - if (file_name != NULL) - { - FILE *fp = fopen(file_name, "rb"); - - if (fp != NULL) - { - if (png_image_read_init(image)) - { - image->opaque->png_ptr->io_ptr = fp; - image->opaque->owned_file = 1; - return png_safe_execute(image, png_image_read_header, image); - } - - /* Clean up: just the opened file. */ - (void)fclose(fp); - } - - else - return png_image_error(image, strerror(errno)); - } - - else - return png_image_error(image, - "png_image_begin_read_from_file: invalid argument"); - } - - else if (image != NULL) - return png_image_error(image, - "png_image_begin_read_from_file: incorrect PNG_IMAGE_VERSION"); - - return 0; -} -#endif /* PNG_STDIO_SUPPORTED */ - -static void PNGCBAPI -png_image_memory_read(png_structp png_ptr, png_bytep out, png_size_t need) -{ - if (png_ptr != NULL) - { - png_imagep image = png_voidcast(png_imagep, png_ptr->io_ptr); - if (image != NULL) - { - png_controlp cp = image->opaque; - if (cp != NULL) - { - png_const_bytep memory = cp->memory; - png_size_t size = cp->size; - - if (memory != NULL && size >= need) - { - memcpy(out, memory, need); - cp->memory = memory + need; - cp->size = size - need; - return; - } - - png_error(png_ptr, "read beyond end of data"); - } - } - - png_error(png_ptr, "invalid memory read"); - } -} - -int PNGAPI png_image_begin_read_from_memory(png_imagep image, - png_const_voidp memory, png_size_t size) -{ - if (image != NULL && image->version == PNG_IMAGE_VERSION) - { - if (memory != NULL && size > 0) - { - if (png_image_read_init(image)) - { - /* Now set the IO functions to read from the memory buffer and - * store it into io_ptr. Again do this in-place to avoid calling a - * libpng function that requires error handling. - */ - image->opaque->memory = png_voidcast(png_const_bytep, memory); - image->opaque->size = size; - image->opaque->png_ptr->io_ptr = image; - image->opaque->png_ptr->read_data_fn = png_image_memory_read; - - return png_safe_execute(image, png_image_read_header, image); - } - } - - else - return png_image_error(image, - "png_image_begin_read_from_memory: invalid argument"); - } - - else if (image != NULL) - return png_image_error(image, - "png_image_begin_read_from_memory: incorrect PNG_IMAGE_VERSION"); - - return 0; -} - -/* Utility function to skip chunks that are not used by the simplified image - * read functions and an appropriate macro to call it. - */ -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -static void -png_image_skip_unused_chunks(png_structrp png_ptr) -{ - /* Prepare the reader to ignore all recognized chunks whose data will not - * be used, i.e., all chunks recognized by libpng except for those - * involved in basic image reading: - * - * IHDR, PLTE, IDAT, IEND - * - * Or image data handling: - * - * tRNS, bKGD, gAMA, cHRM, sRGB, iCCP and sBIT. - * - * This provides a small performance improvement and eliminates any - * potential vulnerability to security problems in the unused chunks. - */ - { - static PNG_CONST png_byte chunks_to_process[] = { - 98, 75, 71, 68, '\0', /* bKGD */ - 99, 72, 82, 77, '\0', /* cHRM */ - 103, 65, 77, 65, '\0', /* gAMA */ - 105, 67, 67, 80, '\0', /* iCCP */ - 115, 66, 73, 84, '\0', /* sBIT */ - 115, 82, 71, 66, '\0', /* sRGB */ - }; - - /* Ignore unknown chunks and all other chunks except for the - * IHDR, PLTE, tRNS, IDAT, and IEND chunks. - */ - png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, - NULL, -1); - - /* But do not ignore image data handling chunks */ - png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_AS_DEFAULT, - chunks_to_process, (sizeof chunks_to_process)/5); - } -} - -# define PNG_SKIP_CHUNKS(p) png_image_skip_unused_chunks(p) -#else -# define PNG_SKIP_CHUNKS(p) ((void)0) -#endif /* PNG_HANDLE_AS_UNKNOWN_SUPPORTED */ - -/* The following macro gives the exact rounded answer for all values in the - * range 0..255 (it actually divides by 51.2, but the rounding still generates - * the correct numbers 0..5 - */ -#define PNG_DIV51(v8) (((v8) * 5 + 130) >> 8) - -/* Utility functions to make particular color-maps */ -static void -set_file_encoding(png_image_read_control *display) -{ - png_fixed_point g = display->image->opaque->png_ptr->colorspace.gamma; - if (png_gamma_significant(g)) - { - if (png_gamma_not_sRGB(g)) - { - display->file_encoding = E_FILE; - display->gamma_to_linear = png_reciprocal(g); - } - - else - display->file_encoding = E_sRGB; - } - - else - display->file_encoding = E_LINEAR8; -} - -static unsigned int -decode_gamma(png_image_read_control *display, png_uint_32 value, int encoding) -{ - if (encoding == E_FILE) /* double check */ - encoding = display->file_encoding; - - if (encoding == E_NOTSET) /* must be the file encoding */ - { - set_file_encoding(display); - encoding = display->file_encoding; - } - - switch (encoding) - { - case E_FILE: - value = png_gamma_16bit_correct(value*257, display->gamma_to_linear); - break; - - case E_sRGB: - value = png_sRGB_table[value]; - break; - - case E_LINEAR: - break; - - case E_LINEAR8: - value *= 257; - break; - - default: - png_error(display->image->opaque->png_ptr, - "unexpected encoding (internal error)"); - break; - } - - return value; -} - -static png_uint_32 -png_colormap_compose(png_image_read_control *display, - png_uint_32 foreground, int foreground_encoding, png_uint_32 alpha, - png_uint_32 background, int encoding) -{ - /* The file value is composed on the background, the background has the given - * encoding and so does the result, the file is encoded with E_FILE and the - * file and alpha are 8-bit values. The (output) encoding will always be - * E_LINEAR or E_sRGB. - */ - png_uint_32 f = decode_gamma(display, foreground, foreground_encoding); - png_uint_32 b = decode_gamma(display, background, encoding); - - /* The alpha is always an 8-bit value (it comes from the palette), the value - * scaled by 255 is what PNG_sRGB_FROM_LINEAR requires. - */ - f = f * alpha + b * (255-alpha); - - if (encoding == E_LINEAR) - { - /* Scale to 65535; divide by 255, approximately (in fact this is extremely - * accurate, it divides by 255.00000005937181414556, with no overflow.) - */ - f *= 257; /* Now scaled by 65535 */ - f += f >> 16; - f = (f+32768) >> 16; - } - - else /* E_sRGB */ - f = PNG_sRGB_FROM_LINEAR(f); - - return f; -} - -/* NOTE: E_LINEAR values to this routine must be 16-bit, but E_FILE values must - * be 8-bit. - */ -static void -png_create_colormap_entry(png_image_read_control *display, - png_uint_32 ip, png_uint_32 red, png_uint_32 green, png_uint_32 blue, - png_uint_32 alpha, int encoding) -{ - png_imagep image = display->image; - const int output_encoding = (image->format & PNG_FORMAT_FLAG_LINEAR) ? - E_LINEAR : E_sRGB; - const int convert_to_Y = (image->format & PNG_FORMAT_FLAG_COLOR) == 0 && - (red != green || green != blue); - - if (ip > 255) - png_error(image->opaque->png_ptr, "color-map index out of range"); - - /* Update the cache with whether the file gamma is significantly different - * from sRGB. - */ - if (encoding == E_FILE) - { - if (display->file_encoding == E_NOTSET) - set_file_encoding(display); - - /* Note that the cached value may be E_FILE too, but if it is then the - * gamma_to_linear member has been set. - */ - encoding = display->file_encoding; - } - - if (encoding == E_FILE) - { - png_fixed_point g = display->gamma_to_linear; - - red = png_gamma_16bit_correct(red*257, g); - green = png_gamma_16bit_correct(green*257, g); - blue = png_gamma_16bit_correct(blue*257, g); - - if (convert_to_Y || output_encoding == E_LINEAR) - { - alpha *= 257; - encoding = E_LINEAR; - } - - else - { - red = PNG_sRGB_FROM_LINEAR(red * 255); - green = PNG_sRGB_FROM_LINEAR(green * 255); - blue = PNG_sRGB_FROM_LINEAR(blue * 255); - encoding = E_sRGB; - } - } - - else if (encoding == E_LINEAR8) - { - /* This encoding occurs quite frequently in test cases because PngSuite - * includes a gAMA 1.0 chunk with most images. - */ - red *= 257; - green *= 257; - blue *= 257; - alpha *= 257; - encoding = E_LINEAR; - } - - else if (encoding == E_sRGB && (convert_to_Y || output_encoding == E_LINEAR)) - { - /* The values are 8-bit sRGB values, but must be converted to 16-bit - * linear. - */ - red = png_sRGB_table[red]; - green = png_sRGB_table[green]; - blue = png_sRGB_table[blue]; - alpha *= 257; - encoding = E_LINEAR; - } - - /* This is set if the color isn't gray but the output is. */ - if (encoding == E_LINEAR) - { - if (convert_to_Y) - { - /* NOTE: these values are copied from png_do_rgb_to_gray */ - png_uint_32 y = (png_uint_32)6968 * red + (png_uint_32)23434 * green + - (png_uint_32)2366 * blue; - - if (output_encoding == E_LINEAR) - y = (y + 16384) >> 15; - - else - { - /* y is scaled by 32768, we need it scaled by 255: */ - y = (y + 128) >> 8; - y *= 255; - y = PNG_sRGB_FROM_LINEAR((y + 64) >> 7); - encoding = E_sRGB; - } - - blue = red = green = y; - } - - else if (output_encoding == E_sRGB) - { - red = PNG_sRGB_FROM_LINEAR(red * 255); - green = PNG_sRGB_FROM_LINEAR(green * 255); - blue = PNG_sRGB_FROM_LINEAR(blue * 255); - alpha = PNG_DIV257(alpha); - encoding = E_sRGB; - } - } - - if (encoding != output_encoding) - png_error(image->opaque->png_ptr, "bad encoding (internal error)"); - - /* Store the value. */ - { -# ifdef PNG_FORMAT_BGR_SUPPORTED - const int afirst = (image->format & PNG_FORMAT_FLAG_AFIRST) != 0 && - (image->format & PNG_FORMAT_FLAG_ALPHA) != 0; -# else -# define afirst 0 -# endif -# ifdef PNG_FORMAT_BGR_SUPPORTED - const int bgr = (image->format & PNG_FORMAT_FLAG_BGR) ? 2 : 0; -# else -# define bgr 0 -# endif - - if (output_encoding == E_LINEAR) - { - png_uint_16p entry = png_voidcast(png_uint_16p, display->colormap); - - entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format); - - /* The linear 16-bit values must be pre-multiplied by the alpha channel - * value, if less than 65535 (this is, effectively, composite on black - * if the alpha channel is removed.) - */ - switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format)) - { - case 4: - entry[afirst ? 0 : 3] = (png_uint_16)alpha; - /* FALL THROUGH */ - - case 3: - if (alpha < 65535) - { - if (alpha > 0) - { - blue = (blue * alpha + 32767U)/65535U; - green = (green * alpha + 32767U)/65535U; - red = (red * alpha + 32767U)/65535U; - } - - else - red = green = blue = 0; - } - entry[afirst + (2 ^ bgr)] = (png_uint_16)blue; - entry[afirst + 1] = (png_uint_16)green; - entry[afirst + bgr] = (png_uint_16)red; - break; - - case 2: - entry[1 ^ afirst] = (png_uint_16)alpha; - /* FALL THROUGH */ - - case 1: - if (alpha < 65535) - { - if (alpha > 0) - green = (green * alpha + 32767U)/65535U; - - else - green = 0; - } - entry[afirst] = (png_uint_16)green; - break; - - default: - break; - } - } - - else /* output encoding is E_sRGB */ - { - png_bytep entry = png_voidcast(png_bytep, display->colormap); - - entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format); - - switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format)) - { - case 4: - entry[afirst ? 0 : 3] = (png_byte)alpha; - case 3: - entry[afirst + (2 ^ bgr)] = (png_byte)blue; - entry[afirst + 1] = (png_byte)green; - entry[afirst + bgr] = (png_byte)red; - break; - - case 2: - entry[1 ^ afirst] = (png_byte)alpha; - case 1: - entry[afirst] = (png_byte)green; - break; - - default: - break; - } - } - -# ifdef afirst -# undef afirst -# endif -# ifdef bgr -# undef bgr -# endif - } -} - -static int -make_gray_file_colormap(png_image_read_control *display) -{ - unsigned int i; - - for (i=0; i<256; ++i) - png_create_colormap_entry(display, i, i, i, i, 255, E_FILE); - - return i; -} - -static int -make_gray_colormap(png_image_read_control *display) -{ - unsigned int i; - - for (i=0; i<256; ++i) - png_create_colormap_entry(display, i, i, i, i, 255, E_sRGB); - - return i; -} -#define PNG_GRAY_COLORMAP_ENTRIES 256 - -static int -make_ga_colormap(png_image_read_control *display) -{ - unsigned int i, a; - - /* Alpha is retained, the output will be a color-map with entries - * selected by six levels of alpha. One transparent entry, 6 gray - * levels for all the intermediate alpha values, leaving 230 entries - * for the opaque grays. The color-map entries are the six values - * [0..5]*51, the GA processing uses PNG_DIV51(value) to find the - * relevant entry. - * - * if (alpha > 229) // opaque - * { - * // The 231 entries are selected to make the math below work: - * base = 0; - * entry = (231 * gray + 128) >> 8; - * } - * else if (alpha < 26) // transparent - * { - * base = 231; - * entry = 0; - * } - * else // partially opaque - * { - * base = 226 + 6 * PNG_DIV51(alpha); - * entry = PNG_DIV51(gray); - * } - */ - i = 0; - while (i < 231) - { - unsigned int gray = (i * 256 + 115) / 231; - png_create_colormap_entry(display, i++, gray, gray, gray, 255, E_sRGB); - } - - /* 255 is used here for the component values for consistency with the code - * that undoes premultiplication in pngwrite.c. - */ - png_create_colormap_entry(display, i++, 255, 255, 255, 0, E_sRGB); - - for (a=1; a<5; ++a) - { - unsigned int g; - - for (g=0; g<6; ++g) - png_create_colormap_entry(display, i++, g*51, g*51, g*51, a*51, - E_sRGB); - } - - return i; -} - -#define PNG_GA_COLORMAP_ENTRIES 256 - -static int -make_rgb_colormap(png_image_read_control *display) -{ - unsigned int i, r; - - /* Build a 6x6x6 opaque RGB cube */ - for (i=r=0; r<6; ++r) - { - unsigned int g; - - for (g=0; g<6; ++g) - { - unsigned int b; - - for (b=0; b<6; ++b) - png_create_colormap_entry(display, i++, r*51, g*51, b*51, 255, - E_sRGB); - } - } - - return i; -} - -#define PNG_RGB_COLORMAP_ENTRIES 216 - -/* Return a palette index to the above palette given three 8-bit sRGB values. */ -#define PNG_RGB_INDEX(r,g,b) \ - ((png_byte)(6 * (6 * PNG_DIV51(r) + PNG_DIV51(g)) + PNG_DIV51(b))) - -static int -png_image_read_colormap(png_voidp argument) -{ - png_image_read_control *display = - png_voidcast(png_image_read_control*, argument); - const png_imagep image = display->image; - - const png_structrp png_ptr = image->opaque->png_ptr; - const png_uint_32 output_format = image->format; - const int output_encoding = (output_format & PNG_FORMAT_FLAG_LINEAR) ? - E_LINEAR : E_sRGB; - - unsigned int cmap_entries; - unsigned int output_processing; /* Output processing option */ - unsigned int data_encoding = E_NOTSET; /* Encoding libpng must produce */ - - /* Background information; the background color and the index of this color - * in the color-map if it exists (else 256). - */ - unsigned int background_index = 256; - png_uint_32 back_r, back_g, back_b; - - /* Flags to accumulate things that need to be done to the input. */ - int expand_tRNS = 0; - - /* Exclude the NYI feature of compositing onto a color-mapped buffer; it is - * very difficult to do, the results look awful, and it is difficult to see - * what possible use it is because the application can't control the - * color-map. - */ - if (((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0 || - png_ptr->num_trans > 0) /* alpha in input */ && - ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) /* no alpha in output */) - { - if (output_encoding == E_LINEAR) /* compose on black */ - back_b = back_g = back_r = 0; - - else if (display->background == NULL /* no way to remove it */) - png_error(png_ptr, - "a background color must be supplied to remove alpha/transparency"); - - /* Get a copy of the background color (this avoids repeating the checks - * below.) The encoding is 8-bit sRGB or 16-bit linear, depending on the - * output format. - */ - else - { - back_g = display->background->green; - if (output_format & PNG_FORMAT_FLAG_COLOR) - { - back_r = display->background->red; - back_b = display->background->blue; - } - else - back_b = back_r = back_g; - } - } - - else if (output_encoding == E_LINEAR) - back_b = back_r = back_g = 65535; - - else - back_b = back_r = back_g = 255; - - /* Default the input file gamma if required - this is necessary because - * libpng assumes that if no gamma information is present the data is in the - * output format, but the simplified API deduces the gamma from the input - * format. - */ - if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) == 0) - { - /* Do this directly, not using the png_colorspace functions, to ensure - * that it happens even if the colorspace is invalid (though probably if - * it is the setting will be ignored) Note that the same thing can be - * achieved at the application interface with png_set_gAMA. - */ - if (png_ptr->bit_depth == 16 && - (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) - png_ptr->colorspace.gamma = PNG_GAMMA_LINEAR; - - else - png_ptr->colorspace.gamma = PNG_GAMMA_sRGB_INVERSE; - - png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; - } - - /* Decide what to do based on the PNG color type of the input data. The - * utility function png_create_colormap_entry deals with most aspects of the - * output transformations; this code works out how to produce bytes of - * color-map entries from the original format. - */ - switch (png_ptr->color_type) - { - case PNG_COLOR_TYPE_GRAY: - if (png_ptr->bit_depth <= 8) - { - /* There at most 256 colors in the output, regardless of - * transparency. - */ - unsigned int step, i, val, trans = 256/*ignore*/, back_alpha = 0; - - cmap_entries = 1U << png_ptr->bit_depth; - if (cmap_entries > image->colormap_entries) - png_error(png_ptr, "gray[8] color-map: too few entries"); - - step = 255 / (cmap_entries - 1); - output_processing = PNG_CMAP_NONE; - - /* If there is a tRNS chunk then this either selects a transparent - * value or, if the output has no alpha, the background color. - */ - if (png_ptr->num_trans > 0) - { - trans = png_ptr->trans_color.gray; - - if ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) - back_alpha = output_encoding == E_LINEAR ? 65535 : 255; - } - - /* png_create_colormap_entry just takes an RGBA and writes the - * corresponding color-map entry using the format from 'image', - * including the required conversion to sRGB or linear as - * appropriate. The input values are always either sRGB (if the - * gamma correction flag is 0) or 0..255 scaled file encoded values - * (if the function must gamma correct them). - */ - for (i=val=0; ibit_depth < 8) - png_set_packing(png_ptr); - } - - else /* bit depth is 16 */ - { - /* The 16-bit input values can be converted directly to 8-bit gamma - * encoded values; however, if a tRNS chunk is present 257 color-map - * entries are required. This means that the extra entry requires - * special processing; add an alpha channel, sacrifice gray level - * 254 and convert transparent (alpha==0) entries to that. - * - * Use libpng to chop the data to 8 bits. Convert it to sRGB at the - * same time to minimize quality loss. If a tRNS chunk is present - * this means libpng must handle it too; otherwise it is impossible - * to do the exact match on the 16-bit value. - * - * If the output has no alpha channel *and* the background color is - * gray then it is possible to let libpng handle the substitution by - * ensuring that the corresponding gray level matches the background - * color exactly. - */ - data_encoding = E_sRGB; - - if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) - png_error(png_ptr, "gray[16] color-map: too few entries"); - - cmap_entries = make_gray_colormap(display); - - if (png_ptr->num_trans > 0) - { - unsigned int back_alpha; - - if (output_format & PNG_FORMAT_FLAG_ALPHA) - back_alpha = 0; - - else - { - if (back_r == back_g && back_g == back_b) - { - /* Background is gray; no special processing will be - * required. - */ - png_color_16 c; - png_uint_32 gray = back_g; - - if (output_encoding == E_LINEAR) - { - gray = PNG_sRGB_FROM_LINEAR(gray * 255); - - /* And make sure the corresponding palette entry - * matches. - */ - png_create_colormap_entry(display, gray, back_g, back_g, - back_g, 65535, E_LINEAR); - } - - /* The background passed to libpng, however, must be the - * sRGB value. - */ - c.index = 0; /*unused*/ - c.gray = c.red = c.green = c.blue = (png_uint_16)gray; - - /* NOTE: does this work without expanding tRNS to alpha? - * It should be the color->gray case below apparently - * doesn't. - */ - png_set_background_fixed(png_ptr, &c, - PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, - 0/*gamma: not used*/); - - output_processing = PNG_CMAP_NONE; - break; - } - - back_alpha = output_encoding == E_LINEAR ? 65535 : 255; - } - - /* output_processing means that the libpng-processed row will be - * 8-bit GA and it has to be processing to single byte color-map - * values. Entry 254 is replaced by either a completely - * transparent entry or by the background color at full - * precision (and the background color is not a simple gray leve - * in this case.) - */ - expand_tRNS = 1; - output_processing = PNG_CMAP_TRANS; - background_index = 254; - - /* And set (overwrite) color-map entry 254 to the actual - * background color at full precision. - */ - png_create_colormap_entry(display, 254, back_r, back_g, back_b, - back_alpha, output_encoding); - } - - else - output_processing = PNG_CMAP_NONE; - } - break; - - case PNG_COLOR_TYPE_GRAY_ALPHA: - /* 8-bit or 16-bit PNG with two channels - gray and alpha. A minimum - * of 65536 combinations. If, however, the alpha channel is to be - * removed there are only 256 possibilities if the background is gray. - * (Otherwise there is a subset of the 65536 possibilities defined by - * the triangle between black, white and the background color.) - * - * Reduce 16-bit files to 8-bit and sRGB encode the result. No need to - * worry about tRNS matching - tRNS is ignored if there is an alpha - * channel. - */ - data_encoding = E_sRGB; - - if (output_format & PNG_FORMAT_FLAG_ALPHA) - { - if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) - png_error(png_ptr, "gray+alpha color-map: too few entries"); - - cmap_entries = make_ga_colormap(display); - - background_index = PNG_CMAP_GA_BACKGROUND; - output_processing = PNG_CMAP_GA; - } - - else /* alpha is removed */ - { - /* Alpha must be removed as the PNG data is processed when the - * background is a color because the G and A channels are - * independent and the vector addition (non-parallel vectors) is a - * 2-D problem. - * - * This can be reduced to the same algorithm as above by making a - * colormap containing gray levels (for the opaque grays), a - * background entry (for a transparent pixel) and a set of four six - * level color values, one set for each intermediate alpha value. - * See the comments in make_ga_colormap for how this works in the - * per-pixel processing. - * - * If the background is gray, however, we only need a 256 entry gray - * level color map. It is sufficient to make the entry generated - * for the background color be exactly the color specified. - */ - if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0 || - (back_r == back_g && back_g == back_b)) - { - /* Background is gray; no special processing will be required. */ - png_color_16 c; - png_uint_32 gray = back_g; - - if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) - png_error(png_ptr, "gray-alpha color-map: too few entries"); - - cmap_entries = make_gray_colormap(display); - - if (output_encoding == E_LINEAR) - { - gray = PNG_sRGB_FROM_LINEAR(gray * 255); - - /* And make sure the corresponding palette entry matches. */ - png_create_colormap_entry(display, gray, back_g, back_g, - back_g, 65535, E_LINEAR); - } - - /* The background passed to libpng, however, must be the sRGB - * value. - */ - c.index = 0; /*unused*/ - c.gray = c.red = c.green = c.blue = (png_uint_16)gray; - - png_set_background_fixed(png_ptr, &c, - PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, - 0/*gamma: not used*/); - - output_processing = PNG_CMAP_NONE; - } - - else - { - png_uint_32 i, a; - - /* This is the same as png_make_ga_colormap, above, except that - * the entries are all opaque. - */ - if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) - png_error(png_ptr, "ga-alpha color-map: too few entries"); - - i = 0; - while (i < 231) - { - png_uint_32 gray = (i * 256 + 115) / 231; - png_create_colormap_entry(display, i++, gray, gray, gray, - 255, E_sRGB); - } - - /* NOTE: this preserves the full precision of the application - * background color. - */ - background_index = i; - png_create_colormap_entry(display, i++, back_r, back_g, back_b, - output_encoding == E_LINEAR ? 65535U : 255U, output_encoding); - - /* For non-opaque input composite on the sRGB background - this - * requires inverting the encoding for each component. The input - * is still converted to the sRGB encoding because this is a - * reasonable approximate to the logarithmic curve of human - * visual sensitivity, at least over the narrow range which PNG - * represents. Consequently 'G' is always sRGB encoded, while - * 'A' is linear. We need the linear background colors. - */ - if (output_encoding == E_sRGB) /* else already linear */ - { - /* This may produce a value not exactly matching the - * background, but that's ok because these numbers are only - * used when alpha != 0 - */ - back_r = png_sRGB_table[back_r]; - back_g = png_sRGB_table[back_g]; - back_b = png_sRGB_table[back_b]; - } - - for (a=1; a<5; ++a) - { - unsigned int g; - - /* PNG_sRGB_FROM_LINEAR expects a 16-bit linear value scaled - * by an 8-bit alpha value (0..255). - */ - png_uint_32 alpha = 51 * a; - png_uint_32 back_rx = (255-alpha) * back_r; - png_uint_32 back_gx = (255-alpha) * back_g; - png_uint_32 back_bx = (255-alpha) * back_b; - - for (g=0; g<6; ++g) - { - png_uint_32 gray = png_sRGB_table[g*51] * alpha; - - png_create_colormap_entry(display, i++, - PNG_sRGB_FROM_LINEAR(gray + back_rx), - PNG_sRGB_FROM_LINEAR(gray + back_gx), - PNG_sRGB_FROM_LINEAR(gray + back_bx), 255, E_sRGB); - } - } - - cmap_entries = i; - output_processing = PNG_CMAP_GA; - } - } - break; - - case PNG_COLOR_TYPE_RGB: - case PNG_COLOR_TYPE_RGB_ALPHA: - /* Exclude the case where the output is gray; we can always handle this - * with the cases above. - */ - if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0) - { - /* The color-map will be grayscale, so we may as well convert the - * input RGB values to a simple grayscale and use the grayscale - * code above. - * - * NOTE: calling this apparently damages the recognition of the - * transparent color in background color handling; call - * png_set_tRNS_to_alpha before png_set_background_fixed. - */ - png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, -1, - -1); - data_encoding = E_sRGB; - - /* The output will now be one or two 8-bit gray or gray+alpha - * channels. The more complex case arises when the input has alpha. - */ - if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || - png_ptr->num_trans > 0) && - (output_format & PNG_FORMAT_FLAG_ALPHA) != 0) - { - /* Both input and output have an alpha channel, so no background - * processing is required; just map the GA bytes to the right - * color-map entry. - */ - expand_tRNS = 1; - - if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) - png_error(png_ptr, "rgb[ga] color-map: too few entries"); - - cmap_entries = make_ga_colormap(display); - background_index = PNG_CMAP_GA_BACKGROUND; - output_processing = PNG_CMAP_GA; - } - - else - { - /* Either the input or the output has no alpha channel, so there - * will be no non-opaque pixels in the color-map; it will just be - * grayscale. - */ - if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) - png_error(png_ptr, "rgb[gray] color-map: too few entries"); - - /* Ideally this code would use libpng to do the gamma correction, - * but if an input alpha channel is to be removed we will hit the - * libpng bug in gamma+compose+rgb-to-gray (the double gamma - * correction bug). Fix this by dropping the gamma correction in - * this case and doing it in the palette; this will result in - * duplicate palette entries, but that's better than the - * alternative of double gamma correction. - */ - if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || - png_ptr->num_trans > 0) && - png_gamma_not_sRGB(png_ptr->colorspace.gamma)) - { - cmap_entries = make_gray_file_colormap(display); - data_encoding = E_FILE; - } - - else - cmap_entries = make_gray_colormap(display); - - /* But if the input has alpha or transparency it must be removed - */ - if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || - png_ptr->num_trans > 0) - { - png_color_16 c; - png_uint_32 gray = back_g; - - /* We need to ensure that the application background exists in - * the colormap and that completely transparent pixels map to - * it. Achieve this simply by ensuring that the entry - * selected for the background really is the background color. - */ - if (data_encoding == E_FILE) /* from the fixup above */ - { - /* The app supplied a gray which is in output_encoding, we - * need to convert it to a value of the input (E_FILE) - * encoding then set this palette entry to the required - * output encoding. - */ - if (output_encoding == E_sRGB) - gray = png_sRGB_table[gray]; /* now E_LINEAR */ - - gray = PNG_DIV257(png_gamma_16bit_correct(gray, - png_ptr->colorspace.gamma)); /* now E_FILE */ - - /* And make sure the corresponding palette entry contains - * exactly the required sRGB value. - */ - png_create_colormap_entry(display, gray, back_g, back_g, - back_g, 0/*unused*/, output_encoding); - } - - else if (output_encoding == E_LINEAR) - { - gray = PNG_sRGB_FROM_LINEAR(gray * 255); - - /* And make sure the corresponding palette entry matches. - */ - png_create_colormap_entry(display, gray, back_g, back_g, - back_g, 0/*unused*/, E_LINEAR); - } - - /* The background passed to libpng, however, must be the - * output (normally sRGB) value. - */ - c.index = 0; /*unused*/ - c.gray = c.red = c.green = c.blue = (png_uint_16)gray; - - /* NOTE: the following is apparently a bug in libpng. Without - * it the transparent color recognition in - * png_set_background_fixed seems to go wrong. - */ - expand_tRNS = 1; - png_set_background_fixed(png_ptr, &c, - PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, - 0/*gamma: not used*/); - } - - output_processing = PNG_CMAP_NONE; - } - } - - else /* output is color */ - { - /* We could use png_quantize here so long as there is no transparent - * color or alpha; png_quantize ignores alpha. Easier overall just - * to do it once and using PNG_DIV51 on the 6x6x6 reduced RGB cube. - * Consequently we always want libpng to produce sRGB data. - */ - data_encoding = E_sRGB; - - /* Is there any transparency or alpha? */ - if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || - png_ptr->num_trans > 0) - { - /* Is there alpha in the output too? If so all four channels are - * processed into a special RGB cube with alpha support. - */ - if (output_format & PNG_FORMAT_FLAG_ALPHA) - { - png_uint_32 r; - - if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries) - png_error(png_ptr, "rgb+alpha color-map: too few entries"); - - cmap_entries = make_rgb_colormap(display); - - /* Add a transparent entry. */ - png_create_colormap_entry(display, cmap_entries, 255, 255, - 255, 0, E_sRGB); - - /* This is stored as the background index for the processing - * algorithm. - */ - background_index = cmap_entries++; - - /* Add 27 r,g,b entries each with alpha 0.5. */ - for (r=0; r<256; r = (r << 1) | 0x7f) - { - png_uint_32 g; - - for (g=0; g<256; g = (g << 1) | 0x7f) - { - png_uint_32 b; - - /* This generates components with the values 0, 127 and - * 255 - */ - for (b=0; b<256; b = (b << 1) | 0x7f) - png_create_colormap_entry(display, cmap_entries++, - r, g, b, 128, E_sRGB); - } - } - - expand_tRNS = 1; - output_processing = PNG_CMAP_RGB_ALPHA; - } - - else - { - /* Alpha/transparency must be removed. The background must - * exist in the color map (achieved by setting adding it after - * the 666 color-map). If the standard processing code will - * pick up this entry automatically that's all that is - * required; libpng can be called to do the background - * processing. - */ - unsigned int sample_size = - PNG_IMAGE_SAMPLE_SIZE(output_format); - png_uint_32 r, g, b; /* sRGB background */ - - if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries) - png_error(png_ptr, "rgb-alpha color-map: too few entries"); - - cmap_entries = make_rgb_colormap(display); - - png_create_colormap_entry(display, cmap_entries, back_r, - back_g, back_b, 0/*unused*/, output_encoding); - - if (output_encoding == E_LINEAR) - { - r = PNG_sRGB_FROM_LINEAR(back_r * 255); - g = PNG_sRGB_FROM_LINEAR(back_g * 255); - b = PNG_sRGB_FROM_LINEAR(back_b * 255); - } - - else - { - r = back_r; - g = back_g; - b = back_g; - } - - /* Compare the newly-created color-map entry with the one the - * PNG_CMAP_RGB algorithm will use. If the two entries don't - * match, add the new one and set this as the background - * index. - */ - if (memcmp((png_const_bytep)display->colormap + - sample_size * cmap_entries, - (png_const_bytep)display->colormap + - sample_size * PNG_RGB_INDEX(r,g,b), - sample_size) != 0) - { - /* The background color must be added. */ - background_index = cmap_entries++; - - /* Add 27 r,g,b entries each with created by composing with - * the background at alpha 0.5. - */ - for (r=0; r<256; r = (r << 1) | 0x7f) - { - for (g=0; g<256; g = (g << 1) | 0x7f) - { - /* This generates components with the values 0, 127 - * and 255 - */ - for (b=0; b<256; b = (b << 1) | 0x7f) - png_create_colormap_entry(display, cmap_entries++, - png_colormap_compose(display, r, E_sRGB, 128, - back_r, output_encoding), - png_colormap_compose(display, g, E_sRGB, 128, - back_g, output_encoding), - png_colormap_compose(display, b, E_sRGB, 128, - back_b, output_encoding), - 0/*unused*/, output_encoding); - } - } - - expand_tRNS = 1; - output_processing = PNG_CMAP_RGB_ALPHA; - } - - else /* background color is in the standard color-map */ - { - png_color_16 c; - - c.index = 0; /*unused*/ - c.red = (png_uint_16)back_r; - c.gray = c.green = (png_uint_16)back_g; - c.blue = (png_uint_16)back_b; - - png_set_background_fixed(png_ptr, &c, - PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, - 0/*gamma: not used*/); - - output_processing = PNG_CMAP_RGB; - } - } - } - - else /* no alpha or transparency in the input */ - { - /* Alpha in the output is irrelevant, simply map the opaque input - * pixels to the 6x6x6 color-map. - */ - if (PNG_RGB_COLORMAP_ENTRIES > image->colormap_entries) - png_error(png_ptr, "rgb color-map: too few entries"); - - cmap_entries = make_rgb_colormap(display); - output_processing = PNG_CMAP_RGB; - } - } - break; - - case PNG_COLOR_TYPE_PALETTE: - /* It's already got a color-map. It may be necessary to eliminate the - * tRNS entries though. - */ - { - unsigned int num_trans = png_ptr->num_trans; - png_const_bytep trans = num_trans > 0 ? png_ptr->trans_alpha : NULL; - png_const_colorp colormap = png_ptr->palette; - const int do_background = trans != NULL && - (output_format & PNG_FORMAT_FLAG_ALPHA) == 0; - unsigned int i; - - /* Just in case: */ - if (trans == NULL) - num_trans = 0; - - output_processing = PNG_CMAP_NONE; - data_encoding = E_FILE; /* Don't change from color-map indicies */ - cmap_entries = png_ptr->num_palette; - if (cmap_entries > 256) - cmap_entries = 256; - - if (cmap_entries > image->colormap_entries) - png_error(png_ptr, "palette color-map: too few entries"); - - for (i=0; i < cmap_entries; ++i) - { - if (do_background && i < num_trans && trans[i] < 255) - { - if (trans[i] == 0) - png_create_colormap_entry(display, i, back_r, back_g, - back_b, 0, output_encoding); - - else - { - /* Must compose the PNG file color in the color-map entry - * on the sRGB color in 'back'. - */ - png_create_colormap_entry(display, i, - png_colormap_compose(display, colormap[i].red, E_FILE, - trans[i], back_r, output_encoding), - png_colormap_compose(display, colormap[i].green, E_FILE, - trans[i], back_g, output_encoding), - png_colormap_compose(display, colormap[i].blue, E_FILE, - trans[i], back_b, output_encoding), - output_encoding == E_LINEAR ? trans[i] * 257U : - trans[i], - output_encoding); - } - } - - else - png_create_colormap_entry(display, i, colormap[i].red, - colormap[i].green, colormap[i].blue, - i < num_trans ? trans[i] : 255U, E_FILE/*8-bit*/); - } - - /* The PNG data may have indicies packed in fewer than 8 bits, it - * must be expanded if so. - */ - if (png_ptr->bit_depth < 8) - png_set_packing(png_ptr); - } - break; - - default: - png_error(png_ptr, "invalid PNG color type"); - /*NOT REACHED*/ - break; - } - - /* Now deal with the output processing */ - if (expand_tRNS && png_ptr->num_trans > 0 && - (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) == 0) - png_set_tRNS_to_alpha(png_ptr); - - switch (data_encoding) - { - default: - png_error(png_ptr, "bad data option (internal error)"); - break; - - case E_sRGB: - /* Change to 8-bit sRGB */ - png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, PNG_GAMMA_sRGB); - /* FALL THROUGH */ - - case E_FILE: - if (png_ptr->bit_depth > 8) - png_set_scale_16(png_ptr); - break; - } - - if (cmap_entries > 256 || cmap_entries > image->colormap_entries) - png_error(png_ptr, "color map overflow (BAD internal error)"); - - image->colormap_entries = cmap_entries; - - /* Double check using the recorded background index */ - switch (output_processing) - { - case PNG_CMAP_NONE: - if (background_index != PNG_CMAP_NONE_BACKGROUND) - goto bad_background; - break; - - case PNG_CMAP_GA: - if (background_index != PNG_CMAP_GA_BACKGROUND) - goto bad_background; - break; - - case PNG_CMAP_TRANS: - if (background_index >= cmap_entries || - background_index != PNG_CMAP_TRANS_BACKGROUND) - goto bad_background; - break; - - case PNG_CMAP_RGB: - if (background_index != PNG_CMAP_RGB_BACKGROUND) - goto bad_background; - break; - - case PNG_CMAP_RGB_ALPHA: - if (background_index != PNG_CMAP_RGB_ALPHA_BACKGROUND) - goto bad_background; - break; - - default: - png_error(png_ptr, "bad processing option (internal error)"); - - bad_background: - png_error(png_ptr, "bad background index (internal error)"); - } - - display->colormap_processing = output_processing; - - return 1/*ok*/; -} - -/* The final part of the color-map read called from png_image_finish_read. */ -static int -png_image_read_and_map(png_voidp argument) -{ - png_image_read_control *display = png_voidcast(png_image_read_control*, - argument); - png_imagep image = display->image; - png_structrp png_ptr = image->opaque->png_ptr; - int passes; - - /* Called when the libpng data must be transformed into the color-mapped - * form. There is a local row buffer in display->local and this routine must - * do the interlace handling. - */ - switch (png_ptr->interlaced) - { - case PNG_INTERLACE_NONE: - passes = 1; - break; - - case PNG_INTERLACE_ADAM7: - passes = PNG_INTERLACE_ADAM7_PASSES; - break; - - default: - passes = 0; - png_error(png_ptr, "unknown interlace type"); - } - - { - png_uint_32 height = image->height; - png_uint_32 width = image->width; - int proc = display->colormap_processing; - png_bytep first_row = png_voidcast(png_bytep, display->first_row); - ptrdiff_t step_row = display->row_bytes; - int pass; - - for (pass = 0; pass < passes; ++pass) - { - unsigned int startx, stepx, stepy; - png_uint_32 y; - - if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) - { - /* The row may be empty for a short image: */ - if (PNG_PASS_COLS(width, pass) == 0) - continue; - - startx = PNG_PASS_START_COL(pass); - stepx = PNG_PASS_COL_OFFSET(pass); - y = PNG_PASS_START_ROW(pass); - stepy = PNG_PASS_ROW_OFFSET(pass); - } - - else - { - y = 0; - startx = 0; - stepx = stepy = 1; - } - - for (; ylocal_row); - png_bytep outrow = first_row + y * step_row; - png_const_bytep end_row = outrow + width; - - /* Read read the libpng data into the temporary buffer. */ - png_read_row(png_ptr, inrow, NULL); - - /* Now process the row according to the processing option, note - * that the caller verifies that the format of the libpng output - * data is as required. - */ - outrow += startx; - switch (proc) - { - case PNG_CMAP_GA: - for (; outrow < end_row; outrow += stepx) - { - /* The data is always in the PNG order */ - unsigned int gray = *inrow++; - unsigned int alpha = *inrow++; - unsigned int entry; - - /* NOTE: this code is copied as a comment in - * make_ga_colormap above. Please update the - * comment if you change this code! - */ - if (alpha > 229) /* opaque */ - { - entry = (231 * gray + 128) >> 8; - } - else if (alpha < 26) /* transparent */ - { - entry = 231; - } - else /* partially opaque */ - { - entry = 226 + 6 * PNG_DIV51(alpha) + PNG_DIV51(gray); - } - - *outrow = (png_byte)entry; - } - break; - - case PNG_CMAP_TRANS: - for (; outrow < end_row; outrow += stepx) - { - png_byte gray = *inrow++; - png_byte alpha = *inrow++; - - if (alpha == 0) - *outrow = PNG_CMAP_TRANS_BACKGROUND; - - else if (gray != PNG_CMAP_TRANS_BACKGROUND) - *outrow = gray; - - else - *outrow = (png_byte)(PNG_CMAP_TRANS_BACKGROUND+1); - } - break; - - case PNG_CMAP_RGB: - for (; outrow < end_row; outrow += stepx) - { - *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]); - inrow += 3; - } - break; - - case PNG_CMAP_RGB_ALPHA: - for (; outrow < end_row; outrow += stepx) - { - unsigned int alpha = inrow[3]; - - /* Because the alpha entries only hold alpha==0.5 values - * split the processing at alpha==0.25 (64) and 0.75 - * (196). - */ - - if (alpha >= 196) - *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], - inrow[2]); - - else if (alpha < 64) - *outrow = PNG_CMAP_RGB_ALPHA_BACKGROUND; - - else - { - /* Likewise there are three entries for each of r, g - * and b. We could select the entry by popcount on - * the top two bits on those architectures that - * support it, this is what the code below does, - * crudely. - */ - unsigned int back_i = PNG_CMAP_RGB_ALPHA_BACKGROUND+1; - - /* Here are how the values map: - * - * 0x00 .. 0x3f -> 0 - * 0x40 .. 0xbf -> 1 - * 0xc0 .. 0xff -> 2 - * - * So, as above with the explicit alpha checks, the - * breakpoints are at 64 and 196. - */ - if (inrow[0] & 0x80) back_i += 9; /* red */ - if (inrow[0] & 0x40) back_i += 9; - if (inrow[0] & 0x80) back_i += 3; /* green */ - if (inrow[0] & 0x40) back_i += 3; - if (inrow[0] & 0x80) back_i += 1; /* blue */ - if (inrow[0] & 0x40) back_i += 1; - - *outrow = (png_byte)back_i; - } - - inrow += 4; - } - break; - - default: - break; - } - } - } - } - - return 1; -} - -static int -png_image_read_colormapped(png_voidp argument) -{ - png_image_read_control *display = png_voidcast(png_image_read_control*, - argument); - png_imagep image = display->image; - png_controlp control = image->opaque; - png_structrp png_ptr = control->png_ptr; - png_inforp info_ptr = control->info_ptr; - - int passes = 0; /* As a flag */ - - PNG_SKIP_CHUNKS(png_ptr); - - /* Update the 'info' structure and make sure the result is as required; first - * make sure to turn on the interlace handling if it will be required - * (because it can't be turned on *after* the call to png_read_update_info!) - */ - if (display->colormap_processing == PNG_CMAP_NONE) - passes = png_set_interlace_handling(png_ptr); - - png_read_update_info(png_ptr, info_ptr); - - /* The expected output can be deduced from the colormap_processing option. */ - switch (display->colormap_processing) - { - case PNG_CMAP_NONE: - /* Output must be one channel and one byte per pixel, the output - * encoding can be anything. - */ - if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE || - info_ptr->color_type == PNG_COLOR_TYPE_GRAY) && - info_ptr->bit_depth == 8) - break; - - goto bad_output; - - case PNG_CMAP_TRANS: - case PNG_CMAP_GA: - /* Output must be two channels and the 'G' one must be sRGB, the latter - * can be checked with an exact number because it should have been set - * to this number above! - */ - if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && - info_ptr->bit_depth == 8 && - png_ptr->screen_gamma == PNG_GAMMA_sRGB && - image->colormap_entries == 256) - break; - - goto bad_output; - - case PNG_CMAP_RGB: - /* Output must be 8-bit sRGB encoded RGB */ - if (info_ptr->color_type == PNG_COLOR_TYPE_RGB && - info_ptr->bit_depth == 8 && - png_ptr->screen_gamma == PNG_GAMMA_sRGB && - image->colormap_entries == 216) - break; - - goto bad_output; - - case PNG_CMAP_RGB_ALPHA: - /* Output must be 8-bit sRGB encoded RGBA */ - if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA && - info_ptr->bit_depth == 8 && - png_ptr->screen_gamma == PNG_GAMMA_sRGB && - image->colormap_entries == 244 /* 216 + 1 + 27 */) - break; - - /* goto bad_output; */ - /* FALL THROUGH */ - - default: - bad_output: - png_error(png_ptr, "bad color-map processing (internal error)"); - } - - /* Now read the rows. Do this here if it is possible to read directly into - * the output buffer, otherwise allocate a local row buffer of the maximum - * size libpng requires and call the relevant processing routine safely. - */ - { - png_voidp first_row = display->buffer; - ptrdiff_t row_bytes = display->row_stride; - - /* The following expression is designed to work correctly whether it gives - * a signed or an unsigned result. - */ - if (row_bytes < 0) - { - char *ptr = png_voidcast(char*, first_row); - ptr += (image->height-1) * (-row_bytes); - first_row = png_voidcast(png_voidp, ptr); - } - - display->first_row = first_row; - display->row_bytes = row_bytes; - } - - if (passes == 0) - { - int result; - png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); - - display->local_row = row; - result = png_safe_execute(image, png_image_read_and_map, display); - display->local_row = NULL; - png_free(png_ptr, row); - - return result; - } - - else - { - png_alloc_size_t row_bytes = display->row_bytes; - - while (--passes >= 0) - { - png_uint_32 y = image->height; - png_bytep row = png_voidcast(png_bytep, display->first_row); - - while (y-- > 0) - { - png_read_row(png_ptr, row, NULL); - row += row_bytes; - } - } - - return 1; - } -} - -/* Just the row reading part of png_image_read. */ -static int -png_image_read_composite(png_voidp argument) -{ - png_image_read_control *display = png_voidcast(png_image_read_control*, - argument); - png_imagep image = display->image; - png_structrp png_ptr = image->opaque->png_ptr; - int passes; - - switch (png_ptr->interlaced) - { - case PNG_INTERLACE_NONE: - passes = 1; - break; - - case PNG_INTERLACE_ADAM7: - passes = PNG_INTERLACE_ADAM7_PASSES; - break; - - default: - passes = 0; - png_error(png_ptr, "unknown interlace type"); - } - - { - png_uint_32 height = image->height; - png_uint_32 width = image->width; - ptrdiff_t step_row = display->row_bytes; - unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1; - int pass; - - for (pass = 0; pass < passes; ++pass) - { - unsigned int startx, stepx, stepy; - png_uint_32 y; - - if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) - { - /* The row may be empty for a short image: */ - if (PNG_PASS_COLS(width, pass) == 0) - continue; - - startx = PNG_PASS_START_COL(pass) * channels; - stepx = PNG_PASS_COL_OFFSET(pass) * channels; - y = PNG_PASS_START_ROW(pass); - stepy = PNG_PASS_ROW_OFFSET(pass); - } - - else - { - y = 0; - startx = 0; - stepx = channels; - stepy = 1; - } - - for (; ylocal_row); - png_bytep outrow; - png_const_bytep end_row; - - /* Read the row, which is packed: */ - png_read_row(png_ptr, inrow, NULL); - - outrow = png_voidcast(png_bytep, display->first_row); - outrow += y * step_row; - end_row = outrow + width * channels; - - /* Now do the composition on each pixel in this row. */ - outrow += startx; - for (; outrow < end_row; outrow += stepx) - { - png_byte alpha = inrow[channels]; - - if (alpha > 0) /* else no change to the output */ - { - unsigned int c; - - for (c=0; cimage; - png_structrp png_ptr = image->opaque->png_ptr; - png_inforp info_ptr = image->opaque->info_ptr; - png_uint_32 height = image->height; - png_uint_32 width = image->width; - int pass, passes; - - /* Double check the convoluted logic below. We expect to get here with - * libpng doing rgb to gray and gamma correction but background processing - * left to the png_image_read_background function. The rows libpng produce - * might be 8 or 16-bit but should always have two channels; gray plus alpha. - */ - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) - png_error(png_ptr, "lost rgb to gray"); - - if ((png_ptr->transformations & PNG_COMPOSE) != 0) - png_error(png_ptr, "unexpected compose"); - - if (png_get_channels(png_ptr, info_ptr) != 2) - png_error(png_ptr, "lost/gained channels"); - - /* Expect the 8-bit case to always remove the alpha channel */ - if ((image->format & PNG_FORMAT_FLAG_LINEAR) == 0 && - (image->format & PNG_FORMAT_FLAG_ALPHA) != 0) - png_error(png_ptr, "unexpected 8-bit transformation"); - - switch (png_ptr->interlaced) - { - case PNG_INTERLACE_NONE: - passes = 1; - break; - - case PNG_INTERLACE_ADAM7: - passes = PNG_INTERLACE_ADAM7_PASSES; - break; - - default: - passes = 0; - png_error(png_ptr, "unknown interlace type"); - } - - switch (png_get_bit_depth(png_ptr, info_ptr)) - { - default: - png_error(png_ptr, "unexpected bit depth"); - break; - - case 8: - /* 8-bit sRGB gray values with an alpha channel; the alpha channel is - * to be removed by composing on a backgroundi: either the row if - * display->background is NULL or display->background->green if not. - * Unlike the code above ALPHA_OPTIMIZED has *not* been done. - */ - { - png_bytep first_row = png_voidcast(png_bytep, display->first_row); - ptrdiff_t step_row = display->row_bytes; - - for (pass = 0; pass < passes; ++pass) - { - png_bytep row = png_voidcast(png_bytep, - display->first_row); - unsigned int startx, stepx, stepy; - png_uint_32 y; - - if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) - { - /* The row may be empty for a short image: */ - if (PNG_PASS_COLS(width, pass) == 0) - continue; - - startx = PNG_PASS_START_COL(pass); - stepx = PNG_PASS_COL_OFFSET(pass); - y = PNG_PASS_START_ROW(pass); - stepy = PNG_PASS_ROW_OFFSET(pass); - } - - else - { - y = 0; - startx = 0; - stepx = stepy = 1; - } - - if (display->background == NULL) - { - for (; ylocal_row); - png_bytep outrow = first_row + y * step_row; - png_const_bytep end_row = outrow + width; - - /* Read the row, which is packed: */ - png_read_row(png_ptr, inrow, NULL); - - /* Now do the composition on each pixel in this row. */ - outrow += startx; - for (; outrow < end_row; outrow += stepx) - { - png_byte alpha = inrow[1]; - - if (alpha > 0) /* else no change to the output */ - { - png_uint_32 component = inrow[0]; - - if (alpha < 255) /* else just use component */ - { - /* Since PNG_OPTIMIZED_ALPHA was not set it is - * necessary to invert the sRGB transfer - * function and multiply the alpha out. - */ - component = png_sRGB_table[component] * alpha; - component += png_sRGB_table[outrow[0]] * - (255-alpha); - component = PNG_sRGB_FROM_LINEAR(component); - } - - outrow[0] = (png_byte)component; - } - - inrow += 2; /* gray and alpha channel */ - } - } - } - - else /* constant background value */ - { - png_byte background8 = display->background->green; - png_uint_16 background = png_sRGB_table[background8]; - - for (; ylocal_row); - png_bytep outrow = first_row + y * step_row; - png_const_bytep end_row = outrow + width; - - /* Read the row, which is packed: */ - png_read_row(png_ptr, inrow, NULL); - - /* Now do the composition on each pixel in this row. */ - outrow += startx; - for (; outrow < end_row; outrow += stepx) - { - png_byte alpha = inrow[1]; - - if (alpha > 0) /* else use background */ - { - png_uint_32 component = inrow[0]; - - if (alpha < 255) /* else just use component */ - { - component = png_sRGB_table[component] * alpha; - component += background * (255-alpha); - component = PNG_sRGB_FROM_LINEAR(component); - } - - outrow[0] = (png_byte)component; - } - - else - outrow[0] = background8; - - inrow += 2; /* gray and alpha channel */ - } - - row += display->row_bytes; - } - } - } - } - break; - - case 16: - /* 16-bit linear with pre-multiplied alpha; the pre-multiplication must - * still be done and, maybe, the alpha channel removed. This code also - * handles the alpha-first option. - */ - { - png_uint_16p first_row = png_voidcast(png_uint_16p, - display->first_row); - /* The division by two is safe because the caller passed in a - * stride which was multiplied by 2 (below) to get row_bytes. - */ - ptrdiff_t step_row = display->row_bytes / 2; - int preserve_alpha = (image->format & PNG_FORMAT_FLAG_ALPHA) != 0; - unsigned int outchannels = 1+preserve_alpha; - int swap_alpha = 0; - - if (preserve_alpha && (image->format & PNG_FORMAT_FLAG_AFIRST)) - swap_alpha = 1; - - for (pass = 0; pass < passes; ++pass) - { - unsigned int startx, stepx, stepy; - png_uint_32 y; - - /* The 'x' start and step are adjusted to output components here. - */ - if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) - { - /* The row may be empty for a short image: */ - if (PNG_PASS_COLS(width, pass) == 0) - continue; - - startx = PNG_PASS_START_COL(pass) * outchannels; - stepx = PNG_PASS_COL_OFFSET(pass) * outchannels; - y = PNG_PASS_START_ROW(pass); - stepy = PNG_PASS_ROW_OFFSET(pass); - } - - else - { - y = 0; - startx = 0; - stepx = outchannels; - stepy = 1; - } - - for (; ylocal_row), NULL); - inrow = png_voidcast(png_const_uint_16p, display->local_row); - - /* Now do the pre-multiplication on each pixel in this row. - */ - outrow += startx; - for (; outrow < end_row; outrow += stepx) - { - png_uint_32 component = inrow[0]; - png_uint_16 alpha = inrow[1]; - - if (alpha > 0) /* else 0 */ - { - if (alpha < 65535) /* else just use component */ - { - component *= alpha; - component += 32767; - component /= 65535; - } - } - - else - component = 0; - - outrow[swap_alpha] = (png_uint_16)component; - if (preserve_alpha) - outrow[1 ^ swap_alpha] = alpha; - - inrow += 2; /* components and alpha channel */ - } - } - } - } - break; - } - - return 1; -} - -/* The guts of png_image_finish_read as a png_safe_execute callback. */ -static int -png_image_read_direct(png_voidp argument) -{ - png_image_read_control *display = png_voidcast(png_image_read_control*, - argument); - png_imagep image = display->image; - png_structrp png_ptr = image->opaque->png_ptr; - png_inforp info_ptr = image->opaque->info_ptr; - - png_uint_32 format = image->format; - int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0; - int do_local_compose = 0; - int do_local_background = 0; /* to avoid double gamma correction bug */ - int passes = 0; - - /* Add transforms to ensure the correct output format is produced then check - * that the required implementation support is there. Always expand; always - * need 8 bits minimum, no palette and expanded tRNS. - */ - png_set_expand(png_ptr); - - /* Now check the format to see if it was modified. */ - { - png_uint_32 base_format = png_image_format(png_ptr) & - ~PNG_FORMAT_FLAG_COLORMAP /* removed by png_set_expand */; - png_uint_32 change = format ^ base_format; - png_fixed_point output_gamma; - int mode; /* alpha mode */ - - /* Do this first so that we have a record if rgb to gray is happening. */ - if (change & PNG_FORMAT_FLAG_COLOR) - { - /* gray<->color transformation required. */ - if (format & PNG_FORMAT_FLAG_COLOR) - png_set_gray_to_rgb(png_ptr); - - else - { - /* libpng can't do both rgb to gray and - * background/pre-multiplication if there is also significant gamma - * correction, because both operations require linear colors and - * the code only supports one transform doing the gamma correction. - * Handle this by doing the pre-multiplication or background - * operation in this code, if necessary. - * - * TODO: fix this by rewriting pngrtran.c (!) - * - * For the moment (given that fixing this in pngrtran.c is an - * enormous change) 'do_local_background' is used to indicate that - * the problem exists. - */ - if (base_format & PNG_FORMAT_FLAG_ALPHA) - do_local_background = 1/*maybe*/; - - png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, - PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT); - } - - change &= ~PNG_FORMAT_FLAG_COLOR; - } - - /* Set the gamma appropriately, linear for 16-bit input, sRGB otherwise. - */ - { - png_fixed_point input_gamma_default; - - if ((base_format & PNG_FORMAT_FLAG_LINEAR) && - (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) - input_gamma_default = PNG_GAMMA_LINEAR; - else - input_gamma_default = PNG_DEFAULT_sRGB; - - /* Call png_set_alpha_mode to set the default for the input gamma; the - * output gamma is set by a second call below. - */ - png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, input_gamma_default); - } - - if (linear) - { - /* If there *is* an alpha channel in the input it must be multiplied - * out; use PNG_ALPHA_STANDARD, otherwise just use PNG_ALPHA_PNG. - */ - if (base_format & PNG_FORMAT_FLAG_ALPHA) - mode = PNG_ALPHA_STANDARD; /* associated alpha */ - - else - mode = PNG_ALPHA_PNG; - - output_gamma = PNG_GAMMA_LINEAR; - } - - else - { - mode = PNG_ALPHA_PNG; - output_gamma = PNG_DEFAULT_sRGB; - } - - /* If 'do_local_background' is set check for the presence of gamma - * correction; this is part of the work-round for the libpng bug - * described above. - * - * TODO: fix libpng and remove this. - */ - if (do_local_background) - { - png_fixed_point gtest; - - /* This is 'png_gamma_threshold' from pngrtran.c; the test used for - * gamma correction, the screen gamma hasn't been set on png_struct - * yet; it's set below. png_struct::gamma, however, is set to the - * final value. - */ - if (png_muldiv(>est, output_gamma, png_ptr->colorspace.gamma, - PNG_FP_1) && !png_gamma_significant(gtest)) - do_local_background = 0; - - else if (mode == PNG_ALPHA_STANDARD) - { - do_local_background = 2/*required*/; - mode = PNG_ALPHA_PNG; /* prevent libpng doing it */ - } - - /* else leave as 1 for the checks below */ - } - - /* If the bit-depth changes then handle that here. */ - if (change & PNG_FORMAT_FLAG_LINEAR) - { - if (linear /*16-bit output*/) - png_set_expand_16(png_ptr); - - else /* 8-bit output */ - png_set_scale_16(png_ptr); - - change &= ~PNG_FORMAT_FLAG_LINEAR; - } - - /* Now the background/alpha channel changes. */ - if (change & PNG_FORMAT_FLAG_ALPHA) - { - /* Removing an alpha channel requires composition for the 8-bit - * formats; for the 16-bit it is already done, above, by the - * pre-multiplication and the channel just needs to be stripped. - */ - if (base_format & PNG_FORMAT_FLAG_ALPHA) - { - /* If RGB->gray is happening the alpha channel must be left and the - * operation completed locally. - * - * TODO: fix libpng and remove this. - */ - if (do_local_background) - do_local_background = 2/*required*/; - - /* 16-bit output: just remove the channel */ - else if (linear) /* compose on black (well, pre-multiply) */ - png_set_strip_alpha(png_ptr); - - /* 8-bit output: do an appropriate compose */ - else if (display->background != NULL) - { - png_color_16 c; - - c.index = 0; /*unused*/ - c.red = display->background->red; - c.green = display->background->green; - c.blue = display->background->blue; - c.gray = display->background->green; - - /* This is always an 8-bit sRGB value, using the 'green' channel - * for gray is much better than calculating the luminance here; - * we can get off-by-one errors in that calculation relative to - * the app expectations and that will show up in transparent - * pixels. - */ - png_set_background_fixed(png_ptr, &c, - PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, - 0/*gamma: not used*/); - } - - else /* compose on row: implemented below. */ - { - do_local_compose = 1; - /* This leaves the alpha channel in the output, so it has to be - * removed by the code below. Set the encoding to the 'OPTIMIZE' - * one so the code only has to hack on the pixels that require - * composition. - */ - mode = PNG_ALPHA_OPTIMIZED; - } - } - - else /* output needs an alpha channel */ - { - /* This is tricky because it happens before the swap operation has - * been accomplished; however, the swap does *not* swap the added - * alpha channel (weird API), so it must be added in the correct - * place. - */ - png_uint_32 filler; /* opaque filler */ - int where; - - if (linear) - filler = 65535; - - else - filler = 255; - -# ifdef PNG_FORMAT_AFIRST_SUPPORTED - if (format & PNG_FORMAT_FLAG_AFIRST) - { - where = PNG_FILLER_BEFORE; - change &= ~PNG_FORMAT_FLAG_AFIRST; - } - - else -# endif - where = PNG_FILLER_AFTER; - - png_set_add_alpha(png_ptr, filler, where); - } - - /* This stops the (irrelevant) call to swap_alpha below. */ - change &= ~PNG_FORMAT_FLAG_ALPHA; - } - - /* Now set the alpha mode correctly; this is always done, even if there is - * no alpha channel in either the input or the output because it correctly - * sets the output gamma. - */ - png_set_alpha_mode_fixed(png_ptr, mode, output_gamma); - -# ifdef PNG_FORMAT_BGR_SUPPORTED - if (change & PNG_FORMAT_FLAG_BGR) - { - /* Check only the output format; PNG is never BGR; don't do this if - * the output is gray, but fix up the 'format' value in that case. - */ - if (format & PNG_FORMAT_FLAG_COLOR) - png_set_bgr(png_ptr); - - else - format &= ~PNG_FORMAT_FLAG_BGR; - - change &= ~PNG_FORMAT_FLAG_BGR; - } -# endif - -# ifdef PNG_FORMAT_AFIRST_SUPPORTED - if (change & PNG_FORMAT_FLAG_AFIRST) - { - /* Only relevant if there is an alpha channel - it's particularly - * important to handle this correctly because do_local_compose may - * be set above and then libpng will keep the alpha channel for this - * code to remove. - */ - if (format & PNG_FORMAT_FLAG_ALPHA) - { - /* Disable this if doing a local background, - * TODO: remove this when local background is no longer required. - */ - if (do_local_background != 2) - png_set_swap_alpha(png_ptr); - } - - else - format &= ~PNG_FORMAT_FLAG_AFIRST; - - change &= ~PNG_FORMAT_FLAG_AFIRST; - } -# endif - - /* If the *output* is 16-bit then we need to check for a byte-swap on this - * architecture. - */ - if (linear) - { - PNG_CONST png_uint_16 le = 0x0001; - - if (*(png_const_bytep)&le) - png_set_swap(png_ptr); - } - - /* If change is not now 0 some transformation is missing - error out. */ - if (change) - png_error(png_ptr, "png_read_image: unsupported transformation"); - } - - PNG_SKIP_CHUNKS(png_ptr); - - /* Update the 'info' structure and make sure the result is as required; first - * make sure to turn on the interlace handling if it will be required - * (because it can't be turned on *after* the call to png_read_update_info!) - * - * TODO: remove the do_local_background fixup below. - */ - if (!do_local_compose && do_local_background != 2) - passes = png_set_interlace_handling(png_ptr); - - png_read_update_info(png_ptr, info_ptr); - - { - png_uint_32 info_format = 0; - - if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) - info_format |= PNG_FORMAT_FLAG_COLOR; - - if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) - { - /* do_local_compose removes this channel below. */ - if (!do_local_compose) - { - /* do_local_background does the same if required. */ - if (do_local_background != 2 || - (format & PNG_FORMAT_FLAG_ALPHA) != 0) - info_format |= PNG_FORMAT_FLAG_ALPHA; - } - } - - else if (do_local_compose) /* internal error */ - png_error(png_ptr, "png_image_read: alpha channel lost"); - - if (info_ptr->bit_depth == 16) - info_format |= PNG_FORMAT_FLAG_LINEAR; - -# ifdef PNG_FORMAT_BGR_SUPPORTED - if (png_ptr->transformations & PNG_BGR) - info_format |= PNG_FORMAT_FLAG_BGR; -# endif - -# ifdef PNG_FORMAT_AFIRST_SUPPORTED - if (do_local_background == 2) - { - if (format & PNG_FORMAT_FLAG_AFIRST) - info_format |= PNG_FORMAT_FLAG_AFIRST; - } - - if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0 || - ((png_ptr->transformations & PNG_ADD_ALPHA) != 0 && - (png_ptr->flags & PNG_FLAG_FILLER_AFTER) == 0)) - { - if (do_local_background == 2) - png_error(png_ptr, "unexpected alpha swap transformation"); - - info_format |= PNG_FORMAT_FLAG_AFIRST; - } -# endif - - /* This is actually an internal error. */ - if (info_format != format) - png_error(png_ptr, "png_read_image: invalid transformations"); - } - - /* Now read the rows. If do_local_compose is set then it is necessary to use - * a local row buffer. The output will be GA, RGBA or BGRA and must be - * converted to G, RGB or BGR as appropriate. The 'local_row' member of the - * display acts as a flag. - */ - { - png_voidp first_row = display->buffer; - ptrdiff_t row_bytes = display->row_stride; - - if (linear) - row_bytes *= 2; - - /* The following expression is designed to work correctly whether it gives - * a signed or an unsigned result. - */ - if (row_bytes < 0) - { - char *ptr = png_voidcast(char*, first_row); - ptr += (image->height-1) * (-row_bytes); - first_row = png_voidcast(png_voidp, ptr); - } - - display->first_row = first_row; - display->row_bytes = row_bytes; - } - - if (do_local_compose) - { - int result; - png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); - - display->local_row = row; - result = png_safe_execute(image, png_image_read_composite, display); - display->local_row = NULL; - png_free(png_ptr, row); - - return result; - } - - else if (do_local_background == 2) - { - int result; - png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); - - display->local_row = row; - result = png_safe_execute(image, png_image_read_background, display); - display->local_row = NULL; - png_free(png_ptr, row); - - return result; - } - - else - { - png_alloc_size_t row_bytes = display->row_bytes; - - while (--passes >= 0) - { - png_uint_32 y = image->height; - png_bytep row = png_voidcast(png_bytep, display->first_row); - - while (y-- > 0) - { - png_read_row(png_ptr, row, NULL); - row += row_bytes; - } - } - - return 1; - } -} - -int PNGAPI -png_image_finish_read(png_imagep image, png_const_colorp background, - void *buffer, png_int_32 row_stride, void *colormap) -{ - if (image != NULL && image->version == PNG_IMAGE_VERSION) - { - png_uint_32 check; - - if (row_stride == 0) - row_stride = PNG_IMAGE_ROW_STRIDE(*image); - - if (row_stride < 0) - check = -row_stride; - - else - check = row_stride; - - if (image->opaque != NULL && buffer != NULL && - check >= PNG_IMAGE_ROW_STRIDE(*image)) - { - if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 || - (image->colormap_entries > 0 && colormap != NULL)) - { - int result; - png_image_read_control display; - - memset(&display, 0, (sizeof display)); - display.image = image; - display.buffer = buffer; - display.row_stride = row_stride; - display.colormap = colormap; - display.background = background; - display.local_row = NULL; - - /* Choose the correct 'end' routine; for the color-map case all the - * setup has already been done. - */ - if (image->format & PNG_FORMAT_FLAG_COLORMAP) - result = - png_safe_execute(image, png_image_read_colormap, &display) && - png_safe_execute(image, png_image_read_colormapped, &display); - - else - result = - png_safe_execute(image, png_image_read_direct, &display); - - png_image_free(image); - return result; - } - - else - return png_image_error(image, - "png_image_finish_read[color-map]: no color-map"); - } - - else - return png_image_error(image, - "png_image_finish_read: invalid argument"); - } - - else if (image != NULL) - return png_image_error(image, - "png_image_finish_read: damaged PNG_IMAGE_VERSION"); - - return 0; -} - -#endif /* PNG_SIMPLIFIED_READ_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pngrio.c b/source/modules/juce_graphics/image_formats/pnglib/pngrio.c deleted file mode 100644 index 2b9c10320..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pngrio.c +++ /dev/null @@ -1,118 +0,0 @@ - -/* pngrio.c - functions for data input - * - * Last changed in libpng 1.6.0 [February 14, 2013] - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file provides a location for all input. Users who need - * special handling are expected to write a function that has the same - * arguments as this and performs a similar function, but that possibly - * has a different input method. Note that you shouldn't change this - * function, but rather write a replacement function and then make - * libpng use it at run time with png_set_read_fn(...). - */ - -#include "pngpriv.h" - -#ifdef PNG_READ_SUPPORTED - -/* Read the data from whatever input you are using. The default routine - * reads from a file pointer. Note that this routine sometimes gets called - * with very small lengths, so you should implement some kind of simple - * buffering if you are using unbuffered reads. This should never be asked - * to read more then 64K on a 16 bit machine. - */ -void /* PRIVATE */ -png_read_data(png_structrp png_ptr, png_bytep data, png_size_t length) -{ - png_debug1(4, "reading %d bytes", (int)length); - - if (png_ptr->read_data_fn != NULL) - (*(png_ptr->read_data_fn))(png_ptr, data, length); - - else - png_error(png_ptr, "Call to NULL read function"); -} - -#ifdef PNG_STDIO_SUPPORTED -/* This is the function that does the actual reading of data. If you are - * not reading from a standard C stream, you should create a replacement - * read_data function and use it at run time with png_set_read_fn(), rather - * than changing the library. - */ -void PNGCBAPI -png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_size_t check; - - if (png_ptr == NULL) - return; - - /* fread() returns 0 on error, so it is OK to store this in a png_size_t - * instead of an int, which is what fread() actually returns. - */ - check = fread(data, 1, length, png_voidcast(png_FILE_p, png_ptr->io_ptr)); - - if (check != length) - png_error(png_ptr, "Read Error"); -} -#endif - -/* This function allows the application to supply a new input function - * for libpng if standard C streams aren't being used. - * - * This function takes as its arguments: - * - * png_ptr - pointer to a png input data structure - * - * io_ptr - pointer to user supplied structure containing info about - * the input functions. May be NULL. - * - * read_data_fn - pointer to a new input function that takes as its - * arguments a pointer to a png_struct, a pointer to - * a location where input data can be stored, and a 32-bit - * unsigned int that is the number of bytes to be read. - * To exit and output any fatal error messages the new write - * function should call png_error(png_ptr, "Error msg"). - * May be NULL, in which case libpng's default function will - * be used. - */ -void PNGAPI -png_set_read_fn(png_structrp png_ptr, png_voidp io_ptr, - png_rw_ptr read_data_fn) -{ - if (png_ptr == NULL) - return; - - png_ptr->io_ptr = io_ptr; - -#ifdef PNG_STDIO_SUPPORTED - if (read_data_fn != NULL) - png_ptr->read_data_fn = read_data_fn; - - else - png_ptr->read_data_fn = png_default_read_data; -#else - png_ptr->read_data_fn = read_data_fn; -#endif - - /* It is an error to write to a read device */ - if (png_ptr->write_data_fn != NULL) - { - png_ptr->write_data_fn = NULL; - png_warning(png_ptr, - "Can't set both read_data_fn and write_data_fn in the" - " same structure"); - } - -#ifdef PNG_WRITE_FLUSH_SUPPORTED - png_ptr->output_flush_fn = NULL; -#endif -} -#endif /* PNG_READ_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pngrtran.c b/source/modules/juce_graphics/image_formats/pnglib/pngrtran.c deleted file mode 100644 index 034b9c309..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pngrtran.c +++ /dev/null @@ -1,5102 +0,0 @@ - -/* pngrtran.c - transforms the data in a row for PNG readers - * - * Last changed in libpng 1.6.1 [March 28, 2013] - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file contains functions optionally called by an application - * in order to tell libpng how to handle data when reading a PNG. - * Transformations that are used in both reading and writing are - * in pngtrans.c. - */ - -#include "pngpriv.h" - -#ifdef PNG_READ_SUPPORTED - -/* Set the action on getting a CRC error for an ancillary or critical chunk. */ -void PNGAPI -png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action) -{ - png_debug(1, "in png_set_crc_action"); - - if (png_ptr == NULL) - return; - - /* Tell libpng how we react to CRC errors in critical chunks */ - switch (crit_action) - { - case PNG_CRC_NO_CHANGE: /* Leave setting as is */ - break; - - case PNG_CRC_WARN_USE: /* Warn/use data */ - png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; - png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE; - break; - - case PNG_CRC_QUIET_USE: /* Quiet/use data */ - png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; - png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE | - PNG_FLAG_CRC_CRITICAL_IGNORE; - break; - - case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */ - png_warning(png_ptr, - "Can't discard critical data on CRC error"); - case PNG_CRC_ERROR_QUIT: /* Error/quit */ - - case PNG_CRC_DEFAULT: - default: - png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; - break; - } - - /* Tell libpng how we react to CRC errors in ancillary chunks */ - switch (ancil_action) - { - case PNG_CRC_NO_CHANGE: /* Leave setting as is */ - break; - - case PNG_CRC_WARN_USE: /* Warn/use data */ - png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; - png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE; - break; - - case PNG_CRC_QUIET_USE: /* Quiet/use data */ - png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; - png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE | - PNG_FLAG_CRC_ANCILLARY_NOWARN; - break; - - case PNG_CRC_ERROR_QUIT: /* Error/quit */ - png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; - png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN; - break; - - case PNG_CRC_WARN_DISCARD: /* Warn/discard data */ - - case PNG_CRC_DEFAULT: - default: - png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; - break; - } -} - -#ifdef PNG_READ_TRANSFORMS_SUPPORTED -/* Is it OK to set a transformation now? Only if png_start_read_image or - * png_read_update_info have not been called. It is not necessary for the IHDR - * to have been read in all cases, the parameter allows for this check too. - */ -static int -png_rtran_ok(png_structrp png_ptr, int need_IHDR) -{ - if (png_ptr != NULL) - { - if (png_ptr->flags & PNG_FLAG_ROW_INIT) - png_app_error(png_ptr, - "invalid after png_start_read_image or png_read_update_info"); - - else if (need_IHDR && (png_ptr->mode & PNG_HAVE_IHDR) == 0) - png_app_error(png_ptr, "invalid before the PNG header has been read"); - - else - { - /* Turn on failure to initialize correctly for all transforms. */ - png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED; - - return 1; /* Ok */ - } - } - - return 0; /* no png_error possible! */ -} -#endif - -#ifdef PNG_READ_BACKGROUND_SUPPORTED -/* Handle alpha and tRNS via a background color */ -void PNGFAPI -png_set_background_fixed(png_structrp png_ptr, - png_const_color_16p background_color, int background_gamma_code, - int need_expand, png_fixed_point background_gamma) -{ - png_debug(1, "in png_set_background_fixed"); - - if (!png_rtran_ok(png_ptr, 0) || background_color == NULL) - return; - - if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN) - { - png_warning(png_ptr, "Application must supply a known background gamma"); - return; - } - - png_ptr->transformations |= PNG_COMPOSE | PNG_STRIP_ALPHA; - png_ptr->transformations &= ~PNG_ENCODE_ALPHA; - png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; - - png_ptr->background = *background_color; - png_ptr->background_gamma = background_gamma; - png_ptr->background_gamma_type = (png_byte)(background_gamma_code); - if (need_expand) - png_ptr->transformations |= PNG_BACKGROUND_EXPAND; - else - png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; -} - -# ifdef PNG_FLOATING_POINT_SUPPORTED -void PNGAPI -png_set_background(png_structrp png_ptr, - png_const_color_16p background_color, int background_gamma_code, - int need_expand, double background_gamma) -{ - png_set_background_fixed(png_ptr, background_color, background_gamma_code, - need_expand, png_fixed(png_ptr, background_gamma, "png_set_background")); -} -# endif /* FLOATING_POINT */ -#endif /* READ_BACKGROUND */ - -/* Scale 16-bit depth files to 8-bit depth. If both of these are set then the - * one that pngrtran does first (scale) happens. This is necessary to allow the - * TRANSFORM and API behavior to be somewhat consistent, and it's simpler. - */ -#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED -void PNGAPI -png_set_scale_16(png_structrp png_ptr) -{ - png_debug(1, "in png_set_scale_16"); - - if (!png_rtran_ok(png_ptr, 0)) - return; - - png_ptr->transformations |= PNG_SCALE_16_TO_8; -} -#endif - -#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED -/* Chop 16-bit depth files to 8-bit depth */ -void PNGAPI -png_set_strip_16(png_structrp png_ptr) -{ - png_debug(1, "in png_set_strip_16"); - - if (!png_rtran_ok(png_ptr, 0)) - return; - - png_ptr->transformations |= PNG_16_TO_8; -} -#endif - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED -void PNGAPI -png_set_strip_alpha(png_structrp png_ptr) -{ - png_debug(1, "in png_set_strip_alpha"); - - if (!png_rtran_ok(png_ptr, 0)) - return; - - png_ptr->transformations |= PNG_STRIP_ALPHA; -} -#endif - -#if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED) -static png_fixed_point -translate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma, - int is_screen) -{ - /* Check for flag values. The main reason for having the old Mac value as a - * flag is that it is pretty near impossible to work out what the correct - * value is from Apple documentation - a working Mac system is needed to - * discover the value! - */ - if (output_gamma == PNG_DEFAULT_sRGB || - output_gamma == PNG_FP_1 / PNG_DEFAULT_sRGB) - { - /* If there is no sRGB support this just sets the gamma to the standard - * sRGB value. (This is a side effect of using this function!) - */ -# ifdef PNG_READ_sRGB_SUPPORTED - png_ptr->flags |= PNG_FLAG_ASSUME_sRGB; -# endif - if (is_screen) - output_gamma = PNG_GAMMA_sRGB; - else - output_gamma = PNG_GAMMA_sRGB_INVERSE; - } - - else if (output_gamma == PNG_GAMMA_MAC_18 || - output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18) - { - if (is_screen) - output_gamma = PNG_GAMMA_MAC_OLD; - else - output_gamma = PNG_GAMMA_MAC_INVERSE; - } - - return output_gamma; -} - -# ifdef PNG_FLOATING_POINT_SUPPORTED -static png_fixed_point -convert_gamma_value(png_structrp png_ptr, double output_gamma) -{ - /* The following silently ignores cases where fixed point (times 100,000) - * gamma values are passed to the floating point API. This is safe and it - * means the fixed point constants work just fine with the floating point - * API. The alternative would just lead to undetected errors and spurious - * bug reports. Negative values fail inside the _fixed API unless they - * correspond to the flag values. - */ - if (output_gamma > 0 && output_gamma < 128) - output_gamma *= PNG_FP_1; - - /* This preserves -1 and -2 exactly: */ - output_gamma = floor(output_gamma + .5); - - if (output_gamma > PNG_FP_MAX || output_gamma < PNG_FP_MIN) - png_fixed_error(png_ptr, "gamma value"); - - return (png_fixed_point)output_gamma; -} -# endif -#endif /* READ_ALPHA_MODE || READ_GAMMA */ - -#ifdef PNG_READ_ALPHA_MODE_SUPPORTED -void PNGFAPI -png_set_alpha_mode_fixed(png_structrp png_ptr, int mode, - png_fixed_point output_gamma) -{ - int compose = 0; - png_fixed_point file_gamma; - - png_debug(1, "in png_set_alpha_mode"); - - if (!png_rtran_ok(png_ptr, 0)) - return; - - output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/); - - /* Validate the value to ensure it is in a reasonable range. The value - * is expected to be 1 or greater, but this range test allows for some - * viewing correction values. The intent is to weed out users of this API - * who use the inverse of the gamma value accidentally! Since some of these - * values are reasonable this may have to be changed. - */ - if (output_gamma < 70000 || output_gamma > 300000) - png_error(png_ptr, "output gamma out of expected range"); - - /* The default file gamma is the inverse of the output gamma; the output - * gamma may be changed below so get the file value first: - */ - file_gamma = png_reciprocal(output_gamma); - - /* There are really 8 possibilities here, composed of any combination - * of: - * - * premultiply the color channels - * do not encode non-opaque pixels - * encode the alpha as well as the color channels - * - * The differences disappear if the input/output ('screen') gamma is 1.0, - * because then the encoding is a no-op and there is only the choice of - * premultiplying the color channels or not. - * - * png_set_alpha_mode and png_set_background interact because both use - * png_compose to do the work. Calling both is only useful when - * png_set_alpha_mode is used to set the default mode - PNG_ALPHA_PNG - along - * with a default gamma value. Otherwise PNG_COMPOSE must not be set. - */ - switch (mode) - { - case PNG_ALPHA_PNG: /* default: png standard */ - /* No compose, but it may be set by png_set_background! */ - png_ptr->transformations &= ~PNG_ENCODE_ALPHA; - png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; - break; - - case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */ - compose = 1; - png_ptr->transformations &= ~PNG_ENCODE_ALPHA; - png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; - /* The output is linear: */ - output_gamma = PNG_FP_1; - break; - - case PNG_ALPHA_OPTIMIZED: /* associated, non-opaque pixels linear */ - compose = 1; - png_ptr->transformations &= ~PNG_ENCODE_ALPHA; - png_ptr->flags |= PNG_FLAG_OPTIMIZE_ALPHA; - /* output_gamma records the encoding of opaque pixels! */ - break; - - case PNG_ALPHA_BROKEN: /* associated, non-linear, alpha encoded */ - compose = 1; - png_ptr->transformations |= PNG_ENCODE_ALPHA; - png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; - break; - - default: - png_error(png_ptr, "invalid alpha mode"); - } - - /* Only set the default gamma if the file gamma has not been set (this has - * the side effect that the gamma in a second call to png_set_alpha_mode will - * be ignored.) - */ - if (png_ptr->colorspace.gamma == 0) - { - png_ptr->colorspace.gamma = file_gamma; - png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; - } - - /* But always set the output gamma: */ - png_ptr->screen_gamma = output_gamma; - - /* Finally, if pre-multiplying, set the background fields to achieve the - * desired result. - */ - if (compose) - { - /* And obtain alpha pre-multiplication by composing on black: */ - memset(&png_ptr->background, 0, (sizeof png_ptr->background)); - png_ptr->background_gamma = png_ptr->colorspace.gamma; /* just in case */ - png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_FILE; - png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; - - if (png_ptr->transformations & PNG_COMPOSE) - png_error(png_ptr, - "conflicting calls to set alpha mode and background"); - - png_ptr->transformations |= PNG_COMPOSE; - } -} - -# ifdef PNG_FLOATING_POINT_SUPPORTED -void PNGAPI -png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma) -{ - png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr, - output_gamma)); -} -# endif -#endif - -#ifdef PNG_READ_QUANTIZE_SUPPORTED -/* Dither file to 8-bit. Supply a palette, the current number - * of elements in the palette, the maximum number of elements - * allowed, and a histogram if possible. If the current number - * of colors is greater then the maximum number, the palette will be - * modified to fit in the maximum number. "full_quantize" indicates - * whether we need a quantizing cube set up for RGB images, or if we - * simply are reducing the number of colors in a paletted image. - */ - -typedef struct png_dsort_struct -{ - struct png_dsort_struct * next; - png_byte left; - png_byte right; -} png_dsort; -typedef png_dsort * png_dsortp; -typedef png_dsort * * png_dsortpp; - -void PNGAPI -png_set_quantize(png_structrp png_ptr, png_colorp palette, - int num_palette, int maximum_colors, png_const_uint_16p histogram, - int full_quantize) -{ - png_debug(1, "in png_set_quantize"); - - if (!png_rtran_ok(png_ptr, 0)) - return; - - png_ptr->transformations |= PNG_QUANTIZE; - - if (!full_quantize) - { - int i; - - png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * (sizeof (png_byte)))); - for (i = 0; i < num_palette; i++) - png_ptr->quantize_index[i] = (png_byte)i; - } - - if (num_palette > maximum_colors) - { - if (histogram != NULL) - { - /* This is easy enough, just throw out the least used colors. - * Perhaps not the best solution, but good enough. - */ - - int i; - - /* Initialize an array to sort colors */ - png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * (sizeof (png_byte)))); - - /* Initialize the quantize_sort array */ - for (i = 0; i < num_palette; i++) - png_ptr->quantize_sort[i] = (png_byte)i; - - /* Find the least used palette entries by starting a - * bubble sort, and running it until we have sorted - * out enough colors. Note that we don't care about - * sorting all the colors, just finding which are - * least used. - */ - - for (i = num_palette - 1; i >= maximum_colors; i--) - { - int done; /* To stop early if the list is pre-sorted */ - int j; - - done = 1; - for (j = 0; j < i; j++) - { - if (histogram[png_ptr->quantize_sort[j]] - < histogram[png_ptr->quantize_sort[j + 1]]) - { - png_byte t; - - t = png_ptr->quantize_sort[j]; - png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1]; - png_ptr->quantize_sort[j + 1] = t; - done = 0; - } - } - - if (done) - break; - } - - /* Swap the palette around, and set up a table, if necessary */ - if (full_quantize) - { - int j = num_palette; - - /* Put all the useful colors within the max, but don't - * move the others. - */ - for (i = 0; i < maximum_colors; i++) - { - if ((int)png_ptr->quantize_sort[i] >= maximum_colors) - { - do - j--; - while ((int)png_ptr->quantize_sort[j] >= maximum_colors); - - palette[i] = palette[j]; - } - } - } - else - { - int j = num_palette; - - /* Move all the used colors inside the max limit, and - * develop a translation table. - */ - for (i = 0; i < maximum_colors; i++) - { - /* Only move the colors we need to */ - if ((int)png_ptr->quantize_sort[i] >= maximum_colors) - { - png_color tmp_color; - - do - j--; - while ((int)png_ptr->quantize_sort[j] >= maximum_colors); - - tmp_color = palette[j]; - palette[j] = palette[i]; - palette[i] = tmp_color; - /* Indicate where the color went */ - png_ptr->quantize_index[j] = (png_byte)i; - png_ptr->quantize_index[i] = (png_byte)j; - } - } - - /* Find closest color for those colors we are not using */ - for (i = 0; i < num_palette; i++) - { - if ((int)png_ptr->quantize_index[i] >= maximum_colors) - { - int min_d, k, min_k, d_index; - - /* Find the closest color to one we threw out */ - d_index = png_ptr->quantize_index[i]; - min_d = PNG_COLOR_DIST(palette[d_index], palette[0]); - for (k = 1, min_k = 0; k < maximum_colors; k++) - { - int d; - - d = PNG_COLOR_DIST(palette[d_index], palette[k]); - - if (d < min_d) - { - min_d = d; - min_k = k; - } - } - /* Point to closest color */ - png_ptr->quantize_index[i] = (png_byte)min_k; - } - } - } - png_free(png_ptr, png_ptr->quantize_sort); - png_ptr->quantize_sort = NULL; - } - else - { - /* This is much harder to do simply (and quickly). Perhaps - * we need to go through a median cut routine, but those - * don't always behave themselves with only a few colors - * as input. So we will just find the closest two colors, - * and throw out one of them (chosen somewhat randomly). - * [We don't understand this at all, so if someone wants to - * work on improving it, be our guest - AED, GRP] - */ - int i; - int max_d; - int num_new_palette; - png_dsortp t; - png_dsortpp hash; - - t = NULL; - - /* Initialize palette index arrays */ - png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * (sizeof (png_byte)))); - png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * (sizeof (png_byte)))); - - /* Initialize the sort array */ - for (i = 0; i < num_palette; i++) - { - png_ptr->index_to_palette[i] = (png_byte)i; - png_ptr->palette_to_index[i] = (png_byte)i; - } - - hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 * - (sizeof (png_dsortp)))); - - num_new_palette = num_palette; - - /* Initial wild guess at how far apart the farthest pixel - * pair we will be eliminating will be. Larger - * numbers mean more areas will be allocated, Smaller - * numbers run the risk of not saving enough data, and - * having to do this all over again. - * - * I have not done extensive checking on this number. - */ - max_d = 96; - - while (num_new_palette > maximum_colors) - { - for (i = 0; i < num_new_palette - 1; i++) - { - int j; - - for (j = i + 1; j < num_new_palette; j++) - { - int d; - - d = PNG_COLOR_DIST(palette[i], palette[j]); - - if (d <= max_d) - { - - t = (png_dsortp)png_malloc_warn(png_ptr, - (png_uint_32)(sizeof (png_dsort))); - - if (t == NULL) - break; - - t->next = hash[d]; - t->left = (png_byte)i; - t->right = (png_byte)j; - hash[d] = t; - } - } - if (t == NULL) - break; - } - - if (t != NULL) - for (i = 0; i <= max_d; i++) - { - if (hash[i] != NULL) - { - png_dsortp p; - - for (p = hash[i]; p; p = p->next) - { - if ((int)png_ptr->index_to_palette[p->left] - < num_new_palette && - (int)png_ptr->index_to_palette[p->right] - < num_new_palette) - { - int j, next_j; - - if (num_new_palette & 0x01) - { - j = p->left; - next_j = p->right; - } - else - { - j = p->right; - next_j = p->left; - } - - num_new_palette--; - palette[png_ptr->index_to_palette[j]] - = palette[num_new_palette]; - if (!full_quantize) - { - int k; - - for (k = 0; k < num_palette; k++) - { - if (png_ptr->quantize_index[k] == - png_ptr->index_to_palette[j]) - png_ptr->quantize_index[k] = - png_ptr->index_to_palette[next_j]; - - if ((int)png_ptr->quantize_index[k] == - num_new_palette) - png_ptr->quantize_index[k] = - png_ptr->index_to_palette[j]; - } - } - - png_ptr->index_to_palette[png_ptr->palette_to_index - [num_new_palette]] = png_ptr->index_to_palette[j]; - - png_ptr->palette_to_index[png_ptr->index_to_palette[j]] - = png_ptr->palette_to_index[num_new_palette]; - - png_ptr->index_to_palette[j] = - (png_byte)num_new_palette; - - png_ptr->palette_to_index[num_new_palette] = - (png_byte)j; - } - if (num_new_palette <= maximum_colors) - break; - } - if (num_new_palette <= maximum_colors) - break; - } - } - - for (i = 0; i < 769; i++) - { - if (hash[i] != NULL) - { - png_dsortp p = hash[i]; - while (p) - { - t = p->next; - png_free(png_ptr, p); - p = t; - } - } - hash[i] = 0; - } - max_d += 96; - } - png_free(png_ptr, hash); - png_free(png_ptr, png_ptr->palette_to_index); - png_free(png_ptr, png_ptr->index_to_palette); - png_ptr->palette_to_index = NULL; - png_ptr->index_to_palette = NULL; - } - num_palette = maximum_colors; - } - if (png_ptr->palette == NULL) - { - png_ptr->palette = palette; - } - png_ptr->num_palette = (png_uint_16)num_palette; - - if (full_quantize) - { - int i; - png_bytep distance; - int total_bits = PNG_QUANTIZE_RED_BITS + PNG_QUANTIZE_GREEN_BITS + - PNG_QUANTIZE_BLUE_BITS; - int num_red = (1 << PNG_QUANTIZE_RED_BITS); - int num_green = (1 << PNG_QUANTIZE_GREEN_BITS); - int num_blue = (1 << PNG_QUANTIZE_BLUE_BITS); - png_size_t num_entries = ((png_size_t)1 << total_bits); - - png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr, - (png_uint_32)(num_entries * (sizeof (png_byte)))); - - distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries * - (sizeof (png_byte)))); - - memset(distance, 0xff, num_entries * (sizeof (png_byte))); - - for (i = 0; i < num_palette; i++) - { - int ir, ig, ib; - int r = (palette[i].red >> (8 - PNG_QUANTIZE_RED_BITS)); - int g = (palette[i].green >> (8 - PNG_QUANTIZE_GREEN_BITS)); - int b = (palette[i].blue >> (8 - PNG_QUANTIZE_BLUE_BITS)); - - for (ir = 0; ir < num_red; ir++) - { - /* int dr = abs(ir - r); */ - int dr = ((ir > r) ? ir - r : r - ir); - int index_r = (ir << (PNG_QUANTIZE_BLUE_BITS + - PNG_QUANTIZE_GREEN_BITS)); - - for (ig = 0; ig < num_green; ig++) - { - /* int dg = abs(ig - g); */ - int dg = ((ig > g) ? ig - g : g - ig); - int dt = dr + dg; - int dm = ((dr > dg) ? dr : dg); - int index_g = index_r | (ig << PNG_QUANTIZE_BLUE_BITS); - - for (ib = 0; ib < num_blue; ib++) - { - int d_index = index_g | ib; - /* int db = abs(ib - b); */ - int db = ((ib > b) ? ib - b : b - ib); - int dmax = ((dm > db) ? dm : db); - int d = dmax + dt + db; - - if (d < (int)distance[d_index]) - { - distance[d_index] = (png_byte)d; - png_ptr->palette_lookup[d_index] = (png_byte)i; - } - } - } - } - } - - png_free(png_ptr, distance); - } -} -#endif /* PNG_READ_QUANTIZE_SUPPORTED */ - -#ifdef PNG_READ_GAMMA_SUPPORTED -void PNGFAPI -png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma, - png_fixed_point file_gamma) -{ - png_debug(1, "in png_set_gamma_fixed"); - - if (!png_rtran_ok(png_ptr, 0)) - return; - - /* New in libpng-1.5.4 - reserve particular negative values as flags. */ - scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/); - file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/); - - /* Checking the gamma values for being >0 was added in 1.5.4 along with the - * premultiplied alpha support; this actually hides an undocumented feature - * of the previous implementation which allowed gamma processing to be - * disabled in background handling. There is no evidence (so far) that this - * was being used; however, png_set_background itself accepted and must still - * accept '0' for the gamma value it takes, because it isn't always used. - * - * Since this is an API change (albeit a very minor one that removes an - * undocumented API feature) the following checks were only enabled in - * libpng-1.6.0. - */ - if (file_gamma <= 0) - png_error(png_ptr, "invalid file gamma in png_set_gamma"); - - if (scrn_gamma <= 0) - png_error(png_ptr, "invalid screen gamma in png_set_gamma"); - - /* Set the gamma values unconditionally - this overrides the value in the PNG - * file if a gAMA chunk was present. png_set_alpha_mode provides a - * different, easier, way to default the file gamma. - */ - png_ptr->colorspace.gamma = file_gamma; - png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; - png_ptr->screen_gamma = scrn_gamma; -} - -# ifdef PNG_FLOATING_POINT_SUPPORTED -void PNGAPI -png_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma) -{ - png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma), - convert_gamma_value(png_ptr, file_gamma)); -} -# endif /* FLOATING_POINT_SUPPORTED */ -#endif /* READ_GAMMA */ - -#ifdef PNG_READ_EXPAND_SUPPORTED -/* Expand paletted images to RGB, expand grayscale images of - * less than 8-bit depth to 8-bit depth, and expand tRNS chunks - * to alpha channels. - */ -void PNGAPI -png_set_expand(png_structrp png_ptr) -{ - png_debug(1, "in png_set_expand"); - - if (!png_rtran_ok(png_ptr, 0)) - return; - - png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); -} - -/* GRR 19990627: the following three functions currently are identical - * to png_set_expand(). However, it is entirely reasonable that someone - * might wish to expand an indexed image to RGB but *not* expand a single, - * fully transparent palette entry to a full alpha channel--perhaps instead - * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace - * the transparent color with a particular RGB value, or drop tRNS entirely. - * IOW, a future version of the library may make the transformations flag - * a bit more fine-grained, with separate bits for each of these three - * functions. - * - * More to the point, these functions make it obvious what libpng will be - * doing, whereas "expand" can (and does) mean any number of things. - * - * GRP 20060307: In libpng-1.2.9, png_set_gray_1_2_4_to_8() was modified - * to expand only the sample depth but not to expand the tRNS to alpha - * and its name was changed to png_set_expand_gray_1_2_4_to_8(). - */ - -/* Expand paletted images to RGB. */ -void PNGAPI -png_set_palette_to_rgb(png_structrp png_ptr) -{ - png_debug(1, "in png_set_palette_to_rgb"); - - if (!png_rtran_ok(png_ptr, 0)) - return; - - png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); -} - -/* Expand grayscale images of less than 8-bit depth to 8 bits. */ -void PNGAPI -png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr) -{ - png_debug(1, "in png_set_expand_gray_1_2_4_to_8"); - - if (!png_rtran_ok(png_ptr, 0)) - return; - - png_ptr->transformations |= PNG_EXPAND; -} - -/* Expand tRNS chunks to alpha channels. */ -void PNGAPI -png_set_tRNS_to_alpha(png_structrp png_ptr) -{ - png_debug(1, "in png_set_tRNS_to_alpha"); - - if (!png_rtran_ok(png_ptr, 0)) - return; - - png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); -} -#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */ - -#ifdef PNG_READ_EXPAND_16_SUPPORTED -/* Expand to 16-bit channels, expand the tRNS chunk too (because otherwise - * it may not work correctly.) - */ -void PNGAPI -png_set_expand_16(png_structrp png_ptr) -{ - png_debug(1, "in png_set_expand_16"); - - if (!png_rtran_ok(png_ptr, 0)) - return; - - png_ptr->transformations |= (PNG_EXPAND_16 | PNG_EXPAND | PNG_EXPAND_tRNS); -} -#endif - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED -void PNGAPI -png_set_gray_to_rgb(png_structrp png_ptr) -{ - png_debug(1, "in png_set_gray_to_rgb"); - - if (!png_rtran_ok(png_ptr, 0)) - return; - - /* Because rgb must be 8 bits or more: */ - png_set_expand_gray_1_2_4_to_8(png_ptr); - png_ptr->transformations |= PNG_GRAY_TO_RGB; -} -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -void PNGFAPI -png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action, - png_fixed_point red, png_fixed_point green) -{ - png_debug(1, "in png_set_rgb_to_gray"); - - /* Need the IHDR here because of the check on color_type below. */ - /* TODO: fix this */ - if (!png_rtran_ok(png_ptr, 1)) - return; - - switch(error_action) - { - case PNG_ERROR_ACTION_NONE: - png_ptr->transformations |= PNG_RGB_TO_GRAY; - break; - - case PNG_ERROR_ACTION_WARN: - png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN; - break; - - case PNG_ERROR_ACTION_ERROR: - png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR; - break; - - default: - png_error(png_ptr, "invalid error action to rgb_to_gray"); - break; - } - - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) -#ifdef PNG_READ_EXPAND_SUPPORTED - png_ptr->transformations |= PNG_EXPAND; -#else - { - /* Make this an error in 1.6 because otherwise the application may assume - * that it just worked and get a memory overwrite. - */ - png_error(png_ptr, - "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED"); - - /* png_ptr->transformations &= ~PNG_RGB_TO_GRAY; */ - } -#endif - { - if (red >= 0 && green >= 0 && red + green <= PNG_FP_1) - { - png_uint_16 red_int, green_int; - - /* NOTE: this calculation does not round, but this behavior is retained - * for consistency, the inaccuracy is very small. The code here always - * overwrites the coefficients, regardless of whether they have been - * defaulted or set already. - */ - red_int = (png_uint_16)(((png_uint_32)red*32768)/100000); - green_int = (png_uint_16)(((png_uint_32)green*32768)/100000); - - png_ptr->rgb_to_gray_red_coeff = red_int; - png_ptr->rgb_to_gray_green_coeff = green_int; - png_ptr->rgb_to_gray_coefficients_set = 1; - } - - else - { - if (red >= 0 && green >= 0) - png_app_warning(png_ptr, - "ignoring out of range rgb_to_gray coefficients"); - - /* Use the defaults, from the cHRM chunk if set, else the historical - * values which are close to the sRGB/HDTV/ITU-Rec 709 values. See - * png_do_rgb_to_gray for more discussion of the values. In this case - * the coefficients are not marked as 'set' and are not overwritten if - * something has already provided a default. - */ - if (png_ptr->rgb_to_gray_red_coeff == 0 && - png_ptr->rgb_to_gray_green_coeff == 0) - { - png_ptr->rgb_to_gray_red_coeff = 6968; - png_ptr->rgb_to_gray_green_coeff = 23434; - /* png_ptr->rgb_to_gray_blue_coeff = 2366; */ - } - } - } -} - -#ifdef PNG_FLOATING_POINT_SUPPORTED -/* Convert a RGB image to a grayscale of the same width. This allows us, - * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image. - */ - -void PNGAPI -png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red, - double green) -{ - png_set_rgb_to_gray_fixed(png_ptr, error_action, - png_fixed(png_ptr, red, "rgb to gray red coefficient"), - png_fixed(png_ptr, green, "rgb to gray green coefficient")); -} -#endif /* FLOATING POINT */ - -#endif /* RGB_TO_GRAY */ - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) -void PNGAPI -png_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr - read_user_transform_fn) -{ - png_debug(1, "in png_set_read_user_transform_fn"); - - if (!png_rtran_ok(png_ptr, 0)) - return; - -#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED - png_ptr->transformations |= PNG_USER_TRANSFORM; - png_ptr->read_user_transform_fn = read_user_transform_fn; -#endif -} -#endif - -#ifdef PNG_READ_TRANSFORMS_SUPPORTED -#ifdef PNG_READ_GAMMA_SUPPORTED -/* In the case of gamma transformations only do transformations on images where - * the [file] gamma and screen_gamma are not close reciprocals, otherwise it - * slows things down slightly, and also needlessly introduces small errors. - */ -static int /* PRIVATE */ -png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma) -{ - /* PNG_GAMMA_THRESHOLD is the threshold for performing gamma - * correction as a difference of the overall transform from 1.0 - * - * We want to compare the threshold with s*f - 1, if we get - * overflow here it is because of wacky gamma values so we - * turn on processing anyway. - */ - png_fixed_point gtest; - return !png_muldiv(>est, screen_gamma, file_gamma, PNG_FP_1) || - png_gamma_significant(gtest); -} -#endif - -/* Initialize everything needed for the read. This includes modifying - * the palette. - */ - -/*For the moment 'png_init_palette_transformations' and - * 'png_init_rgb_transformations' only do some flag canceling optimizations. - * The intent is that these two routines should have palette or rgb operations - * extracted from 'png_init_read_transformations'. - */ -static void /* PRIVATE */ -png_init_palette_transformations(png_structrp png_ptr) -{ - /* Called to handle the (input) palette case. In png_do_read_transformations - * the first step is to expand the palette if requested, so this code must - * take care to only make changes that are invariant with respect to the - * palette expansion, or only do them if there is no expansion. - * - * STRIP_ALPHA has already been handled in the caller (by setting num_trans - * to 0.) - */ - int input_has_alpha = 0; - int input_has_transparency = 0; - - if (png_ptr->num_trans > 0) - { - int i; - - /* Ignore if all the entries are opaque (unlikely!) */ - for (i=0; inum_trans; ++i) - if (png_ptr->trans_alpha[i] == 255) - continue; - else if (png_ptr->trans_alpha[i] == 0) - input_has_transparency = 1; - else - input_has_alpha = 1; - } - - /* If no alpha we can optimize. */ - if (!input_has_alpha) - { - /* Any alpha means background and associative alpha processing is - * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA - * and ENCODE_ALPHA are irrelevant. - */ - png_ptr->transformations &= ~PNG_ENCODE_ALPHA; - png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; - - if (!input_has_transparency) - png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); - } - -#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) - /* png_set_background handling - deals with the complexity of whether the - * background color is in the file format or the screen format in the case - * where an 'expand' will happen. - */ - - /* The following code cannot be entered in the alpha pre-multiplication case - * because PNG_BACKGROUND_EXPAND is cancelled below. - */ - if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - (png_ptr->transformations & PNG_EXPAND)) - { - { - png_ptr->background.red = - png_ptr->palette[png_ptr->background.index].red; - png_ptr->background.green = - png_ptr->palette[png_ptr->background.index].green; - png_ptr->background.blue = - png_ptr->palette[png_ptr->background.index].blue; - -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_ALPHA) - { - if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) - { - /* Invert the alpha channel (in tRNS) unless the pixels are - * going to be expanded, in which case leave it for later - */ - int i, istop = png_ptr->num_trans; - - for (i=0; itrans_alpha[i] = (png_byte)(255 - - png_ptr->trans_alpha[i]); - } - } -#endif /* PNG_READ_INVERT_ALPHA_SUPPORTED */ - } - } /* background expand and (therefore) no alpha association. */ -#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */ -} - -static void /* PRIVATE */ -png_init_rgb_transformations(png_structrp png_ptr) -{ - /* Added to libpng-1.5.4: check the color type to determine whether there - * is any alpha or transparency in the image and simply cancel the - * background and alpha mode stuff if there isn't. - */ - int input_has_alpha = (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0; - int input_has_transparency = png_ptr->num_trans > 0; - - /* If no alpha we can optimize. */ - if (!input_has_alpha) - { - /* Any alpha means background and associative alpha processing is - * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA - * and ENCODE_ALPHA are irrelevant. - */ -# ifdef PNG_READ_ALPHA_MODE_SUPPORTED - png_ptr->transformations &= ~PNG_ENCODE_ALPHA; - png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; -# endif - - if (!input_has_transparency) - png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); - } - -#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) - /* png_set_background handling - deals with the complexity of whether the - * background color is in the file format or the screen format in the case - * where an 'expand' will happen. - */ - - /* The following code cannot be entered in the alpha pre-multiplication case - * because PNG_BACKGROUND_EXPAND is cancelled below. - */ - if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - (png_ptr->transformations & PNG_EXPAND) && - !(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) - /* i.e., GRAY or GRAY_ALPHA */ - { - { - /* Expand background and tRNS chunks */ - int gray = png_ptr->background.gray; - int trans_gray = png_ptr->trans_color.gray; - - switch (png_ptr->bit_depth) - { - case 1: - gray *= 0xff; - trans_gray *= 0xff; - break; - - case 2: - gray *= 0x55; - trans_gray *= 0x55; - break; - - case 4: - gray *= 0x11; - trans_gray *= 0x11; - break; - - default: - - case 8: - /* FALL THROUGH (Already 8 bits) */ - - case 16: - /* Already a full 16 bits */ - break; - } - - png_ptr->background.red = png_ptr->background.green = - png_ptr->background.blue = (png_uint_16)gray; - - if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) - { - png_ptr->trans_color.red = png_ptr->trans_color.green = - png_ptr->trans_color.blue = (png_uint_16)trans_gray; - } - } - } /* background expand and (therefore) no alpha association. */ -#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */ -} - -void /* PRIVATE */ -png_init_read_transformations(png_structrp png_ptr) -{ - png_debug(1, "in png_init_read_transformations"); - - /* This internal function is called from png_read_start_row in pngrutil.c - * and it is called before the 'rowbytes' calculation is done, so the code - * in here can change or update the transformations flags. - * - * First do updates that do not depend on the details of the PNG image data - * being processed. - */ - -#ifdef PNG_READ_GAMMA_SUPPORTED - /* Prior to 1.5.4 these tests were performed from png_set_gamma, 1.5.4 adds - * png_set_alpha_mode and this is another source for a default file gamma so - * the test needs to be performed later - here. In addition prior to 1.5.4 - * the tests were repeated for the PALETTE color type here - this is no - * longer necessary (and doesn't seem to have been necessary before.) - */ - { - /* The following temporary indicates if overall gamma correction is - * required. - */ - int gamma_correction = 0; - - if (png_ptr->colorspace.gamma != 0) /* has been set */ - { - if (png_ptr->screen_gamma != 0) /* screen set too */ - gamma_correction = png_gamma_threshold(png_ptr->colorspace.gamma, - png_ptr->screen_gamma); - - else - /* Assume the output matches the input; a long time default behavior - * of libpng, although the standard has nothing to say about this. - */ - png_ptr->screen_gamma = png_reciprocal(png_ptr->colorspace.gamma); - } - - else if (png_ptr->screen_gamma != 0) - /* The converse - assume the file matches the screen, note that this - * perhaps undesireable default can (from 1.5.4) be changed by calling - * png_set_alpha_mode (even if the alpha handling mode isn't required - * or isn't changed from the default.) - */ - png_ptr->colorspace.gamma = png_reciprocal(png_ptr->screen_gamma); - - else /* neither are set */ - /* Just in case the following prevents any processing - file and screen - * are both assumed to be linear and there is no way to introduce a - * third gamma value other than png_set_background with 'UNIQUE', and, - * prior to 1.5.4 - */ - png_ptr->screen_gamma = png_ptr->colorspace.gamma = PNG_FP_1; - - /* We have a gamma value now. */ - png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; - - /* Now turn the gamma transformation on or off as appropriate. Notice - * that PNG_GAMMA just refers to the file->screen correction. Alpha - * composition may independently cause gamma correction because it needs - * linear data (e.g. if the file has a gAMA chunk but the screen gamma - * hasn't been specified.) In any case this flag may get turned off in - * the code immediately below if the transform can be handled outside the - * row loop. - */ - if (gamma_correction) - png_ptr->transformations |= PNG_GAMMA; - - else - png_ptr->transformations &= ~PNG_GAMMA; - } -#endif - - /* Certain transformations have the effect of preventing other - * transformations that happen afterward in png_do_read_transformations, - * resolve the interdependencies here. From the code of - * png_do_read_transformations the order is: - * - * 1) PNG_EXPAND (including PNG_EXPAND_tRNS) - * 2) PNG_STRIP_ALPHA (if no compose) - * 3) PNG_RGB_TO_GRAY - * 4) PNG_GRAY_TO_RGB iff !PNG_BACKGROUND_IS_GRAY - * 5) PNG_COMPOSE - * 6) PNG_GAMMA - * 7) PNG_STRIP_ALPHA (if compose) - * 8) PNG_ENCODE_ALPHA - * 9) PNG_SCALE_16_TO_8 - * 10) PNG_16_TO_8 - * 11) PNG_QUANTIZE (converts to palette) - * 12) PNG_EXPAND_16 - * 13) PNG_GRAY_TO_RGB iff PNG_BACKGROUND_IS_GRAY - * 14) PNG_INVERT_MONO - * 15) PNG_SHIFT - * 16) PNG_PACK - * 17) PNG_BGR - * 18) PNG_PACKSWAP - * 19) PNG_FILLER (includes PNG_ADD_ALPHA) - * 20) PNG_INVERT_ALPHA - * 21) PNG_SWAP_ALPHA - * 22) PNG_SWAP_BYTES - * 23) PNG_USER_TRANSFORM [must be last] - */ -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if ((png_ptr->transformations & PNG_STRIP_ALPHA) && - !(png_ptr->transformations & PNG_COMPOSE)) - { - /* Stripping the alpha channel happens immediately after the 'expand' - * transformations, before all other transformation, so it cancels out - * the alpha handling. It has the side effect negating the effect of - * PNG_EXPAND_tRNS too: - */ - png_ptr->transformations &= ~(PNG_BACKGROUND_EXPAND | PNG_ENCODE_ALPHA | - PNG_EXPAND_tRNS); - png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; - - /* Kill the tRNS chunk itself too. Prior to 1.5.4 this did not happen - * so transparency information would remain just so long as it wasn't - * expanded. This produces unexpected API changes if the set of things - * that do PNG_EXPAND_tRNS changes (perfectly possible given the - * documentation - which says ask for what you want, accept what you - * get.) This makes the behavior consistent from 1.5.4: - */ - png_ptr->num_trans = 0; - } -#endif /* STRIP_ALPHA supported, no COMPOSE */ - -#ifdef PNG_READ_ALPHA_MODE_SUPPORTED - /* If the screen gamma is about 1.0 then the OPTIMIZE_ALPHA and ENCODE_ALPHA - * settings will have no effect. - */ - if (!png_gamma_significant(png_ptr->screen_gamma)) - { - png_ptr->transformations &= ~PNG_ENCODE_ALPHA; - png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; - } -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - /* Make sure the coefficients for the rgb to gray conversion are set - * appropriately. - */ - if (png_ptr->transformations & PNG_RGB_TO_GRAY) - png_colorspace_set_rgb_coefficients(png_ptr); -#endif - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED -#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) - /* Detect gray background and attempt to enable optimization for - * gray --> RGB case. - * - * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or - * RGB_ALPHA (in which case need_expand is superfluous anyway), the - * background color might actually be gray yet not be flagged as such. - * This is not a problem for the current code, which uses - * PNG_BACKGROUND_IS_GRAY only to decide when to do the - * png_do_gray_to_rgb() transformation. - * - * TODO: this code needs to be revised to avoid the complexity and - * interdependencies. The color type of the background should be recorded in - * png_set_background, along with the bit depth, then the code has a record - * of exactly what color space the background is currently in. - */ - if (png_ptr->transformations & PNG_BACKGROUND_EXPAND) - { - /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if - * the file was grayscale the background value is gray. - */ - if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) - png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; - } - - else if (png_ptr->transformations & PNG_COMPOSE) - { - /* PNG_COMPOSE: png_set_background was called with need_expand false, - * so the color is in the color space of the output or png_set_alpha_mode - * was called and the color is black. Ignore RGB_TO_GRAY because that - * happens before GRAY_TO_RGB. - */ - if (png_ptr->transformations & PNG_GRAY_TO_RGB) - { - if (png_ptr->background.red == png_ptr->background.green && - png_ptr->background.red == png_ptr->background.blue) - { - png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; - png_ptr->background.gray = png_ptr->background.red; - } - } - } -#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */ -#endif /* PNG_READ_GRAY_TO_RGB_SUPPORTED */ - - /* For indexed PNG data (PNG_COLOR_TYPE_PALETTE) many of the transformations - * can be performed directly on the palette, and some (such as rgb to gray) - * can be optimized inside the palette. This is particularly true of the - * composite (background and alpha) stuff, which can be pretty much all done - * in the palette even if the result is expanded to RGB or gray afterward. - * - * NOTE: this is Not Yet Implemented, the code behaves as in 1.5.1 and - * earlier and the palette stuff is actually handled on the first row. This - * leads to the reported bug that the palette returned by png_get_PLTE is not - * updated. - */ - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - png_init_palette_transformations(png_ptr); - - else - png_init_rgb_transformations(png_ptr); - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ - defined(PNG_READ_EXPAND_16_SUPPORTED) - if ((png_ptr->transformations & PNG_EXPAND_16) && - (png_ptr->transformations & PNG_COMPOSE) && - !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - png_ptr->bit_depth != 16) - { - /* TODO: fix this. Because the expand_16 operation is after the compose - * handling the background color must be 8, not 16, bits deep, but the - * application will supply a 16-bit value so reduce it here. - * - * The PNG_BACKGROUND_EXPAND code above does not expand to 16 bits at - * present, so that case is ok (until do_expand_16 is moved.) - * - * NOTE: this discards the low 16 bits of the user supplied background - * color, but until expand_16 works properly there is no choice! - */ -# define CHOP(x) (x)=((png_uint_16)PNG_DIV257(x)) - CHOP(png_ptr->background.red); - CHOP(png_ptr->background.green); - CHOP(png_ptr->background.blue); - CHOP(png_ptr->background.gray); -# undef CHOP - } -#endif /* PNG_READ_BACKGROUND_SUPPORTED && PNG_READ_EXPAND_16_SUPPORTED */ - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ - (defined(PNG_READ_SCALE_16_TO_8_SUPPORTED) || \ - defined(PNG_READ_STRIP_16_TO_8_SUPPORTED)) - if ((png_ptr->transformations & (PNG_16_TO_8|PNG_SCALE_16_TO_8)) && - (png_ptr->transformations & PNG_COMPOSE) && - !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - png_ptr->bit_depth == 16) - { - /* On the other hand, if a 16-bit file is to be reduced to 8-bits per - * component this will also happen after PNG_COMPOSE and so the background - * color must be pre-expanded here. - * - * TODO: fix this too. - */ - png_ptr->background.red = (png_uint_16)(png_ptr->background.red * 257); - png_ptr->background.green = - (png_uint_16)(png_ptr->background.green * 257); - png_ptr->background.blue = (png_uint_16)(png_ptr->background.blue * 257); - png_ptr->background.gray = (png_uint_16)(png_ptr->background.gray * 257); - } -#endif - - /* NOTE: below 'PNG_READ_ALPHA_MODE_SUPPORTED' is presumed to also enable the - * background support (see the comments in scripts/pnglibconf.dfa), this - * allows pre-multiplication of the alpha channel to be implemented as - * compositing on black. This is probably sub-optimal and has been done in - * 1.5.4 betas simply to enable external critique and testing (i.e. to - * implement the new API quickly, without lots of internal changes.) - */ - -#ifdef PNG_READ_GAMMA_SUPPORTED -# ifdef PNG_READ_BACKGROUND_SUPPORTED - /* Includes ALPHA_MODE */ - png_ptr->background_1 = png_ptr->background; -# endif - - /* This needs to change - in the palette image case a whole set of tables are - * built when it would be quicker to just calculate the correct value for - * each palette entry directly. Also, the test is too tricky - why check - * PNG_RGB_TO_GRAY if PNG_GAMMA is not set? The answer seems to be that - * PNG_GAMMA is cancelled even if the gamma is known? The test excludes the - * PNG_COMPOSE case, so apparently if there is no *overall* gamma correction - * the gamma tables will not be built even if composition is required on a - * gamma encoded value. - * - * In 1.5.4 this is addressed below by an additional check on the individual - * file gamma - if it is not 1.0 both RGB_TO_GRAY and COMPOSE need the - * tables. - */ - if ((png_ptr->transformations & PNG_GAMMA) - || ((png_ptr->transformations & PNG_RGB_TO_GRAY) - && (png_gamma_significant(png_ptr->colorspace.gamma) || - png_gamma_significant(png_ptr->screen_gamma))) - || ((png_ptr->transformations & PNG_COMPOSE) - && (png_gamma_significant(png_ptr->colorspace.gamma) - || png_gamma_significant(png_ptr->screen_gamma) -# ifdef PNG_READ_BACKGROUND_SUPPORTED - || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE - && png_gamma_significant(png_ptr->background_gamma)) -# endif - )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) - && png_gamma_significant(png_ptr->screen_gamma)) - ) - { - png_build_gamma_table(png_ptr, png_ptr->bit_depth); - -#ifdef PNG_READ_BACKGROUND_SUPPORTED - if (png_ptr->transformations & PNG_COMPOSE) - { - /* Issue a warning about this combination: because RGB_TO_GRAY is - * optimized to do the gamma transform if present yet do_background has - * to do the same thing if both options are set a - * double-gamma-correction happens. This is true in all versions of - * libpng to date. - */ - if (png_ptr->transformations & PNG_RGB_TO_GRAY) - png_warning(png_ptr, - "libpng does not support gamma+background+rgb_to_gray"); - - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - /* We don't get to here unless there is a tRNS chunk with non-opaque - * entries - see the checking code at the start of this function. - */ - png_color back, back_1; - png_colorp palette = png_ptr->palette; - int num_palette = png_ptr->num_palette; - int i; - if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE) - { - - back.red = png_ptr->gamma_table[png_ptr->background.red]; - back.green = png_ptr->gamma_table[png_ptr->background.green]; - back.blue = png_ptr->gamma_table[png_ptr->background.blue]; - - back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; - back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; - back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; - } - else - { - png_fixed_point g, gs; - - switch (png_ptr->background_gamma_type) - { - case PNG_BACKGROUND_GAMMA_SCREEN: - g = (png_ptr->screen_gamma); - gs = PNG_FP_1; - break; - - case PNG_BACKGROUND_GAMMA_FILE: - g = png_reciprocal(png_ptr->colorspace.gamma); - gs = png_reciprocal2(png_ptr->colorspace.gamma, - png_ptr->screen_gamma); - break; - - case PNG_BACKGROUND_GAMMA_UNIQUE: - g = png_reciprocal(png_ptr->background_gamma); - gs = png_reciprocal2(png_ptr->background_gamma, - png_ptr->screen_gamma); - break; - default: - g = PNG_FP_1; /* back_1 */ - gs = PNG_FP_1; /* back */ - break; - } - - if (png_gamma_significant(gs)) - { - back.red = png_gamma_8bit_correct(png_ptr->background.red, - gs); - back.green = png_gamma_8bit_correct(png_ptr->background.green, - gs); - back.blue = png_gamma_8bit_correct(png_ptr->background.blue, - gs); - } - - else - { - back.red = (png_byte)png_ptr->background.red; - back.green = (png_byte)png_ptr->background.green; - back.blue = (png_byte)png_ptr->background.blue; - } - - if (png_gamma_significant(g)) - { - back_1.red = png_gamma_8bit_correct(png_ptr->background.red, - g); - back_1.green = png_gamma_8bit_correct( - png_ptr->background.green, g); - back_1.blue = png_gamma_8bit_correct(png_ptr->background.blue, - g); - } - - else - { - back_1.red = (png_byte)png_ptr->background.red; - back_1.green = (png_byte)png_ptr->background.green; - back_1.blue = (png_byte)png_ptr->background.blue; - } - } - - for (i = 0; i < num_palette; i++) - { - if (i < (int)png_ptr->num_trans && - png_ptr->trans_alpha[i] != 0xff) - { - if (png_ptr->trans_alpha[i] == 0) - { - palette[i] = back; - } - else /* if (png_ptr->trans_alpha[i] != 0xff) */ - { - png_byte v, w; - - v = png_ptr->gamma_to_1[palette[i].red]; - png_composite(w, v, png_ptr->trans_alpha[i], back_1.red); - palette[i].red = png_ptr->gamma_from_1[w]; - - v = png_ptr->gamma_to_1[palette[i].green]; - png_composite(w, v, png_ptr->trans_alpha[i], back_1.green); - palette[i].green = png_ptr->gamma_from_1[w]; - - v = png_ptr->gamma_to_1[palette[i].blue]; - png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue); - palette[i].blue = png_ptr->gamma_from_1[w]; - } - } - else - { - palette[i].red = png_ptr->gamma_table[palette[i].red]; - palette[i].green = png_ptr->gamma_table[palette[i].green]; - palette[i].blue = png_ptr->gamma_table[palette[i].blue]; - } - } - - /* Prevent the transformations being done again. - * - * NOTE: this is highly dubious; it removes the transformations in - * place. This seems inconsistent with the general treatment of the - * transformations elsewhere. - */ - png_ptr->transformations &= ~(PNG_COMPOSE | PNG_GAMMA); - } /* color_type == PNG_COLOR_TYPE_PALETTE */ - - /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */ - else /* color_type != PNG_COLOR_TYPE_PALETTE */ - { - int gs_sig, g_sig; - png_fixed_point g = PNG_FP_1; /* Correction to linear */ - png_fixed_point gs = PNG_FP_1; /* Correction to screen */ - - switch (png_ptr->background_gamma_type) - { - case PNG_BACKGROUND_GAMMA_SCREEN: - g = png_ptr->screen_gamma; - /* gs = PNG_FP_1; */ - break; - - case PNG_BACKGROUND_GAMMA_FILE: - g = png_reciprocal(png_ptr->colorspace.gamma); - gs = png_reciprocal2(png_ptr->colorspace.gamma, - png_ptr->screen_gamma); - break; - - case PNG_BACKGROUND_GAMMA_UNIQUE: - g = png_reciprocal(png_ptr->background_gamma); - gs = png_reciprocal2(png_ptr->background_gamma, - png_ptr->screen_gamma); - break; - - default: - png_error(png_ptr, "invalid background gamma type"); - } - - g_sig = png_gamma_significant(g); - gs_sig = png_gamma_significant(gs); - - if (g_sig) - png_ptr->background_1.gray = png_gamma_correct(png_ptr, - png_ptr->background.gray, g); - - if (gs_sig) - png_ptr->background.gray = png_gamma_correct(png_ptr, - png_ptr->background.gray, gs); - - if ((png_ptr->background.red != png_ptr->background.green) || - (png_ptr->background.red != png_ptr->background.blue) || - (png_ptr->background.red != png_ptr->background.gray)) - { - /* RGB or RGBA with color background */ - if (g_sig) - { - png_ptr->background_1.red = png_gamma_correct(png_ptr, - png_ptr->background.red, g); - - png_ptr->background_1.green = png_gamma_correct(png_ptr, - png_ptr->background.green, g); - - png_ptr->background_1.blue = png_gamma_correct(png_ptr, - png_ptr->background.blue, g); - } - - if (gs_sig) - { - png_ptr->background.red = png_gamma_correct(png_ptr, - png_ptr->background.red, gs); - - png_ptr->background.green = png_gamma_correct(png_ptr, - png_ptr->background.green, gs); - - png_ptr->background.blue = png_gamma_correct(png_ptr, - png_ptr->background.blue, gs); - } - } - - else - { - /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */ - png_ptr->background_1.red = png_ptr->background_1.green - = png_ptr->background_1.blue = png_ptr->background_1.gray; - - png_ptr->background.red = png_ptr->background.green - = png_ptr->background.blue = png_ptr->background.gray; - } - - /* The background is now in screen gamma: */ - png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_SCREEN; - } /* color_type != PNG_COLOR_TYPE_PALETTE */ - }/* png_ptr->transformations & PNG_BACKGROUND */ - - else - /* Transformation does not include PNG_BACKGROUND */ -#endif /* PNG_READ_BACKGROUND_SUPPORTED */ - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - /* RGB_TO_GRAY needs to have non-gamma-corrected values! */ - && ((png_ptr->transformations & PNG_EXPAND) == 0 || - (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) -#endif - ) - { - png_colorp palette = png_ptr->palette; - int num_palette = png_ptr->num_palette; - int i; - - /* NOTE: there are other transformations that should probably be in - * here too. - */ - for (i = 0; i < num_palette; i++) - { - palette[i].red = png_ptr->gamma_table[palette[i].red]; - palette[i].green = png_ptr->gamma_table[palette[i].green]; - palette[i].blue = png_ptr->gamma_table[palette[i].blue]; - } - - /* Done the gamma correction. */ - png_ptr->transformations &= ~PNG_GAMMA; - } /* color_type == PALETTE && !PNG_BACKGROUND transformation */ - } -#ifdef PNG_READ_BACKGROUND_SUPPORTED - else -#endif -#endif /* PNG_READ_GAMMA_SUPPORTED */ - -#ifdef PNG_READ_BACKGROUND_SUPPORTED - /* No GAMMA transformation (see the hanging else 4 lines above) */ - if ((png_ptr->transformations & PNG_COMPOSE) && - (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) - { - int i; - int istop = (int)png_ptr->num_trans; - png_color back; - png_colorp palette = png_ptr->palette; - - back.red = (png_byte)png_ptr->background.red; - back.green = (png_byte)png_ptr->background.green; - back.blue = (png_byte)png_ptr->background.blue; - - for (i = 0; i < istop; i++) - { - if (png_ptr->trans_alpha[i] == 0) - { - palette[i] = back; - } - - else if (png_ptr->trans_alpha[i] != 0xff) - { - /* The png_composite() macro is defined in png.h */ - png_composite(palette[i].red, palette[i].red, - png_ptr->trans_alpha[i], back.red); - - png_composite(palette[i].green, palette[i].green, - png_ptr->trans_alpha[i], back.green); - - png_composite(palette[i].blue, palette[i].blue, - png_ptr->trans_alpha[i], back.blue); - } - } - - png_ptr->transformations &= ~PNG_COMPOSE; - } -#endif /* PNG_READ_BACKGROUND_SUPPORTED */ - -#ifdef PNG_READ_SHIFT_SUPPORTED - if ((png_ptr->transformations & PNG_SHIFT) && - !(png_ptr->transformations & PNG_EXPAND) && - (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) - { - int i; - int istop = png_ptr->num_palette; - int shift = 8 - png_ptr->sig_bit.red; - - png_ptr->transformations &= ~PNG_SHIFT; - - /* significant bits can be in the range 1 to 7 for a meaninful result, if - * the number of significant bits is 0 then no shift is done (this is an - * error condition which is silently ignored.) - */ - if (shift > 0 && shift < 8) for (i=0; ipalette[i].red; - - component >>= shift; - png_ptr->palette[i].red = (png_byte)component; - } - - shift = 8 - png_ptr->sig_bit.green; - if (shift > 0 && shift < 8) for (i=0; ipalette[i].green; - - component >>= shift; - png_ptr->palette[i].green = (png_byte)component; - } - - shift = 8 - png_ptr->sig_bit.blue; - if (shift > 0 && shift < 8) for (i=0; ipalette[i].blue; - - component >>= shift; - png_ptr->palette[i].blue = (png_byte)component; - } - } -#endif /* PNG_READ_SHIFT_SUPPORTED */ -} - -/* Modify the info structure to reflect the transformations. The - * info should be updated so a PNG file could be written with it, - * assuming the transformations result in valid PNG data. - */ -void /* PRIVATE */ -png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) -{ - png_debug(1, "in png_read_transform_info"); - -#ifdef PNG_READ_EXPAND_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND) - { - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - /* This check must match what actually happens in - * png_do_expand_palette; if it ever checks the tRNS chunk to see if - * it is all opaque we must do the same (at present it does not.) - */ - if (png_ptr->num_trans > 0) - info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA; - - else - info_ptr->color_type = PNG_COLOR_TYPE_RGB; - - info_ptr->bit_depth = 8; - info_ptr->num_trans = 0; - } - else - { - if (png_ptr->num_trans) - { - if (png_ptr->transformations & PNG_EXPAND_tRNS) - info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; - } - if (info_ptr->bit_depth < 8) - info_ptr->bit_depth = 8; - - info_ptr->num_trans = 0; - } - } -#endif - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ - defined(PNG_READ_ALPHA_MODE_SUPPORTED) - /* The following is almost certainly wrong unless the background value is in - * the screen space! - */ - if (png_ptr->transformations & PNG_COMPOSE) - info_ptr->background = png_ptr->background; -#endif - -#ifdef PNG_READ_GAMMA_SUPPORTED - /* The following used to be conditional on PNG_GAMMA (prior to 1.5.4), - * however it seems that the code in png_init_read_transformations, which has - * been called before this from png_read_update_info->png_read_start_row - * sometimes does the gamma transform and cancels the flag. - * - * TODO: this looks wrong; the info_ptr should end up with a gamma equal to - * the screen_gamma value. The following probably results in weirdness if - * the info_ptr is used by the app after the rows have been read. - */ - info_ptr->colorspace.gamma = png_ptr->colorspace.gamma; -#endif - - if (info_ptr->bit_depth == 16) - { -# ifdef PNG_READ_16BIT_SUPPORTED -# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED - if (png_ptr->transformations & PNG_SCALE_16_TO_8) - info_ptr->bit_depth = 8; -# endif - -# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED - if (png_ptr->transformations & PNG_16_TO_8) - info_ptr->bit_depth = 8; -# endif - -# else - /* No 16 bit support: force chopping 16-bit input down to 8, in this case - * the app program can chose if both APIs are available by setting the - * correct scaling to use. - */ -# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED - /* For compatibility with previous versions use the strip method by - * default. This code works because if PNG_SCALE_16_TO_8 is already - * set the code below will do that in preference to the chop. - */ - png_ptr->transformations |= PNG_16_TO_8; - info_ptr->bit_depth = 8; -# else - -# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED - png_ptr->transformations |= PNG_SCALE_16_TO_8; - info_ptr->bit_depth = 8; -# else - - CONFIGURATION ERROR: you must enable at least one 16 to 8 method -# endif -# endif -#endif /* !READ_16BIT_SUPPORTED */ - } - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - if (png_ptr->transformations & PNG_GRAY_TO_RGB) - info_ptr->color_type = (png_byte)(info_ptr->color_type | - PNG_COLOR_MASK_COLOR); -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - if (png_ptr->transformations & PNG_RGB_TO_GRAY) - info_ptr->color_type = (png_byte)(info_ptr->color_type & - ~PNG_COLOR_MASK_COLOR); -#endif - -#ifdef PNG_READ_QUANTIZE_SUPPORTED - if (png_ptr->transformations & PNG_QUANTIZE) - { - if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || - (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) && - png_ptr->palette_lookup && info_ptr->bit_depth == 8) - { - info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; - } - } -#endif - -#ifdef PNG_READ_EXPAND_16_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND_16 && info_ptr->bit_depth == 8 && - info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) - { - info_ptr->bit_depth = 16; - } -#endif - -#ifdef PNG_READ_PACK_SUPPORTED - if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8)) - info_ptr->bit_depth = 8; -#endif - - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - info_ptr->channels = 1; - - else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) - info_ptr->channels = 3; - - else - info_ptr->channels = 1; - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_STRIP_ALPHA) - { - info_ptr->color_type = (png_byte)(info_ptr->color_type & - ~PNG_COLOR_MASK_ALPHA); - info_ptr->num_trans = 0; - } -#endif - - if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) - info_ptr->channels++; - -#ifdef PNG_READ_FILLER_SUPPORTED - /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */ - if ((png_ptr->transformations & PNG_FILLER) && - ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || - (info_ptr->color_type == PNG_COLOR_TYPE_GRAY))) - { - info_ptr->channels++; - /* If adding a true alpha channel not just filler */ - if (png_ptr->transformations & PNG_ADD_ALPHA) - info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; - } -#endif - -#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \ -defined(PNG_READ_USER_TRANSFORM_SUPPORTED) - if (png_ptr->transformations & PNG_USER_TRANSFORM) - { - if (info_ptr->bit_depth < png_ptr->user_transform_depth) - info_ptr->bit_depth = png_ptr->user_transform_depth; - - if (info_ptr->channels < png_ptr->user_transform_channels) - info_ptr->channels = png_ptr->user_transform_channels; - } -#endif - - info_ptr->pixel_depth = (png_byte)(info_ptr->channels * - info_ptr->bit_depth); - - info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width); - - /* Adding in 1.5.4: cache the above value in png_struct so that we can later - * check in png_rowbytes that the user buffer won't get overwritten. Note - * that the field is not always set - if png_read_update_info isn't called - * the application has to either not do any transforms or get the calculation - * right itself. - */ - png_ptr->info_rowbytes = info_ptr->rowbytes; - -#ifndef PNG_READ_EXPAND_SUPPORTED - if (png_ptr) - return; -#endif -} - -/* Transform the row. The order of transformations is significant, - * and is very touchy. If you add a transformation, take care to - * decide how it fits in with the other transformations here. - */ -void /* PRIVATE */ -png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info) -{ - png_debug(1, "in png_do_read_transformations"); - - if (png_ptr->row_buf == NULL) - { - /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this - * error is incredibly rare and incredibly easy to debug without this - * information. - */ - png_error(png_ptr, "NULL row buffer"); - } - - /* The following is debugging; prior to 1.5.4 the code was never compiled in; - * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro - * PNG_WARN_UNINITIALIZED_ROW removed. In 1.6 the new flag is set only for - * all transformations, however in practice the ROW_INIT always gets done on - * demand, if necessary. - */ - if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 && - !(png_ptr->flags & PNG_FLAG_ROW_INIT)) - { - /* Application has failed to call either png_read_start_image() or - * png_read_update_info() after setting transforms that expand pixels. - * This check added to libpng-1.2.19 (but not enabled until 1.5.4). - */ - png_error(png_ptr, "Uninitialized row"); - } - -#ifdef PNG_READ_EXPAND_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND) - { - if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) - { - png_do_expand_palette(row_info, png_ptr->row_buf + 1, - png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans); - } - - else - { - if (png_ptr->num_trans && - (png_ptr->transformations & PNG_EXPAND_tRNS)) - png_do_expand(row_info, png_ptr->row_buf + 1, - &(png_ptr->trans_color)); - - else - png_do_expand(row_info, png_ptr->row_buf + 1, - NULL); - } - } -#endif - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if ((png_ptr->transformations & PNG_STRIP_ALPHA) && - !(png_ptr->transformations & PNG_COMPOSE) && - (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || - row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) - png_do_strip_channel(row_info, png_ptr->row_buf + 1, - 0 /* at_start == false, because SWAP_ALPHA happens later */); -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - if (png_ptr->transformations & PNG_RGB_TO_GRAY) - { - int rgb_error = - png_do_rgb_to_gray(png_ptr, row_info, - png_ptr->row_buf + 1); - - if (rgb_error) - { - png_ptr->rgb_to_gray_status=1; - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == - PNG_RGB_TO_GRAY_WARN) - png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel"); - - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == - PNG_RGB_TO_GRAY_ERR) - png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel"); - } - } -#endif - -/* From Andreas Dilger e-mail to png-implement, 26 March 1998: - * - * In most cases, the "simple transparency" should be done prior to doing - * gray-to-RGB, or you will have to test 3x as many bytes to check if a - * pixel is transparent. You would also need to make sure that the - * transparency information is upgraded to RGB. - * - * To summarize, the current flow is: - * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite - * with background "in place" if transparent, - * convert to RGB if necessary - * - Gray + alpha -> composite with gray background and remove alpha bytes, - * convert to RGB if necessary - * - * To support RGB backgrounds for gray images we need: - * - Gray + simple transparency -> convert to RGB + simple transparency, - * compare 3 or 6 bytes and composite with - * background "in place" if transparent - * (3x compare/pixel compared to doing - * composite with gray bkgrnd) - * - Gray + alpha -> convert to RGB + alpha, composite with background and - * remove alpha bytes (3x float - * operations/pixel compared with composite - * on gray background) - * - * Greg's change will do this. The reason it wasn't done before is for - * performance, as this increases the per-pixel operations. If we would check - * in advance if the background was gray or RGB, and position the gray-to-RGB - * transform appropriately, then it would save a lot of work/time. - */ - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - /* If gray -> RGB, do so now only if background is non-gray; else do later - * for performance reasons - */ - if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && - !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) - png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); -#endif - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ - defined(PNG_READ_ALPHA_MODE_SUPPORTED) - if (png_ptr->transformations & PNG_COMPOSE) - png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr); -#endif - -#ifdef PNG_READ_GAMMA_SUPPORTED - if ((png_ptr->transformations & PNG_GAMMA) && -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - /* Because RGB_TO_GRAY does the gamma transform. */ - !(png_ptr->transformations & PNG_RGB_TO_GRAY) && -#endif -#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ - defined(PNG_READ_ALPHA_MODE_SUPPORTED) - /* Because PNG_COMPOSE does the gamma transform if there is something to - * do (if there is an alpha channel or transparency.) - */ - !((png_ptr->transformations & PNG_COMPOSE) && - ((png_ptr->num_trans != 0) || - (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) && -#endif - /* Because png_init_read_transformations transforms the palette, unless - * RGB_TO_GRAY will do the transform. - */ - (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) - png_do_gamma(row_info, png_ptr->row_buf + 1, png_ptr); -#endif - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if ((png_ptr->transformations & PNG_STRIP_ALPHA) && - (png_ptr->transformations & PNG_COMPOSE) && - (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || - row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) - png_do_strip_channel(row_info, png_ptr->row_buf + 1, - 0 /* at_start == false, because SWAP_ALPHA happens later */); -#endif - -#ifdef PNG_READ_ALPHA_MODE_SUPPORTED - if ((png_ptr->transformations & PNG_ENCODE_ALPHA) && - (row_info->color_type & PNG_COLOR_MASK_ALPHA)) - png_do_encode_alpha(row_info, png_ptr->row_buf + 1, png_ptr); -#endif - -#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED - if (png_ptr->transformations & PNG_SCALE_16_TO_8) - png_do_scale_16_to_8(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED - /* There is no harm in doing both of these because only one has any effect, - * by putting the 'scale' option first if the app asks for scale (either by - * calling the API or in a TRANSFORM flag) this is what happens. - */ - if (png_ptr->transformations & PNG_16_TO_8) - png_do_chop(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_QUANTIZE_SUPPORTED - if (png_ptr->transformations & PNG_QUANTIZE) - { - png_do_quantize(row_info, png_ptr->row_buf + 1, - png_ptr->palette_lookup, png_ptr->quantize_index); - - if (row_info->rowbytes == 0) - png_error(png_ptr, "png_do_quantize returned rowbytes=0"); - } -#endif /* PNG_READ_QUANTIZE_SUPPORTED */ - -#ifdef PNG_READ_EXPAND_16_SUPPORTED - /* Do the expansion now, after all the arithmetic has been done. Notice - * that previous transformations can handle the PNG_EXPAND_16 flag if this - * is efficient (particularly true in the case of gamma correction, where - * better accuracy results faster!) - */ - if (png_ptr->transformations & PNG_EXPAND_16) - png_do_expand_16(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - /* NOTE: moved here in 1.5.4 (from much later in this list.) */ - if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && - (png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) - png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_INVERT_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_MONO) - png_do_invert(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_SHIFT_SUPPORTED - if (png_ptr->transformations & PNG_SHIFT) - png_do_unshift(row_info, png_ptr->row_buf + 1, - &(png_ptr->shift)); -#endif - -#ifdef PNG_READ_PACK_SUPPORTED - if (png_ptr->transformations & PNG_PACK) - png_do_unpack(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED - /* Added at libpng-1.5.10 */ - if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && - png_ptr->num_palette_max >= 0) - png_do_check_palette_indexes(png_ptr, row_info); -#endif - -#ifdef PNG_READ_BGR_SUPPORTED - if (png_ptr->transformations & PNG_BGR) - png_do_bgr(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) - png_do_packswap(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_FILLER_SUPPORTED - if (png_ptr->transformations & PNG_FILLER) - png_do_read_filler(row_info, png_ptr->row_buf + 1, - (png_uint_32)png_ptr->filler, png_ptr->flags); -#endif - -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_ALPHA) - png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_ALPHA) - png_do_read_swap_alpha(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_16BIT_SUPPORTED -#ifdef PNG_READ_SWAP_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_BYTES) - png_do_swap(row_info, png_ptr->row_buf + 1); -#endif -#endif - -#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED - if (png_ptr->transformations & PNG_USER_TRANSFORM) - { - if (png_ptr->read_user_transform_fn != NULL) - (*(png_ptr->read_user_transform_fn)) /* User read transform function */ - (png_ptr, /* png_ptr */ - row_info, /* row_info: */ - /* png_uint_32 width; width of row */ - /* png_size_t rowbytes; number of bytes in row */ - /* png_byte color_type; color type of pixels */ - /* png_byte bit_depth; bit depth of samples */ - /* png_byte channels; number of channels (1-4) */ - /* png_byte pixel_depth; bits per pixel (depth*channels) */ - png_ptr->row_buf + 1); /* start of pixel data for row */ -#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED - if (png_ptr->user_transform_depth) - row_info->bit_depth = png_ptr->user_transform_depth; - - if (png_ptr->user_transform_channels) - row_info->channels = png_ptr->user_transform_channels; -#endif - row_info->pixel_depth = (png_byte)(row_info->bit_depth * - row_info->channels); - - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width); - } -#endif -} - -#ifdef PNG_READ_PACK_SUPPORTED -/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel, - * without changing the actual values. Thus, if you had a row with - * a bit depth of 1, you would end up with bytes that only contained - * the numbers 0 or 1. If you would rather they contain 0 and 255, use - * png_do_shift() after this. - */ -void /* PRIVATE */ -png_do_unpack(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_unpack"); - - if (row_info->bit_depth < 8) - { - png_uint_32 i; - png_uint_32 row_width=row_info->width; - - switch (row_info->bit_depth) - { - case 1: - { - png_bytep sp = row + (png_size_t)((row_width - 1) >> 3); - png_bytep dp = row + (png_size_t)row_width - 1; - png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07); - for (i = 0; i < row_width; i++) - { - *dp = (png_byte)((*sp >> shift) & 0x01); - - if (shift == 7) - { - shift = 0; - sp--; - } - - else - shift++; - - dp--; - } - break; - } - - case 2: - { - - png_bytep sp = row + (png_size_t)((row_width - 1) >> 2); - png_bytep dp = row + (png_size_t)row_width - 1; - png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); - for (i = 0; i < row_width; i++) - { - *dp = (png_byte)((*sp >> shift) & 0x03); - - if (shift == 6) - { - shift = 0; - sp--; - } - - else - shift += 2; - - dp--; - } - break; - } - - case 4: - { - png_bytep sp = row + (png_size_t)((row_width - 1) >> 1); - png_bytep dp = row + (png_size_t)row_width - 1; - png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); - for (i = 0; i < row_width; i++) - { - *dp = (png_byte)((*sp >> shift) & 0x0f); - - if (shift == 4) - { - shift = 0; - sp--; - } - - else - shift = 4; - - dp--; - } - break; - } - - default: - break; - } - row_info->bit_depth = 8; - row_info->pixel_depth = (png_byte)(8 * row_info->channels); - row_info->rowbytes = row_width * row_info->channels; - } -} -#endif - -#ifdef PNG_READ_SHIFT_SUPPORTED -/* Reverse the effects of png_do_shift. This routine merely shifts the - * pixels back to their significant bits values. Thus, if you have - * a row of bit depth 8, but only 5 are significant, this will shift - * the values back to 0 through 31. - */ -void /* PRIVATE */ -png_do_unshift(png_row_infop row_info, png_bytep row, - png_const_color_8p sig_bits) -{ - int color_type; - - png_debug(1, "in png_do_unshift"); - - /* The palette case has already been handled in the _init routine. */ - color_type = row_info->color_type; - - if (color_type != PNG_COLOR_TYPE_PALETTE) - { - int shift[4]; - int channels = 0; - int bit_depth = row_info->bit_depth; - - if (color_type & PNG_COLOR_MASK_COLOR) - { - shift[channels++] = bit_depth - sig_bits->red; - shift[channels++] = bit_depth - sig_bits->green; - shift[channels++] = bit_depth - sig_bits->blue; - } - - else - { - shift[channels++] = bit_depth - sig_bits->gray; - } - - if (color_type & PNG_COLOR_MASK_ALPHA) - { - shift[channels++] = bit_depth - sig_bits->alpha; - } - - { - int c, have_shift; - - for (c = have_shift = 0; c < channels; ++c) - { - /* A shift of more than the bit depth is an error condition but it - * gets ignored here. - */ - if (shift[c] <= 0 || shift[c] >= bit_depth) - shift[c] = 0; - - else - have_shift = 1; - } - - if (!have_shift) - return; - } - - switch (bit_depth) - { - default: - /* Must be 1bpp gray: should not be here! */ - /* NOTREACHED */ - break; - - case 2: - /* Must be 2bpp gray */ - /* assert(channels == 1 && shift[0] == 1) */ - { - png_bytep bp = row; - png_bytep bp_end = bp + row_info->rowbytes; - - while (bp < bp_end) - { - int b = (*bp >> 1) & 0x55; - *bp++ = (png_byte)b; - } - break; - } - - case 4: - /* Must be 4bpp gray */ - /* assert(channels == 1) */ - { - png_bytep bp = row; - png_bytep bp_end = bp + row_info->rowbytes; - int gray_shift = shift[0]; - int mask = 0xf >> gray_shift; - - mask |= mask << 4; - - while (bp < bp_end) - { - int b = (*bp >> gray_shift) & mask; - *bp++ = (png_byte)b; - } - break; - } - - case 8: - /* Single byte components, G, GA, RGB, RGBA */ - { - png_bytep bp = row; - png_bytep bp_end = bp + row_info->rowbytes; - int channel = 0; - - while (bp < bp_end) - { - int b = *bp >> shift[channel]; - if (++channel >= channels) - channel = 0; - *bp++ = (png_byte)b; - } - break; - } - -#ifdef PNG_READ_16BIT_SUPPORTED - case 16: - /* Double byte components, G, GA, RGB, RGBA */ - { - png_bytep bp = row; - png_bytep bp_end = bp + row_info->rowbytes; - int channel = 0; - - while (bp < bp_end) - { - int value = (bp[0] << 8) + bp[1]; - - value >>= shift[channel]; - if (++channel >= channels) - channel = 0; - *bp++ = (png_byte)(value >> 8); - *bp++ = (png_byte)(value & 0xff); - } - break; - } -#endif - } - } -} -#endif - -#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED -/* Scale rows of bit depth 16 down to 8 accurately */ -void /* PRIVATE */ -png_do_scale_16_to_8(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_scale_16_to_8"); - - if (row_info->bit_depth == 16) - { - png_bytep sp = row; /* source */ - png_bytep dp = row; /* destination */ - png_bytep ep = sp + row_info->rowbytes; /* end+1 */ - - while (sp < ep) - { - /* The input is an array of 16 bit components, these must be scaled to - * 8 bits each. For a 16 bit value V the required value (from the PNG - * specification) is: - * - * (V * 255) / 65535 - * - * This reduces to round(V / 257), or floor((V + 128.5)/257) - * - * Represent V as the two byte value vhi.vlo. Make a guess that the - * result is the top byte of V, vhi, then the correction to this value - * is: - * - * error = floor(((V-vhi.vhi) + 128.5) / 257) - * = floor(((vlo-vhi) + 128.5) / 257) - * - * This can be approximated using integer arithmetic (and a signed - * shift): - * - * error = (vlo-vhi+128) >> 8; - * - * The approximate differs from the exact answer only when (vlo-vhi) is - * 128; it then gives a correction of +1 when the exact correction is - * 0. This gives 128 errors. The exact answer (correct for all 16 bit - * input values) is: - * - * error = (vlo-vhi+128)*65535 >> 24; - * - * An alternative arithmetic calculation which also gives no errors is: - * - * (V * 255 + 32895) >> 16 - */ - - png_int_32 tmp = *sp++; /* must be signed! */ - tmp += (((int)*sp++ - tmp + 128) * 65535) >> 24; - *dp++ = (png_byte)tmp; - } - - row_info->bit_depth = 8; - row_info->pixel_depth = (png_byte)(8 * row_info->channels); - row_info->rowbytes = row_info->width * row_info->channels; - } -} -#endif - -#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED -void /* PRIVATE */ -/* Simply discard the low byte. This was the default behavior prior - * to libpng-1.5.4. - */ -png_do_chop(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_chop"); - - if (row_info->bit_depth == 16) - { - png_bytep sp = row; /* source */ - png_bytep dp = row; /* destination */ - png_bytep ep = sp + row_info->rowbytes; /* end+1 */ - - while (sp < ep) - { - *dp++ = *sp; - sp += 2; /* skip low byte */ - } - - row_info->bit_depth = 8; - row_info->pixel_depth = (png_byte)(8 * row_info->channels); - row_info->rowbytes = row_info->width * row_info->channels; - } -} -#endif - -#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED -void /* PRIVATE */ -png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_read_swap_alpha"); - - { - png_uint_32 row_width = row_info->width; - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - /* This converts from RGBA to ARGB */ - if (row_info->bit_depth == 8) - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_byte save; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - save = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = save; - } - } - -#ifdef PNG_READ_16BIT_SUPPORTED - /* This converts from RRGGBBAA to AARRGGBB */ - else - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_byte save[2]; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - save[0] = *(--sp); - save[1] = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = save[0]; - *(--dp) = save[1]; - } - } -#endif - } - - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - /* This converts from GA to AG */ - if (row_info->bit_depth == 8) - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_byte save; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - save = *(--sp); - *(--dp) = *(--sp); - *(--dp) = save; - } - } - -#ifdef PNG_READ_16BIT_SUPPORTED - /* This converts from GGAA to AAGG */ - else - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_byte save[2]; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - save[0] = *(--sp); - save[1] = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = save[0]; - *(--dp) = save[1]; - } - } -#endif - } - } -} -#endif - -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED -void /* PRIVATE */ -png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) -{ - png_uint_32 row_width; - png_debug(1, "in png_do_read_invert_alpha"); - - row_width = row_info->width; - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - if (row_info->bit_depth == 8) - { - /* This inverts the alpha channel in RGBA */ - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - *(--dp) = (png_byte)(255 - *(--sp)); - -/* This does nothing: - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - We can replace it with: -*/ - sp-=3; - dp=sp; - } - } - -#ifdef PNG_READ_16BIT_SUPPORTED - /* This inverts the alpha channel in RRGGBBAA */ - else - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - *(--dp) = (png_byte)(255 - *(--sp)); - *(--dp) = (png_byte)(255 - *(--sp)); - -/* This does nothing: - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - We can replace it with: -*/ - sp-=6; - dp=sp; - } - } -#endif - } - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - if (row_info->bit_depth == 8) - { - /* This inverts the alpha channel in GA */ - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - *(--dp) = (png_byte)(255 - *(--sp)); - *(--dp) = *(--sp); - } - } - -#ifdef PNG_READ_16BIT_SUPPORTED - else - { - /* This inverts the alpha channel in GGAA */ - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - *(--dp) = (png_byte)(255 - *(--sp)); - *(--dp) = (png_byte)(255 - *(--sp)); -/* - *(--dp) = *(--sp); - *(--dp) = *(--sp); -*/ - sp-=2; - dp=sp; - } - } -#endif - } -} -#endif - -#ifdef PNG_READ_FILLER_SUPPORTED -/* Add filler channel if we have RGB color */ -void /* PRIVATE */ -png_do_read_filler(png_row_infop row_info, png_bytep row, - png_uint_32 filler, png_uint_32 flags) -{ - png_uint_32 i; - png_uint_32 row_width = row_info->width; - -#ifdef PNG_READ_16BIT_SUPPORTED - png_byte hi_filler = (png_byte)((filler>>8) & 0xff); -#endif - png_byte lo_filler = (png_byte)(filler & 0xff); - - png_debug(1, "in png_do_read_filler"); - - if ( - row_info->color_type == PNG_COLOR_TYPE_GRAY) - { - if (row_info->bit_depth == 8) - { - if (flags & PNG_FLAG_FILLER_AFTER) - { - /* This changes the data from G to GX */ - png_bytep sp = row + (png_size_t)row_width; - png_bytep dp = sp + (png_size_t)row_width; - for (i = 1; i < row_width; i++) - { - *(--dp) = lo_filler; - *(--dp) = *(--sp); - } - *(--dp) = lo_filler; - row_info->channels = 2; - row_info->pixel_depth = 16; - row_info->rowbytes = row_width * 2; - } - - else - { - /* This changes the data from G to XG */ - png_bytep sp = row + (png_size_t)row_width; - png_bytep dp = sp + (png_size_t)row_width; - for (i = 0; i < row_width; i++) - { - *(--dp) = *(--sp); - *(--dp) = lo_filler; - } - row_info->channels = 2; - row_info->pixel_depth = 16; - row_info->rowbytes = row_width * 2; - } - } - -#ifdef PNG_READ_16BIT_SUPPORTED - else if (row_info->bit_depth == 16) - { - if (flags & PNG_FLAG_FILLER_AFTER) - { - /* This changes the data from GG to GGXX */ - png_bytep sp = row + (png_size_t)row_width * 2; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 1; i < row_width; i++) - { - *(--dp) = hi_filler; - *(--dp) = lo_filler; - *(--dp) = *(--sp); - *(--dp) = *(--sp); - } - *(--dp) = hi_filler; - *(--dp) = lo_filler; - row_info->channels = 2; - row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; - } - - else - { - /* This changes the data from GG to XXGG */ - png_bytep sp = row + (png_size_t)row_width * 2; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 0; i < row_width; i++) - { - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = hi_filler; - *(--dp) = lo_filler; - } - row_info->channels = 2; - row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; - } - } -#endif - } /* COLOR_TYPE == GRAY */ - else if (row_info->color_type == PNG_COLOR_TYPE_RGB) - { - if (row_info->bit_depth == 8) - { - if (flags & PNG_FLAG_FILLER_AFTER) - { - /* This changes the data from RGB to RGBX */ - png_bytep sp = row + (png_size_t)row_width * 3; - png_bytep dp = sp + (png_size_t)row_width; - for (i = 1; i < row_width; i++) - { - *(--dp) = lo_filler; - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - } - *(--dp) = lo_filler; - row_info->channels = 4; - row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; - } - - else - { - /* This changes the data from RGB to XRGB */ - png_bytep sp = row + (png_size_t)row_width * 3; - png_bytep dp = sp + (png_size_t)row_width; - for (i = 0; i < row_width; i++) - { - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = lo_filler; - } - row_info->channels = 4; - row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; - } - } - -#ifdef PNG_READ_16BIT_SUPPORTED - else if (row_info->bit_depth == 16) - { - if (flags & PNG_FLAG_FILLER_AFTER) - { - /* This changes the data from RRGGBB to RRGGBBXX */ - png_bytep sp = row + (png_size_t)row_width * 6; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 1; i < row_width; i++) - { - *(--dp) = hi_filler; - *(--dp) = lo_filler; - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - } - *(--dp) = hi_filler; - *(--dp) = lo_filler; - row_info->channels = 4; - row_info->pixel_depth = 64; - row_info->rowbytes = row_width * 8; - } - - else - { - /* This changes the data from RRGGBB to XXRRGGBB */ - png_bytep sp = row + (png_size_t)row_width * 6; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 0; i < row_width; i++) - { - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = hi_filler; - *(--dp) = lo_filler; - } - - row_info->channels = 4; - row_info->pixel_depth = 64; - row_info->rowbytes = row_width * 8; - } - } -#endif - } /* COLOR_TYPE == RGB */ -} -#endif - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED -/* Expand grayscale files to RGB, with or without alpha */ -void /* PRIVATE */ -png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) -{ - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - png_debug(1, "in png_do_gray_to_rgb"); - - if (row_info->bit_depth >= 8 && - !(row_info->color_type & PNG_COLOR_MASK_COLOR)) - { - if (row_info->color_type == PNG_COLOR_TYPE_GRAY) - { - if (row_info->bit_depth == 8) - { - /* This changes G to RGB */ - png_bytep sp = row + (png_size_t)row_width - 1; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 0; i < row_width; i++) - { - *(dp--) = *sp; - *(dp--) = *sp; - *(dp--) = *(sp--); - } - } - - else - { - /* This changes GG to RRGGBB */ - png_bytep sp = row + (png_size_t)row_width * 2 - 1; - png_bytep dp = sp + (png_size_t)row_width * 4; - for (i = 0; i < row_width; i++) - { - *(dp--) = *sp; - *(dp--) = *(sp - 1); - *(dp--) = *sp; - *(dp--) = *(sp - 1); - *(dp--) = *(sp--); - *(dp--) = *(sp--); - } - } - } - - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - if (row_info->bit_depth == 8) - { - /* This changes GA to RGBA */ - png_bytep sp = row + (png_size_t)row_width * 2 - 1; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 0; i < row_width; i++) - { - *(dp--) = *(sp--); - *(dp--) = *sp; - *(dp--) = *sp; - *(dp--) = *(sp--); - } - } - - else - { - /* This changes GGAA to RRGGBBAA */ - png_bytep sp = row + (png_size_t)row_width * 4 - 1; - png_bytep dp = sp + (png_size_t)row_width * 4; - for (i = 0; i < row_width; i++) - { - *(dp--) = *(sp--); - *(dp--) = *(sp--); - *(dp--) = *sp; - *(dp--) = *(sp - 1); - *(dp--) = *sp; - *(dp--) = *(sp - 1); - *(dp--) = *(sp--); - *(dp--) = *(sp--); - } - } - } - row_info->channels = (png_byte)(row_info->channels + 2); - row_info->color_type |= PNG_COLOR_MASK_COLOR; - row_info->pixel_depth = (png_byte)(row_info->channels * - row_info->bit_depth); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } -} -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -/* Reduce RGB files to grayscale, with or without alpha - * using the equation given in Poynton's ColorFAQ of 1998-01-04 at - * (THIS LINK IS DEAD June 2008 but - * versions dated 1998 through November 2002 have been archived at - * http://web.archive.org/web/20000816232553/http://www.inforamp.net/ - * ~poynton/notes/colour_and_gamma/ColorFAQ.txt ) - * Charles Poynton poynton at poynton.com - * - * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B - * - * which can be expressed with integers as - * - * Y = (6969 * R + 23434 * G + 2365 * B)/32768 - * - * Poynton's current link (as of January 2003 through July 2011): - * - * has changed the numbers slightly: - * - * Y = 0.2126*R + 0.7152*G + 0.0722*B - * - * which can be expressed with integers as - * - * Y = (6966 * R + 23436 * G + 2366 * B)/32768 - * - * Historically, however, libpng uses numbers derived from the ITU-R Rec 709 - * end point chromaticities and the D65 white point. Depending on the - * precision used for the D65 white point this produces a variety of different - * numbers, however if the four decimal place value used in ITU-R Rec 709 is - * used (0.3127,0.3290) the Y calculation would be: - * - * Y = (6968 * R + 23435 * G + 2366 * B)/32768 - * - * While this is correct the rounding results in an overflow for white, because - * the sum of the rounded coefficients is 32769, not 32768. Consequently - * libpng uses, instead, the closest non-overflowing approximation: - * - * Y = (6968 * R + 23434 * G + 2366 * B)/32768 - * - * Starting with libpng-1.5.5, if the image being converted has a cHRM chunk - * (including an sRGB chunk) then the chromaticities are used to calculate the - * coefficients. See the chunk handling in pngrutil.c for more information. - * - * In all cases the calculation is to be done in a linear colorspace. If no - * gamma information is available to correct the encoding of the original RGB - * values this results in an implicit assumption that the original PNG RGB - * values were linear. - * - * Other integer coefficents can be used via png_set_rgb_to_gray(). Because - * the API takes just red and green coefficients the blue coefficient is - * calculated to make the sum 32768. This will result in different rounding - * to that used above. - */ -int /* PRIVATE */ -png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) - -{ - int rgb_error = 0; - - png_debug(1, "in png_do_rgb_to_gray"); - - if (!(row_info->color_type & PNG_COLOR_MASK_PALETTE) && - (row_info->color_type & PNG_COLOR_MASK_COLOR)) - { - PNG_CONST png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; - PNG_CONST png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; - PNG_CONST png_uint_32 bc = 32768 - rc - gc; - PNG_CONST png_uint_32 row_width = row_info->width; - PNG_CONST int have_alpha = - (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0; - - if (row_info->bit_depth == 8) - { -#ifdef PNG_READ_GAMMA_SUPPORTED - /* Notice that gamma to/from 1 are not necessarily inverses (if - * there is an overall gamma correction). Prior to 1.5.5 this code - * checked the linearized values for equality; this doesn't match - * the documentation, the original values must be checked. - */ - if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) - { - png_bytep sp = row; - png_bytep dp = row; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - png_byte red = *(sp++); - png_byte green = *(sp++); - png_byte blue = *(sp++); - - if (red != green || red != blue) - { - red = png_ptr->gamma_to_1[red]; - green = png_ptr->gamma_to_1[green]; - blue = png_ptr->gamma_to_1[blue]; - - rgb_error |= 1; - *(dp++) = png_ptr->gamma_from_1[ - (rc*red + gc*green + bc*blue + 16384)>>15]; - } - - else - { - /* If there is no overall correction the table will not be - * set. - */ - if (png_ptr->gamma_table != NULL) - red = png_ptr->gamma_table[red]; - - *(dp++) = red; - } - - if (have_alpha) - *(dp++) = *(sp++); - } - } - else -#endif - { - png_bytep sp = row; - png_bytep dp = row; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - png_byte red = *(sp++); - png_byte green = *(sp++); - png_byte blue = *(sp++); - - if (red != green || red != blue) - { - rgb_error |= 1; - /* NOTE: this is the historical approach which simply - * truncates the results. - */ - *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); - } - - else - *(dp++) = red; - - if (have_alpha) - *(dp++) = *(sp++); - } - } - } - - else /* RGB bit_depth == 16 */ - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (png_ptr->gamma_16_to_1 != NULL && png_ptr->gamma_16_from_1 != NULL) - { - png_bytep sp = row; - png_bytep dp = row; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - png_uint_16 red, green, blue, w; - - red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - - if (red == green && red == blue) - { - if (png_ptr->gamma_16_table != NULL) - w = png_ptr->gamma_16_table[(red&0xff) - >> png_ptr->gamma_shift][red>>8]; - - else - w = red; - } - - else - { - png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) - >> png_ptr->gamma_shift][red>>8]; - png_uint_16 green_1 = - png_ptr->gamma_16_to_1[(green&0xff) >> - png_ptr->gamma_shift][green>>8]; - png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) - >> png_ptr->gamma_shift][blue>>8]; - png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 - + bc*blue_1 + 16384)>>15); - w = png_ptr->gamma_16_from_1[(gray16&0xff) >> - png_ptr->gamma_shift][gray16 >> 8]; - rgb_error |= 1; - } - - *(dp++) = (png_byte)((w>>8) & 0xff); - *(dp++) = (png_byte)(w & 0xff); - - if (have_alpha) - { - *(dp++) = *(sp++); - *(dp++) = *(sp++); - } - } - } - else -#endif - { - png_bytep sp = row; - png_bytep dp = row; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - png_uint_16 red, green, blue, gray16; - - red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - - if (red != green || red != blue) - rgb_error |= 1; - - /* From 1.5.5 in the 16 bit case do the accurate conversion even - * in the 'fast' case - this is because this is where the code - * ends up when handling linear 16 bit data. - */ - gray16 = (png_uint_16)((rc*red + gc*green + bc*blue + 16384) >> - 15); - *(dp++) = (png_byte)((gray16>>8) & 0xff); - *(dp++) = (png_byte)(gray16 & 0xff); - - if (have_alpha) - { - *(dp++) = *(sp++); - *(dp++) = *(sp++); - } - } - } - } - - row_info->channels = (png_byte)(row_info->channels - 2); - row_info->color_type = (png_byte)(row_info->color_type & - ~PNG_COLOR_MASK_COLOR); - row_info->pixel_depth = (png_byte)(row_info->channels * - row_info->bit_depth); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } - return rgb_error; -} -#endif -#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ - -#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED -/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth - * large of png_color. This lets grayscale images be treated as - * paletted. Most useful for gamma correction and simplification - * of code. This API is not used internally. - */ -void PNGAPI -png_build_grayscale_palette(int bit_depth, png_colorp palette) -{ - int num_palette; - int color_inc; - int i; - int v; - - png_debug(1, "in png_do_build_grayscale_palette"); - - if (palette == NULL) - return; - - switch (bit_depth) - { - case 1: - num_palette = 2; - color_inc = 0xff; - break; - - case 2: - num_palette = 4; - color_inc = 0x55; - break; - - case 4: - num_palette = 16; - color_inc = 0x11; - break; - - case 8: - num_palette = 256; - color_inc = 1; - break; - - default: - num_palette = 0; - color_inc = 0; - break; - } - - for (i = 0, v = 0; i < num_palette; i++, v += color_inc) - { - palette[i].red = (png_byte)v; - palette[i].green = (png_byte)v; - palette[i].blue = (png_byte)v; - } -} -#endif - - -#ifdef PNG_READ_TRANSFORMS_SUPPORTED -#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ - defined(PNG_READ_ALPHA_MODE_SUPPORTED) -/* Replace any alpha or transparency with the supplied background color. - * "background" is already in the screen gamma, while "background_1" is - * at a gamma of 1.0. Paletted files have already been taken care of. - */ -void /* PRIVATE */ -png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr) -{ -#ifdef PNG_READ_GAMMA_SUPPORTED - png_const_bytep gamma_table = png_ptr->gamma_table; - png_const_bytep gamma_from_1 = png_ptr->gamma_from_1; - png_const_bytep gamma_to_1 = png_ptr->gamma_to_1; - png_const_uint_16pp gamma_16 = png_ptr->gamma_16_table; - png_const_uint_16pp gamma_16_from_1 = png_ptr->gamma_16_from_1; - png_const_uint_16pp gamma_16_to_1 = png_ptr->gamma_16_to_1; - int gamma_shift = png_ptr->gamma_shift; - int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0; -#endif - - png_bytep sp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - int shift; - - png_debug(1, "in png_do_compose"); - - { - switch (row_info->color_type) - { - case PNG_COLOR_TYPE_GRAY: - { - switch (row_info->bit_depth) - { - case 1: - { - sp = row; - shift = 7; - for (i = 0; i < row_width; i++) - { - if ((png_uint_16)((*sp >> shift) & 0x01) - == png_ptr->trans_color.gray) - { - unsigned int tmp = *sp & (0x7f7f >> (7 - shift)); - tmp |= png_ptr->background.gray << shift; - *sp = (png_byte)(tmp & 0xff); - } - - if (!shift) - { - shift = 7; - sp++; - } - - else - shift--; - } - break; - } - - case 2: - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_table != NULL) - { - sp = row; - shift = 6; - for (i = 0; i < row_width; i++) - { - if ((png_uint_16)((*sp >> shift) & 0x03) - == png_ptr->trans_color.gray) - { - unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); - tmp |= png_ptr->background.gray << shift; - *sp = (png_byte)(tmp & 0xff); - } - - else - { - unsigned int p = (*sp >> shift) & 0x03; - unsigned int g = (gamma_table [p | (p << 2) | - (p << 4) | (p << 6)] >> 6) & 0x03; - unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); - tmp |= g << shift; - *sp = (png_byte)(tmp & 0xff); - } - - if (!shift) - { - shift = 6; - sp++; - } - - else - shift -= 2; - } - } - - else -#endif - { - sp = row; - shift = 6; - for (i = 0; i < row_width; i++) - { - if ((png_uint_16)((*sp >> shift) & 0x03) - == png_ptr->trans_color.gray) - { - unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); - tmp |= png_ptr->background.gray << shift; - *sp = (png_byte)(tmp & 0xff); - } - - if (!shift) - { - shift = 6; - sp++; - } - - else - shift -= 2; - } - } - break; - } - - case 4: - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_table != NULL) - { - sp = row; - shift = 4; - for (i = 0; i < row_width; i++) - { - if ((png_uint_16)((*sp >> shift) & 0x0f) - == png_ptr->trans_color.gray) - { - unsigned int tmp = *sp & (0xf0f >> (4 - shift)); - tmp |= png_ptr->background.gray << shift; - *sp = (png_byte)(tmp & 0xff); - } - - else - { - unsigned int p = (*sp >> shift) & 0x0f; - unsigned int g = (gamma_table[p | (p << 4)] >> 4) & - 0x0f; - unsigned int tmp = *sp & (0xf0f >> (4 - shift)); - tmp |= g << shift; - *sp = (png_byte)(tmp & 0xff); - } - - if (!shift) - { - shift = 4; - sp++; - } - - else - shift -= 4; - } - } - - else -#endif - { - sp = row; - shift = 4; - for (i = 0; i < row_width; i++) - { - if ((png_uint_16)((*sp >> shift) & 0x0f) - == png_ptr->trans_color.gray) - { - unsigned int tmp = *sp & (0xf0f >> (4 - shift)); - tmp |= png_ptr->background.gray << shift; - *sp = (png_byte)(tmp & 0xff); - } - - if (!shift) - { - shift = 4; - sp++; - } - - else - shift -= 4; - } - } - break; - } - - case 8: - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_table != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp++) - { - if (*sp == png_ptr->trans_color.gray) - *sp = (png_byte)png_ptr->background.gray; - - else - *sp = gamma_table[*sp]; - } - } - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp++) - { - if (*sp == png_ptr->trans_color.gray) - *sp = (png_byte)png_ptr->background.gray; - } - } - break; - } - - case 16: - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_16 != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 2) - { - png_uint_16 v; - - v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - - if (v == png_ptr->trans_color.gray) - { - /* Background is already in screen gamma */ - *sp = (png_byte)((png_ptr->background.gray >> 8) - & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.gray - & 0xff); - } - - else - { - v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - } - } - } - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 2) - { - png_uint_16 v; - - v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - - if (v == png_ptr->trans_color.gray) - { - *sp = (png_byte)((png_ptr->background.gray >> 8) - & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.gray - & 0xff); - } - } - } - break; - } - - default: - break; - } - break; - } - - case PNG_COLOR_TYPE_RGB: - { - if (row_info->bit_depth == 8) - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_table != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 3) - { - if (*sp == png_ptr->trans_color.red && - *(sp + 1) == png_ptr->trans_color.green && - *(sp + 2) == png_ptr->trans_color.blue) - { - *sp = (png_byte)png_ptr->background.red; - *(sp + 1) = (png_byte)png_ptr->background.green; - *(sp + 2) = (png_byte)png_ptr->background.blue; - } - - else - { - *sp = gamma_table[*sp]; - *(sp + 1) = gamma_table[*(sp + 1)]; - *(sp + 2) = gamma_table[*(sp + 2)]; - } - } - } - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 3) - { - if (*sp == png_ptr->trans_color.red && - *(sp + 1) == png_ptr->trans_color.green && - *(sp + 2) == png_ptr->trans_color.blue) - { - *sp = (png_byte)png_ptr->background.red; - *(sp + 1) = (png_byte)png_ptr->background.green; - *(sp + 2) = (png_byte)png_ptr->background.blue; - } - } - } - } - else /* if (row_info->bit_depth == 16) */ - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_16 != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 6) - { - png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - - png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) - + *(sp + 3)); - - png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) - + *(sp + 5)); - - if (r == png_ptr->trans_color.red && - g == png_ptr->trans_color.green && - b == png_ptr->trans_color.blue) - { - /* Background is already in screen gamma */ - *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); - *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) - & 0xff); - *(sp + 3) = (png_byte)(png_ptr->background.green - & 0xff); - *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) - & 0xff); - *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); - } - - else - { - png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - - v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; - *(sp + 2) = (png_byte)((v >> 8) & 0xff); - *(sp + 3) = (png_byte)(v & 0xff); - - v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; - *(sp + 4) = (png_byte)((v >> 8) & 0xff); - *(sp + 5) = (png_byte)(v & 0xff); - } - } - } - - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 6) - { - png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - - png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) - + *(sp + 3)); - - png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) - + *(sp + 5)); - - if (r == png_ptr->trans_color.red && - g == png_ptr->trans_color.green && - b == png_ptr->trans_color.blue) - { - *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); - *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) - & 0xff); - *(sp + 3) = (png_byte)(png_ptr->background.green - & 0xff); - *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) - & 0xff); - *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); - } - } - } - } - break; - } - - case PNG_COLOR_TYPE_GRAY_ALPHA: - { - if (row_info->bit_depth == 8) - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_to_1 != NULL && gamma_from_1 != NULL && - gamma_table != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 2) - { - png_uint_16 a = *(sp + 1); - - if (a == 0xff) - *sp = gamma_table[*sp]; - - else if (a == 0) - { - /* Background is already in screen gamma */ - *sp = (png_byte)png_ptr->background.gray; - } - - else - { - png_byte v, w; - - v = gamma_to_1[*sp]; - png_composite(w, v, a, png_ptr->background_1.gray); - if (!optimize) - w = gamma_from_1[w]; - *sp = w; - } - } - } - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 2) - { - png_byte a = *(sp + 1); - - if (a == 0) - *sp = (png_byte)png_ptr->background.gray; - - else if (a < 0xff) - png_composite(*sp, *sp, a, png_ptr->background.gray); - } - } - } - else /* if (png_ptr->bit_depth == 16) */ - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_16 != NULL && gamma_16_from_1 != NULL && - gamma_16_to_1 != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 4) - { - png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8) - + *(sp + 3)); - - if (a == (png_uint_16)0xffff) - { - png_uint_16 v; - - v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - } - - else if (a == 0) - { - /* Background is already in screen gamma */ - *sp = (png_byte)((png_ptr->background.gray >> 8) - & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); - } - - else - { - png_uint_16 g, v, w; - - g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; - png_composite_16(v, g, a, png_ptr->background_1.gray); - if (optimize) - w = v; - else - w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8]; - *sp = (png_byte)((w >> 8) & 0xff); - *(sp + 1) = (png_byte)(w & 0xff); - } - } - } - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 4) - { - png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8) - + *(sp + 3)); - - if (a == 0) - { - *sp = (png_byte)((png_ptr->background.gray >> 8) - & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); - } - - else if (a < 0xffff) - { - png_uint_16 g, v; - - g = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - png_composite_16(v, g, a, png_ptr->background.gray); - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - } - } - } - } - break; - } - - case PNG_COLOR_TYPE_RGB_ALPHA: - { - if (row_info->bit_depth == 8) - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_to_1 != NULL && gamma_from_1 != NULL && - gamma_table != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 4) - { - png_byte a = *(sp + 3); - - if (a == 0xff) - { - *sp = gamma_table[*sp]; - *(sp + 1) = gamma_table[*(sp + 1)]; - *(sp + 2) = gamma_table[*(sp + 2)]; - } - - else if (a == 0) - { - /* Background is already in screen gamma */ - *sp = (png_byte)png_ptr->background.red; - *(sp + 1) = (png_byte)png_ptr->background.green; - *(sp + 2) = (png_byte)png_ptr->background.blue; - } - - else - { - png_byte v, w; - - v = gamma_to_1[*sp]; - png_composite(w, v, a, png_ptr->background_1.red); - if (!optimize) w = gamma_from_1[w]; - *sp = w; - - v = gamma_to_1[*(sp + 1)]; - png_composite(w, v, a, png_ptr->background_1.green); - if (!optimize) w = gamma_from_1[w]; - *(sp + 1) = w; - - v = gamma_to_1[*(sp + 2)]; - png_composite(w, v, a, png_ptr->background_1.blue); - if (!optimize) w = gamma_from_1[w]; - *(sp + 2) = w; - } - } - } - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 4) - { - png_byte a = *(sp + 3); - - if (a == 0) - { - *sp = (png_byte)png_ptr->background.red; - *(sp + 1) = (png_byte)png_ptr->background.green; - *(sp + 2) = (png_byte)png_ptr->background.blue; - } - - else if (a < 0xff) - { - png_composite(*sp, *sp, a, png_ptr->background.red); - - png_composite(*(sp + 1), *(sp + 1), a, - png_ptr->background.green); - - png_composite(*(sp + 2), *(sp + 2), a, - png_ptr->background.blue); - } - } - } - } - else /* if (row_info->bit_depth == 16) */ - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_16 != NULL && gamma_16_from_1 != NULL && - gamma_16_to_1 != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 8) - { - png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) - << 8) + (png_uint_16)(*(sp + 7))); - - if (a == (png_uint_16)0xffff) - { - png_uint_16 v; - - v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - - v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; - *(sp + 2) = (png_byte)((v >> 8) & 0xff); - *(sp + 3) = (png_byte)(v & 0xff); - - v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; - *(sp + 4) = (png_byte)((v >> 8) & 0xff); - *(sp + 5) = (png_byte)(v & 0xff); - } - - else if (a == 0) - { - /* Background is already in screen gamma */ - *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); - *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) - & 0xff); - *(sp + 3) = (png_byte)(png_ptr->background.green - & 0xff); - *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) - & 0xff); - *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); - } - - else - { - png_uint_16 v, w; - - v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; - png_composite_16(w, v, a, png_ptr->background_1.red); - if (!optimize) - w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> - 8]; - *sp = (png_byte)((w >> 8) & 0xff); - *(sp + 1) = (png_byte)(w & 0xff); - - v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; - png_composite_16(w, v, a, png_ptr->background_1.green); - if (!optimize) - w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> - 8]; - - *(sp + 2) = (png_byte)((w >> 8) & 0xff); - *(sp + 3) = (png_byte)(w & 0xff); - - v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; - png_composite_16(w, v, a, png_ptr->background_1.blue); - if (!optimize) - w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> - 8]; - - *(sp + 4) = (png_byte)((w >> 8) & 0xff); - *(sp + 5) = (png_byte)(w & 0xff); - } - } - } - - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 8) - { - png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) - << 8) + (png_uint_16)(*(sp + 7))); - - if (a == 0) - { - *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); - *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) - & 0xff); - *(sp + 3) = (png_byte)(png_ptr->background.green - & 0xff); - *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) - & 0xff); - *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); - } - - else if (a < 0xffff) - { - png_uint_16 v; - - png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) - + *(sp + 3)); - png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) - + *(sp + 5)); - - png_composite_16(v, r, a, png_ptr->background.red); - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - - png_composite_16(v, g, a, png_ptr->background.green); - *(sp + 2) = (png_byte)((v >> 8) & 0xff); - *(sp + 3) = (png_byte)(v & 0xff); - - png_composite_16(v, b, a, png_ptr->background.blue); - *(sp + 4) = (png_byte)((v >> 8) & 0xff); - *(sp + 5) = (png_byte)(v & 0xff); - } - } - } - } - break; - } - - default: - break; - } - } -} -#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_READ_ALPHA_MODE_SUPPORTED */ - -#ifdef PNG_READ_GAMMA_SUPPORTED -/* Gamma correct the image, avoiding the alpha channel. Make sure - * you do this after you deal with the transparency issue on grayscale - * or RGB images. If your bit depth is 8, use gamma_table, if it - * is 16, use gamma_16_table and gamma_shift. Build these with - * build_gamma_table(). - */ -void /* PRIVATE */ -png_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr) -{ - png_const_bytep gamma_table = png_ptr->gamma_table; - png_const_uint_16pp gamma_16_table = png_ptr->gamma_16_table; - int gamma_shift = png_ptr->gamma_shift; - - png_bytep sp; - png_uint_32 i; - png_uint_32 row_width=row_info->width; - - png_debug(1, "in png_do_gamma"); - - if (((row_info->bit_depth <= 8 && gamma_table != NULL) || - (row_info->bit_depth == 16 && gamma_16_table != NULL))) - { - switch (row_info->color_type) - { - case PNG_COLOR_TYPE_RGB: - { - if (row_info->bit_depth == 8) - { - sp = row; - for (i = 0; i < row_width; i++) - { - *sp = gamma_table[*sp]; - sp++; - *sp = gamma_table[*sp]; - sp++; - *sp = gamma_table[*sp]; - sp++; - } - } - - else /* if (row_info->bit_depth == 16) */ - { - sp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 v; - - v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - - v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - - v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - } - } - break; - } - - case PNG_COLOR_TYPE_RGB_ALPHA: - { - if (row_info->bit_depth == 8) - { - sp = row; - for (i = 0; i < row_width; i++) - { - *sp = gamma_table[*sp]; - sp++; - - *sp = gamma_table[*sp]; - sp++; - - *sp = gamma_table[*sp]; - sp++; - - sp++; - } - } - - else /* if (row_info->bit_depth == 16) */ - { - sp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - - v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - - v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 4; - } - } - break; - } - - case PNG_COLOR_TYPE_GRAY_ALPHA: - { - if (row_info->bit_depth == 8) - { - sp = row; - for (i = 0; i < row_width; i++) - { - *sp = gamma_table[*sp]; - sp += 2; - } - } - - else /* if (row_info->bit_depth == 16) */ - { - sp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 4; - } - } - break; - } - - case PNG_COLOR_TYPE_GRAY: - { - if (row_info->bit_depth == 2) - { - sp = row; - for (i = 0; i < row_width; i += 4) - { - int a = *sp & 0xc0; - int b = *sp & 0x30; - int c = *sp & 0x0c; - int d = *sp & 0x03; - - *sp = (png_byte)( - ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)| - ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)| - ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)| - ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) )); - sp++; - } - } - - if (row_info->bit_depth == 4) - { - sp = row; - for (i = 0; i < row_width; i += 2) - { - int msb = *sp & 0xf0; - int lsb = *sp & 0x0f; - - *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0) - | (((int)gamma_table[(lsb << 4) | lsb]) >> 4)); - sp++; - } - } - - else if (row_info->bit_depth == 8) - { - sp = row; - for (i = 0; i < row_width; i++) - { - *sp = gamma_table[*sp]; - sp++; - } - } - - else if (row_info->bit_depth == 16) - { - sp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - } - } - break; - } - - default: - break; - } - } -} -#endif - -#ifdef PNG_READ_ALPHA_MODE_SUPPORTED -/* Encode the alpha channel to the output gamma (the input channel is always - * linear.) Called only with color types that have an alpha channel. Needs the - * from_1 tables. - */ -void /* PRIVATE */ -png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr) -{ - png_uint_32 row_width = row_info->width; - - png_debug(1, "in png_do_encode_alpha"); - - if (row_info->color_type & PNG_COLOR_MASK_ALPHA) - { - if (row_info->bit_depth == 8) - { - PNG_CONST png_bytep table = png_ptr->gamma_from_1; - - if (table != NULL) - { - PNG_CONST int step = - (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 4 : 2; - - /* The alpha channel is the last component: */ - row += step - 1; - - for (; row_width > 0; --row_width, row += step) - *row = table[*row]; - - return; - } - } - - else if (row_info->bit_depth == 16) - { - PNG_CONST png_uint_16pp table = png_ptr->gamma_16_from_1; - PNG_CONST int gamma_shift = png_ptr->gamma_shift; - - if (table != NULL) - { - PNG_CONST int step = - (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 8 : 4; - - /* The alpha channel is the last component: */ - row += step - 2; - - for (; row_width > 0; --row_width, row += step) - { - png_uint_16 v; - - v = table[*(row + 1) >> gamma_shift][*row]; - *row = (png_byte)((v >> 8) & 0xff); - *(row + 1) = (png_byte)(v & 0xff); - } - - return; - } - } - } - - /* Only get to here if called with a weird row_info; no harm has been done, - * so just issue a warning. - */ - png_warning(png_ptr, "png_do_encode_alpha: unexpected call"); -} -#endif - -#ifdef PNG_READ_EXPAND_SUPPORTED -/* Expands a palette row to an RGB or RGBA row depending - * upon whether you supply trans and num_trans. - */ -void /* PRIVATE */ -png_do_expand_palette(png_row_infop row_info, png_bytep row, - png_const_colorp palette, png_const_bytep trans_alpha, int num_trans) -{ - int shift, value; - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width=row_info->width; - - png_debug(1, "in png_do_expand_palette"); - - if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) - { - if (row_info->bit_depth < 8) - { - switch (row_info->bit_depth) - { - case 1: - { - sp = row + (png_size_t)((row_width - 1) >> 3); - dp = row + (png_size_t)row_width - 1; - shift = 7 - (int)((row_width + 7) & 0x07); - for (i = 0; i < row_width; i++) - { - if ((*sp >> shift) & 0x01) - *dp = 1; - - else - *dp = 0; - - if (shift == 7) - { - shift = 0; - sp--; - } - - else - shift++; - - dp--; - } - break; - } - - case 2: - { - sp = row + (png_size_t)((row_width - 1) >> 2); - dp = row + (png_size_t)row_width - 1; - shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); - for (i = 0; i < row_width; i++) - { - value = (*sp >> shift) & 0x03; - *dp = (png_byte)value; - if (shift == 6) - { - shift = 0; - sp--; - } - - else - shift += 2; - - dp--; - } - break; - } - - case 4: - { - sp = row + (png_size_t)((row_width - 1) >> 1); - dp = row + (png_size_t)row_width - 1; - shift = (int)((row_width & 0x01) << 2); - for (i = 0; i < row_width; i++) - { - value = (*sp >> shift) & 0x0f; - *dp = (png_byte)value; - if (shift == 4) - { - shift = 0; - sp--; - } - - else - shift += 4; - - dp--; - } - break; - } - - default: - break; - } - row_info->bit_depth = 8; - row_info->pixel_depth = 8; - row_info->rowbytes = row_width; - } - - if (row_info->bit_depth == 8) - { - { - if (num_trans > 0) - { - sp = row + (png_size_t)row_width - 1; - dp = row + (png_size_t)(row_width << 2) - 1; - - for (i = 0; i < row_width; i++) - { - if ((int)(*sp) >= num_trans) - *dp-- = 0xff; - - else - *dp-- = trans_alpha[*sp]; - - *dp-- = palette[*sp].blue; - *dp-- = palette[*sp].green; - *dp-- = palette[*sp].red; - sp--; - } - row_info->bit_depth = 8; - row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; - row_info->color_type = 6; - row_info->channels = 4; - } - - else - { - sp = row + (png_size_t)row_width - 1; - dp = row + (png_size_t)(row_width * 3) - 1; - - for (i = 0; i < row_width; i++) - { - *dp-- = palette[*sp].blue; - *dp-- = palette[*sp].green; - *dp-- = palette[*sp].red; - sp--; - } - - row_info->bit_depth = 8; - row_info->pixel_depth = 24; - row_info->rowbytes = row_width * 3; - row_info->color_type = 2; - row_info->channels = 3; - } - } - } - } -} - -/* If the bit depth < 8, it is expanded to 8. Also, if the already - * expanded transparency value is supplied, an alpha channel is built. - */ -void /* PRIVATE */ -png_do_expand(png_row_infop row_info, png_bytep row, - png_const_color_16p trans_color) -{ - int shift, value; - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width=row_info->width; - - png_debug(1, "in png_do_expand"); - - { - if (row_info->color_type == PNG_COLOR_TYPE_GRAY) - { - unsigned int gray = trans_color ? trans_color->gray : 0; - - if (row_info->bit_depth < 8) - { - switch (row_info->bit_depth) - { - case 1: - { - gray = (gray & 0x01) * 0xff; - sp = row + (png_size_t)((row_width - 1) >> 3); - dp = row + (png_size_t)row_width - 1; - shift = 7 - (int)((row_width + 7) & 0x07); - for (i = 0; i < row_width; i++) - { - if ((*sp >> shift) & 0x01) - *dp = 0xff; - - else - *dp = 0; - - if (shift == 7) - { - shift = 0; - sp--; - } - - else - shift++; - - dp--; - } - break; - } - - case 2: - { - gray = (gray & 0x03) * 0x55; - sp = row + (png_size_t)((row_width - 1) >> 2); - dp = row + (png_size_t)row_width - 1; - shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); - for (i = 0; i < row_width; i++) - { - value = (*sp >> shift) & 0x03; - *dp = (png_byte)(value | (value << 2) | (value << 4) | - (value << 6)); - if (shift == 6) - { - shift = 0; - sp--; - } - - else - shift += 2; - - dp--; - } - break; - } - - case 4: - { - gray = (gray & 0x0f) * 0x11; - sp = row + (png_size_t)((row_width - 1) >> 1); - dp = row + (png_size_t)row_width - 1; - shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); - for (i = 0; i < row_width; i++) - { - value = (*sp >> shift) & 0x0f; - *dp = (png_byte)(value | (value << 4)); - if (shift == 4) - { - shift = 0; - sp--; - } - - else - shift = 4; - - dp--; - } - break; - } - - default: - break; - } - - row_info->bit_depth = 8; - row_info->pixel_depth = 8; - row_info->rowbytes = row_width; - } - - if (trans_color != NULL) - { - if (row_info->bit_depth == 8) - { - gray = gray & 0xff; - sp = row + (png_size_t)row_width - 1; - dp = row + (png_size_t)(row_width << 1) - 1; - - for (i = 0; i < row_width; i++) - { - if (*sp == gray) - *dp-- = 0; - - else - *dp-- = 0xff; - - *dp-- = *sp--; - } - } - - else if (row_info->bit_depth == 16) - { - unsigned int gray_high = (gray >> 8) & 0xff; - unsigned int gray_low = gray & 0xff; - sp = row + row_info->rowbytes - 1; - dp = row + (row_info->rowbytes << 1) - 1; - for (i = 0; i < row_width; i++) - { - if (*(sp - 1) == gray_high && *(sp) == gray_low) - { - *dp-- = 0; - *dp-- = 0; - } - - else - { - *dp-- = 0xff; - *dp-- = 0xff; - } - - *dp-- = *sp--; - *dp-- = *sp--; - } - } - - row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA; - row_info->channels = 2; - row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, - row_width); - } - } - else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_color) - { - if (row_info->bit_depth == 8) - { - png_byte red = (png_byte)(trans_color->red & 0xff); - png_byte green = (png_byte)(trans_color->green & 0xff); - png_byte blue = (png_byte)(trans_color->blue & 0xff); - sp = row + (png_size_t)row_info->rowbytes - 1; - dp = row + (png_size_t)(row_width << 2) - 1; - for (i = 0; i < row_width; i++) - { - if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue) - *dp-- = 0; - - else - *dp-- = 0xff; - - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - } - } - else if (row_info->bit_depth == 16) - { - png_byte red_high = (png_byte)((trans_color->red >> 8) & 0xff); - png_byte green_high = (png_byte)((trans_color->green >> 8) & 0xff); - png_byte blue_high = (png_byte)((trans_color->blue >> 8) & 0xff); - png_byte red_low = (png_byte)(trans_color->red & 0xff); - png_byte green_low = (png_byte)(trans_color->green & 0xff); - png_byte blue_low = (png_byte)(trans_color->blue & 0xff); - sp = row + row_info->rowbytes - 1; - dp = row + (png_size_t)(row_width << 3) - 1; - for (i = 0; i < row_width; i++) - { - if (*(sp - 5) == red_high && - *(sp - 4) == red_low && - *(sp - 3) == green_high && - *(sp - 2) == green_low && - *(sp - 1) == blue_high && - *(sp ) == blue_low) - { - *dp-- = 0; - *dp-- = 0; - } - - else - { - *dp-- = 0xff; - *dp-- = 0xff; - } - - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - } - } - row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA; - row_info->channels = 4; - row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } - } -} -#endif - -#ifdef PNG_READ_EXPAND_16_SUPPORTED -/* If the bit depth is 8 and the color type is not a palette type expand the - * whole row to 16 bits. Has no effect otherwise. - */ -void /* PRIVATE */ -png_do_expand_16(png_row_infop row_info, png_bytep row) -{ - if (row_info->bit_depth == 8 && - row_info->color_type != PNG_COLOR_TYPE_PALETTE) - { - /* The row have a sequence of bytes containing [0..255] and we need - * to turn it into another row containing [0..65535], to do this we - * calculate: - * - * (input / 255) * 65535 - * - * Which happens to be exactly input * 257 and this can be achieved - * simply by byte replication in place (copying backwards). - */ - png_byte *sp = row + row_info->rowbytes; /* source, last byte + 1 */ - png_byte *dp = sp + row_info->rowbytes; /* destination, end + 1 */ - while (dp > sp) - dp[-2] = dp[-1] = *--sp, dp -= 2; - - row_info->rowbytes *= 2; - row_info->bit_depth = 16; - row_info->pixel_depth = (png_byte)(row_info->channels * 16); - } -} -#endif - -#ifdef PNG_READ_QUANTIZE_SUPPORTED -void /* PRIVATE */ -png_do_quantize(png_row_infop row_info, png_bytep row, - png_const_bytep palette_lookup, png_const_bytep quantize_lookup) -{ - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width=row_info->width; - - png_debug(1, "in png_do_quantize"); - - if (row_info->bit_depth == 8) - { - if (row_info->color_type == PNG_COLOR_TYPE_RGB && palette_lookup) - { - int r, g, b, p; - sp = row; - dp = row; - for (i = 0; i < row_width; i++) - { - r = *sp++; - g = *sp++; - b = *sp++; - - /* This looks real messy, but the compiler will reduce - * it down to a reasonable formula. For example, with - * 5 bits per color, we get: - * p = (((r >> 3) & 0x1f) << 10) | - * (((g >> 3) & 0x1f) << 5) | - * ((b >> 3) & 0x1f); - */ - p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) & - ((1 << PNG_QUANTIZE_RED_BITS) - 1)) << - (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) | - (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) & - ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) << - (PNG_QUANTIZE_BLUE_BITS)) | - ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) & - ((1 << PNG_QUANTIZE_BLUE_BITS) - 1)); - - *dp++ = palette_lookup[p]; - } - - row_info->color_type = PNG_COLOR_TYPE_PALETTE; - row_info->channels = 1; - row_info->pixel_depth = row_info->bit_depth; - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } - - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && - palette_lookup != NULL) - { - int r, g, b, p; - sp = row; - dp = row; - for (i = 0; i < row_width; i++) - { - r = *sp++; - g = *sp++; - b = *sp++; - sp++; - - p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) & - ((1 << PNG_QUANTIZE_RED_BITS) - 1)) << - (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) | - (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) & - ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) << - (PNG_QUANTIZE_BLUE_BITS)) | - ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) & - ((1 << PNG_QUANTIZE_BLUE_BITS) - 1)); - - *dp++ = palette_lookup[p]; - } - - row_info->color_type = PNG_COLOR_TYPE_PALETTE; - row_info->channels = 1; - row_info->pixel_depth = row_info->bit_depth; - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } - - else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && - quantize_lookup) - { - sp = row; - - for (i = 0; i < row_width; i++, sp++) - { - *sp = quantize_lookup[*sp]; - } - } - } -} -#endif /* PNG_READ_QUANTIZE_SUPPORTED */ -#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ - -#ifdef PNG_MNG_FEATURES_SUPPORTED -/* Undoes intrapixel differencing */ -void /* PRIVATE */ -png_do_read_intrapixel(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_read_intrapixel"); - - if ( - (row_info->color_type & PNG_COLOR_MASK_COLOR)) - { - int bytes_per_pixel; - png_uint_32 row_width = row_info->width; - - if (row_info->bit_depth == 8) - { - png_bytep rp; - png_uint_32 i; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 3; - - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 4; - - else - return; - - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - *(rp) = (png_byte)((256 + *rp + *(rp + 1)) & 0xff); - *(rp+2) = (png_byte)((256 + *(rp + 2) + *(rp + 1)) & 0xff); - } - } - else if (row_info->bit_depth == 16) - { - png_bytep rp; - png_uint_32 i; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 6; - - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 8; - - else - return; - - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); - png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); - png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); - png_uint_32 red = (s0 + s1 + 65536) & 0xffff; - png_uint_32 blue = (s2 + s1 + 65536) & 0xffff; - *(rp ) = (png_byte)((red >> 8) & 0xff); - *(rp + 1) = (png_byte)(red & 0xff); - *(rp + 4) = (png_byte)((blue >> 8) & 0xff); - *(rp + 5) = (png_byte)(blue & 0xff); - } - } - } -} -#endif /* PNG_MNG_FEATURES_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pngrutil.c b/source/modules/juce_graphics/image_formats/pnglib/pngrutil.c deleted file mode 100644 index b998fe6ef..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pngrutil.c +++ /dev/null @@ -1,4459 +0,0 @@ - -/* pngrutil.c - utilities to read a PNG file - * - * Last changed in libpng 1.6.1 [March 28, 2013] - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file contains routines that are only called from within - * libpng itself during the course of reading an image. - */ - -#include "pngpriv.h" - -#ifdef PNG_READ_SUPPORTED - -#define png_strtod(p,a,b) strtod(a,b) - -png_uint_32 PNGAPI -png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf) -{ - png_uint_32 uval = png_get_uint_32(buf); - - if (uval > PNG_UINT_31_MAX) - png_error(png_ptr, "PNG unsigned integer out of range"); - - return (uval); -} - -#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_READ_cHRM_SUPPORTED) -/* The following is a variation on the above for use with the fixed - * point values used for gAMA and cHRM. Instead of png_error it - * issues a warning and returns (-1) - an invalid value because both - * gAMA and cHRM use *unsigned* integers for fixed point values. - */ -#define PNG_FIXED_ERROR (-1) - -static png_fixed_point /* PRIVATE */ -png_get_fixed_point(png_structrp png_ptr, png_const_bytep buf) -{ - png_uint_32 uval = png_get_uint_32(buf); - - if (uval <= PNG_UINT_31_MAX) - return (png_fixed_point)uval; /* known to be in range */ - - /* The caller can turn off the warning by passing NULL. */ - if (png_ptr != NULL) - png_warning(png_ptr, "PNG fixed point integer out of range"); - - return PNG_FIXED_ERROR; -} -#endif - -#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED -/* NOTE: the read macros will obscure these definitions, so that if - * PNG_USE_READ_MACROS is set the library will not use them internally, - * but the APIs will still be available externally. - * - * The parentheses around "PNGAPI function_name" in the following three - * functions are necessary because they allow the macros to co-exist with - * these (unused but exported) functions. - */ - -/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */ -png_uint_32 (PNGAPI -png_get_uint_32)(png_const_bytep buf) -{ - png_uint_32 uval = - ((png_uint_32)(*(buf )) << 24) + - ((png_uint_32)(*(buf + 1)) << 16) + - ((png_uint_32)(*(buf + 2)) << 8) + - ((png_uint_32)(*(buf + 3)) ) ; - - return uval; -} - -/* Grab a signed 32-bit integer from a buffer in big-endian format. The - * data is stored in the PNG file in two's complement format and there - * is no guarantee that a 'png_int_32' is exactly 32 bits, therefore - * the following code does a two's complement to native conversion. - */ -png_int_32 (PNGAPI -png_get_int_32)(png_const_bytep buf) -{ - png_uint_32 uval = png_get_uint_32(buf); - if ((uval & 0x80000000) == 0) /* non-negative */ - return uval; - - uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */ - return -(png_int_32)uval; -} - -/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */ -png_uint_16 (PNGAPI -png_get_uint_16)(png_const_bytep buf) -{ - /* ANSI-C requires an int value to accomodate at least 16 bits so this - * works and allows the compiler not to worry about possible narrowing - * on 32 bit systems. (Pre-ANSI systems did not make integers smaller - * than 16 bits either.) - */ - unsigned int val = - ((unsigned int)(*buf) << 8) + - ((unsigned int)(*(buf + 1))); - - return (png_uint_16)val; -} - -#endif /* PNG_READ_INT_FUNCTIONS_SUPPORTED */ - -/* Read and check the PNG file signature */ -void /* PRIVATE */ -png_read_sig(png_structrp png_ptr, png_inforp info_ptr) -{ - png_size_t num_checked, num_to_check; - - /* Exit if the user application does not expect a signature. */ - if (png_ptr->sig_bytes >= 8) - return; - - num_checked = png_ptr->sig_bytes; - num_to_check = 8 - num_checked; - -#ifdef PNG_IO_STATE_SUPPORTED - png_ptr->io_state = PNG_IO_READING | PNG_IO_SIGNATURE; -#endif - - /* The signature must be serialized in a single I/O call. */ - png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); - png_ptr->sig_bytes = 8; - - if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) - { - if (num_checked < 4 && - png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) - png_error(png_ptr, "Not a PNG file"); - else - png_error(png_ptr, "PNG file corrupted by ASCII conversion"); - } - if (num_checked < 3) - png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; -} - -/* Read the chunk header (length + type name). - * Put the type name into png_ptr->chunk_name, and return the length. - */ -png_uint_32 /* PRIVATE */ -png_read_chunk_header(png_structrp png_ptr) -{ - png_byte buf[8]; - png_uint_32 length; - -#ifdef PNG_IO_STATE_SUPPORTED - png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR; -#endif - - /* Read the length and the chunk name. - * This must be performed in a single I/O call. - */ - png_read_data(png_ptr, buf, 8); - length = png_get_uint_31(png_ptr, buf); - - /* Put the chunk name into png_ptr->chunk_name. */ - png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(buf+4); - - png_debug2(0, "Reading %lx chunk, length = %lu", - (unsigned long)png_ptr->chunk_name, (unsigned long)length); - - /* Reset the crc and run it over the chunk name. */ - png_reset_crc(png_ptr); - png_calculate_crc(png_ptr, buf + 4, 4); - - /* Check to see if chunk name is valid. */ - png_check_chunk_name(png_ptr, png_ptr->chunk_name); - -#ifdef PNG_IO_STATE_SUPPORTED - png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA; -#endif - - return length; -} - -/* Read data, and (optionally) run it through the CRC. */ -void /* PRIVATE */ -png_crc_read(png_structrp png_ptr, png_bytep buf, png_uint_32 length) -{ - if (png_ptr == NULL) - return; - - png_read_data(png_ptr, buf, length); - png_calculate_crc(png_ptr, buf, length); -} - -/* Optionally skip data and then check the CRC. Depending on whether we - * are reading an ancillary or critical chunk, and how the program has set - * things up, we may calculate the CRC on the data and print a message. - * Returns '1' if there was a CRC error, '0' otherwise. - */ -int /* PRIVATE */ -png_crc_finish(png_structrp png_ptr, png_uint_32 skip) -{ - /* The size of the local buffer for inflate is a good guess as to a - * reasonable size to use for buffering reads from the application. - */ - while (skip > 0) - { - png_uint_32 len; - png_byte tmpbuf[PNG_INFLATE_BUF_SIZE]; - - len = (sizeof tmpbuf); - if (len > skip) - len = skip; - skip -= len; - - png_crc_read(png_ptr, tmpbuf, len); - } - - if (png_crc_error(png_ptr)) - { - if (PNG_CHUNK_ANCILLIARY(png_ptr->chunk_name) ? - !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) : - (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)) - { - png_chunk_warning(png_ptr, "CRC error"); - } - - else - { - png_chunk_benign_error(png_ptr, "CRC error"); - return (0); - } - - return (1); - } - - return (0); -} - -/* Compare the CRC stored in the PNG file with that calculated by libpng from - * the data it has read thus far. - */ -int /* PRIVATE */ -png_crc_error(png_structrp png_ptr) -{ - png_byte crc_bytes[4]; - png_uint_32 crc; - int need_crc = 1; - - if (PNG_CHUNK_ANCILLIARY(png_ptr->chunk_name)) - { - if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == - (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) - need_crc = 0; - } - - else /* critical */ - { - if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) - need_crc = 0; - } - -#ifdef PNG_IO_STATE_SUPPORTED - png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC; -#endif - - /* The chunk CRC must be serialized in a single I/O call. */ - png_read_data(png_ptr, crc_bytes, 4); - - if (need_crc) - { - crc = png_get_uint_32(crc_bytes); - return ((int)(crc != png_ptr->crc)); - } - - else - return (0); -} - -/* Manage the read buffer; this simply reallocates the buffer if it is not small - * enough (or if it is not allocated). The routine returns a pointer to the - * buffer; if an error occurs and 'warn' is set the routine returns NULL, else - * it will call png_error (via png_malloc) on failure. (warn == 2 means - * 'silent'). - */ -static png_bytep -png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn) -{ - png_bytep buffer = png_ptr->read_buffer; - - if (buffer != NULL && new_size > png_ptr->read_buffer_size) - { - png_ptr->read_buffer = NULL; - png_ptr->read_buffer = NULL; - png_ptr->read_buffer_size = 0; - png_free(png_ptr, buffer); - buffer = NULL; - } - - if (buffer == NULL) - { - buffer = png_voidcast(png_bytep, png_malloc_base(png_ptr, new_size)); - - if (buffer != NULL) - { - png_ptr->read_buffer = buffer; - png_ptr->read_buffer_size = new_size; - } - - else if (warn < 2) /* else silent */ - { -#ifdef PNG_WARNINGS_SUPPORTED - if (warn) - png_chunk_warning(png_ptr, "insufficient memory to read chunk"); - else -#endif - { -#ifdef PNG_ERROR_TEXT_SUPPORTED - png_chunk_error(png_ptr, "insufficient memory to read chunk"); -#endif - } - } - } - - return buffer; -} - -/* png_inflate_claim: claim the zstream for some nefarious purpose that involves - * decompression. Returns Z_OK on success, else a zlib error code. It checks - * the owner but, in final release builds, just issues a warning if some other - * chunk apparently owns the stream. Prior to release it does a png_error. - */ -static int -png_inflate_claim(png_structrp png_ptr, png_uint_32 owner, int window_bits) -{ - if (png_ptr->zowner != 0) - { - char msg[64]; - - PNG_STRING_FROM_CHUNK(msg, png_ptr->zowner); - /* So the message that results is " using zstream"; this is an - * internal error, but is very useful for debugging. i18n requirements - * are minimal. - */ - (void)png_safecat(msg, (sizeof msg), 4, " using zstream"); -# if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC - png_chunk_warning(png_ptr, msg); - png_ptr->zowner = 0; -# else - png_chunk_error(png_ptr, msg); -# endif - } - - /* Implementation note: unlike 'png_deflate_claim' this internal function - * does not take the size of the data as an argument. Some efficiency could - * be gained by using this when it is known *if* the zlib stream itself does - * not record the number; however, this is an illusion: the original writer - * of the PNG may have selected a lower window size, and we really must - * follow that because, for systems with with limited capabilities, we - * would otherwise reject the application's attempts to use a smaller window - * size (zlib doesn't have an interface to say "this or lower"!). - * - * inflateReset2 was added to zlib 1.2.4; before this the window could not be - * reset, therefore it is necessary to always allocate the maximum window - * size with earlier zlibs just in case later compressed chunks need it. - */ - { - int ret; /* zlib return code */ - - /* Set this for safety, just in case the previous owner left pointers to - * memory allocations. - */ - png_ptr->zstream.next_in = NULL; - png_ptr->zstream.avail_in = 0; - png_ptr->zstream.next_out = NULL; - png_ptr->zstream.avail_out = 0; - - if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) - { -# if ZLIB_VERNUM < 0x1240 - PNG_UNUSED(window_bits) - ret = inflateReset(&png_ptr->zstream); -# else - ret = inflateReset2(&png_ptr->zstream, window_bits); -# endif - } - - else - { -# if ZLIB_VERNUM < 0x1240 - ret = inflateInit(&png_ptr->zstream); -# else - ret = inflateInit2(&png_ptr->zstream, window_bits); -# endif - - if (ret == Z_OK) - png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; - } - - if (ret == Z_OK) - png_ptr->zowner = owner; - - else - png_zstream_error(png_ptr, ret); - - return ret; - } -} - -#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED -/* png_inflate now returns zlib error codes including Z_OK and Z_STREAM_END to - * allow the caller to do multiple calls if required. If the 'finish' flag is - * set Z_FINISH will be passed to the final inflate() call and Z_STREAM_END must - * be returned or there has been a problem, otherwise Z_SYNC_FLUSH is used and - * Z_OK or Z_STREAM_END will be returned on success. - * - * The input and output sizes are updated to the actual amounts of data consumed - * or written, not the amount available (as in a z_stream). The data pointers - * are not changed, so the next input is (data+input_size) and the next - * available output is (output+output_size). - */ -static int -png_inflate(png_structrp png_ptr, png_uint_32 owner, int finish, - /* INPUT: */ png_const_bytep input, png_uint_32p input_size_ptr, - /* OUTPUT: */ png_bytep output, png_alloc_size_t *output_size_ptr) -{ - if (png_ptr->zowner == owner) /* Else not claimed */ - { - int ret; - png_alloc_size_t avail_out = *output_size_ptr; - png_uint_32 avail_in = *input_size_ptr; - - /* zlib can't necessarily handle more than 65535 bytes at once (i.e. it - * can't even necessarily handle 65536 bytes) because the type uInt is - * "16 bits or more". Consequently it is necessary to chunk the input to - * zlib. This code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the - * maximum value that can be stored in a uInt.) It is possible to set - * ZLIB_IO_MAX to a lower value in pngpriv.h and this may sometimes have - * a performance advantage, because it reduces the amount of data accessed - * at each step and that may give the OS more time to page it in. - */ - png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input); - /* avail_in and avail_out are set below from 'size' */ - png_ptr->zstream.avail_in = 0; - png_ptr->zstream.avail_out = 0; - - /* Read directly into the output if it is available (this is set to - * a local buffer below if output is NULL). - */ - if (output != NULL) - png_ptr->zstream.next_out = output; - - do - { - uInt avail; - unsigned char local_buffer[PNG_INFLATE_BUF_SIZE]; - - /* zlib INPUT BUFFER */ - /* The setting of 'avail_in' used to be outside the loop; by setting it - * inside it is possible to chunk the input to zlib and simply rely on - * zlib to advance the 'next_in' pointer. This allows arbitrary - * amounts of data to be passed through zlib at the unavoidable cost of - * requiring a window save (memcpy of up to 32768 output bytes) - * every ZLIB_IO_MAX input bytes. - */ - avail_in += png_ptr->zstream.avail_in; /* not consumed last time */ - - avail = ZLIB_IO_MAX; - - if (avail_in < avail) - avail = (uInt)avail_in; /* safe: < than ZLIB_IO_MAX */ - - avail_in -= avail; - png_ptr->zstream.avail_in = avail; - - /* zlib OUTPUT BUFFER */ - avail_out += png_ptr->zstream.avail_out; /* not written last time */ - - avail = ZLIB_IO_MAX; /* maximum zlib can process */ - - if (output == NULL) - { - /* Reset the output buffer each time round if output is NULL and - * make available the full buffer, up to 'remaining_space' - */ - png_ptr->zstream.next_out = local_buffer; - if ((sizeof local_buffer) < avail) - avail = (sizeof local_buffer); - } - - if (avail_out < avail) - avail = (uInt)avail_out; /* safe: < ZLIB_IO_MAX */ - - png_ptr->zstream.avail_out = avail; - avail_out -= avail; - - /* zlib inflate call */ - /* In fact 'avail_out' may be 0 at this point, that happens at the end - * of the read when the final LZ end code was not passed at the end of - * the previous chunk of input data. Tell zlib if we have reached the - * end of the output buffer. - */ - ret = inflate(&png_ptr->zstream, avail_out > 0 ? Z_NO_FLUSH : - (finish ? Z_FINISH : Z_SYNC_FLUSH)); - } while (ret == Z_OK); - - /* For safety kill the local buffer pointer now */ - if (output == NULL) - png_ptr->zstream.next_out = NULL; - - /* Claw back the 'size' and 'remaining_space' byte counts. */ - avail_in += png_ptr->zstream.avail_in; - avail_out += png_ptr->zstream.avail_out; - - /* Update the input and output sizes; the updated values are the amount - * consumed or written, effectively the inverse of what zlib uses. - */ - if (avail_out > 0) - *output_size_ptr -= avail_out; - - if (avail_in > 0) - *input_size_ptr -= avail_in; - - /* Ensure png_ptr->zstream.msg is set (even in the success case!) */ - png_zstream_error(png_ptr, ret); - return ret; - } - - else - { - /* This is a bad internal error. The recovery assigns to the zstream msg - * pointer, which is not owned by the caller, but this is safe; it's only - * used on errors! - */ - png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed"); - return Z_STREAM_ERROR; - } -} - -/* - * Decompress trailing data in a chunk. The assumption is that read_buffer - * points at an allocated area holding the contents of a chunk with a - * trailing compressed part. What we get back is an allocated area - * holding the original prefix part and an uncompressed version of the - * trailing part (the malloc area passed in is freed). - */ -static int -png_decompress_chunk(png_structrp png_ptr, - png_uint_32 chunklength, png_uint_32 prefix_size, - png_alloc_size_t *newlength /* must be initialized to the maximum! */, - int terminate /*add a '\0' to the end of the uncompressed data*/) -{ - /* TODO: implement different limits for different types of chunk. - * - * The caller supplies *newlength set to the maximum length of the - * uncompressed data, but this routine allocates space for the prefix and - * maybe a '\0' terminator too. We have to assume that 'prefix_size' is - * limited only by the maximum chunk size. - */ - png_alloc_size_t limit = PNG_SIZE_MAX; - -# ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED - if (png_ptr->user_chunk_malloc_max > 0 && - png_ptr->user_chunk_malloc_max < limit) - limit = png_ptr->user_chunk_malloc_max; -# elif PNG_USER_CHUNK_MALLOC_MAX > 0 - if (PNG_USER_CHUNK_MALLOC_MAX < limit) - limit = PNG_USER_CHUNK_MALLOC_MAX; -# endif - - if (limit >= prefix_size + (terminate != 0)) - { - int ret; - - limit -= prefix_size + (terminate != 0); - - if (limit < *newlength) - *newlength = limit; - - /* Now try to claim the stream; the 'warn' setting causes zlib to be told - * to use the maximum window size during inflate; this hides errors in the - * deflate header window bits value which is used if '0' is passed. In - * fact this only has an effect with zlib versions 1.2.4 and later - see - * the comments in png_inflate_claim above. - */ - ret = png_inflate_claim(png_ptr, png_ptr->chunk_name, - png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN ? 15 : 0); - - if (ret == Z_OK) - { - png_uint_32 lzsize = chunklength - prefix_size; - - ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, - /* input: */ png_ptr->read_buffer + prefix_size, &lzsize, - /* output: */ NULL, newlength); - - if (ret == Z_STREAM_END) - { - /* Use 'inflateReset' here, not 'inflateReset2' because this - * preserves the previously decided window size (otherwise it would - * be necessary to store the previous window size.) In practice - * this doesn't matter anyway, because png_inflate will call inflate - * with Z_FINISH in almost all cases, so the window will not be - * maintained. - */ - if (inflateReset(&png_ptr->zstream) == Z_OK) - { - /* Because of the limit checks above we know that the new, - * expanded, size will fit in a size_t (let alone an - * png_alloc_size_t). Use png_malloc_base here to avoid an - * extra OOM message. - */ - png_alloc_size_t new_size = *newlength; - png_alloc_size_t buffer_size = prefix_size + new_size + - (terminate != 0); - png_bytep text = png_voidcast(png_bytep, png_malloc_base(png_ptr, - buffer_size)); - - if (text != NULL) - { - ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, - png_ptr->read_buffer + prefix_size, &lzsize, - text + prefix_size, newlength); - - if (ret == Z_STREAM_END) - { - if (new_size == *newlength) - { - if (terminate) - text[prefix_size + *newlength] = 0; - - if (prefix_size > 0) - memcpy(text, png_ptr->read_buffer, prefix_size); - - { - png_bytep old_ptr = png_ptr->read_buffer; - - png_ptr->read_buffer = text; - png_ptr->read_buffer_size = buffer_size; - text = old_ptr; /* freed below */ - } - } - - else - { - /* The size changed on the second read, there can be no - * guarantee that anything is correct at this point. - * The 'msg' pointer has been set to "unexpected end of - * LZ stream", which is fine, but return an error code - * that the caller won't accept. - */ - ret = PNG_UNEXPECTED_ZLIB_RETURN; - } - } - - else if (ret == Z_OK) - ret = PNG_UNEXPECTED_ZLIB_RETURN; /* for safety */ - - /* Free the text pointer (this is the old read_buffer on - * success) - */ - png_free(png_ptr, text); - - /* This really is very benign, but it's still an error because - * the extra space may otherwise be used as a Trojan Horse. - */ - if (ret == Z_STREAM_END && - chunklength - prefix_size != lzsize) - png_chunk_benign_error(png_ptr, "extra compressed data"); - } - - else - { - /* Out of memory allocating the buffer */ - ret = Z_MEM_ERROR; - png_zstream_error(png_ptr, Z_MEM_ERROR); - } - } - - else - { - /* inflateReset failed, store the error message */ - png_zstream_error(png_ptr, ret); - - if (ret == Z_STREAM_END) - ret = PNG_UNEXPECTED_ZLIB_RETURN; - } - } - - else if (ret == Z_OK) - ret = PNG_UNEXPECTED_ZLIB_RETURN; - - /* Release the claimed stream */ - png_ptr->zowner = 0; - } - - else /* the claim failed */ if (ret == Z_STREAM_END) /* impossible! */ - ret = PNG_UNEXPECTED_ZLIB_RETURN; - - return ret; - } - - else - { - /* Application/configuration limits exceeded */ - png_zstream_error(png_ptr, Z_MEM_ERROR); - return Z_MEM_ERROR; - } -} -#endif /* PNG_READ_COMPRESSED_TEXT_SUPPORTED */ - -#ifdef PNG_READ_iCCP_SUPPORTED -/* Perform a partial read and decompress, producing 'avail_out' bytes and - * reading from the current chunk as required. - */ -static int -png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size, - png_uint_32p chunk_bytes, png_bytep next_out, png_alloc_size_t *out_size, - int finish) -{ - if (png_ptr->zowner == png_ptr->chunk_name) - { - int ret; - - /* next_in and avail_in must have been initialized by the caller. */ - png_ptr->zstream.next_out = next_out; - png_ptr->zstream.avail_out = 0; /* set in the loop */ - - do - { - if (png_ptr->zstream.avail_in == 0) - { - if (read_size > *chunk_bytes) - read_size = (uInt)*chunk_bytes; - *chunk_bytes -= read_size; - - if (read_size > 0) - png_crc_read(png_ptr, read_buffer, read_size); - - png_ptr->zstream.next_in = read_buffer; - png_ptr->zstream.avail_in = read_size; - } - - if (png_ptr->zstream.avail_out == 0) - { - uInt avail = ZLIB_IO_MAX; - if (avail > *out_size) - avail = (uInt)*out_size; - *out_size -= avail; - - png_ptr->zstream.avail_out = avail; - } - - /* Use Z_SYNC_FLUSH when there is no more chunk data to ensure that all - * the available output is produced; this allows reading of truncated - * streams. - */ - ret = inflate(&png_ptr->zstream, - *chunk_bytes > 0 ? Z_NO_FLUSH : (finish ? Z_FINISH : Z_SYNC_FLUSH)); - } - while (ret == Z_OK && (*out_size > 0 || png_ptr->zstream.avail_out > 0)); - - *out_size += png_ptr->zstream.avail_out; - png_ptr->zstream.avail_out = 0; /* Should not be required, but is safe */ - - /* Ensure the error message pointer is always set: */ - png_zstream_error(png_ptr, ret); - return ret; - } - - else - { - png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed"); - return Z_STREAM_ERROR; - } -} -#endif - -/* Read and check the IDHR chunk */ -void /* PRIVATE */ -png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_byte buf[13]; - png_uint_32 width, height; - int bit_depth, color_type, compression_type, filter_type; - int interlace_type; - - png_debug(1, "in png_handle_IHDR"); - - if (png_ptr->mode & PNG_HAVE_IHDR) - png_chunk_error(png_ptr, "out of place"); - - /* Check the length */ - if (length != 13) - png_chunk_error(png_ptr, "invalid"); - - png_ptr->mode |= PNG_HAVE_IHDR; - - png_crc_read(png_ptr, buf, 13); - png_crc_finish(png_ptr, 0); - - width = png_get_uint_31(png_ptr, buf); - height = png_get_uint_31(png_ptr, buf + 4); - bit_depth = buf[8]; - color_type = buf[9]; - compression_type = buf[10]; - filter_type = buf[11]; - interlace_type = buf[12]; - - /* Set internal variables */ - png_ptr->width = width; - png_ptr->height = height; - png_ptr->bit_depth = (png_byte)bit_depth; - png_ptr->interlaced = (png_byte)interlace_type; - png_ptr->color_type = (png_byte)color_type; -#ifdef PNG_MNG_FEATURES_SUPPORTED - png_ptr->filter_type = (png_byte)filter_type; -#endif - png_ptr->compression_type = (png_byte)compression_type; - - /* Find number of channels */ - switch (png_ptr->color_type) - { - default: /* invalid, png_set_IHDR calls png_error */ - case PNG_COLOR_TYPE_GRAY: - case PNG_COLOR_TYPE_PALETTE: - png_ptr->channels = 1; - break; - - case PNG_COLOR_TYPE_RGB: - png_ptr->channels = 3; - break; - - case PNG_COLOR_TYPE_GRAY_ALPHA: - png_ptr->channels = 2; - break; - - case PNG_COLOR_TYPE_RGB_ALPHA: - png_ptr->channels = 4; - break; - } - - /* Set up other useful info */ - png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * - png_ptr->channels); - png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width); - png_debug1(3, "bit_depth = %d", png_ptr->bit_depth); - png_debug1(3, "channels = %d", png_ptr->channels); - png_debug1(3, "rowbytes = %lu", (unsigned long)png_ptr->rowbytes); - png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, - color_type, interlace_type, compression_type, filter_type); -} - -/* Read and check the palette */ -void /* PRIVATE */ -png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_color palette[PNG_MAX_PALETTE_LENGTH]; - int num, i; -#ifdef PNG_POINTER_INDEXING_SUPPORTED - png_colorp pal_ptr; -#endif - - png_debug(1, "in png_handle_PLTE"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - /* Moved to before the 'after IDAT' check below because otherwise duplicate - * PLTE chunks are potentially ignored (the spec says there shall not be more - * than one PLTE, the error is not treated as benign, so this check trumps - * the requirement that PLTE appears before IDAT.) - */ - else if (png_ptr->mode & PNG_HAVE_PLTE) - png_chunk_error(png_ptr, "duplicate"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - /* This is benign because the non-benign error happened before, when an - * IDAT was encountered in a color-mapped image with no PLTE. - */ - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of place"); - return; - } - - png_ptr->mode |= PNG_HAVE_PLTE; - - if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "ignored in grayscale PNG"); - return; - } - -#ifndef PNG_READ_OPT_PLTE_SUPPORTED - if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) - { - png_crc_finish(png_ptr, length); - return; - } -#endif - - if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3) - { - png_crc_finish(png_ptr, length); - - if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) - png_chunk_benign_error(png_ptr, "invalid"); - - else - png_chunk_error(png_ptr, "invalid"); - - return; - } - - /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */ - num = (int)length / 3; - -#ifdef PNG_POINTER_INDEXING_SUPPORTED - for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++) - { - png_byte buf[3]; - - png_crc_read(png_ptr, buf, 3); - pal_ptr->red = buf[0]; - pal_ptr->green = buf[1]; - pal_ptr->blue = buf[2]; - } -#else - for (i = 0; i < num; i++) - { - png_byte buf[3]; - - png_crc_read(png_ptr, buf, 3); - /* Don't depend upon png_color being any order */ - palette[i].red = buf[0]; - palette[i].green = buf[1]; - palette[i].blue = buf[2]; - } -#endif - - /* If we actually need the PLTE chunk (ie for a paletted image), we do - * whatever the normal CRC configuration tells us. However, if we - * have an RGB image, the PLTE can be considered ancillary, so - * we will act as though it is. - */ -#ifndef PNG_READ_OPT_PLTE_SUPPORTED - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) -#endif - { - png_crc_finish(png_ptr, 0); - } - -#ifndef PNG_READ_OPT_PLTE_SUPPORTED - else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */ - { - /* If we don't want to use the data from an ancillary chunk, - * we have two options: an error abort, or a warning and we - * ignore the data in this chunk (which should be OK, since - * it's considered ancillary for a RGB or RGBA image). - * - * IMPLEMENTATION NOTE: this is only here because png_crc_finish uses the - * chunk type to determine whether to check the ancillary or the critical - * flags. - */ - if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE)) - { - if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) - { - png_chunk_benign_error(png_ptr, "CRC error"); - } - - else - { - png_chunk_warning(png_ptr, "CRC error"); - return; - } - } - - /* Otherwise, we (optionally) emit a warning and use the chunk. */ - else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) - { - png_chunk_warning(png_ptr, "CRC error"); - } - } -#endif - - /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to its - * own copy of the palette. This has the side effect that when png_start_row - * is called (this happens after any call to png_read_update_info) the - * info_ptr palette gets changed. This is extremely unexpected and - * confusing. - * - * Fix this by not sharing the palette in this way. - */ - png_set_PLTE(png_ptr, info_ptr, palette, num); - - /* The three chunks, bKGD, hIST and tRNS *must* appear after PLTE and before - * IDAT. Prior to 1.6.0 this was not checked; instead the code merely - * checked the apparent validity of a tRNS chunk inserted before PLTE on a - * palette PNG. 1.6.0 attempts to rigorously follow the standard and - * therefore does a benign error if the erroneous condition is detected *and* - * cancels the tRNS if the benign error returns. The alternative is to - * amend the standard since it would be rather hypocritical of the standards - * maintainers to ignore it. - */ -#ifdef PNG_READ_tRNS_SUPPORTED - if (png_ptr->num_trans > 0 || - (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0)) - { - /* Cancel this because otherwise it would be used if the transforms - * require it. Don't cancel the 'valid' flag because this would prevent - * detection of duplicate chunks. - */ - png_ptr->num_trans = 0; - - if (info_ptr != NULL) - info_ptr->num_trans = 0; - - png_chunk_benign_error(png_ptr, "tRNS must be after"); - } -#endif - -#ifdef PNG_READ_hIST_SUPPORTED - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0) - png_chunk_benign_error(png_ptr, "hIST must be after"); -#endif - -#ifdef PNG_READ_bKGD_SUPPORTED - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0) - png_chunk_benign_error(png_ptr, "bKGD must be after"); -#endif -} - -void /* PRIVATE */ -png_handle_IEND(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_debug(1, "in png_handle_IEND"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT)) - png_chunk_error(png_ptr, "out of place"); - - png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND); - - png_crc_finish(png_ptr, length); - - if (length != 0) - png_chunk_benign_error(png_ptr, "invalid"); - - PNG_UNUSED(info_ptr) -} - -#ifdef PNG_READ_gAMA_SUPPORTED -void /* PRIVATE */ -png_handle_gAMA(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_fixed_point igamma; - png_byte buf[4]; - - png_debug(1, "in png_handle_gAMA"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of place"); - return; - } - - if (length != 4) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "invalid"); - return; - } - - png_crc_read(png_ptr, buf, 4); - - if (png_crc_finish(png_ptr, 0)) - return; - - igamma = png_get_fixed_point(NULL, buf); - - png_colorspace_set_gamma(png_ptr, &png_ptr->colorspace, igamma); - png_colorspace_sync(png_ptr, info_ptr); -} -#endif - -#ifdef PNG_READ_sBIT_SUPPORTED -void /* PRIVATE */ -png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - unsigned int truelen; - png_byte buf[4]; - - png_debug(1, "in png_handle_sBIT"); - - buf[0] = buf[1] = buf[2] = buf[3] = 0; - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of place"); - return; - } - - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "duplicate"); - return; - } - - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - truelen = 3; - - else - truelen = png_ptr->channels; - - if (length != truelen || length > 4) - { - png_chunk_benign_error(png_ptr, "invalid"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, truelen); - - if (png_crc_finish(png_ptr, 0)) - return; - - if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) - { - png_ptr->sig_bit.red = buf[0]; - png_ptr->sig_bit.green = buf[1]; - png_ptr->sig_bit.blue = buf[2]; - png_ptr->sig_bit.alpha = buf[3]; - } - - else - { - png_ptr->sig_bit.gray = buf[0]; - png_ptr->sig_bit.red = buf[0]; - png_ptr->sig_bit.green = buf[0]; - png_ptr->sig_bit.blue = buf[0]; - png_ptr->sig_bit.alpha = buf[1]; - } - - png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit)); -} -#endif - -#ifdef PNG_READ_cHRM_SUPPORTED -void /* PRIVATE */ -png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_byte buf[32]; - png_xy xy; - - png_debug(1, "in png_handle_cHRM"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of place"); - return; - } - - if (length != 32) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "invalid"); - return; - } - - png_crc_read(png_ptr, buf, 32); - - if (png_crc_finish(png_ptr, 0)) - return; - - xy.whitex = png_get_fixed_point(NULL, buf); - xy.whitey = png_get_fixed_point(NULL, buf + 4); - xy.redx = png_get_fixed_point(NULL, buf + 8); - xy.redy = png_get_fixed_point(NULL, buf + 12); - xy.greenx = png_get_fixed_point(NULL, buf + 16); - xy.greeny = png_get_fixed_point(NULL, buf + 20); - xy.bluex = png_get_fixed_point(NULL, buf + 24); - xy.bluey = png_get_fixed_point(NULL, buf + 28); - - if (xy.whitex == PNG_FIXED_ERROR || - xy.whitey == PNG_FIXED_ERROR || - xy.redx == PNG_FIXED_ERROR || - xy.redy == PNG_FIXED_ERROR || - xy.greenx == PNG_FIXED_ERROR || - xy.greeny == PNG_FIXED_ERROR || - xy.bluex == PNG_FIXED_ERROR || - xy.bluey == PNG_FIXED_ERROR) - { - png_chunk_benign_error(png_ptr, "invalid values"); - return; - } - - /* If a colorspace error has already been output skip this chunk */ - if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) - return; - - if (png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) - { - png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; - png_colorspace_sync(png_ptr, info_ptr); - png_chunk_benign_error(png_ptr, "duplicate"); - return; - } - - png_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; - (void)png_colorspace_set_chromaticities(png_ptr, &png_ptr->colorspace, &xy, - 1/*prefer cHRM values*/); - png_colorspace_sync(png_ptr, info_ptr); -} -#endif - -#ifdef PNG_READ_sRGB_SUPPORTED -void /* PRIVATE */ -png_handle_sRGB(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_byte intent; - - png_debug(1, "in png_handle_sRGB"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of place"); - return; - } - - if (length != 1) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "invalid"); - return; - } - - png_crc_read(png_ptr, &intent, 1); - - if (png_crc_finish(png_ptr, 0)) - return; - - /* If a colorspace error has already been output skip this chunk */ - if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) - return; - - /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect - * this. - */ - if (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) - { - png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; - png_colorspace_sync(png_ptr, info_ptr); - png_chunk_benign_error(png_ptr, "too many profiles"); - return; - } - - (void)png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent); - png_colorspace_sync(png_ptr, info_ptr); -} -#endif /* PNG_READ_sRGB_SUPPORTED */ - -#ifdef PNG_READ_iCCP_SUPPORTED -void /* PRIVATE */ -png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -/* Note: this does not properly handle profiles that are > 64K under DOS */ -{ - png_const_charp errmsg = NULL; /* error message output, or no error */ - int finished = 0; /* crc checked */ - - png_debug(1, "in png_handle_iCCP"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of place"); - return; - } - - /* Consistent with all the above colorspace handling an obviously *invalid* - * chunk is just ignored, so does not invalidate the color space. An - * alternative is to set the 'invalid' flags at the start of this routine - * and only clear them in they were not set before and all the tests pass. - * The minimum 'deflate' stream is assumed to be just the 2 byte header and 4 - * byte checksum. The keyword must be one character and there is a - * terminator (0) byte and the compression method. - */ - if (length < 9) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "too short"); - return; - } - - /* If a colorspace error has already been output skip this chunk */ - if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) - { - png_crc_finish(png_ptr, length); - return; - } - - /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect - * this. - */ - if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) == 0) - { - uInt read_length, keyword_length; - char keyword[81]; - - /* Find the keyword; the keyword plus separator and compression method - * bytes can be at most 81 characters long. - */ - read_length = 81; /* maximum */ - if (read_length > length) - read_length = (uInt)length; - - png_crc_read(png_ptr, (png_bytep)keyword, read_length); - length -= read_length; - - keyword_length = 0; - while (keyword_length < 80 && keyword_length < read_length && - keyword[keyword_length] != 0) - ++keyword_length; - - /* TODO: make the keyword checking common */ - if (keyword_length >= 1 && keyword_length <= 79) - { - /* We only understand '0' compression - deflate - so if we get a - * different value we can't safely decode the chunk. - */ - if (keyword_length+1 < read_length && - keyword[keyword_length+1] == PNG_COMPRESSION_TYPE_BASE) - { - read_length -= keyword_length+2; - - if (png_inflate_claim(png_ptr, png_iCCP, - png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN ? 15 : 0) == Z_OK) - { - unsigned char profile_header[132]; - unsigned char local_buffer[PNG_INFLATE_BUF_SIZE]; - png_alloc_size_t size = (sizeof profile_header); - - png_ptr->zstream.next_in = (Bytef*)keyword + (keyword_length+2); - png_ptr->zstream.avail_in = read_length; - (void)png_inflate_read(png_ptr, local_buffer, - (sizeof local_buffer), &length, profile_header, &size, - 0/*finish: don't, because the output is too small*/); - - if (size == 0) - { - /* We have the ICC profile header; do the basic header checks. - */ - const png_uint_32 profile_length = - png_get_uint_32(profile_header); - - if (png_icc_check_length(png_ptr, &png_ptr->colorspace, - keyword, profile_length)) - { - /* The length is apparently ok, so we can check the 132 - * byte header. - */ - if (png_icc_check_header(png_ptr, &png_ptr->colorspace, - keyword, profile_length, profile_header, - png_ptr->color_type)) - { - /* Now read the tag table; a variable size buffer is - * needed at this point, allocate one for the whole - * profile. The header check has already validated - * that none of these stuff will overflow. - */ - const png_uint_32 tag_count = png_get_uint_32( - profile_header+128); - png_bytep profile = png_read_buffer(png_ptr, - profile_length, 2/*silent*/); - - if (profile != NULL) - { - memcpy(profile, profile_header, - (sizeof profile_header)); - - size = 12 * tag_count; - - (void)png_inflate_read(png_ptr, local_buffer, - (sizeof local_buffer), &length, - profile + (sizeof profile_header), &size, 0); - - /* Still expect a a buffer error because we expect - * there to be some tag data! - */ - if (size == 0) - { - if (png_icc_check_tag_table(png_ptr, - &png_ptr->colorspace, keyword, profile_length, - profile)) - { - /* The profile has been validated for basic - * security issues, so read the whole thing in. - */ - size = profile_length - (sizeof profile_header) - - 12 * tag_count; - - (void)png_inflate_read(png_ptr, local_buffer, - (sizeof local_buffer), &length, - profile + (sizeof profile_header) + - 12 * tag_count, &size, 1/*finish*/); - - if (length > 0 && !(png_ptr->flags & - PNG_FLAG_BENIGN_ERRORS_WARN)) - errmsg = "extra compressed data"; - - /* But otherwise allow extra data: */ - else if (size == 0) - { - if (length > 0) - { - /* This can be handled completely, so - * keep going. - */ - png_chunk_warning(png_ptr, - "extra compressed data"); - } - - png_crc_finish(png_ptr, length); - finished = 1; - -# ifdef PNG_sRGB_SUPPORTED - /* Check for a match against sRGB */ - png_icc_set_sRGB(png_ptr, - &png_ptr->colorspace, profile, - png_ptr->zstream.adler); -# endif - - /* Steal the profile for info_ptr. */ - if (info_ptr != NULL) - { - png_free_data(png_ptr, info_ptr, - PNG_FREE_ICCP, 0); - - info_ptr->iccp_name = png_voidcast(char*, - png_malloc_base(png_ptr, - keyword_length+1)); - if (info_ptr->iccp_name != NULL) - { - memcpy(info_ptr->iccp_name, keyword, - keyword_length+1); - info_ptr->iccp_proflen = - profile_length; - info_ptr->iccp_profile = profile; - png_ptr->read_buffer = NULL; /*steal*/ - info_ptr->free_me |= PNG_FREE_ICCP; - info_ptr->valid |= PNG_INFO_iCCP; - } - - else - { - png_ptr->colorspace.flags |= - PNG_COLORSPACE_INVALID; - errmsg = "out of memory"; - } - } - - /* else the profile remains in the read - * buffer which gets reused for subsequent - * chunks. - */ - - if (info_ptr != NULL) - png_colorspace_sync(png_ptr, info_ptr); - - if (errmsg == NULL) - { - png_ptr->zowner = 0; - return; - } - } - - else if (size > 0) - errmsg = "truncated"; - - else - errmsg = png_ptr->zstream.msg; - } - - /* else png_icc_check_tag_table output an error */ - } - - else /* profile truncated */ - errmsg = png_ptr->zstream.msg; - } - - else - errmsg = "out of memory"; - } - - /* else png_icc_check_header output an error */ - } - - /* else png_icc_check_length output an error */ - } - - else /* profile truncated */ - errmsg = png_ptr->zstream.msg; - - /* Release the stream */ - png_ptr->zowner = 0; - } - - else /* png_inflate_claim failed */ - errmsg = png_ptr->zstream.msg; - } - - else - errmsg = "bad compression method"; /* or missing */ - } - - else - errmsg = "bad keyword"; - } - - else - errmsg = "too many profiles"; - - /* Failure: the reason is in 'errmsg' */ - if (!finished) - png_crc_finish(png_ptr, length); - - png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; - png_colorspace_sync(png_ptr, info_ptr); - if (errmsg != NULL) /* else already output */ - png_chunk_benign_error(png_ptr, errmsg); -} -#endif /* PNG_READ_iCCP_SUPPORTED */ - -#ifdef PNG_READ_sPLT_SUPPORTED -void /* PRIVATE */ -png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -/* Note: this does not properly handle chunks that are > 64K under DOS */ -{ - png_bytep entry_start, buffer; - png_sPLT_t new_palette; - png_sPLT_entryp pp; - png_uint_32 data_length; - int entry_size, i; - png_uint_32 skip = 0; - png_uint_32 dl; - png_size_t max_dl; - - png_debug(1, "in png_handle_sPLT"); - -#ifdef PNG_USER_LIMITS_SUPPORTED - if (png_ptr->user_chunk_cache_max != 0) - { - if (png_ptr->user_chunk_cache_max == 1) - { - png_crc_finish(png_ptr, length); - return; - } - - if (--png_ptr->user_chunk_cache_max == 1) - { - png_warning(png_ptr, "No space in chunk cache for sPLT"); - png_crc_finish(png_ptr, length); - return; - } - } -#endif - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of place"); - return; - } - -#ifdef PNG_MAX_MALLOC_64K - if (length > 65535U) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "too large to fit in memory"); - return; - } -#endif - - buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); - if (buffer == NULL) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of memory"); - return; - } - - - /* WARNING: this may break if size_t is less than 32 bits; it is assumed - * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a - * potential breakage point if the types in pngconf.h aren't exactly right. - */ - png_crc_read(png_ptr, buffer, length); - - if (png_crc_finish(png_ptr, skip)) - return; - - buffer[length] = 0; - - for (entry_start = buffer; *entry_start; entry_start++) - /* Empty loop to find end of name */ ; - - ++entry_start; - - /* A sample depth should follow the separator, and we should be on it */ - if (entry_start > buffer + length - 2) - { - png_warning(png_ptr, "malformed sPLT chunk"); - return; - } - - new_palette.depth = *entry_start++; - entry_size = (new_palette.depth == 8 ? 6 : 10); - /* This must fit in a png_uint_32 because it is derived from the original - * chunk data length. - */ - data_length = length - (png_uint_32)(entry_start - buffer); - - /* Integrity-check the data length */ - if (data_length % entry_size) - { - png_warning(png_ptr, "sPLT chunk has bad length"); - return; - } - - dl = (png_int_32)(data_length / entry_size); - max_dl = PNG_SIZE_MAX / (sizeof (png_sPLT_entry)); - - if (dl > max_dl) - { - png_warning(png_ptr, "sPLT chunk too long"); - return; - } - - new_palette.nentries = (png_int_32)(data_length / entry_size); - - new_palette.entries = (png_sPLT_entryp)png_malloc_warn( - png_ptr, new_palette.nentries * (sizeof (png_sPLT_entry))); - - if (new_palette.entries == NULL) - { - png_warning(png_ptr, "sPLT chunk requires too much memory"); - return; - } - -#ifdef PNG_POINTER_INDEXING_SUPPORTED - for (i = 0; i < new_palette.nentries; i++) - { - pp = new_palette.entries + i; - - if (new_palette.depth == 8) - { - pp->red = *entry_start++; - pp->green = *entry_start++; - pp->blue = *entry_start++; - pp->alpha = *entry_start++; - } - - else - { - pp->red = png_get_uint_16(entry_start); entry_start += 2; - pp->green = png_get_uint_16(entry_start); entry_start += 2; - pp->blue = png_get_uint_16(entry_start); entry_start += 2; - pp->alpha = png_get_uint_16(entry_start); entry_start += 2; - } - - pp->frequency = png_get_uint_16(entry_start); entry_start += 2; - } -#else - pp = new_palette.entries; - - for (i = 0; i < new_palette.nentries; i++) - { - - if (new_palette.depth == 8) - { - pp[i].red = *entry_start++; - pp[i].green = *entry_start++; - pp[i].blue = *entry_start++; - pp[i].alpha = *entry_start++; - } - - else - { - pp[i].red = png_get_uint_16(entry_start); entry_start += 2; - pp[i].green = png_get_uint_16(entry_start); entry_start += 2; - pp[i].blue = png_get_uint_16(entry_start); entry_start += 2; - pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2; - } - - pp[i].frequency = png_get_uint_16(entry_start); entry_start += 2; - } -#endif - - /* Discard all chunk data except the name and stash that */ - new_palette.name = (png_charp)buffer; - - png_set_sPLT(png_ptr, info_ptr, &new_palette, 1); - - png_free(png_ptr, new_palette.entries); -} -#endif /* PNG_READ_sPLT_SUPPORTED */ - -#ifdef PNG_READ_tRNS_SUPPORTED -void /* PRIVATE */ -png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_byte readbuf[PNG_MAX_PALETTE_LENGTH]; - - png_debug(1, "in png_handle_tRNS"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of place"); - return; - } - - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "duplicate"); - return; - } - - if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) - { - png_byte buf[2]; - - if (length != 2) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "invalid"); - return; - } - - png_crc_read(png_ptr, buf, 2); - png_ptr->num_trans = 1; - png_ptr->trans_color.gray = png_get_uint_16(buf); - } - - else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) - { - png_byte buf[6]; - - if (length != 6) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "invalid"); - return; - } - - png_crc_read(png_ptr, buf, length); - png_ptr->num_trans = 1; - png_ptr->trans_color.red = png_get_uint_16(buf); - png_ptr->trans_color.green = png_get_uint_16(buf + 2); - png_ptr->trans_color.blue = png_get_uint_16(buf + 4); - } - - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - if (!(png_ptr->mode & PNG_HAVE_PLTE)) - { - /* TODO: is this actually an error in the ISO spec? */ - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of place"); - return; - } - - if (length > png_ptr->num_palette || length > PNG_MAX_PALETTE_LENGTH || - length == 0) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "invalid"); - return; - } - - png_crc_read(png_ptr, readbuf, length); - png_ptr->num_trans = (png_uint_16)length; - } - - else - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "invalid with alpha channel"); - return; - } - - if (png_crc_finish(png_ptr, 0)) - { - png_ptr->num_trans = 0; - return; - } - - /* TODO: this is a horrible side effect in the palette case because the - * png_struct ends up with a pointer to the tRNS buffer owned by the - * png_info. Fix this. - */ - png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, - &(png_ptr->trans_color)); -} -#endif - -#ifdef PNG_READ_bKGD_SUPPORTED -void /* PRIVATE */ -png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - unsigned int truelen; - png_byte buf[6]; - png_color_16 background; - - png_debug(1, "in png_handle_bKGD"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - else if ((png_ptr->mode & PNG_HAVE_IDAT) || - (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE))) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of place"); - return; - } - - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD)) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "duplicate"); - return; - } - - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - truelen = 1; - - else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) - truelen = 6; - - else - truelen = 2; - - if (length != truelen) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "invalid"); - return; - } - - png_crc_read(png_ptr, buf, truelen); - - if (png_crc_finish(png_ptr, 0)) - return; - - /* We convert the index value into RGB components so that we can allow - * arbitrary RGB values for background when we have transparency, and - * so it is easy to determine the RGB values of the background color - * from the info_ptr struct. - */ - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - background.index = buf[0]; - - if (info_ptr && info_ptr->num_palette) - { - if (buf[0] >= info_ptr->num_palette) - { - png_chunk_benign_error(png_ptr, "invalid index"); - return; - } - - background.red = (png_uint_16)png_ptr->palette[buf[0]].red; - background.green = (png_uint_16)png_ptr->palette[buf[0]].green; - background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue; - } - - else - background.red = background.green = background.blue = 0; - - background.gray = 0; - } - - else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */ - { - background.index = 0; - background.red = - background.green = - background.blue = - background.gray = png_get_uint_16(buf); - } - - else - { - background.index = 0; - background.red = png_get_uint_16(buf); - background.green = png_get_uint_16(buf + 2); - background.blue = png_get_uint_16(buf + 4); - background.gray = 0; - } - - png_set_bKGD(png_ptr, info_ptr, &background); -} -#endif - -#ifdef PNG_READ_hIST_SUPPORTED -void /* PRIVATE */ -png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - unsigned int num, i; - png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH]; - - png_debug(1, "in png_handle_hIST"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - else if ((png_ptr->mode & PNG_HAVE_IDAT) || !(png_ptr->mode & PNG_HAVE_PLTE)) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of place"); - return; - } - - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST)) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "duplicate"); - return; - } - - num = length / 2 ; - - if (num != png_ptr->num_palette || num > PNG_MAX_PALETTE_LENGTH) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "invalid"); - return; - } - - for (i = 0; i < num; i++) - { - png_byte buf[2]; - - png_crc_read(png_ptr, buf, 2); - readbuf[i] = png_get_uint_16(buf); - } - - if (png_crc_finish(png_ptr, 0)) - return; - - png_set_hIST(png_ptr, info_ptr, readbuf); -} -#endif - -#ifdef PNG_READ_pHYs_SUPPORTED -void /* PRIVATE */ -png_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_byte buf[9]; - png_uint_32 res_x, res_y; - int unit_type; - - png_debug(1, "in png_handle_pHYs"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of place"); - return; - } - - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "duplicate"); - return; - } - - if (length != 9) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "invalid"); - return; - } - - png_crc_read(png_ptr, buf, 9); - - if (png_crc_finish(png_ptr, 0)) - return; - - res_x = png_get_uint_32(buf); - res_y = png_get_uint_32(buf + 4); - unit_type = buf[8]; - png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type); -} -#endif - -#ifdef PNG_READ_oFFs_SUPPORTED -void /* PRIVATE */ -png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_byte buf[9]; - png_int_32 offset_x, offset_y; - int unit_type; - - png_debug(1, "in png_handle_oFFs"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of place"); - return; - } - - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "duplicate"); - return; - } - - if (length != 9) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "invalid"); - return; - } - - png_crc_read(png_ptr, buf, 9); - - if (png_crc_finish(png_ptr, 0)) - return; - - offset_x = png_get_int_32(buf); - offset_y = png_get_int_32(buf + 4); - unit_type = buf[8]; - png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type); -} -#endif - -#ifdef PNG_READ_pCAL_SUPPORTED -/* Read the pCAL chunk (described in the PNG Extensions document) */ -void /* PRIVATE */ -png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_int_32 X0, X1; - png_byte type, nparams; - png_bytep buffer, buf, units, endptr; - png_charpp params; - int i; - - png_debug(1, "in png_handle_pCAL"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of place"); - return; - } - - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL)) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "duplicate"); - return; - } - - png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)", - length + 1); - - buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); - - if (buffer == NULL) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of memory"); - return; - } - - png_crc_read(png_ptr, buffer, length); - - if (png_crc_finish(png_ptr, 0)) - return; - - buffer[length] = 0; /* Null terminate the last string */ - - png_debug(3, "Finding end of pCAL purpose string"); - for (buf = buffer; *buf; buf++) - /* Empty loop */ ; - - endptr = buffer + length; - - /* We need to have at least 12 bytes after the purpose string - * in order to get the parameter information. - */ - if (endptr <= buf + 12) - { - png_chunk_benign_error(png_ptr, "invalid"); - return; - } - - png_debug(3, "Reading pCAL X0, X1, type, nparams, and units"); - X0 = png_get_int_32((png_bytep)buf+1); - X1 = png_get_int_32((png_bytep)buf+5); - type = buf[9]; - nparams = buf[10]; - units = buf + 11; - - png_debug(3, "Checking pCAL equation type and number of parameters"); - /* Check that we have the right number of parameters for known - * equation types. - */ - if ((type == PNG_EQUATION_LINEAR && nparams != 2) || - (type == PNG_EQUATION_BASE_E && nparams != 3) || - (type == PNG_EQUATION_ARBITRARY && nparams != 3) || - (type == PNG_EQUATION_HYPERBOLIC && nparams != 4)) - { - png_chunk_benign_error(png_ptr, "invalid parameter count"); - return; - } - - else if (type >= PNG_EQUATION_LAST) - { - png_chunk_benign_error(png_ptr, "unrecognized equation type"); - } - - for (buf = units; *buf; buf++) - /* Empty loop to move past the units string. */ ; - - png_debug(3, "Allocating pCAL parameters array"); - - params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, - nparams * (sizeof (png_charp)))); - - if (params == NULL) - { - png_chunk_benign_error(png_ptr, "out of memory"); - return; - } - - /* Get pointers to the start of each parameter string. */ - for (i = 0; i < nparams; i++) - { - buf++; /* Skip the null string terminator from previous parameter. */ - - png_debug1(3, "Reading pCAL parameter %d", i); - - for (params[i] = (png_charp)buf; buf <= endptr && *buf != 0; buf++) - /* Empty loop to move past each parameter string */ ; - - /* Make sure we haven't run out of data yet */ - if (buf > endptr) - { - png_free(png_ptr, params); - png_chunk_benign_error(png_ptr, "invalid data"); - return; - } - } - - png_set_pCAL(png_ptr, info_ptr, (png_charp)buffer, X0, X1, type, nparams, - (png_charp)units, params); - - png_free(png_ptr, params); -} -#endif - -#ifdef PNG_READ_sCAL_SUPPORTED -/* Read the sCAL chunk */ -void /* PRIVATE */ -png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_bytep buffer; - png_size_t i; - int state; - - png_debug(1, "in png_handle_sCAL"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of place"); - return; - } - - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL)) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "duplicate"); - return; - } - - /* Need unit type, width, \0, height: minimum 4 bytes */ - else if (length < 4) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "invalid"); - return; - } - - png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)", - length + 1); - - buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); - - if (buffer == NULL) - { - png_chunk_benign_error(png_ptr, "out of memory"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buffer, length); - buffer[length] = 0; /* Null terminate the last string */ - - if (png_crc_finish(png_ptr, 0)) - return; - - /* Validate the unit. */ - if (buffer[0] != 1 && buffer[0] != 2) - { - png_chunk_benign_error(png_ptr, "invalid unit"); - return; - } - - /* Validate the ASCII numbers, need two ASCII numbers separated by - * a '\0' and they need to fit exactly in the chunk data. - */ - i = 1; - state = 0; - - if (!png_check_fp_number((png_const_charp)buffer, length, &state, &i) || - i >= length || buffer[i++] != 0) - png_chunk_benign_error(png_ptr, "bad width format"); - - else if (!PNG_FP_IS_POSITIVE(state)) - png_chunk_benign_error(png_ptr, "non-positive width"); - - else - { - png_size_t heighti = i; - - state = 0; - if (!png_check_fp_number((png_const_charp)buffer, length, &state, &i) || - i != length) - png_chunk_benign_error(png_ptr, "bad height format"); - - else if (!PNG_FP_IS_POSITIVE(state)) - png_chunk_benign_error(png_ptr, "non-positive height"); - - else - /* This is the (only) success case. */ - png_set_sCAL_s(png_ptr, info_ptr, buffer[0], - (png_charp)buffer+1, (png_charp)buffer+heighti); - } -} -#endif - -#ifdef PNG_READ_tIME_SUPPORTED -void /* PRIVATE */ -png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_byte buf[7]; - png_time mod_time; - - png_debug(1, "in png_handle_tIME"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME)) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "duplicate"); - return; - } - - if (png_ptr->mode & PNG_HAVE_IDAT) - png_ptr->mode |= PNG_AFTER_IDAT; - - if (length != 7) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "invalid"); - return; - } - - png_crc_read(png_ptr, buf, 7); - - if (png_crc_finish(png_ptr, 0)) - return; - - mod_time.second = buf[6]; - mod_time.minute = buf[5]; - mod_time.hour = buf[4]; - mod_time.day = buf[3]; - mod_time.month = buf[2]; - mod_time.year = png_get_uint_16(buf); - - png_set_tIME(png_ptr, info_ptr, &mod_time); -} -#endif - -#ifdef PNG_READ_tEXt_SUPPORTED -/* Note: this does not properly handle chunks that are > 64K under DOS */ -void /* PRIVATE */ -png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_text text_info; - png_bytep buffer; - png_charp key; - png_charp text; - png_uint_32 skip = 0; - - png_debug(1, "in png_handle_tEXt"); - -#ifdef PNG_USER_LIMITS_SUPPORTED - if (png_ptr->user_chunk_cache_max != 0) - { - if (png_ptr->user_chunk_cache_max == 1) - { - png_crc_finish(png_ptr, length); - return; - } - - if (--png_ptr->user_chunk_cache_max == 1) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "no space in chunk cache"); - return; - } - } -#endif - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - if (png_ptr->mode & PNG_HAVE_IDAT) - png_ptr->mode |= PNG_AFTER_IDAT; - -#ifdef PNG_MAX_MALLOC_64K - if (length > 65535U) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "too large to fit in memory"); - return; - } -#endif - - buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/); - - if (buffer == NULL) - { - png_chunk_benign_error(png_ptr, "out of memory"); - return; - } - - png_crc_read(png_ptr, buffer, length); - - if (png_crc_finish(png_ptr, skip)) - return; - - key = (png_charp)buffer; - key[length] = 0; - - for (text = key; *text; text++) - /* Empty loop to find end of key */ ; - - if (text != key + length) - text++; - - text_info.compression = PNG_TEXT_COMPRESSION_NONE; - text_info.key = key; - text_info.lang = NULL; - text_info.lang_key = NULL; - text_info.itxt_length = 0; - text_info.text = text; - text_info.text_length = strlen(text); - - if (png_set_text_2(png_ptr, info_ptr, &text_info, 1)) - png_warning(png_ptr, "Insufficient memory to process text chunk"); -} -#endif - -#ifdef PNG_READ_zTXt_SUPPORTED -/* Note: this does not correctly handle chunks that are > 64K under DOS */ -void /* PRIVATE */ -png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_const_charp errmsg = NULL; - png_bytep buffer; - png_uint_32 keyword_length; - - png_debug(1, "in png_handle_zTXt"); - -#ifdef PNG_USER_LIMITS_SUPPORTED - if (png_ptr->user_chunk_cache_max != 0) - { - if (png_ptr->user_chunk_cache_max == 1) - { - png_crc_finish(png_ptr, length); - return; - } - - if (--png_ptr->user_chunk_cache_max == 1) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "no space in chunk cache"); - return; - } - } -#endif - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - if (png_ptr->mode & PNG_HAVE_IDAT) - png_ptr->mode |= PNG_AFTER_IDAT; - - buffer = png_read_buffer(png_ptr, length, 2/*silent*/); - - if (buffer == NULL) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of memory"); - return; - } - - png_crc_read(png_ptr, buffer, length); - - if (png_crc_finish(png_ptr, 0)) - return; - - /* TODO: also check that the keyword contents match the spec! */ - for (keyword_length = 0; - keyword_length < length && buffer[keyword_length] != 0; - ++keyword_length) - /* Empty loop to find end of name */ ; - - if (keyword_length > 79 || keyword_length < 1) - errmsg = "bad keyword"; - - /* zTXt must have some LZ data after the keyword, although it may expand to - * zero bytes; we need a '\0' at the end of the keyword, the compression type - * then the LZ data: - */ - else if (keyword_length + 3 > length) - errmsg = "truncated"; - - else if (buffer[keyword_length+1] != PNG_COMPRESSION_TYPE_BASE) - errmsg = "unknown compression type"; - - else - { - png_alloc_size_t uncompressed_length = PNG_SIZE_MAX; - - /* TODO: at present png_decompress_chunk imposes a single application - * level memory limit, this should be split to different values for iCCP - * and text chunks. - */ - if (png_decompress_chunk(png_ptr, length, keyword_length+2, - &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) - { - png_text text; - - /* It worked; png_ptr->read_buffer now looks like a tEXt chunk except - * for the extra compression type byte and the fact that it isn't - * necessarily '\0' terminated. - */ - buffer = png_ptr->read_buffer; - buffer[uncompressed_length+(keyword_length+2)] = 0; - - text.compression = PNG_TEXT_COMPRESSION_zTXt; - text.key = (png_charp)buffer; - text.text = (png_charp)(buffer + keyword_length+2); - text.text_length = uncompressed_length; - text.itxt_length = 0; - text.lang = NULL; - text.lang_key = NULL; - - if (png_set_text_2(png_ptr, info_ptr, &text, 1)) - errmsg = "insufficient memory"; - } - - else - errmsg = png_ptr->zstream.msg; - } - - if (errmsg != NULL) - png_chunk_benign_error(png_ptr, errmsg); -} -#endif - -#ifdef PNG_READ_iTXt_SUPPORTED -/* Note: this does not correctly handle chunks that are > 64K under DOS */ -void /* PRIVATE */ -png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_const_charp errmsg = NULL; - png_bytep buffer; - png_uint_32 prefix_length; - - png_debug(1, "in png_handle_iTXt"); - -#ifdef PNG_USER_LIMITS_SUPPORTED - if (png_ptr->user_chunk_cache_max != 0) - { - if (png_ptr->user_chunk_cache_max == 1) - { - png_crc_finish(png_ptr, length); - return; - } - - if (--png_ptr->user_chunk_cache_max == 1) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "no space in chunk cache"); - return; - } - } -#endif - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_chunk_error(png_ptr, "missing IHDR"); - - if (png_ptr->mode & PNG_HAVE_IDAT) - png_ptr->mode |= PNG_AFTER_IDAT; - - buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/); - - if (buffer == NULL) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of memory"); - return; - } - - png_crc_read(png_ptr, buffer, length); - - if (png_crc_finish(png_ptr, 0)) - return; - - /* First the keyword. */ - for (prefix_length=0; - prefix_length < length && buffer[prefix_length] != 0; - ++prefix_length) - /* Empty loop */ ; - - /* Perform a basic check on the keyword length here. */ - if (prefix_length > 79 || prefix_length < 1) - errmsg = "bad keyword"; - - /* Expect keyword, compression flag, compression type, language, translated - * keyword (both may be empty but are 0 terminated) then the text, which may - * be empty. - */ - else if (prefix_length + 5 > length) - errmsg = "truncated"; - - else if (buffer[prefix_length+1] == 0 || - (buffer[prefix_length+1] == 1 && - buffer[prefix_length+2] == PNG_COMPRESSION_TYPE_BASE)) - { - int compressed = buffer[prefix_length+1] != 0; - png_uint_32 language_offset, translated_keyword_offset; - png_alloc_size_t uncompressed_length = 0; - - /* Now the language tag */ - prefix_length += 3; - language_offset = prefix_length; - - for (; prefix_length < length && buffer[prefix_length] != 0; - ++prefix_length) - /* Empty loop */ ; - - /* WARNING: the length may be invalid here, this is checked below. */ - translated_keyword_offset = ++prefix_length; - - for (; prefix_length < length && buffer[prefix_length] != 0; - ++prefix_length) - /* Empty loop */ ; - - /* prefix_length should now be at the trailing '\0' of the translated - * keyword, but it may already be over the end. None of this arithmetic - * can overflow because chunks are at most 2^31 bytes long, but on 16-bit - * systems the available allocaton may overflow. - */ - ++prefix_length; - - if (!compressed && prefix_length <= length) - uncompressed_length = length - prefix_length; - - else if (compressed && prefix_length < length) - { - uncompressed_length = PNG_SIZE_MAX; - - /* TODO: at present png_decompress_chunk imposes a single application - * level memory limit, this should be split to different values for - * iCCP and text chunks. - */ - if (png_decompress_chunk(png_ptr, length, prefix_length, - &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) - buffer = png_ptr->read_buffer; - - else - errmsg = png_ptr->zstream.msg; - } - - else - errmsg = "truncated"; - - if (errmsg == NULL) - { - png_text text; - - buffer[uncompressed_length+prefix_length] = 0; - - if (compressed) - text.compression = PNG_ITXT_COMPRESSION_NONE; - - else - text.compression = PNG_ITXT_COMPRESSION_zTXt; - - text.key = (png_charp)buffer; - text.lang = (png_charp)buffer + language_offset; - text.lang_key = (png_charp)buffer + translated_keyword_offset; - text.text = (png_charp)buffer + prefix_length; - text.text_length = 0; - text.itxt_length = uncompressed_length; - - if (png_set_text_2(png_ptr, info_ptr, &text, 1)) - errmsg = "insufficient memory"; - } - } - - else - errmsg = "bad compression info"; - - if (errmsg != NULL) - png_chunk_benign_error(png_ptr, errmsg); -} -#endif - -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED -/* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */ -static int -png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length) -{ - png_alloc_size_t limit = PNG_SIZE_MAX; - - if (png_ptr->unknown_chunk.data != NULL) - { - png_free(png_ptr, png_ptr->unknown_chunk.data); - png_ptr->unknown_chunk.data = NULL; - } - -# ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED - if (png_ptr->user_chunk_malloc_max > 0 && - png_ptr->user_chunk_malloc_max < limit) - limit = png_ptr->user_chunk_malloc_max; - -# elif PNG_USER_CHUNK_MALLOC_MAX > 0 - if (PNG_USER_CHUNK_MALLOC_MAX < limit) - limit = PNG_USER_CHUNK_MALLOC_MAX; -# endif - - if (length <= limit) - { - PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name); - /* The following is safe because of the PNG_SIZE_MAX init above */ - png_ptr->unknown_chunk.size = (png_size_t)length/*SAFE*/; - /* 'mode' is a flag array, only the bottom four bits matter here */ - png_ptr->unknown_chunk.location = (png_byte)png_ptr->mode/*SAFE*/; - - if (length == 0) - png_ptr->unknown_chunk.data = NULL; - - else - { - /* Do a 'warn' here - it is handled below. */ - png_ptr->unknown_chunk.data = png_voidcast(png_bytep, - png_malloc_warn(png_ptr, length)); - } - } - - if (png_ptr->unknown_chunk.data == NULL && length > 0) - { - /* This is benign because we clean up correctly */ - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "unknown chunk exceeds memory limits"); - return 0; - } - - else - { - if (length > 0) - png_crc_read(png_ptr, png_ptr->unknown_chunk.data, length); - png_crc_finish(png_ptr, 0); - return 1; - } -} -#endif /* PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ - -/* Handle an unknown, or known but disabled, chunk */ -void /* PRIVATE */ -png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr, - png_uint_32 length, int keep) -{ - int handled = 0; /* the chunk was handled */ - - png_debug(1, "in png_handle_unknown"); - -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED - /* NOTE: this code is based on the code in libpng-1.4.12 except for fixing - * the bug which meant that setting a non-default behavior for a specific - * chunk would be ignored (the default was always used unless a user - * callback was installed). - * - * 'keep' is the value from the png_chunk_unknown_handling, the setting for - * this specific chunk_name, if PNG_HANDLE_AS_UNKNOWN_SUPPORTED, if not it - * will always be PNG_HANDLE_CHUNK_AS_DEFAULT and it needs to be set here. - * This is just an optimization to avoid multiple calls to the lookup - * function. - */ -# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED - keep = png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name); -# endif -# endif - - /* One of the following methods will read the chunk or skip it (at least one - * of these is always defined because this is the only way to switch on - * PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) - */ -# ifdef PNG_READ_USER_CHUNKS_SUPPORTED - /* The user callback takes precedence over the chunk keep value, but the - * keep value is still required to validate a save of a critical chunk. - */ - if (png_ptr->read_user_chunk_fn != NULL) - { - if (png_cache_unknown_chunk(png_ptr, length)) - { - /* Callback to user unknown chunk handler */ - int ret = (*(png_ptr->read_user_chunk_fn))(png_ptr, - &png_ptr->unknown_chunk); - - /* ret is: - * negative: An error occured, png_chunk_error will be called. - * zero: The chunk was not handled, the chunk will be discarded - * unless png_set_keep_unknown_chunks has been used to set - * a 'keep' behavior for this particular chunk, in which - * case that will be used. A critical chunk will cause an - * error at this point unless it is to be saved. - * positive: The chunk was handled, libpng will ignore/discard it. - */ - if (ret < 0) - png_chunk_error(png_ptr, "error in user chunk"); - - else if (ret == 0) - { - /* If the keep value is 'default' or 'never' override it, but - * still error out on critical chunks unless the keep value is - * 'always' While this is weird it is the behavior in 1.4.12. - * A possible improvement would be to obey the value set for the - * chunk, but this would be an API change that would probably - * damage some applications. - * - * The png_app_warning below catches the case that matters, where - * the application has not set specific save or ignore for this - * chunk or global save or ignore. - */ - if (keep < PNG_HANDLE_CHUNK_IF_SAFE) - { -# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED - if (png_ptr->unknown_default < PNG_HANDLE_CHUNK_IF_SAFE) - { - png_chunk_warning(png_ptr, "Saving unknown chunk:"); - png_app_warning(png_ptr, - "forcing save of an unhandled chunk;" - " please call png_set_keep_unknown_chunks"); - /* with keep = PNG_HANDLE_CHUNK_IF_SAFE */ - } -# endif - keep = PNG_HANDLE_CHUNK_IF_SAFE; - } - } - - else /* chunk was handled */ - { - handled = 1; - /* Critical chunks can be safely discarded at this point. */ - keep = PNG_HANDLE_CHUNK_NEVER; - } - } - - else - keep = PNG_HANDLE_CHUNK_NEVER; /* insufficient memory */ - } - - else - /* Use the SAVE_UNKNOWN_CHUNKS code or skip the chunk */ -# endif /* PNG_READ_USER_CHUNKS_SUPPORTED */ - -# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED - { - /* keep is currently just the per-chunk setting, if there was no - * setting change it to the global default now (not that this may - * still be AS_DEFAULT) then obtain the cache of the chunk if required, - * if not simply skip the chunk. - */ - if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT) - keep = png_ptr->unknown_default; - - if (keep == PNG_HANDLE_CHUNK_ALWAYS || - (keep == PNG_HANDLE_CHUNK_IF_SAFE && - PNG_CHUNK_ANCILLIARY(png_ptr->chunk_name))) - { - if (!png_cache_unknown_chunk(png_ptr, length)) - keep = PNG_HANDLE_CHUNK_NEVER; - } - - else - png_crc_finish(png_ptr, length); - } -# else -# ifndef PNG_READ_USER_CHUNKS_SUPPORTED -# error no method to support READ_UNKNOWN_CHUNKS -# endif - - { - /* If here there is no read callback pointer set and no support is - * compiled in to just save the unknown chunks, so simply skip this - * chunk. If 'keep' is something other than AS_DEFAULT or NEVER then - * the app has erroneously asked for unknown chunk saving when there - * is no support. - */ - if (keep > PNG_HANDLE_CHUNK_NEVER) - png_app_error(png_ptr, "no unknown chunk support available"); - - png_crc_finish(png_ptr, length); - } -# endif - -# ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED - /* Now store the chunk in the chunk list if appropriate, and if the limits - * permit it. - */ - if (keep == PNG_HANDLE_CHUNK_ALWAYS || - (keep == PNG_HANDLE_CHUNK_IF_SAFE && - PNG_CHUNK_ANCILLIARY(png_ptr->chunk_name))) - { -# ifdef PNG_USER_LIMITS_SUPPORTED - switch (png_ptr->user_chunk_cache_max) - { - case 2: - png_ptr->user_chunk_cache_max = 1; - png_chunk_benign_error(png_ptr, "no space in chunk cache"); - /* FALL THROUGH */ - case 1: - /* NOTE: prior to 1.6.0 this case resulted in an unknown critical - * chunk being skipped, now there will be a hard error below. - */ - break; - - default: /* not at limit */ - --(png_ptr->user_chunk_cache_max); - /* FALL THROUGH */ - case 0: /* no limit */ -# endif /* PNG_USER_LIMITS_SUPPORTED */ - /* Here when the limit isn't reached or when limits are compiled - * out; store the chunk. - */ - png_set_unknown_chunks(png_ptr, info_ptr, - &png_ptr->unknown_chunk, 1); - handled = 1; -# ifdef PNG_USER_LIMITS_SUPPORTED - break; - } -# endif - } -# else /* no store support! */ - PNG_UNUSED(info_ptr) -# error untested code (reading unknown chunks with no store support) -# endif - - /* Regardless of the error handling below the cached data (if any) can be - * freed now. Notice that the data is not freed if there is a png_error, but - * it will be freed by destroy_read_struct. - */ - if (png_ptr->unknown_chunk.data != NULL) - png_free(png_ptr, png_ptr->unknown_chunk.data); - png_ptr->unknown_chunk.data = NULL; - -#else /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ - /* There is no support to read an unknown chunk, so just skip it. */ - png_crc_finish(png_ptr, length); - PNG_UNUSED(info_ptr) - PNG_UNUSED(keep) -#endif /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ - - /* Check for unhandled critical chunks */ - if (!handled && PNG_CHUNK_CRITICAL(png_ptr->chunk_name)) - png_chunk_error(png_ptr, "unhandled critical chunk"); -} - -/* This function is called to verify that a chunk name is valid. - * This function can't have the "critical chunk check" incorporated - * into it, since in the future we will need to be able to call user - * functions to handle unknown critical chunks after we check that - * the chunk name itself is valid. - */ - -/* Bit hacking: the test for an invalid byte in the 4 byte chunk name is: - * - * ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) - */ - -void /* PRIVATE */ -png_check_chunk_name(png_structrp png_ptr, png_uint_32 chunk_name) -{ - int i; - - png_debug(1, "in png_check_chunk_name"); - - for (i=1; i<=4; ++i) - { - int c = chunk_name & 0xff; - - if (c < 65 || c > 122 || (c > 90 && c < 97)) - png_chunk_error(png_ptr, "invalid chunk type"); - - chunk_name >>= 8; - } -} - -/* Combines the row recently read in with the existing pixels in the row. This - * routine takes care of alpha and transparency if requested. This routine also - * handles the two methods of progressive display of interlaced images, - * depending on the 'display' value; if 'display' is true then the whole row - * (dp) is filled from the start by replicating the available pixels. If - * 'display' is false only those pixels present in the pass are filled in. - */ -void /* PRIVATE */ -png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) -{ - unsigned int pixel_depth = png_ptr->transformed_pixel_depth; - png_const_bytep sp = png_ptr->row_buf + 1; - png_uint_32 row_width = png_ptr->width; - unsigned int pass = png_ptr->pass; - png_bytep end_ptr = 0; - png_byte end_byte = 0; - unsigned int end_mask; - - png_debug(1, "in png_combine_row"); - - /* Added in 1.5.6: it should not be possible to enter this routine until at - * least one row has been read from the PNG data and transformed. - */ - if (pixel_depth == 0) - png_error(png_ptr, "internal row logic error"); - - /* Added in 1.5.4: the pixel depth should match the information returned by - * any call to png_read_update_info at this point. Do not continue if we got - * this wrong. - */ - if (png_ptr->info_rowbytes != 0 && png_ptr->info_rowbytes != - PNG_ROWBYTES(pixel_depth, row_width)) - png_error(png_ptr, "internal row size calculation error"); - - /* Don't expect this to ever happen: */ - if (row_width == 0) - png_error(png_ptr, "internal row width error"); - - /* Preserve the last byte in cases where only part of it will be overwritten, - * the multiply below may overflow, we don't care because ANSI-C guarantees - * we get the low bits. - */ - end_mask = (pixel_depth * row_width) & 7; - if (end_mask != 0) - { - /* end_ptr == NULL is a flag to say do nothing */ - end_ptr = dp + PNG_ROWBYTES(pixel_depth, row_width) - 1; - end_byte = *end_ptr; -# ifdef PNG_READ_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) /* little-endian byte */ - end_mask = 0xff << end_mask; - - else /* big-endian byte */ -# endif - end_mask = 0xff >> end_mask; - /* end_mask is now the bits to *keep* from the destination row */ - } - - /* For non-interlaced images this reduces to a memcpy(). A memcpy() - * will also happen if interlacing isn't supported or if the application - * does not call png_set_interlace_handling(). In the latter cases the - * caller just gets a sequence of the unexpanded rows from each interlace - * pass. - */ -#ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE) && - pass < 6 && (display == 0 || - /* The following copies everything for 'display' on passes 0, 2 and 4. */ - (display == 1 && (pass & 1) != 0))) - { - /* Narrow images may have no bits in a pass; the caller should handle - * this, but this test is cheap: - */ - if (row_width <= PNG_PASS_START_COL(pass)) - return; - - if (pixel_depth < 8) - { - /* For pixel depths up to 4 bpp the 8-pixel mask can be expanded to fit - * into 32 bits, then a single loop over the bytes using the four byte - * values in the 32-bit mask can be used. For the 'display' option the - * expanded mask may also not require any masking within a byte. To - * make this work the PACKSWAP option must be taken into account - it - * simply requires the pixels to be reversed in each byte. - * - * The 'regular' case requires a mask for each of the first 6 passes, - * the 'display' case does a copy for the even passes in the range - * 0..6. This has already been handled in the test above. - * - * The masks are arranged as four bytes with the first byte to use in - * the lowest bits (little-endian) regardless of the order (PACKSWAP or - * not) of the pixels in each byte. - * - * NOTE: the whole of this logic depends on the caller of this function - * only calling it on rows appropriate to the pass. This function only - * understands the 'x' logic; the 'y' logic is handled by the caller. - * - * The following defines allow generation of compile time constant bit - * masks for each pixel depth and each possibility of swapped or not - * swapped bytes. Pass 'p' is in the range 0..6; 'x', a pixel index, - * is in the range 0..7; and the result is 1 if the pixel is to be - * copied in the pass, 0 if not. 'S' is for the sparkle method, 'B' - * for the block method. - * - * With some compilers a compile time expression of the general form: - * - * (shift >= 32) ? (a >> (shift-32)) : (b >> shift) - * - * Produces warnings with values of 'shift' in the range 33 to 63 - * because the right hand side of the ?: expression is evaluated by - * the compiler even though it isn't used. Microsoft Visual C (various - * versions) and the Intel C compiler are known to do this. To avoid - * this the following macros are used in 1.5.6. This is a temporary - * solution to avoid destabilizing the code during the release process. - */ -# if PNG_USE_COMPILE_TIME_MASKS -# define PNG_LSR(x,s) ((x)>>((s) & 0x1f)) -# define PNG_LSL(x,s) ((x)<<((s) & 0x1f)) -# else -# define PNG_LSR(x,s) ((x)>>(s)) -# define PNG_LSL(x,s) ((x)<<(s)) -# endif -# define S_COPY(p,x) (((p)<4 ? PNG_LSR(0x80088822,(3-(p))*8+(7-(x))) :\ - PNG_LSR(0xaa55ff00,(7-(p))*8+(7-(x)))) & 1) -# define B_COPY(p,x) (((p)<4 ? PNG_LSR(0xff0fff33,(3-(p))*8+(7-(x))) :\ - PNG_LSR(0xff55ff00,(7-(p))*8+(7-(x)))) & 1) - - /* Return a mask for pass 'p' pixel 'x' at depth 'd'. The mask is - * little endian - the first pixel is at bit 0 - however the extra - * parameter 's' can be set to cause the mask position to be swapped - * within each byte, to match the PNG format. This is done by XOR of - * the shift with 7, 6 or 4 for bit depths 1, 2 and 4. - */ -# define PIXEL_MASK(p,x,d,s) \ - (PNG_LSL(((PNG_LSL(1U,(d)))-1),(((x)*(d))^((s)?8-(d):0)))) - - /* Hence generate the appropriate 'block' or 'sparkle' pixel copy mask. - */ -# define S_MASKx(p,x,d,s) (S_COPY(p,x)?PIXEL_MASK(p,x,d,s):0) -# define B_MASKx(p,x,d,s) (B_COPY(p,x)?PIXEL_MASK(p,x,d,s):0) - - /* Combine 8 of these to get the full mask. For the 1-bpp and 2-bpp - * cases the result needs replicating, for the 4-bpp case the above - * generates a full 32 bits. - */ -# define MASK_EXPAND(m,d) ((m)*((d)==1?0x01010101:((d)==2?0x00010001:1))) - -# define S_MASK(p,d,s) MASK_EXPAND(S_MASKx(p,0,d,s) + S_MASKx(p,1,d,s) +\ - S_MASKx(p,2,d,s) + S_MASKx(p,3,d,s) + S_MASKx(p,4,d,s) +\ - S_MASKx(p,5,d,s) + S_MASKx(p,6,d,s) + S_MASKx(p,7,d,s), d) - -# define B_MASK(p,d,s) MASK_EXPAND(B_MASKx(p,0,d,s) + B_MASKx(p,1,d,s) +\ - B_MASKx(p,2,d,s) + B_MASKx(p,3,d,s) + B_MASKx(p,4,d,s) +\ - B_MASKx(p,5,d,s) + B_MASKx(p,6,d,s) + B_MASKx(p,7,d,s), d) - -#if PNG_USE_COMPILE_TIME_MASKS - /* Utility macros to construct all the masks for a depth/swap - * combination. The 's' parameter says whether the format is PNG - * (big endian bytes) or not. Only the three odd-numbered passes are - * required for the display/block algorithm. - */ -# define S_MASKS(d,s) { S_MASK(0,d,s), S_MASK(1,d,s), S_MASK(2,d,s),\ - S_MASK(3,d,s), S_MASK(4,d,s), S_MASK(5,d,s) } - -# define B_MASKS(d,s) { B_MASK(1,d,s), S_MASK(3,d,s), S_MASK(5,d,s) } - -# define DEPTH_INDEX(d) ((d)==1?0:((d)==2?1:2)) - - /* Hence the pre-compiled masks indexed by PACKSWAP (or not), depth and - * then pass: - */ - static PNG_CONST png_uint_32 row_mask[2/*PACKSWAP*/][3/*depth*/][6] = - { - /* Little-endian byte masks for PACKSWAP */ - { S_MASKS(1,0), S_MASKS(2,0), S_MASKS(4,0) }, - /* Normal (big-endian byte) masks - PNG format */ - { S_MASKS(1,1), S_MASKS(2,1), S_MASKS(4,1) } - }; - - /* display_mask has only three entries for the odd passes, so index by - * pass>>1. - */ - static PNG_CONST png_uint_32 display_mask[2][3][3] = - { - /* Little-endian byte masks for PACKSWAP */ - { B_MASKS(1,0), B_MASKS(2,0), B_MASKS(4,0) }, - /* Normal (big-endian byte) masks - PNG format */ - { B_MASKS(1,1), B_MASKS(2,1), B_MASKS(4,1) } - }; - -# define MASK(pass,depth,display,png)\ - ((display)?display_mask[png][DEPTH_INDEX(depth)][pass>>1]:\ - row_mask[png][DEPTH_INDEX(depth)][pass]) - -#else /* !PNG_USE_COMPILE_TIME_MASKS */ - /* This is the runtime alternative: it seems unlikely that this will - * ever be either smaller or faster than the compile time approach. - */ -# define MASK(pass,depth,display,png)\ - ((display)?B_MASK(pass,depth,png):S_MASK(pass,depth,png)) -#endif /* !PNG_USE_COMPILE_TIME_MASKS */ - - /* Use the appropriate mask to copy the required bits. In some cases - * the byte mask will be 0 or 0xff, optimize these cases. row_width is - * the number of pixels, but the code copies bytes, so it is necessary - * to special case the end. - */ - png_uint_32 pixels_per_byte = 8 / pixel_depth; - png_uint_32 mask; - -# ifdef PNG_READ_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) - mask = MASK(pass, pixel_depth, display, 0); - - else -# endif - mask = MASK(pass, pixel_depth, display, 1); - - for (;;) - { - png_uint_32 m; - - /* It doesn't matter in the following if png_uint_32 has more than - * 32 bits because the high bits always match those in m<<24; it is, - * however, essential to use OR here, not +, because of this. - */ - m = mask; - mask = (m >> 8) | (m << 24); /* rotate right to good compilers */ - m &= 0xff; - - if (m != 0) /* something to copy */ - { - if (m != 0xff) - *dp = (png_byte)((*dp & ~m) | (*sp & m)); - else - *dp = *sp; - } - - /* NOTE: this may overwrite the last byte with garbage if the image - * is not an exact number of bytes wide; libpng has always done - * this. - */ - if (row_width <= pixels_per_byte) - break; /* May need to restore part of the last byte */ - - row_width -= pixels_per_byte; - ++dp; - ++sp; - } - } - - else /* pixel_depth >= 8 */ - { - unsigned int bytes_to_copy, bytes_to_jump; - - /* Validate the depth - it must be a multiple of 8 */ - if (pixel_depth & 7) - png_error(png_ptr, "invalid user transform pixel depth"); - - pixel_depth >>= 3; /* now in bytes */ - row_width *= pixel_depth; - - /* Regardless of pass number the Adam 7 interlace always results in a - * fixed number of pixels to copy then to skip. There may be a - * different number of pixels to skip at the start though. - */ - { - unsigned int offset = PNG_PASS_START_COL(pass) * pixel_depth; - - row_width -= offset; - dp += offset; - sp += offset; - } - - /* Work out the bytes to copy. */ - if (display) - { - /* When doing the 'block' algorithm the pixel in the pass gets - * replicated to adjacent pixels. This is why the even (0,2,4,6) - * passes are skipped above - the entire expanded row is copied. - */ - bytes_to_copy = (1<<((6-pass)>>1)) * pixel_depth; - - /* But don't allow this number to exceed the actual row width. */ - if (bytes_to_copy > row_width) - bytes_to_copy = row_width; - } - - else /* normal row; Adam7 only ever gives us one pixel to copy. */ - bytes_to_copy = pixel_depth; - - /* In Adam7 there is a constant offset between where the pixels go. */ - bytes_to_jump = PNG_PASS_COL_OFFSET(pass) * pixel_depth; - - /* And simply copy these bytes. Some optimization is possible here, - * depending on the value of 'bytes_to_copy'. Special case the low - * byte counts, which we know to be frequent. - * - * Notice that these cases all 'return' rather than 'break' - this - * avoids an unnecessary test on whether to restore the last byte - * below. - */ - switch (bytes_to_copy) - { - case 1: - for (;;) - { - *dp = *sp; - - if (row_width <= bytes_to_jump) - return; - - dp += bytes_to_jump; - sp += bytes_to_jump; - row_width -= bytes_to_jump; - } - - case 2: - /* There is a possibility of a partial copy at the end here; this - * slows the code down somewhat. - */ - do - { - dp[0] = sp[0], dp[1] = sp[1]; - - if (row_width <= bytes_to_jump) - return; - - sp += bytes_to_jump; - dp += bytes_to_jump; - row_width -= bytes_to_jump; - } - while (row_width > 1); - - /* And there can only be one byte left at this point: */ - *dp = *sp; - return; - - case 3: - /* This can only be the RGB case, so each copy is exactly one - * pixel and it is not necessary to check for a partial copy. - */ - for(;;) - { - dp[0] = sp[0], dp[1] = sp[1], dp[2] = sp[2]; - - if (row_width <= bytes_to_jump) - return; - - sp += bytes_to_jump; - dp += bytes_to_jump; - row_width -= bytes_to_jump; - } - - default: -#if PNG_ALIGN_TYPE != PNG_ALIGN_NONE - /* Check for double byte alignment and, if possible, use a - * 16-bit copy. Don't attempt this for narrow images - ones that - * are less than an interlace panel wide. Don't attempt it for - * wide bytes_to_copy either - use the memcpy there. - */ - if (bytes_to_copy < 16 /*else use memcpy*/ && - png_isaligned(dp, png_uint_16) && - png_isaligned(sp, png_uint_16) && - bytes_to_copy % (sizeof (png_uint_16)) == 0 && - bytes_to_jump % (sizeof (png_uint_16)) == 0) - { - /* Everything is aligned for png_uint_16 copies, but try for - * png_uint_32 first. - */ - if (png_isaligned(dp, png_uint_32) && - png_isaligned(sp, png_uint_32) && - bytes_to_copy % (sizeof (png_uint_32)) == 0 && - bytes_to_jump % (sizeof (png_uint_32)) == 0) - { - png_uint_32p dp32 = png_aligncast(png_uint_32p,dp); - png_const_uint_32p sp32 = png_aligncastconst( - png_const_uint_32p, sp); - size_t skip = (bytes_to_jump-bytes_to_copy) / - (sizeof (png_uint_32)); - - do - { - size_t c = bytes_to_copy; - do - { - *dp32++ = *sp32++; - c -= (sizeof (png_uint_32)); - } - while (c > 0); - - if (row_width <= bytes_to_jump) - return; - - dp32 += skip; - sp32 += skip; - row_width -= bytes_to_jump; - } - while (bytes_to_copy <= row_width); - - /* Get to here when the row_width truncates the final copy. - * There will be 1-3 bytes left to copy, so don't try the - * 16-bit loop below. - */ - dp = (png_bytep)dp32; - sp = (png_const_bytep)sp32; - do - *dp++ = *sp++; - while (--row_width > 0); - return; - } - - /* Else do it in 16-bit quantities, but only if the size is - * not too large. - */ - else - { - png_uint_16p dp16 = png_aligncast(png_uint_16p, dp); - png_const_uint_16p sp16 = png_aligncastconst( - png_const_uint_16p, sp); - size_t skip = (bytes_to_jump-bytes_to_copy) / - (sizeof (png_uint_16)); - - do - { - size_t c = bytes_to_copy; - do - { - *dp16++ = *sp16++; - c -= (sizeof (png_uint_16)); - } - while (c > 0); - - if (row_width <= bytes_to_jump) - return; - - dp16 += skip; - sp16 += skip; - row_width -= bytes_to_jump; - } - while (bytes_to_copy <= row_width); - - /* End of row - 1 byte left, bytes_to_copy > row_width: */ - dp = (png_bytep)dp16; - sp = (png_const_bytep)sp16; - do - *dp++ = *sp++; - while (--row_width > 0); - return; - } - } -#endif /* PNG_ALIGN_ code */ - - /* The true default - use a memcpy: */ - for (;;) - { - memcpy(dp, sp, bytes_to_copy); - - if (row_width <= bytes_to_jump) - return; - - sp += bytes_to_jump; - dp += bytes_to_jump; - row_width -= bytes_to_jump; - if (bytes_to_copy > row_width) - bytes_to_copy = row_width; - } - } - - /* NOT REACHED*/ - } /* pixel_depth >= 8 */ - - /* Here if pixel_depth < 8 to check 'end_ptr' below. */ - } - else -#endif - - /* If here then the switch above wasn't used so just memcpy the whole row - * from the temporary row buffer (notice that this overwrites the end of the - * destination row if it is a partial byte.) - */ - memcpy(dp, sp, PNG_ROWBYTES(pixel_depth, row_width)); - - /* Restore the overwritten bits from the last byte if necessary. */ - if (end_ptr != NULL) - *end_ptr = (png_byte)((end_byte & end_mask) | (*end_ptr & ~end_mask)); -} - -#ifdef PNG_READ_INTERLACING_SUPPORTED -void /* PRIVATE */ -png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, - png_uint_32 transformations /* Because these may affect the byte layout */) -{ - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - /* Offset to next interlace block */ - static PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - png_debug(1, "in png_do_read_interlace"); - if (row != NULL && row_info != NULL) - { - png_uint_32 final_width; - - final_width = row_info->width * png_pass_inc[pass]; - - switch (row_info->pixel_depth) - { - case 1: - { - png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3); - png_bytep dp = row + (png_size_t)((final_width - 1) >> 3); - int sshift, dshift; - int s_start, s_end, s_inc; - int jstop = png_pass_inc[pass]; - png_byte v; - png_uint_32 i; - int j; - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (transformations & PNG_PACKSWAP) - { - sshift = (int)((row_info->width + 7) & 0x07); - dshift = (int)((final_width + 7) & 0x07); - s_start = 7; - s_end = 0; - s_inc = -1; - } - - else -#endif - { - sshift = 7 - (int)((row_info->width + 7) & 0x07); - dshift = 7 - (int)((final_width + 7) & 0x07); - s_start = 0; - s_end = 7; - s_inc = 1; - } - - for (i = 0; i < row_info->width; i++) - { - v = (png_byte)((*sp >> sshift) & 0x01); - for (j = 0; j < jstop; j++) - { - unsigned int tmp = *dp & (0x7f7f >> (7 - dshift)); - tmp |= v << dshift; - *dp = (png_byte)(tmp & 0xff); - - if (dshift == s_end) - { - dshift = s_start; - dp--; - } - - else - dshift += s_inc; - } - - if (sshift == s_end) - { - sshift = s_start; - sp--; - } - - else - sshift += s_inc; - } - break; - } - - case 2: - { - png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2); - png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2); - int sshift, dshift; - int s_start, s_end, s_inc; - int jstop = png_pass_inc[pass]; - png_uint_32 i; - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (transformations & PNG_PACKSWAP) - { - sshift = (int)(((row_info->width + 3) & 0x03) << 1); - dshift = (int)(((final_width + 3) & 0x03) << 1); - s_start = 6; - s_end = 0; - s_inc = -2; - } - - else -#endif - { - sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1); - dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1); - s_start = 0; - s_end = 6; - s_inc = 2; - } - - for (i = 0; i < row_info->width; i++) - { - png_byte v; - int j; - - v = (png_byte)((*sp >> sshift) & 0x03); - for (j = 0; j < jstop; j++) - { - unsigned int tmp = *dp & (0x3f3f >> (6 - dshift)); - tmp |= v << dshift; - *dp = (png_byte)(tmp & 0xff); - - if (dshift == s_end) - { - dshift = s_start; - dp--; - } - - else - dshift += s_inc; - } - - if (sshift == s_end) - { - sshift = s_start; - sp--; - } - - else - sshift += s_inc; - } - break; - } - - case 4: - { - png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1); - png_bytep dp = row + (png_size_t)((final_width - 1) >> 1); - int sshift, dshift; - int s_start, s_end, s_inc; - png_uint_32 i; - int jstop = png_pass_inc[pass]; - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (transformations & PNG_PACKSWAP) - { - sshift = (int)(((row_info->width + 1) & 0x01) << 2); - dshift = (int)(((final_width + 1) & 0x01) << 2); - s_start = 4; - s_end = 0; - s_inc = -4; - } - - else -#endif - { - sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2); - dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2); - s_start = 0; - s_end = 4; - s_inc = 4; - } - - for (i = 0; i < row_info->width; i++) - { - png_byte v = (png_byte)((*sp >> sshift) & 0x0f); - int j; - - for (j = 0; j < jstop; j++) - { - unsigned int tmp = *dp & (0xf0f >> (4 - dshift)); - tmp |= v << dshift; - *dp = (png_byte)(tmp & 0xff); - - if (dshift == s_end) - { - dshift = s_start; - dp--; - } - - else - dshift += s_inc; - } - - if (sshift == s_end) - { - sshift = s_start; - sp--; - } - - else - sshift += s_inc; - } - break; - } - - default: - { - png_size_t pixel_bytes = (row_info->pixel_depth >> 3); - - png_bytep sp = row + (png_size_t)(row_info->width - 1) - * pixel_bytes; - - png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes; - - int jstop = png_pass_inc[pass]; - png_uint_32 i; - - for (i = 0; i < row_info->width; i++) - { - png_byte v[8]; - int j; - - memcpy(v, sp, pixel_bytes); - - for (j = 0; j < jstop; j++) - { - memcpy(dp, v, pixel_bytes); - dp -= pixel_bytes; - } - - sp -= pixel_bytes; - } - break; - } - } - - row_info->width = final_width; - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width); - } -#ifndef PNG_READ_PACKSWAP_SUPPORTED - PNG_UNUSED(transformations) /* Silence compiler warning */ -#endif -} -#endif /* PNG_READ_INTERLACING_SUPPORTED */ - -static void -png_read_filter_row_sub(png_row_infop row_info, png_bytep row, - png_const_bytep prev_row) -{ - png_size_t i; - png_size_t istop = row_info->rowbytes; - unsigned int bpp = (row_info->pixel_depth + 7) >> 3; - png_bytep rp = row + bpp; - - PNG_UNUSED(prev_row) - - for (i = bpp; i < istop; i++) - { - *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff); - rp++; - } -} - -static void -png_read_filter_row_up(png_row_infop row_info, png_bytep row, - png_const_bytep prev_row) -{ - png_size_t i; - png_size_t istop = row_info->rowbytes; - png_bytep rp = row; - png_const_bytep pp = prev_row; - - for (i = 0; i < istop; i++) - { - *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); - rp++; - } -} - -static void -png_read_filter_row_avg(png_row_infop row_info, png_bytep row, - png_const_bytep prev_row) -{ - png_size_t i; - png_bytep rp = row; - png_const_bytep pp = prev_row; - unsigned int bpp = (row_info->pixel_depth + 7) >> 3; - png_size_t istop = row_info->rowbytes - bpp; - - for (i = 0; i < bpp; i++) - { - *rp = (png_byte)(((int)(*rp) + - ((int)(*pp++) / 2 )) & 0xff); - - rp++; - } - - for (i = 0; i < istop; i++) - { - *rp = (png_byte)(((int)(*rp) + - (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff); - - rp++; - } -} - -static void -png_read_filter_row_paeth_1byte_pixel(png_row_infop row_info, png_bytep row, - png_const_bytep prev_row) -{ - png_bytep rp_end = row + row_info->rowbytes; - int a, c; - - /* First pixel/byte */ - c = *prev_row++; - a = *row + c; - *row++ = (png_byte)a; - - /* Remainder */ - while (row < rp_end) - { - int b, pa, pb, pc, p; - - a &= 0xff; /* From previous iteration or start */ - b = *prev_row++; - - p = b - c; - pc = a - c; - -# ifdef PNG_USE_ABS - pa = abs(p); - pb = abs(pc); - pc = abs(p + pc); -# else - pa = p < 0 ? -p : p; - pb = pc < 0 ? -pc : pc; - pc = (p + pc) < 0 ? -(p + pc) : p + pc; -# endif - - /* Find the best predictor, the least of pa, pb, pc favoring the earlier - * ones in the case of a tie. - */ - if (pb < pa) pa = pb, a = b; - if (pc < pa) a = c; - - /* Calculate the current pixel in a, and move the previous row pixel to c - * for the next time round the loop - */ - c = b; - a += *row; - *row++ = (png_byte)a; - } -} - -static void -png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row, - png_const_bytep prev_row) -{ - int bpp = (row_info->pixel_depth + 7) >> 3; - png_bytep rp_end = row + bpp; - - /* Process the first pixel in the row completely (this is the same as 'up' - * because there is only one candidate predictor for the first row). - */ - while (row < rp_end) - { - int a = *row + *prev_row++; - *row++ = (png_byte)a; - } - - /* Remainder */ - rp_end += row_info->rowbytes - bpp; - - while (row < rp_end) - { - int a, b, c, pa, pb, pc, p; - - c = *(prev_row - bpp); - a = *(row - bpp); - b = *prev_row++; - - p = b - c; - pc = a - c; - -# ifdef PNG_USE_ABS - pa = abs(p); - pb = abs(pc); - pc = abs(p + pc); -# else - pa = p < 0 ? -p : p; - pb = pc < 0 ? -pc : pc; - pc = (p + pc) < 0 ? -(p + pc) : p + pc; -# endif - - if (pb < pa) pa = pb, a = b; - if (pc < pa) a = c; - - //c = b; - a += *row; - *row++ = (png_byte)a; - } -} - -static void -png_init_filter_functions(png_structrp pp) - /* This function is called once for every PNG image to set the - * implementations required to reverse the filtering of PNG rows. Reversing - * the filter is the first transformation performed on the row data. It is - * performed in place, therefore an implementation can be selected based on - * the image pixel format. If the implementation depends on image width then - * take care to ensure that it works corretly if the image is interlaced - - * interlacing causes the actual row width to vary. - */ -{ - unsigned int bpp = (pp->pixel_depth + 7) >> 3; - - pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub; - pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up; - pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg; - if (bpp == 1) - pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = - png_read_filter_row_paeth_1byte_pixel; - else - pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = - png_read_filter_row_paeth_multibyte_pixel; - -#ifdef PNG_FILTER_OPTIMIZATIONS - /* To use this define PNG_FILTER_OPTIMIZATIONS as the name of a function to - * call to install hardware optimizations for the above functions; simply - * replace whatever elements of the pp->read_filter[] array with a hardware - * specific (or, for that matter, generic) optimization. - * - * To see an example of this examine what configure.ac does when - * --enable-arm-neon is specified on the command line. - */ - PNG_FILTER_OPTIMIZATIONS(pp, bpp); -#endif -} - -void /* PRIVATE */ -png_read_filter_row(png_structrp pp, png_row_infop row_info, png_bytep row, - png_const_bytep prev_row, int filter) -{ - /* OPTIMIZATION: DO NOT MODIFY THIS FUNCTION, instead #define - * PNG_FILTER_OPTIMIZATIONS to a function that overrides the generic - * implementations. See png_init_filter_functions above. - */ - if (pp->read_filter[0] == NULL) - png_init_filter_functions(pp); - if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST) - pp->read_filter[filter-1](row_info, row, prev_row); -} - -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -void /* PRIVATE */ -png_read_IDAT_data(png_structrp png_ptr, png_bytep output, - png_alloc_size_t avail_out) -{ - /* Loop reading IDATs and decompressing the result into output[avail_out] */ - png_ptr->zstream.next_out = output; - png_ptr->zstream.avail_out = 0; /* safety: set below */ - - if (output == NULL) - avail_out = 0; - - do - { - int ret; - png_byte tmpbuf[PNG_INFLATE_BUF_SIZE]; - - if (png_ptr->zstream.avail_in == 0) - { - uInt avail_in; - png_bytep buffer; - - while (png_ptr->idat_size == 0) - { - png_crc_finish(png_ptr, 0); - - png_ptr->idat_size = png_read_chunk_header(png_ptr); - /* This is an error even in the 'check' case because the code just - * consumed a non-IDAT header. - */ - if (png_ptr->chunk_name != png_IDAT) - png_error(png_ptr, "Not enough image data"); - } - - avail_in = png_ptr->IDAT_read_size; - - if (avail_in > png_ptr->idat_size) - avail_in = (uInt)png_ptr->idat_size; - - /* A PNG with a gradually increasing IDAT size will defeat this attempt - * to minimize memory usage by causing lots of re-allocs, but - * realistically doing IDAT_read_size re-allocs is not likely to be a - * big problem. - */ - buffer = png_read_buffer(png_ptr, avail_in, 0/*error*/); - - png_crc_read(png_ptr, buffer, avail_in); - png_ptr->idat_size -= avail_in; - - png_ptr->zstream.next_in = buffer; - png_ptr->zstream.avail_in = avail_in; - } - - /* And set up the output side. */ - if (output != NULL) /* standard read */ - { - uInt out = ZLIB_IO_MAX; - - if (out > avail_out) - out = (uInt)avail_out; - - avail_out -= out; - png_ptr->zstream.avail_out = out; - } - - else /* check for end */ - { - png_ptr->zstream.next_out = tmpbuf; - png_ptr->zstream.avail_out = (sizeof tmpbuf); - } - - /* Use NO_FLUSH; this gives zlib the maximum opportunity to optimize the - * process. If the LZ stream is truncated the sequential reader will - * terminally damage the stream, above, by reading the chunk header of the - * following chunk (it then exits with png_error). - * - * TODO: deal more elegantly with truncated IDAT lists. - */ - ret = inflate(&png_ptr->zstream, Z_NO_FLUSH); - - /* Take the unconsumed output back (so, in the 'check' case this just - * counts up). - */ - avail_out += png_ptr->zstream.avail_out; - png_ptr->zstream.avail_out = 0; - - if (ret == Z_STREAM_END) - { - /* Do this for safety; we won't read any more into this row. */ - png_ptr->zstream.next_out = NULL; - - png_ptr->mode |= PNG_AFTER_IDAT; - png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; - - if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0) - png_chunk_benign_error(png_ptr, "Extra compressed data"); - break; - } - - if (ret != Z_OK) - { - png_zstream_error(png_ptr, ret); - - if (output != NULL) - png_chunk_error(png_ptr, png_ptr->zstream.msg); - - else /* checking */ - { - png_chunk_benign_error(png_ptr, png_ptr->zstream.msg); - return; - } - } - } while (avail_out > 0); - - if (avail_out > 0) - { - /* The stream ended before the image; this is the same as too few IDATs so - * should be handled the same way. - */ - if (output != NULL) - png_error(png_ptr, "Not enough image data"); - - else /* checking */ - png_chunk_benign_error(png_ptr, "Too much image data"); - } -} - -void /* PRIVATE */ -png_read_finish_IDAT(png_structrp png_ptr) -{ - /* We don't need any more data and the stream should have ended, however the - * LZ end code may actually not have been processed. In this case we must - * read it otherwise stray unread IDAT data or, more likely, an IDAT chunk - * may still remain to be consumed. - */ - if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) - { - /* The NULL causes png_read_IDAT_data to swallow any remaining bytes in - * the compressed stream, but the stream may be damaged too, so even after - * this call we may need to terminate the zstream ownership. - */ - png_read_IDAT_data(png_ptr, NULL, 0); - png_ptr->zstream.next_out = NULL; /* safety */ - - /* Now clear everything out for safety; the following may not have been - * done. - */ - if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) - { - png_ptr->mode |= PNG_AFTER_IDAT; - png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; - } - } - - /* If the zstream has not been released do it now *and* terminate the reading - * of the final IDAT chunk. - */ - if (png_ptr->zowner == png_IDAT) - { - /* Always do this; the pointers otherwise point into the read buffer. */ - png_ptr->zstream.next_in = NULL; - png_ptr->zstream.avail_in = 0; - - /* Now we no longer own the zstream. */ - png_ptr->zowner = 0; - - /* The slightly weird semantics of the sequential IDAT reading is that we - * are always in or at the end of an IDAT chunk, so we always need to do a - * crc_finish here. If idat_size is non-zero we also need to read the - * spurious bytes at the end of the chunk now. - */ - (void)png_crc_finish(png_ptr, png_ptr->idat_size); - } -} - -void /* PRIVATE */ -png_read_finish_row(png_structrp png_ptr) -{ -#ifdef PNG_READ_INTERLACING_SUPPORTED - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif /* PNG_READ_INTERLACING_SUPPORTED */ - - png_debug(1, "in png_read_finish_row"); - png_ptr->row_number++; - if (png_ptr->row_number < png_ptr->num_rows) - return; - -#ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced) - { - png_ptr->row_number = 0; - - /* TO DO: don't do this if prev_row isn't needed (requires - * read-ahead of the next row's filter byte. - */ - memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); - - do - { - png_ptr->pass++; - - if (png_ptr->pass >= 7) - break; - - png_ptr->iwidth = (png_ptr->width + - png_pass_inc[png_ptr->pass] - 1 - - png_pass_start[png_ptr->pass]) / - png_pass_inc[png_ptr->pass]; - - if (!(png_ptr->transformations & PNG_INTERLACE)) - { - png_ptr->num_rows = (png_ptr->height + - png_pass_yinc[png_ptr->pass] - 1 - - png_pass_ystart[png_ptr->pass]) / - png_pass_yinc[png_ptr->pass]; - } - - else /* if (png_ptr->transformations & PNG_INTERLACE) */ - break; /* libpng deinterlacing sees every row */ - - } while (png_ptr->num_rows == 0 || png_ptr->iwidth == 0); - - if (png_ptr->pass < 7) - return; - } -#endif /* PNG_READ_INTERLACING_SUPPORTED */ - - /* Here after at the end of the last row of the last pass. */ - png_read_finish_IDAT(png_ptr); -} -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ - -void /* PRIVATE */ -png_read_start_row(png_structrp png_ptr) -{ -#ifdef PNG_READ_INTERLACING_SUPPORTED - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif - - int max_pixel_depth; - png_size_t row_bytes; - - png_debug(1, "in png_read_start_row"); - -#ifdef PNG_READ_TRANSFORMS_SUPPORTED - png_init_read_transformations(png_ptr); -#endif -#ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced) - { - if (!(png_ptr->transformations & PNG_INTERLACE)) - png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - - png_pass_ystart[0]) / png_pass_yinc[0]; - - else - png_ptr->num_rows = png_ptr->height; - - png_ptr->iwidth = (png_ptr->width + - png_pass_inc[png_ptr->pass] - 1 - - png_pass_start[png_ptr->pass]) / - png_pass_inc[png_ptr->pass]; - } - - else -#endif /* PNG_READ_INTERLACING_SUPPORTED */ - { - png_ptr->num_rows = png_ptr->height; - png_ptr->iwidth = png_ptr->width; - } - - max_pixel_depth = png_ptr->pixel_depth; - - /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpliar set of - * calculations to calculate the final pixel depth, then - * png_do_read_transforms actually does the transforms. This means that the - * code which effectively calculates this value is actually repeated in three - * separate places. They must all match. Innocent changes to the order of - * transformations can and will break libpng in a way that causes memory - * overwrites. - * - * TODO: fix this. - */ -#ifdef PNG_READ_PACK_SUPPORTED - if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8) - max_pixel_depth = 8; -#endif - -#ifdef PNG_READ_EXPAND_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND) - { - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - if (png_ptr->num_trans) - max_pixel_depth = 32; - - else - max_pixel_depth = 24; - } - - else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) - { - if (max_pixel_depth < 8) - max_pixel_depth = 8; - - if (png_ptr->num_trans) - max_pixel_depth *= 2; - } - - else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) - { - if (png_ptr->num_trans) - { - max_pixel_depth *= 4; - max_pixel_depth /= 3; - } - } - } -#endif - -#ifdef PNG_READ_EXPAND_16_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND_16) - { -# ifdef PNG_READ_EXPAND_SUPPORTED - /* In fact it is an error if it isn't supported, but checking is - * the safe way. - */ - if (png_ptr->transformations & PNG_EXPAND) - { - if (png_ptr->bit_depth < 16) - max_pixel_depth *= 2; - } - else -# endif - png_ptr->transformations &= ~PNG_EXPAND_16; - } -#endif - -#ifdef PNG_READ_FILLER_SUPPORTED - if (png_ptr->transformations & (PNG_FILLER)) - { - if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) - { - if (max_pixel_depth <= 8) - max_pixel_depth = 16; - - else - max_pixel_depth = 32; - } - - else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB || - png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - if (max_pixel_depth <= 32) - max_pixel_depth = 32; - - else - max_pixel_depth = 64; - } - } -#endif - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - if (png_ptr->transformations & PNG_GRAY_TO_RGB) - { - if ( -#ifdef PNG_READ_EXPAND_SUPPORTED - (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) || -#endif -#ifdef PNG_READ_FILLER_SUPPORTED - (png_ptr->transformations & (PNG_FILLER)) || -#endif - png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - if (max_pixel_depth <= 16) - max_pixel_depth = 32; - - else - max_pixel_depth = 64; - } - - else - { - if (max_pixel_depth <= 8) - { - if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - max_pixel_depth = 32; - - else - max_pixel_depth = 24; - } - - else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - max_pixel_depth = 64; - - else - max_pixel_depth = 48; - } - } -#endif - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \ -defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) - if (png_ptr->transformations & PNG_USER_TRANSFORM) - { - int user_pixel_depth = png_ptr->user_transform_depth * - png_ptr->user_transform_channels; - - if (user_pixel_depth > max_pixel_depth) - max_pixel_depth = user_pixel_depth; - } -#endif - - /* This value is stored in png_struct and double checked in the row read - * code. - */ - png_ptr->maximum_pixel_depth = (png_byte)max_pixel_depth; - png_ptr->transformed_pixel_depth = 0; /* calculated on demand */ - - /* Align the width on the next larger 8 pixels. Mainly used - * for interlacing - */ - row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7)); - /* Calculate the maximum bytes needed, adding a byte and a pixel - * for safety's sake - */ - row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) + - 1 + ((max_pixel_depth + 7) >> 3); - -#ifdef PNG_MAX_MALLOC_64K - if (row_bytes > (png_uint_32)65536L) - png_error(png_ptr, "This image requires a row greater than 64KB"); -#endif - - if (row_bytes + 48 > png_ptr->old_big_row_buf_size) - { - png_free(png_ptr, png_ptr->big_row_buf); - png_free(png_ptr, png_ptr->big_prev_row); - - if (png_ptr->interlaced) - png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr, - row_bytes + 48); - - else - png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes + 48); - - png_ptr->big_prev_row = (png_bytep)png_malloc(png_ptr, row_bytes + 48); - -#ifdef PNG_ALIGNED_MEMORY_SUPPORTED - /* Use 16-byte aligned memory for row_buf with at least 16 bytes - * of padding before and after row_buf; treat prev_row similarly. - * NOTE: the alignment is to the start of the pixels, one beyond the start - * of the buffer, because of the filter byte. Prior to libpng 1.5.6 this - * was incorrect; the filter byte was aligned, which had the exact - * opposite effect of that intended. - */ - { - png_bytep temp = png_ptr->big_row_buf + 32; - int extra = (int)((temp - (png_bytep)0) & 0x0f); - png_ptr->row_buf = temp - extra - 1/*filter byte*/; - - temp = png_ptr->big_prev_row + 32; - extra = (int)((temp - (png_bytep)0) & 0x0f); - png_ptr->prev_row = temp - extra - 1/*filter byte*/; - } - -#else - /* Use 31 bytes of padding before and 17 bytes after row_buf. */ - png_ptr->row_buf = png_ptr->big_row_buf + 31; - png_ptr->prev_row = png_ptr->big_prev_row + 31; -#endif - png_ptr->old_big_row_buf_size = row_bytes + 48; - } - -#ifdef PNG_MAX_MALLOC_64K - if (png_ptr->rowbytes > 65535) - png_error(png_ptr, "This image requires a row greater than 64KB"); - -#endif - if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1)) - png_error(png_ptr, "Row has too many bytes to allocate in memory"); - - memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); - - png_debug1(3, "width = %u,", png_ptr->width); - png_debug1(3, "height = %u,", png_ptr->height); - png_debug1(3, "iwidth = %u,", png_ptr->iwidth); - png_debug1(3, "num_rows = %u,", png_ptr->num_rows); - png_debug1(3, "rowbytes = %lu,", (unsigned long)png_ptr->rowbytes); - png_debug1(3, "irowbytes = %lu", - (unsigned long)PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1); - - /* The sequential reader needs a buffer for IDAT, but the progressive reader - * does not, so free the read buffer now regardless; the sequential reader - * reallocates it on demand. - */ - if (png_ptr->read_buffer) - { - png_bytep buffer = png_ptr->read_buffer; - - png_ptr->read_buffer_size = 0; - png_ptr->read_buffer = NULL; - png_free(png_ptr, buffer); - } - - /* Finally claim the zstream for the inflate of the IDAT data, use the bits - * value from the stream (note that this will result in a fatal error if the - * IDAT stream has a bogus deflate header window_bits value, but this should - * not be happening any longer!) - */ - if (png_inflate_claim(png_ptr, png_IDAT, 0) != Z_OK) - png_error(png_ptr, png_ptr->zstream.msg); - - png_ptr->flags |= PNG_FLAG_ROW_INIT; -} -#endif /* PNG_READ_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pngset.c b/source/modules/juce_graphics/image_formats/pnglib/pngset.c deleted file mode 100644 index a1b9d4967..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pngset.c +++ /dev/null @@ -1,1606 +0,0 @@ - -/* pngset.c - storage of image information into info struct - * - * Last changed in libpng 1.6.1 [March 28, 2013] - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * The functions here are used during reads to store data from the file - * into the info struct, and during writes to store application data - * into the info struct for writing into the file. This abstracts the - * info struct and allows us to change the structure in the future. - */ - -#include "pngpriv.h" - -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) - -#ifdef PNG_bKGD_SUPPORTED -void PNGAPI -png_set_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, - png_const_color_16p background) -{ - png_debug1(1, "in %s storage function", "bKGD"); - - if (png_ptr == NULL || info_ptr == NULL || background == NULL) - return; - - info_ptr->background = *background; - info_ptr->valid |= PNG_INFO_bKGD; -} -#endif - -#ifdef PNG_cHRM_SUPPORTED -void PNGFAPI -png_set_cHRM_fixed(png_const_structrp png_ptr, png_inforp info_ptr, - png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, - png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, - png_fixed_point blue_x, png_fixed_point blue_y) -{ - png_xy xy; - - png_debug1(1, "in %s storage function", "cHRM fixed"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - xy.redx = red_x; - xy.redy = red_y; - xy.greenx = green_x; - xy.greeny = green_y; - xy.bluex = blue_x; - xy.bluey = blue_y; - xy.whitex = white_x; - xy.whitey = white_y; - - if (png_colorspace_set_chromaticities(png_ptr, &info_ptr->colorspace, &xy, - 2/* override with app values*/)) - info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; - - png_colorspace_sync_info(png_ptr, info_ptr); -} - -void PNGFAPI -png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr, - png_fixed_point int_red_X, png_fixed_point int_red_Y, - png_fixed_point int_red_Z, png_fixed_point int_green_X, - png_fixed_point int_green_Y, png_fixed_point int_green_Z, - png_fixed_point int_blue_X, png_fixed_point int_blue_Y, - png_fixed_point int_blue_Z) -{ - png_XYZ XYZ; - - png_debug1(1, "in %s storage function", "cHRM XYZ fixed"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - XYZ.red_X = int_red_X; - XYZ.red_Y = int_red_Y; - XYZ.red_Z = int_red_Z; - XYZ.green_X = int_green_X; - XYZ.green_Y = int_green_Y; - XYZ.green_Z = int_green_Z; - XYZ.blue_X = int_blue_X; - XYZ.blue_Y = int_blue_Y; - XYZ.blue_Z = int_blue_Z; - - if (png_colorspace_set_endpoints(png_ptr, &info_ptr->colorspace, &XYZ, 2)) - info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; - - png_colorspace_sync_info(png_ptr, info_ptr); -} - -# ifdef PNG_FLOATING_POINT_SUPPORTED -void PNGAPI -png_set_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, - double white_x, double white_y, double red_x, double red_y, - double green_x, double green_y, double blue_x, double blue_y) -{ - png_set_cHRM_fixed(png_ptr, info_ptr, - png_fixed(png_ptr, white_x, "cHRM White X"), - png_fixed(png_ptr, white_y, "cHRM White Y"), - png_fixed(png_ptr, red_x, "cHRM Red X"), - png_fixed(png_ptr, red_y, "cHRM Red Y"), - png_fixed(png_ptr, green_x, "cHRM Green X"), - png_fixed(png_ptr, green_y, "cHRM Green Y"), - png_fixed(png_ptr, blue_x, "cHRM Blue X"), - png_fixed(png_ptr, blue_y, "cHRM Blue Y")); -} - -void PNGAPI -png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X, - double red_Y, double red_Z, double green_X, double green_Y, double green_Z, - double blue_X, double blue_Y, double blue_Z) -{ - png_set_cHRM_XYZ_fixed(png_ptr, info_ptr, - png_fixed(png_ptr, red_X, "cHRM Red X"), - png_fixed(png_ptr, red_Y, "cHRM Red Y"), - png_fixed(png_ptr, red_Z, "cHRM Red Z"), - png_fixed(png_ptr, green_X, "cHRM Red X"), - png_fixed(png_ptr, green_Y, "cHRM Red Y"), - png_fixed(png_ptr, green_Z, "cHRM Red Z"), - png_fixed(png_ptr, blue_X, "cHRM Red X"), - png_fixed(png_ptr, blue_Y, "cHRM Red Y"), - png_fixed(png_ptr, blue_Z, "cHRM Red Z")); -} -# endif /* PNG_FLOATING_POINT_SUPPORTED */ - -#endif /* PNG_cHRM_SUPPORTED */ - -#ifdef PNG_gAMA_SUPPORTED -void PNGFAPI -png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr, - png_fixed_point file_gamma) -{ - png_debug1(1, "in %s storage function", "gAMA"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma); - png_colorspace_sync_info(png_ptr, info_ptr); -} - -# ifdef PNG_FLOATING_POINT_SUPPORTED -void PNGAPI -png_set_gAMA(png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma) -{ - png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma, - "png_set_gAMA")); -} -# endif -#endif - -#ifdef PNG_hIST_SUPPORTED -void PNGAPI -png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr, - png_const_uint_16p hist) -{ - int i; - - png_debug1(1, "in %s storage function", "hIST"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - if (info_ptr->num_palette == 0 || info_ptr->num_palette - > PNG_MAX_PALETTE_LENGTH) - { - png_warning(png_ptr, - "Invalid palette size, hIST allocation skipped"); - - return; - } - - png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0); - - /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in - * version 1.2.1 - */ - info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr, - PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16)))); - - if (info_ptr->hist == NULL) - { - png_warning(png_ptr, "Insufficient memory for hIST chunk data"); - return; - } - - info_ptr->free_me |= PNG_FREE_HIST; - - for (i = 0; i < info_ptr->num_palette; i++) - info_ptr->hist[i] = hist[i]; - - info_ptr->valid |= PNG_INFO_hIST; -} -#endif - -void PNGAPI -png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr, - png_uint_32 width, png_uint_32 height, int bit_depth, - int color_type, int interlace_type, int compression_type, - int filter_type) -{ - png_debug1(1, "in %s storage function", "IHDR"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - info_ptr->width = width; - info_ptr->height = height; - info_ptr->bit_depth = (png_byte)bit_depth; - info_ptr->color_type = (png_byte)color_type; - info_ptr->compression_type = (png_byte)compression_type; - info_ptr->filter_type = (png_byte)filter_type; - info_ptr->interlace_type = (png_byte)interlace_type; - - png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height, - info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, - info_ptr->compression_type, info_ptr->filter_type); - - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - info_ptr->channels = 1; - - else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) - info_ptr->channels = 3; - - else - info_ptr->channels = 1; - - if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) - info_ptr->channels++; - - info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); - - /* Check for potential overflow */ - if (width > - (PNG_UINT_32_MAX >> 3) /* 8-byte RRGGBBAA pixels */ - - 48 /* bigrowbuf hack */ - - 1 /* filter byte */ - - 7*8 /* rounding of width to multiple of 8 pixels */ - - 8) /* extra max_pixel_depth pad */ - info_ptr->rowbytes = 0; - else - info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); -} - -#ifdef PNG_oFFs_SUPPORTED -void PNGAPI -png_set_oFFs(png_const_structrp png_ptr, png_inforp info_ptr, - png_int_32 offset_x, png_int_32 offset_y, int unit_type) -{ - png_debug1(1, "in %s storage function", "oFFs"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - info_ptr->x_offset = offset_x; - info_ptr->y_offset = offset_y; - info_ptr->offset_unit_type = (png_byte)unit_type; - info_ptr->valid |= PNG_INFO_oFFs; -} -#endif - -#ifdef PNG_pCAL_SUPPORTED -void PNGAPI -png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, - png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type, - int nparams, png_const_charp units, png_charpp params) -{ - png_size_t length; - int i; - - png_debug1(1, "in %s storage function", "pCAL"); - - if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL - || (nparams > 0 && params == NULL)) - return; - - length = strlen(purpose) + 1; - png_debug1(3, "allocating purpose for info (%lu bytes)", - (unsigned long)length); - - /* TODO: validate format of calibration name and unit name */ - - /* Check that the type matches the specification. */ - if (type < 0 || type > 3) - png_error(png_ptr, "Invalid pCAL equation type"); - - if (nparams < 0 || nparams > 255) - png_error(png_ptr, "Invalid pCAL parameter count"); - - /* Validate params[nparams] */ - for (i=0; ipcal_purpose = png_voidcast(png_charp, - png_malloc_warn(png_ptr, length)); - - if (info_ptr->pcal_purpose == NULL) - { - png_warning(png_ptr, "Insufficient memory for pCAL purpose"); - return; - } - - memcpy(info_ptr->pcal_purpose, purpose, length); - - png_debug(3, "storing X0, X1, type, and nparams in info"); - info_ptr->pcal_X0 = X0; - info_ptr->pcal_X1 = X1; - info_ptr->pcal_type = (png_byte)type; - info_ptr->pcal_nparams = (png_byte)nparams; - - length = strlen(units) + 1; - png_debug1(3, "allocating units for info (%lu bytes)", - (unsigned long)length); - - info_ptr->pcal_units = png_voidcast(png_charp, - png_malloc_warn(png_ptr, length)); - - if (info_ptr->pcal_units == NULL) - { - png_warning(png_ptr, "Insufficient memory for pCAL units"); - return; - } - - memcpy(info_ptr->pcal_units, units, length); - - info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, - (png_size_t)((nparams + 1) * (sizeof (png_charp))))); - - if (info_ptr->pcal_params == NULL) - { - png_warning(png_ptr, "Insufficient memory for pCAL params"); - return; - } - - memset(info_ptr->pcal_params, 0, (nparams + 1) * (sizeof (png_charp))); - - for (i = 0; i < nparams; i++) - { - length = strlen(params[i]) + 1; - png_debug2(3, "allocating parameter %d for info (%lu bytes)", i, - (unsigned long)length); - - info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length); - - if (info_ptr->pcal_params[i] == NULL) - { - png_warning(png_ptr, "Insufficient memory for pCAL parameter"); - return; - } - - memcpy(info_ptr->pcal_params[i], params[i], length); - } - - info_ptr->valid |= PNG_INFO_pCAL; - info_ptr->free_me |= PNG_FREE_PCAL; -} -#endif - -#ifdef PNG_sCAL_SUPPORTED -void PNGAPI -png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr, - int unit, png_const_charp swidth, png_const_charp sheight) -{ - png_size_t lengthw = 0, lengthh = 0; - - png_debug1(1, "in %s storage function", "sCAL"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - /* Double check the unit (should never get here with an invalid - * unit unless this is an API call.) - */ - if (unit != 1 && unit != 2) - png_error(png_ptr, "Invalid sCAL unit"); - - if (swidth == NULL || (lengthw = strlen(swidth)) == 0 || - swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw)) - png_error(png_ptr, "Invalid sCAL width"); - - if (sheight == NULL || (lengthh = strlen(sheight)) == 0 || - sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh)) - png_error(png_ptr, "Invalid sCAL height"); - - info_ptr->scal_unit = (png_byte)unit; - - ++lengthw; - - png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthw); - - info_ptr->scal_s_width = png_voidcast(png_charp, - png_malloc_warn(png_ptr, lengthw)); - - if (info_ptr->scal_s_width == NULL) - { - png_warning(png_ptr, "Memory allocation failed while processing sCAL"); - return; - } - - memcpy(info_ptr->scal_s_width, swidth, lengthw); - - ++lengthh; - - png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthh); - - info_ptr->scal_s_height = png_voidcast(png_charp, - png_malloc_warn(png_ptr, lengthh)); - - if (info_ptr->scal_s_height == NULL) - { - png_free (png_ptr, info_ptr->scal_s_width); - info_ptr->scal_s_width = NULL; - - png_warning(png_ptr, "Memory allocation failed while processing sCAL"); - return; - } - - memcpy(info_ptr->scal_s_height, sheight, lengthh); - - info_ptr->valid |= PNG_INFO_sCAL; - info_ptr->free_me |= PNG_FREE_SCAL; -} - -# ifdef PNG_FLOATING_POINT_SUPPORTED -void PNGAPI -png_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit, - double width, double height) -{ - png_debug1(1, "in %s storage function", "sCAL"); - - /* Check the arguments. */ - if (width <= 0) - png_warning(png_ptr, "Invalid sCAL width ignored"); - - else if (height <= 0) - png_warning(png_ptr, "Invalid sCAL height ignored"); - - else - { - /* Convert 'width' and 'height' to ASCII. */ - char swidth[PNG_sCAL_MAX_DIGITS+1]; - char sheight[PNG_sCAL_MAX_DIGITS+1]; - - png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width, - PNG_sCAL_PRECISION); - png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height, - PNG_sCAL_PRECISION); - - png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); - } -} -# endif - -# ifdef PNG_FIXED_POINT_SUPPORTED -void PNGAPI -png_set_sCAL_fixed(png_const_structrp png_ptr, png_inforp info_ptr, int unit, - png_fixed_point width, png_fixed_point height) -{ - png_debug1(1, "in %s storage function", "sCAL"); - - /* Check the arguments. */ - if (width <= 0) - png_warning(png_ptr, "Invalid sCAL width ignored"); - - else if (height <= 0) - png_warning(png_ptr, "Invalid sCAL height ignored"); - - else - { - /* Convert 'width' and 'height' to ASCII. */ - char swidth[PNG_sCAL_MAX_DIGITS+1]; - char sheight[PNG_sCAL_MAX_DIGITS+1]; - - png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width); - png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height); - - png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); - } -} -# endif -#endif - -#ifdef PNG_pHYs_SUPPORTED -void PNGAPI -png_set_pHYs(png_const_structrp png_ptr, png_inforp info_ptr, - png_uint_32 res_x, png_uint_32 res_y, int unit_type) -{ - png_debug1(1, "in %s storage function", "pHYs"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - info_ptr->x_pixels_per_unit = res_x; - info_ptr->y_pixels_per_unit = res_y; - info_ptr->phys_unit_type = (png_byte)unit_type; - info_ptr->valid |= PNG_INFO_pHYs; -} -#endif - -void PNGAPI -png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, - png_const_colorp palette, int num_palette) -{ - - png_debug1(1, "in %s storage function", "PLTE"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - if (num_palette < 0 || num_palette > PNG_MAX_PALETTE_LENGTH) - { - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - png_error(png_ptr, "Invalid palette length"); - - else - { - png_warning(png_ptr, "Invalid palette length"); - return; - } - } - - if ((num_palette > 0 && palette == NULL) || - (num_palette == 0 -# ifdef PNG_MNG_FEATURES_SUPPORTED - && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 -# endif - )) - { - png_chunk_report(png_ptr, "Invalid palette", PNG_CHUNK_ERROR); - return; - } - - /* It may not actually be necessary to set png_ptr->palette here; - * we do it for backward compatibility with the way the png_handle_tRNS - * function used to do the allocation. - * - * 1.6.0: the above statement appears to be incorrect; something has to set - * the palette inside png_struct on read. - */ - png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); - - /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead - * of num_palette entries, in case of an invalid PNG file that has - * too-large sample values. - */ - png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, - PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); - - if (num_palette > 0) - memcpy(png_ptr->palette, palette, num_palette * (sizeof (png_color))); - info_ptr->palette = png_ptr->palette; - info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; - - info_ptr->free_me |= PNG_FREE_PLTE; - - info_ptr->valid |= PNG_INFO_PLTE; -} - -#ifdef PNG_sBIT_SUPPORTED -void PNGAPI -png_set_sBIT(png_const_structrp png_ptr, png_inforp info_ptr, - png_const_color_8p sig_bit) -{ - png_debug1(1, "in %s storage function", "sBIT"); - - if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL) - return; - - info_ptr->sig_bit = *sig_bit; - info_ptr->valid |= PNG_INFO_sBIT; -} -#endif - -#ifdef PNG_sRGB_SUPPORTED -void PNGAPI -png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent) -{ - png_debug1(1, "in %s storage function", "sRGB"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent); - png_colorspace_sync_info(png_ptr, info_ptr); -} - -void PNGAPI -png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, - int srgb_intent) -{ - png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent)) - { - /* This causes the gAMA and cHRM to be written too */ - info_ptr->colorspace.flags |= - PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM; - } - - png_colorspace_sync_info(png_ptr, info_ptr); -} -#endif /* sRGB */ - - -#ifdef PNG_iCCP_SUPPORTED -void PNGAPI -png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, - png_const_charp name, int compression_type, - png_const_bytep profile, png_uint_32 proflen) -{ - png_charp new_iccp_name; - png_bytep new_iccp_profile; - png_size_t length; - - png_debug1(1, "in %s storage function", "iCCP"); - - if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL) - return; - - if (compression_type != PNG_COMPRESSION_TYPE_BASE) - png_app_error(png_ptr, "Invalid iCCP compression method"); - - /* Set the colorspace first because this validates the profile; do not - * override previously set app cHRM or gAMA here (because likely as not the - * application knows better than libpng what the correct values are.) Pass - * the info_ptr color_type field to png_colorspace_set_ICC because in the - * write case it has not yet been stored in png_ptr. - */ - { - int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name, - proflen, profile, info_ptr->color_type); - - png_colorspace_sync_info(png_ptr, info_ptr); - - /* Don't do any of the copying if the profile was bad, or inconsistent. */ - if (!result) - return; - - /* But do write the gAMA and cHRM chunks from the profile. */ - info_ptr->colorspace.flags |= - PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM; - } - - length = strlen(name)+1; - new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length)); - - if (new_iccp_name == NULL) - { - png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk"); - return; - } - - memcpy(new_iccp_name, name, length); - new_iccp_profile = png_voidcast(png_bytep, - png_malloc_warn(png_ptr, proflen)); - - if (new_iccp_profile == NULL) - { - png_free(png_ptr, new_iccp_name); - png_benign_error(png_ptr, - "Insufficient memory to process iCCP profile"); - return; - } - - memcpy(new_iccp_profile, profile, proflen); - - png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0); - - info_ptr->iccp_proflen = proflen; - info_ptr->iccp_name = new_iccp_name; - info_ptr->iccp_profile = new_iccp_profile; - info_ptr->free_me |= PNG_FREE_ICCP; - info_ptr->valid |= PNG_INFO_iCCP; -} -#endif - -#ifdef PNG_TEXT_SUPPORTED -void PNGAPI -png_set_text(png_const_structrp png_ptr, png_inforp info_ptr, - png_const_textp text_ptr, int num_text) -{ - int ret; - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text); - - if (ret) - png_error(png_ptr, "Insufficient memory to store text"); -} - -int /* PRIVATE */ -png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, - png_const_textp text_ptr, int num_text) -{ - int i; - - png_debug1(1, "in %lx storage function", png_ptr == NULL ? "unexpected" : - (unsigned long)png_ptr->chunk_name); - - if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL) - return(0); - - /* Make sure we have enough space in the "text" array in info_struct - * to hold all of the incoming text_ptr objects. This compare can't overflow - * because max_text >= num_text (anyway, subtract of two positive integers - * can't overflow in any case.) - */ - if (num_text > info_ptr->max_text - info_ptr->num_text) - { - int old_num_text = info_ptr->num_text; - int max_text; - png_textp new_text = NULL; - - /* Calculate an appropriate max_text, checking for overflow. */ - max_text = old_num_text; - if (num_text <= INT_MAX - max_text) - { - max_text += num_text; - - /* Round up to a multiple of 8 */ - if (max_text < INT_MAX-8) - max_text = (max_text + 8) & ~0x7; - - else - max_text = INT_MAX; - - /* Now allocate a new array and copy the old members in, this does all - * the overflow checks. - */ - new_text = png_voidcast(png_textp,png_realloc_array(png_ptr, - info_ptr->text, old_num_text, max_text-old_num_text, - sizeof *new_text)); - } - - if (new_text == NULL) - { - png_chunk_report(png_ptr, "too many text chunks", - PNG_CHUNK_WRITE_ERROR); - return 1; - } - - png_free(png_ptr, info_ptr->text); - - info_ptr->text = new_text; - info_ptr->free_me |= PNG_FREE_TEXT; - info_ptr->max_text = max_text; - /* num_text is adjusted below as the entries are copied in */ - - png_debug1(3, "allocated %d entries for info_ptr->text", max_text); - } - - for (i = 0; i < num_text; i++) - { - size_t text_length, key_len; - size_t lang_len, lang_key_len; - png_textp textp = &(info_ptr->text[info_ptr->num_text]); - - if (text_ptr[i].key == NULL) - continue; - - if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE || - text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST) - { - png_chunk_report(png_ptr, "text compression mode is out of range", - PNG_CHUNK_WRITE_ERROR); - continue; - } - - key_len = strlen(text_ptr[i].key); - - if (text_ptr[i].compression <= 0) - { - lang_len = 0; - lang_key_len = 0; - } - - else -# ifdef PNG_iTXt_SUPPORTED - { - /* Set iTXt data */ - - if (text_ptr[i].lang != NULL) - lang_len = strlen(text_ptr[i].lang); - - else - lang_len = 0; - - if (text_ptr[i].lang_key != NULL) - lang_key_len = strlen(text_ptr[i].lang_key); - - else - lang_key_len = 0; - } -# else /* PNG_iTXt_SUPPORTED */ - { - png_chunk_report(png_ptr, "iTXt chunk not supported", - PNG_CHUNK_WRITE_ERROR); - continue; - } -# endif - - if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0') - { - text_length = 0; -# ifdef PNG_iTXt_SUPPORTED - if (text_ptr[i].compression > 0) - textp->compression = PNG_ITXT_COMPRESSION_NONE; - - else -# endif - textp->compression = PNG_TEXT_COMPRESSION_NONE; - } - - else - { - text_length = strlen(text_ptr[i].text); - textp->compression = text_ptr[i].compression; - } - - textp->key = png_voidcast(png_charp,png_malloc_base(png_ptr, - key_len + text_length + lang_len + lang_key_len + 4)); - - if (textp->key == NULL) - { - png_chunk_report(png_ptr, "text chunk: out of memory", - PNG_CHUNK_WRITE_ERROR); - return 1; - } - - png_debug2(2, "Allocated %lu bytes at %p in png_set_text", - (unsigned long)(png_uint_32) - (key_len + lang_len + lang_key_len + text_length + 4), - textp->key); - - memcpy(textp->key, text_ptr[i].key, key_len); - *(textp->key + key_len) = '\0'; - - if (text_ptr[i].compression > 0) - { - textp->lang = textp->key + key_len + 1; - memcpy(textp->lang, text_ptr[i].lang, lang_len); - *(textp->lang + lang_len) = '\0'; - textp->lang_key = textp->lang + lang_len + 1; - memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len); - *(textp->lang_key + lang_key_len) = '\0'; - textp->text = textp->lang_key + lang_key_len + 1; - } - - else - { - textp->lang=NULL; - textp->lang_key=NULL; - textp->text = textp->key + key_len + 1; - } - - if (text_length) - memcpy(textp->text, text_ptr[i].text, text_length); - - *(textp->text + text_length) = '\0'; - -# ifdef PNG_iTXt_SUPPORTED - if (textp->compression > 0) - { - textp->text_length = 0; - textp->itxt_length = text_length; - } - - else -# endif - { - textp->text_length = text_length; - textp->itxt_length = 0; - } - - info_ptr->num_text++; - png_debug1(3, "transferred text chunk %d", info_ptr->num_text); - } - - return(0); -} -#endif - -#ifdef PNG_tIME_SUPPORTED -void PNGAPI -png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr, - png_const_timep mod_time) -{ - png_debug1(1, "in %s storage function", "tIME"); - - if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL || - (png_ptr->mode & PNG_WROTE_tIME)) - return; - - if (mod_time->month == 0 || mod_time->month > 12 || - mod_time->day == 0 || mod_time->day > 31 || - mod_time->hour > 23 || mod_time->minute > 59 || - mod_time->second > 60) - { - png_warning(png_ptr, "Ignoring invalid time value"); - return; - } - - info_ptr->mod_time = *mod_time; - info_ptr->valid |= PNG_INFO_tIME; -} -#endif - -#ifdef PNG_tRNS_SUPPORTED -void PNGAPI -png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr, - png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color) -{ - png_debug1(1, "in %s storage function", "tRNS"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - if (trans_alpha != NULL) - { - /* It may not actually be necessary to set png_ptr->trans_alpha here; - * we do it for backward compatibility with the way the png_handle_tRNS - * function used to do the allocation. - * - * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively - * relies on png_set_tRNS storing the information in png_struct - * (otherwise it won't be there for the code in pngrtran.c). - */ - - png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); - - /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */ - png_ptr->trans_alpha = info_ptr->trans_alpha = png_voidcast(png_bytep, - png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH)); - - if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) - memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans); - } - - if (trans_color != NULL) - { - int sample_max = (1 << info_ptr->bit_depth); - - if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && - trans_color->gray > sample_max) || - (info_ptr->color_type == PNG_COLOR_TYPE_RGB && - (trans_color->red > sample_max || - trans_color->green > sample_max || - trans_color->blue > sample_max))) - png_warning(png_ptr, - "tRNS chunk has out-of-range samples for bit_depth"); - - info_ptr->trans_color = *trans_color; - - if (num_trans == 0) - num_trans = 1; - } - - info_ptr->num_trans = (png_uint_16)num_trans; - - if (num_trans != 0) - { - info_ptr->valid |= PNG_INFO_tRNS; - info_ptr->free_me |= PNG_FREE_TRNS; - } -} -#endif - -#ifdef PNG_sPLT_SUPPORTED -void PNGAPI -png_set_sPLT(png_const_structrp png_ptr, - png_inforp info_ptr, png_const_sPLT_tp entries, int nentries) -/* - * entries - array of png_sPLT_t structures - * to be added to the list of palettes - * in the info structure. - * - * nentries - number of palette structures to be - * added. - */ -{ - png_sPLT_tp np; - - if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL) - return; - - /* Use the internal realloc function, which checks for all the possible - * overflows. Notice that the parameters are (int) and (size_t) - */ - np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr, - info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries, - sizeof *np)); - - if (np == NULL) - { - /* Out of memory or too many chunks */ - png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR); - return; - } - - png_free(png_ptr, info_ptr->splt_palettes); - info_ptr->splt_palettes = np; - info_ptr->free_me |= PNG_FREE_SPLT; - - np += info_ptr->splt_palettes_num; - - do - { - png_size_t length; - - /* Skip invalid input entries */ - if (entries->name == NULL || entries->entries == NULL) - { - /* png_handle_sPLT doesn't do this, so this is an app error */ - png_app_error(png_ptr, "png_set_sPLT: invalid sPLT"); - /* Just skip the invalid entry */ - continue; - } - - np->depth = entries->depth; - - /* In the even of out-of-memory just return - there's no point keeping on - * trying to add sPLT chunks. - */ - length = strlen(entries->name) + 1; - np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length)); - - if (np->name == NULL) - break; - - memcpy(np->name, entries->name, length); - - /* IMPORTANT: we have memory now that won't get freed if something else - * goes wrong, this code must free it. png_malloc_array produces no - * warnings, use a png_chunk_report (below) if there is an error. - */ - np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr, - entries->nentries, sizeof (png_sPLT_entry))); - - if (np->entries == NULL) - { - png_free(png_ptr, np->name); - break; - } - - np->nentries = entries->nentries; - /* This multiply can't overflow because png_malloc_array has already - * checked it when doing the allocation. - */ - memcpy(np->entries, entries->entries, - entries->nentries * sizeof (png_sPLT_entry)); - - /* Note that 'continue' skips the advance of the out pointer and out - * count, so an invalid entry is not added. - */ - info_ptr->valid |= PNG_INFO_sPLT; - ++(info_ptr->splt_palettes_num); - ++np; - } - while (++entries, --nentries); - - if (nentries > 0) - png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR); -} -#endif /* PNG_sPLT_SUPPORTED */ - -#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED -static png_byte -check_location(png_const_structrp png_ptr, int location) -{ - location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT); - - /* New in 1.6.0; copy the location and check it. This is an API - * change, previously the app had to use the - * png_set_unknown_chunk_location API below for each chunk. - */ - if (location == 0 && !(png_ptr->mode & PNG_IS_READ_STRUCT)) - { - /* Write struct, so unknown chunks come from the app */ - png_app_warning(png_ptr, - "png_set_unknown_chunks now expects a valid location"); - /* Use the old behavior */ - location = (png_byte)(png_ptr->mode & - (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)); - } - - /* This need not be an internal error - if the app calls - * png_set_unknown_chunks on a read pointer it must get the location right. - */ - if (location == 0) - png_error(png_ptr, "invalid location in png_set_unknown_chunks"); - - /* Now reduce the location to the top-most set bit by removing each least - * significant bit in turn. - */ - while (location != (location & -location)) - location &= ~(location & -location); - - /* The cast is safe because 'location' is a bit mask and only the low four - * bits are significant. - */ - return (png_byte)location; -} - -void PNGAPI -png_set_unknown_chunks(png_const_structrp png_ptr, - png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns) -{ - png_unknown_chunkp np; - - if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 || - unknowns == NULL) - return; - - /* Check for the failure cases where support has been disabled at compile - * time. This code is hardly ever compiled - it's here because - * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this - * code) but may be meaningless if the read or write handling of unknown - * chunks is not compiled in. - */ -# if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \ - defined(PNG_READ_SUPPORTED) - if (png_ptr->mode & PNG_IS_READ_STRUCT) - { - png_app_error(png_ptr, "no unknown chunk support on read"); - return; - } -# endif -# if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \ - defined(PNG_WRITE_SUPPORTED) - if (!(png_ptr->mode & PNG_IS_READ_STRUCT)) - { - png_app_error(png_ptr, "no unknown chunk support on write"); - return; - } -# endif - - /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that - * unknown critical chunks could be lost with just a warning resulting in - * undefined behavior. Now png_chunk_report is used to provide behavior - * appropriate to read or write. - */ - np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr, - info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns, - sizeof *np)); - - if (np == NULL) - { - png_chunk_report(png_ptr, "too many unknown chunks", - PNG_CHUNK_WRITE_ERROR); - return; - } - - png_free(png_ptr, info_ptr->unknown_chunks); - info_ptr->unknown_chunks = np; /* safe because it is initialized */ - info_ptr->free_me |= PNG_FREE_UNKN; - - np += info_ptr->unknown_chunks_num; - - /* Increment unknown_chunks_num each time round the loop to protect the - * just-allocated chunk data. - */ - for (; num_unknowns > 0; --num_unknowns, ++unknowns) - { - memcpy(np->name, unknowns->name, (sizeof np->name)); - np->name[(sizeof np->name)-1] = '\0'; - np->location = check_location(png_ptr, unknowns->location); - - if (unknowns->size == 0) - { - np->data = NULL; - np->size = 0; - } - - else - { - np->data = png_voidcast(png_bytep, - png_malloc_base(png_ptr, unknowns->size)); - - if (np->data == NULL) - { - png_chunk_report(png_ptr, "unknown chunk: out of memory", - PNG_CHUNK_WRITE_ERROR); - /* But just skip storing the unknown chunk */ - continue; - } - - memcpy(np->data, unknowns->data, unknowns->size); - np->size = unknowns->size; - } - - /* These increments are skipped on out-of-memory for the data - the - * unknown chunk entry gets overwritten if the png_chunk_report returns. - * This is correct in the read case (the chunk is just dropped.) - */ - ++np; - ++(info_ptr->unknown_chunks_num); - } -} - -void PNGAPI -png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr, - int chunk, int location) -{ - /* This API is pretty pointless in 1.6.0 because the location can be set - * before the call to png_set_unknown_chunks. - * - * TODO: add a png_app_warning in 1.7 - */ - if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 && - chunk < info_ptr->unknown_chunks_num) - { - if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0) - { - png_app_error(png_ptr, "invalid unknown chunk location"); - /* Fake out the pre 1.6.0 behavior: */ - if ((location & PNG_HAVE_IDAT)) /* undocumented! */ - location = PNG_AFTER_IDAT; - - else - location = PNG_HAVE_IHDR; /* also undocumented */ - } - - info_ptr->unknown_chunks[chunk].location = - check_location(png_ptr, location); - } -} -#endif - - -#ifdef PNG_MNG_FEATURES_SUPPORTED -png_uint_32 PNGAPI -png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features) -{ - png_debug(1, "in png_permit_mng_features"); - - if (png_ptr == NULL) - return 0; - - png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES; - - return png_ptr->mng_features_permitted; -} -#endif - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -static unsigned int -add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep) -{ - unsigned int i; - - /* Utility function: update the 'keep' state of a chunk if it is already in - * the list, otherwise add it to the list. - */ - for (i=0; i= PNG_HANDLE_CHUNK_LAST) - { - png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep"); - return; - } - - if (num_chunks_in <= 0) - { - png_ptr->unknown_default = keep; - - /* '0' means just set the flags, so stop here */ - if (num_chunks_in == 0) - return; - } - - if (num_chunks_in < 0) - { - /* Ignore all unknown chunks and all chunks recognized by - * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND - */ - static PNG_CONST png_byte chunks_to_ignore[] = { - 98, 75, 71, 68, '\0', /* bKGD */ - 99, 72, 82, 77, '\0', /* cHRM */ - 103, 65, 77, 65, '\0', /* gAMA */ - 104, 73, 83, 84, '\0', /* hIST */ - 105, 67, 67, 80, '\0', /* iCCP */ - 105, 84, 88, 116, '\0', /* iTXt */ - 111, 70, 70, 115, '\0', /* oFFs */ - 112, 67, 65, 76, '\0', /* pCAL */ - 112, 72, 89, 115, '\0', /* pHYs */ - 115, 66, 73, 84, '\0', /* sBIT */ - 115, 67, 65, 76, '\0', /* sCAL */ - 115, 80, 76, 84, '\0', /* sPLT */ - 115, 84, 69, 82, '\0', /* sTER */ - 115, 82, 71, 66, '\0', /* sRGB */ - 116, 69, 88, 116, '\0', /* tEXt */ - 116, 73, 77, 69, '\0', /* tIME */ - 122, 84, 88, 116, '\0' /* zTXt */ - }; - - chunk_list = chunks_to_ignore; - num_chunks = (sizeof chunks_to_ignore)/5; - } - - else /* num_chunks_in > 0 */ - { - if (chunk_list == NULL) - { - /* Prior to 1.6.0 this was silently ignored, now it is an app_error - * which can be switched off. - */ - png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list"); - return; - } - - num_chunks = num_chunks_in; - } - - old_num_chunks = png_ptr->num_chunk_list; - if (png_ptr->chunk_list == NULL) - old_num_chunks = 0; - - /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow. - */ - if (num_chunks + old_num_chunks > UINT_MAX/5) - { - png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks"); - return; - } - - /* If these chunks are being reset to the default then no more memory is - * required because add_one_chunk above doesn't extend the list if the 'keep' - * parameter is the default. - */ - if (keep) - { - new_list = png_voidcast(png_bytep, png_malloc(png_ptr, - 5 * (num_chunks + old_num_chunks))); - - if (old_num_chunks > 0) - memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks); - } - - else if (old_num_chunks > 0) - new_list = png_ptr->chunk_list; - - else - new_list = NULL; - - /* Add the new chunks together with each one's handling code. If the chunk - * already exists the code is updated, otherwise the chunk is added to the - * end. (In libpng 1.6.0 order no longer matters because this code enforces - * the earlier convention that the last setting is the one that is used.) - */ - if (new_list != NULL) - { - png_const_bytep inlist; - png_bytep outlist; - unsigned int i; - - for (i=0; ichunk_list != new_list) - png_free(png_ptr, new_list); - - new_list = NULL; - } - } - - else - num_chunks = 0; - - png_ptr->num_chunk_list = num_chunks; - - if (png_ptr->chunk_list != new_list) - { - if (png_ptr->chunk_list != NULL) - png_free(png_ptr, png_ptr->chunk_list); - - png_ptr->chunk_list = new_list; - } -} -#endif - -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED -void PNGAPI -png_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr, - png_user_chunk_ptr read_user_chunk_fn) -{ - png_debug(1, "in png_set_read_user_chunk_fn"); - - if (png_ptr == NULL) - return; - - png_ptr->read_user_chunk_fn = read_user_chunk_fn; - png_ptr->user_chunk_ptr = user_chunk_ptr; -} -#endif - -#ifdef PNG_INFO_IMAGE_SUPPORTED -void PNGAPI -png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr, - png_bytepp row_pointers) -{ - png_debug1(1, "in %s storage function", "rows"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - if (info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers)) - png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); - - info_ptr->row_pointers = row_pointers; - - if (row_pointers) - info_ptr->valid |= PNG_INFO_IDAT; -} -#endif - -void PNGAPI -png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size) -{ - if (png_ptr == NULL) - return; - - if (size == 0 || size > PNG_UINT_31_MAX) - png_error(png_ptr, "invalid compression buffer size"); - -# ifdef PNG_SEQUENTIAL_READ_SUPPORTED - if (png_ptr->mode & PNG_IS_READ_STRUCT) - { - png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */ - return; - } -# endif - -# ifdef PNG_WRITE_SUPPORTED - if (!(png_ptr->mode & PNG_IS_READ_STRUCT)) - { - if (png_ptr->zowner != 0) - { - png_warning(png_ptr, - "Compression buffer size cannot be changed because it is in use"); - return; - } - - if (size > ZLIB_IO_MAX) - { - png_warning(png_ptr, - "Compression buffer size limited to system maximum"); - size = ZLIB_IO_MAX; /* must fit */ - } - - else if (size < 6) - { - /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH - * if this is permitted. - */ - png_warning(png_ptr, - "Compression buffer size cannot be reduced below 6"); - return; - } - - if (png_ptr->zbuffer_size != size) - { - png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); - png_ptr->zbuffer_size = (uInt)size; - } - } -# endif -} - -void PNGAPI -png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask) -{ - if (png_ptr && info_ptr) - info_ptr->valid &= ~mask; -} - - -#ifdef PNG_SET_USER_LIMITS_SUPPORTED -/* This function was added to libpng 1.2.6 */ -void PNGAPI -png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max, - png_uint_32 user_height_max) -{ - /* Images with dimensions larger than these limits will be - * rejected by png_set_IHDR(). To accept any PNG datastream - * regardless of dimensions, set both limits to 0x7ffffffL. - */ - if (png_ptr == NULL) - return; - - png_ptr->user_width_max = user_width_max; - png_ptr->user_height_max = user_height_max; -} - -/* This function was added to libpng 1.4.0 */ -void PNGAPI -png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max) -{ - if (png_ptr) - png_ptr->user_chunk_cache_max = user_chunk_cache_max; -} - -/* This function was added to libpng 1.4.1 */ -void PNGAPI -png_set_chunk_malloc_max (png_structrp png_ptr, - png_alloc_size_t user_chunk_malloc_max) -{ - if (png_ptr) - png_ptr->user_chunk_malloc_max = user_chunk_malloc_max; -} -#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ - - -#ifdef PNG_BENIGN_ERRORS_SUPPORTED -void PNGAPI -png_set_benign_errors(png_structrp png_ptr, int allowed) -{ - png_debug(1, "in png_set_benign_errors"); - - /* If allowed is 1, png_benign_error() is treated as a warning. - * - * If allowed is 0, png_benign_error() is treated as an error (which - * is the default behavior if png_set_benign_errors() is not called). - */ - - if (allowed) - png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN | - PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN; - - else - png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN | - PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN); -} -#endif /* PNG_BENIGN_ERRORS_SUPPORTED */ - -#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED - /* Whether to report invalid palette index; added at libng-1.5.10. - * It is possible for an indexed (color-type==3) PNG file to contain - * pixels with invalid (out-of-range) indexes if the PLTE chunk has - * fewer entries than the image's bit-depth would allow. We recover - * from this gracefully by filling any incomplete palette with zeroes - * (opaque black). By default, when this occurs libpng will issue - * a benign error. This API can be used to override that behavior. - */ -void PNGAPI -png_set_check_for_invalid_index(png_structrp png_ptr, int allowed) -{ - png_debug(1, "in png_set_check_for_invalid_index"); - - if (allowed > 0) - png_ptr->num_palette_max = 0; - - else - png_ptr->num_palette_max = -1; -} -#endif -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pngstruct.h b/source/modules/juce_graphics/image_formats/pnglib/pngstruct.h deleted file mode 100644 index 89605b18b..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pngstruct.h +++ /dev/null @@ -1,489 +0,0 @@ - -/* pngstruct.h - header file for PNG reference library - * - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * Last changed in libpng 1.6.1 [March 28, 2013] - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - */ - -/* The structure that holds the information to read and write PNG files. - * The only people who need to care about what is inside of this are the - * people who will be modifying the library for their own special needs. - * It should NOT be accessed directly by an application. - */ - -#ifndef PNGSTRUCT_H -#define PNGSTRUCT_H -/* zlib.h defines the structure z_stream, an instance of which is included - * in this structure and is required for decompressing the LZ compressed - * data in PNG files. - */ -#ifndef ZLIB_CONST - /* We must ensure that zlib uses 'const' in declarations. */ -# define ZLIB_CONST -#endif -#include "../../../juce_core/zip/zlib/zlib.h" -#ifdef const - /* zlib.h sometimes #defines const to nothing, undo this. */ -# undef const -#endif - -/* zlib.h has mediocre z_const use before 1.2.6, this stuff is for compatibility - * with older builds. - */ -#if ZLIB_VERNUM < 0x1260 -# define PNGZ_MSG_CAST(s) png_constcast(char*,s) -# define PNGZ_INPUT_CAST(b) png_constcast(png_bytep,b) -#else -# define PNGZ_MSG_CAST(s) (s) -# define PNGZ_INPUT_CAST(b) (b) -#endif - -/* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib - * can handle at once. This type need be no larger than 16 bits (so maximum of - * 65535), this define allows us to discover how big it is, but limited by the - * maximuum for png_size_t. The value can be overriden in a library build - * (pngusr.h, or set it in CPPFLAGS) and it works to set it to a considerably - * lower value (e.g. 255 works). A lower value may help memory usage (slightly) - * and may even improve performance on some systems (and degrade it on others.) - */ -#ifndef ZLIB_IO_MAX -# define ZLIB_IO_MAX ((uInt)-1) -#endif - -#ifdef PNG_WRITE_SUPPORTED -/* The type of a compression buffer list used by the write code. */ -typedef struct png_compression_buffer -{ - struct png_compression_buffer *next; - png_byte output[1]; /* actually zbuf_size */ -} png_compression_buffer, *png_compression_bufferp; - -#define PNG_COMPRESSION_BUFFER_SIZE(pp)\ - (offsetof(png_compression_buffer, output) + (pp)->zbuffer_size) -#endif - -/* Colorspace support; structures used in png_struct, png_info and in internal - * functions to hold and communicate information about the color space. - * - * PNG_COLORSPACE_SUPPORTED is only required if the application will perform - * colorspace corrections, otherwise all the colorspace information can be - * skipped and the size of libpng can be reduced (significantly) by compiling - * out the colorspace support. - */ -#ifdef PNG_COLORSPACE_SUPPORTED -/* The chromaticities of the red, green and blue colorants and the chromaticity - * of the corresponding white point (i.e. of rgb(1.0,1.0,1.0)). - */ -typedef struct png_xy -{ - png_fixed_point redx, redy; - png_fixed_point greenx, greeny; - png_fixed_point bluex, bluey; - png_fixed_point whitex, whitey; -} png_xy; - -/* The same data as above but encoded as CIE XYZ values. When this data comes - * from chromaticities the sum of the Y values is assumed to be 1.0 - */ -typedef struct png_XYZ -{ - png_fixed_point red_X, red_Y, red_Z; - png_fixed_point green_X, green_Y, green_Z; - png_fixed_point blue_X, blue_Y, blue_Z; -} png_XYZ; -#endif /* COLORSPACE */ - -#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) -/* A colorspace is all the above plus, potentially, profile information, - * however at present libpng does not use the profile internally so it is only - * stored in the png_info struct (if iCCP is supported.) The rendering intent - * is retained here and is checked. - * - * The file gamma encoding information is also stored here and gamma correction - * is done by libpng, whereas color correction must currently be done by the - * application. - */ -typedef struct png_colorspace -{ -#ifdef PNG_GAMMA_SUPPORTED - png_fixed_point gamma; /* File gamma */ -#endif - -#ifdef PNG_COLORSPACE_SUPPORTED - png_xy end_points_xy; /* End points as chromaticities */ - png_XYZ end_points_XYZ; /* End points as CIE XYZ colorant values */ - png_uint_16 rendering_intent; /* Rendering intent of a profile */ -#endif - - /* Flags are always defined to simplify the code. */ - png_uint_16 flags; /* As defined below */ -} png_colorspace, * PNG_RESTRICT png_colorspacerp; - -typedef const png_colorspace * PNG_RESTRICT png_const_colorspacerp; - -/* General flags for the 'flags' field */ -#define PNG_COLORSPACE_HAVE_GAMMA 0x0001 -#define PNG_COLORSPACE_HAVE_ENDPOINTS 0x0002 -#define PNG_COLORSPACE_HAVE_INTENT 0x0004 -#define PNG_COLORSPACE_FROM_gAMA 0x0008 -#define PNG_COLORSPACE_FROM_cHRM 0x0010 -#define PNG_COLORSPACE_FROM_sRGB 0x0020 -#define PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB 0x0040 -#define PNG_COLORSPACE_MATCHES_sRGB 0x0080 /* exact match on profile */ -#define PNG_COLORSPACE_INVALID 0x8000 -#define PNG_COLORSPACE_CANCEL(flags) (0xffff ^ (flags)) -#endif /* COLORSPACE || GAMMA */ - -struct png_struct_def -{ -#ifdef PNG_SETJMP_SUPPORTED - jmp_buf jmp_buf_local; /* New name in 1.6.0 for jmp_buf in png_struct */ - png_longjmp_ptr longjmp_fn;/* setjmp non-local goto function. */ - jmp_buf *jmp_buf_ptr; /* passed to longjmp_fn */ - size_t jmp_buf_size; /* size of the above, if allocated */ -#endif - png_error_ptr error_fn; /* function for printing errors and aborting */ -#ifdef PNG_WARNINGS_SUPPORTED - png_error_ptr warning_fn; /* function for printing warnings */ -#endif - png_voidp error_ptr; /* user supplied struct for error functions */ - png_rw_ptr write_data_fn; /* function for writing output data */ - png_rw_ptr read_data_fn; /* function for reading input data */ - png_voidp io_ptr; /* ptr to application struct for I/O functions */ - -#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED - png_user_transform_ptr read_user_transform_fn; /* user read transform */ -#endif - -#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED - png_user_transform_ptr write_user_transform_fn; /* user write transform */ -#endif - -/* These were added in libpng-1.0.2 */ -#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) - png_voidp user_transform_ptr; /* user supplied struct for user transform */ - png_byte user_transform_depth; /* bit depth of user transformed pixels */ - png_byte user_transform_channels; /* channels in user transformed pixels */ -#endif -#endif - - png_uint_32 mode; /* tells us where we are in the PNG file */ - png_uint_32 flags; /* flags indicating various things to libpng */ - png_uint_32 transformations; /* which transformations to perform */ - - png_uint_32 zowner; /* ID (chunk type) of zstream owner, 0 if none */ - z_stream zstream; /* decompression structure */ - -#ifdef PNG_WRITE_SUPPORTED - png_compression_bufferp zbuffer_list; /* Created on demand during write */ - uInt zbuffer_size; /* size of the actual buffer */ - - int zlib_level; /* holds zlib compression level */ - int zlib_method; /* holds zlib compression method */ - int zlib_window_bits; /* holds zlib compression window bits */ - int zlib_mem_level; /* holds zlib compression memory level */ - int zlib_strategy; /* holds zlib compression strategy */ -#endif -/* Added at libpng 1.5.4 */ -#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED - int zlib_text_level; /* holds zlib compression level */ - int zlib_text_method; /* holds zlib compression method */ - int zlib_text_window_bits; /* holds zlib compression window bits */ - int zlib_text_mem_level; /* holds zlib compression memory level */ - int zlib_text_strategy; /* holds zlib compression strategy */ -#endif -/* End of material added at libpng 1.5.4 */ -/* Added at libpng 1.6.0 */ -#ifdef PNG_WRITE_SUPPORTED - int zlib_set_level; /* Actual values set into the zstream on write */ - int zlib_set_method; - int zlib_set_window_bits; - int zlib_set_mem_level; - int zlib_set_strategy; -#endif - - png_uint_32 width; /* width of image in pixels */ - png_uint_32 height; /* height of image in pixels */ - png_uint_32 num_rows; /* number of rows in current pass */ - png_uint_32 usr_width; /* width of row at start of write */ - png_size_t rowbytes; /* size of row in bytes */ - png_uint_32 iwidth; /* width of current interlaced row in pixels */ - png_uint_32 row_number; /* current row in interlace pass */ - png_uint_32 chunk_name; /* PNG_CHUNK() id of current chunk */ - png_bytep prev_row; /* buffer to save previous (unfiltered) row. - * This is a pointer into big_prev_row - */ - png_bytep row_buf; /* buffer to save current (unfiltered) row. - * This is a pointer into big_row_buf - */ -#ifdef PNG_WRITE_SUPPORTED - png_bytep sub_row; /* buffer to save "sub" row when filtering */ - png_bytep up_row; /* buffer to save "up" row when filtering */ - png_bytep avg_row; /* buffer to save "avg" row when filtering */ - png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */ -#endif - png_size_t info_rowbytes; /* Added in 1.5.4: cache of updated row bytes */ - - png_uint_32 idat_size; /* current IDAT size for read */ - png_uint_32 crc; /* current chunk CRC value */ - png_colorp palette; /* palette from the input file */ - png_uint_16 num_palette; /* number of color entries in palette */ - -/* Added at libpng-1.5.10 */ -#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED - int num_palette_max; /* maximum palette index found in IDAT */ -#endif - - png_uint_16 num_trans; /* number of transparency values */ - png_byte compression; /* file compression type (always 0) */ - png_byte filter; /* file filter type (always 0) */ - png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ - png_byte pass; /* current interlace pass (0 - 6) */ - png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */ - png_byte color_type; /* color type of file */ - png_byte bit_depth; /* bit depth of file */ - png_byte usr_bit_depth; /* bit depth of users row: write only */ - png_byte pixel_depth; /* number of bits per pixel */ - png_byte channels; /* number of channels in file */ -#ifdef PNG_WRITE_SUPPORTED - png_byte usr_channels; /* channels at start of write: write only */ -#endif - png_byte sig_bytes; /* magic bytes read/written from start of file */ - png_byte maximum_pixel_depth; - /* pixel depth used for the row buffers */ - png_byte transformed_pixel_depth; - /* pixel depth after read/write transforms */ -#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) - png_uint_16 filler; /* filler bytes for pixel expansion */ -#endif - -#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ - defined(PNG_READ_ALPHA_MODE_SUPPORTED) - png_byte background_gamma_type; - png_fixed_point background_gamma; - png_color_16 background; /* background color in screen gamma space */ -#ifdef PNG_READ_GAMMA_SUPPORTED - png_color_16 background_1; /* background normalized to gamma 1.0 */ -#endif -#endif /* PNG_bKGD_SUPPORTED */ - -#ifdef PNG_WRITE_FLUSH_SUPPORTED - png_flush_ptr output_flush_fn; /* Function for flushing output */ - png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */ - png_uint_32 flush_rows; /* number of rows written since last flush */ -#endif - -#ifdef PNG_READ_GAMMA_SUPPORTED - int gamma_shift; /* number of "insignificant" bits in 16-bit gamma */ - png_fixed_point screen_gamma; /* screen gamma value (display_exponent) */ - - png_bytep gamma_table; /* gamma table for 8-bit depth files */ - png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */ -#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ - defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ - defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - png_bytep gamma_from_1; /* converts from 1.0 to screen */ - png_bytep gamma_to_1; /* converts from file to 1.0 */ - png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */ - png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ -#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) - png_color_8 sig_bit; /* significant bits in each available channel */ -#endif - -#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) - png_color_8 shift; /* shift for significant bit tranformation */ -#endif - -#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \ - || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - png_bytep trans_alpha; /* alpha values for paletted files */ - png_color_16 trans_color; /* transparent color for non-paletted files */ -#endif - - png_read_status_ptr read_row_fn; /* called after each row is decoded */ - png_write_status_ptr write_row_fn; /* called after each row is encoded */ -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED - png_progressive_info_ptr info_fn; /* called after header data fully read */ - png_progressive_row_ptr row_fn; /* called after a prog. row is decoded */ - png_progressive_end_ptr end_fn; /* called after image is complete */ - png_bytep save_buffer_ptr; /* current location in save_buffer */ - png_bytep save_buffer; /* buffer for previously read data */ - png_bytep current_buffer_ptr; /* current location in current_buffer */ - png_bytep current_buffer; /* buffer for recently used data */ - png_uint_32 push_length; /* size of current input chunk */ - png_uint_32 skip_length; /* bytes to skip in input data */ - png_size_t save_buffer_size; /* amount of data now in save_buffer */ - png_size_t save_buffer_max; /* total size of save_buffer */ - png_size_t buffer_size; /* total amount of available input data */ - png_size_t current_buffer_size; /* amount of data now in current_buffer */ - int process_mode; /* what push library is currently doing */ - int cur_palette; /* current push library palette index */ - -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ - -#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) -/* For the Borland special 64K segment handler */ - png_bytepp offset_table_ptr; - png_bytep offset_table; - png_uint_16 offset_table_number; - png_uint_16 offset_table_count; - png_uint_16 offset_table_count_free; -#endif - -#ifdef PNG_READ_QUANTIZE_SUPPORTED - png_bytep palette_lookup; /* lookup table for quantizing */ - png_bytep quantize_index; /* index translation for palette files */ -#endif - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - png_byte heuristic_method; /* heuristic for row filter selection */ - png_byte num_prev_filters; /* number of weights for previous rows */ - png_bytep prev_filters; /* filter type(s) of previous row(s) */ - png_uint_16p filter_weights; /* weight(s) for previous line(s) */ - png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */ - png_uint_16p filter_costs; /* relative filter calculation cost */ - png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */ -#endif - - /* Options */ -#ifdef PNG_SET_OPTION_SUPPORTED - png_byte options; /* On/off state (up to 4 options) */ -#endif - -#if PNG_LIBPNG_VER < 10700 -/* To do: remove this from libpng-1.7 */ -#ifdef PNG_TIME_RFC1123_SUPPORTED - char time_buffer[29]; /* String to hold RFC 1123 time text */ -#endif -#endif - -/* New members added in libpng-1.0.6 */ - - png_uint_32 free_me; /* flags items libpng is responsible for freeing */ - -#ifdef PNG_USER_CHUNKS_SUPPORTED - png_voidp user_chunk_ptr; -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED - png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ -#endif -#endif - -#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED - int unknown_default; /* As PNG_HANDLE_* */ - unsigned int num_chunk_list; /* Number of entries in the list */ - png_bytep chunk_list; /* List of png_byte[5]; the textual chunk name - * followed by a PNG_HANDLE_* byte */ -#endif - -/* New members added in libpng-1.0.3 */ -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - png_byte rgb_to_gray_status; - /* Added in libpng 1.5.5 to record setting of coefficients: */ - png_byte rgb_to_gray_coefficients_set; - /* These were changed from png_byte in libpng-1.0.6 */ - png_uint_16 rgb_to_gray_red_coeff; - png_uint_16 rgb_to_gray_green_coeff; - /* deleted in 1.5.5: rgb_to_gray_blue_coeff; */ -#endif - -/* New member added in libpng-1.0.4 (renamed in 1.0.9) */ -#if defined(PNG_MNG_FEATURES_SUPPORTED) -/* Changed from png_byte to png_uint_32 at version 1.2.0 */ - png_uint_32 mng_features_permitted; -#endif - -/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */ -#ifdef PNG_MNG_FEATURES_SUPPORTED - png_byte filter_type; -#endif - -/* New members added in libpng-1.2.0 */ - -/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */ -#ifdef PNG_USER_MEM_SUPPORTED - png_voidp mem_ptr; /* user supplied struct for mem functions */ - png_malloc_ptr malloc_fn; /* function for allocating memory */ - png_free_ptr free_fn; /* function for freeing memory */ -#endif - -/* New member added in libpng-1.0.13 and 1.2.0 */ - png_bytep big_row_buf; /* buffer to save current (unfiltered) row */ - -#ifdef PNG_READ_QUANTIZE_SUPPORTED -/* The following three members were added at version 1.0.14 and 1.2.4 */ - png_bytep quantize_sort; /* working sort array */ - png_bytep index_to_palette; /* where the original index currently is - in the palette */ - png_bytep palette_to_index; /* which original index points to this - palette color */ -#endif - -/* New members added in libpng-1.0.16 and 1.2.6 */ - png_byte compression_type; - -#ifdef PNG_USER_LIMITS_SUPPORTED - png_uint_32 user_width_max; - png_uint_32 user_height_max; - - /* Added in libpng-1.4.0: Total number of sPLT, text, and unknown - * chunks that can be stored (0 means unlimited). - */ - png_uint_32 user_chunk_cache_max; - - /* Total memory that a zTXt, sPLT, iTXt, iCCP, or unknown chunk - * can occupy when decompressed. 0 means unlimited. - */ - png_alloc_size_t user_chunk_malloc_max; -#endif - -/* New member added in libpng-1.0.25 and 1.2.17 */ -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED - /* Temporary storage for unknown chunk that the library doesn't recognize, - * used while reading the chunk. - */ - png_unknown_chunk unknown_chunk; -#endif - -/* New member added in libpng-1.2.26 */ - png_size_t old_big_row_buf_size; - -#ifdef PNG_READ_SUPPORTED -/* New member added in libpng-1.2.30 */ - png_bytep read_buffer; /* buffer for reading chunk data */ - png_alloc_size_t read_buffer_size; /* current size of the buffer */ -#endif -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED - uInt IDAT_read_size; /* limit on read buffer size for IDAT */ -#endif - -#ifdef PNG_IO_STATE_SUPPORTED -/* New member added in libpng-1.4.0 */ - png_uint_32 io_state; -#endif - -/* New member added in libpng-1.5.6 */ - png_bytep big_prev_row; - -/* New member added in libpng-1.5.7 */ - void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info, - png_bytep row, png_const_bytep prev_row); - -#ifdef PNG_READ_SUPPORTED -#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) - png_colorspace colorspace; -#endif -#endif -}; -#endif /* PNGSTRUCT_H */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pngtrans.c b/source/modules/juce_graphics/image_formats/pnglib/pngtrans.c deleted file mode 100644 index 20558af3a..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pngtrans.c +++ /dev/null @@ -1,830 +0,0 @@ - -/* pngtrans.c - transforms the data in a row (used by both readers and writers) - * - * Last changed in libpng 1.6.0 [February 14, 2013] - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - */ - -#include "pngpriv.h" - -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) - -#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) -/* Turn on BGR-to-RGB mapping */ -void PNGAPI -png_set_bgr(png_structrp png_ptr) -{ - png_debug(1, "in png_set_bgr"); - - if (png_ptr == NULL) - return; - - png_ptr->transformations |= PNG_BGR; -} -#endif - -#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) -/* Turn on 16 bit byte swapping */ -void PNGAPI -png_set_swap(png_structrp png_ptr) -{ - png_debug(1, "in png_set_swap"); - - if (png_ptr == NULL) - return; - - if (png_ptr->bit_depth == 16) - png_ptr->transformations |= PNG_SWAP_BYTES; -} -#endif - -#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) -/* Turn on pixel packing */ -void PNGAPI -png_set_packing(png_structrp png_ptr) -{ - png_debug(1, "in png_set_packing"); - - if (png_ptr == NULL) - return; - - if (png_ptr->bit_depth < 8) - { - png_ptr->transformations |= PNG_PACK; - png_ptr->usr_bit_depth = 8; - } -} -#endif - -#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) -/* Turn on packed pixel swapping */ -void PNGAPI -png_set_packswap(png_structrp png_ptr) -{ - png_debug(1, "in png_set_packswap"); - - if (png_ptr == NULL) - return; - - if (png_ptr->bit_depth < 8) - png_ptr->transformations |= PNG_PACKSWAP; -} -#endif - -#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) -void PNGAPI -png_set_shift(png_structrp png_ptr, png_const_color_8p true_bits) -{ - png_debug(1, "in png_set_shift"); - - if (png_ptr == NULL) - return; - - png_ptr->transformations |= PNG_SHIFT; - png_ptr->shift = *true_bits; -} -#endif - -#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ - defined(PNG_WRITE_INTERLACING_SUPPORTED) -int PNGAPI -png_set_interlace_handling(png_structrp png_ptr) -{ - png_debug(1, "in png_set_interlace handling"); - - if (png_ptr && png_ptr->interlaced) - { - png_ptr->transformations |= PNG_INTERLACE; - return (7); - } - - return (1); -} -#endif - -#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) -/* Add a filler byte on read, or remove a filler or alpha byte on write. - * The filler type has changed in v0.95 to allow future 2-byte fillers - * for 48-bit input data, as well as to avoid problems with some compilers - * that don't like bytes as parameters. - */ -void PNGAPI -png_set_filler(png_structrp png_ptr, png_uint_32 filler, int filler_loc) -{ - png_debug(1, "in png_set_filler"); - - if (png_ptr == NULL) - return; - - /* In libpng 1.6 it is possible to determine whether this is a read or write - * operation and therefore to do more checking here for a valid call. - */ - if (png_ptr->mode & PNG_IS_READ_STRUCT) - { -# ifdef PNG_READ_FILLER_SUPPORTED - /* On read png_set_filler is always valid, regardless of the base PNG - * format, because other transformations can give a format where the - * filler code can execute (basically an 8 or 16-bit component RGB or G - * format.) - * - * NOTE: usr_channels is not used by the read code! (This has led to - * confusion in the past.) The filler is only used in the read code. - */ - png_ptr->filler = (png_uint_16)filler; -# else - png_app_error(png_ptr, "png_set_filler not supported on read"); - PNG_UNUSED(filler) /* not used in the write case */ - return; -# endif - } - - else /* write */ - { -# ifdef PNG_WRITE_FILLER_SUPPORTED - /* On write the usr_channels parameter must be set correctly at the - * start to record the number of channels in the app-supplied data. - */ - switch (png_ptr->color_type) - { - case PNG_COLOR_TYPE_RGB: - png_ptr->usr_channels = 4; - break; - - case PNG_COLOR_TYPE_GRAY: - if (png_ptr->bit_depth >= 8) - { - png_ptr->usr_channels = 2; - break; - } - - else - { - /* There simply isn't any code in libpng to strip out bits - * from bytes when the components are less than a byte in - * size! - */ - png_app_error(png_ptr, - "png_set_filler is invalid for low bit depth gray output"); - return; - } - - default: - png_app_error(png_ptr, - "png_set_filler: inappropriate color type"); - return; - } -# else - png_app_error(png_ptr, "png_set_filler not supported on write"); - return; -# endif - } - - /* Here on success - libpng supports the operation, set the transformation - * and the flag to say where the filler channel is. - */ - png_ptr->transformations |= PNG_FILLER; - - if (filler_loc == PNG_FILLER_AFTER) - png_ptr->flags |= PNG_FLAG_FILLER_AFTER; - - else - png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER; -} - -/* Added to libpng-1.2.7 */ -void PNGAPI -png_set_add_alpha(png_structrp png_ptr, png_uint_32 filler, int filler_loc) -{ - png_debug(1, "in png_set_add_alpha"); - - if (png_ptr == NULL) - return; - - png_set_filler(png_ptr, filler, filler_loc); - /* The above may fail to do anything. */ - if (png_ptr->transformations & PNG_FILLER) - png_ptr->transformations |= PNG_ADD_ALPHA; -} - -#endif - -#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ - defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) -void PNGAPI -png_set_swap_alpha(png_structrp png_ptr) -{ - png_debug(1, "in png_set_swap_alpha"); - - if (png_ptr == NULL) - return; - - png_ptr->transformations |= PNG_SWAP_ALPHA; -} -#endif - -#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ - defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) -void PNGAPI -png_set_invert_alpha(png_structrp png_ptr) -{ - png_debug(1, "in png_set_invert_alpha"); - - if (png_ptr == NULL) - return; - - png_ptr->transformations |= PNG_INVERT_ALPHA; -} -#endif - -#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) -void PNGAPI -png_set_invert_mono(png_structrp png_ptr) -{ - png_debug(1, "in png_set_invert_mono"); - - if (png_ptr == NULL) - return; - - png_ptr->transformations |= PNG_INVERT_MONO; -} - -/* Invert monochrome grayscale data */ -void /* PRIVATE */ -png_do_invert(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_invert"); - - /* This test removed from libpng version 1.0.13 and 1.2.0: - * if (row_info->bit_depth == 1 && - */ - if (row_info->color_type == PNG_COLOR_TYPE_GRAY) - { - png_bytep rp = row; - png_size_t i; - png_size_t istop = row_info->rowbytes; - - for (i = 0; i < istop; i++) - { - *rp = (png_byte)(~(*rp)); - rp++; - } - } - - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && - row_info->bit_depth == 8) - { - png_bytep rp = row; - png_size_t i; - png_size_t istop = row_info->rowbytes; - - for (i = 0; i < istop; i += 2) - { - *rp = (png_byte)(~(*rp)); - rp += 2; - } - } - -#ifdef PNG_16BIT_SUPPORTED - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && - row_info->bit_depth == 16) - { - png_bytep rp = row; - png_size_t i; - png_size_t istop = row_info->rowbytes; - - for (i = 0; i < istop; i += 4) - { - *rp = (png_byte)(~(*rp)); - *(rp + 1) = (png_byte)(~(*(rp + 1))); - rp += 4; - } - } -#endif -} -#endif - -#ifdef PNG_16BIT_SUPPORTED -#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) -/* Swaps byte order on 16 bit depth images */ -void /* PRIVATE */ -png_do_swap(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_swap"); - - if (row_info->bit_depth == 16) - { - png_bytep rp = row; - png_uint_32 i; - png_uint_32 istop= row_info->width * row_info->channels; - - for (i = 0; i < istop; i++, rp += 2) - { - png_byte t = *rp; - *rp = *(rp + 1); - *(rp + 1) = t; - } - } -} -#endif -#endif - -#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) -static PNG_CONST png_byte onebppswaptable[256] = { - 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, - 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, - 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, - 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, - 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, - 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, - 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, - 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, - 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, - 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, - 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, - 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, - 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, - 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, - 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, - 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, - 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, - 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, - 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, - 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, - 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, - 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, - 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, - 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, - 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, - 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, - 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, - 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, - 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, - 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, - 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, - 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF -}; - -static PNG_CONST png_byte twobppswaptable[256] = { - 0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0, - 0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0, - 0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4, - 0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4, - 0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8, - 0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8, - 0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC, - 0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC, - 0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1, - 0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1, - 0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5, - 0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5, - 0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9, - 0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9, - 0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD, - 0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD, - 0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2, - 0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2, - 0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6, - 0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6, - 0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA, - 0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA, - 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE, - 0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE, - 0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3, - 0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3, - 0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7, - 0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7, - 0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB, - 0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB, - 0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF, - 0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF -}; - -static PNG_CONST png_byte fourbppswaptable[256] = { - 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, - 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, - 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, - 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1, - 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, - 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2, - 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, - 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3, - 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, - 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4, - 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, - 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5, - 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76, - 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6, - 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, - 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7, - 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, - 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8, - 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79, - 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9, - 0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A, - 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA, - 0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, - 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB, - 0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, - 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC, - 0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D, - 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD, - 0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E, - 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE, - 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, - 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF -}; - -/* Swaps pixel packing order within bytes */ -void /* PRIVATE */ -png_do_packswap(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_packswap"); - - if (row_info->bit_depth < 8) - { - png_bytep rp; - png_const_bytep end, table; - - end = row + row_info->rowbytes; - - if (row_info->bit_depth == 1) - table = onebppswaptable; - - else if (row_info->bit_depth == 2) - table = twobppswaptable; - - else if (row_info->bit_depth == 4) - table = fourbppswaptable; - - else - return; - - for (rp = row; rp < end; rp++) - *rp = table[*rp]; - } -} -#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */ - -#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ - defined(PNG_READ_STRIP_ALPHA_SUPPORTED) -/* Remove a channel - this used to be 'png_do_strip_filler' but it used a - * somewhat weird combination of flags to determine what to do. All the calls - * to png_do_strip_filler are changed in 1.5.2 to call this instead with the - * correct arguments. - * - * The routine isn't general - the channel must be the channel at the start or - * end (not in the middle) of each pixel. - */ -void /* PRIVATE */ -png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) -{ - png_bytep sp = row; /* source pointer */ - png_bytep dp = row; /* destination pointer */ - png_bytep ep = row + row_info->rowbytes; /* One beyond end of row */ - - /* At the start sp will point to the first byte to copy and dp to where - * it is copied to. ep always points just beyond the end of the row, so - * the loop simply copies (channels-1) channels until sp reaches ep. - * - * at_start: 0 -- convert AG, XG, ARGB, XRGB, AAGG, XXGG, etc. - * nonzero -- convert GA, GX, RGBA, RGBX, GGAA, RRGGBBXX, etc. - */ - - /* GA, GX, XG cases */ - if (row_info->channels == 2) - { - if (row_info->bit_depth == 8) - { - if (at_start) /* Skip initial filler */ - ++sp; - else /* Skip initial channel and, for sp, the filler */ - sp += 2, ++dp; - - /* For a 1 pixel wide image there is nothing to do */ - while (sp < ep) - *dp++ = *sp, sp += 2; - - row_info->pixel_depth = 8; - } - - else if (row_info->bit_depth == 16) - { - if (at_start) /* Skip initial filler */ - sp += 2; - else /* Skip initial channel and, for sp, the filler */ - sp += 4, dp += 2; - - while (sp < ep) - *dp++ = *sp++, *dp++ = *sp, sp += 3; - - row_info->pixel_depth = 16; - } - - else - return; /* bad bit depth */ - - row_info->channels = 1; - - /* Finally fix the color type if it records an alpha channel */ - if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - row_info->color_type = PNG_COLOR_TYPE_GRAY; - } - - /* RGBA, RGBX, XRGB cases */ - else if (row_info->channels == 4) - { - if (row_info->bit_depth == 8) - { - if (at_start) /* Skip initial filler */ - ++sp; - else /* Skip initial channels and, for sp, the filler */ - sp += 4, dp += 3; - - /* Note that the loop adds 3 to dp and 4 to sp each time. */ - while (sp < ep) - *dp++ = *sp++, *dp++ = *sp++, *dp++ = *sp, sp += 2; - - row_info->pixel_depth = 24; - } - - else if (row_info->bit_depth == 16) - { - if (at_start) /* Skip initial filler */ - sp += 2; - else /* Skip initial channels and, for sp, the filler */ - sp += 8, dp += 6; - - while (sp < ep) - { - /* Copy 6 bytes, skip 2 */ - *dp++ = *sp++, *dp++ = *sp++; - *dp++ = *sp++, *dp++ = *sp++; - *dp++ = *sp++, *dp++ = *sp, sp += 3; - } - - row_info->pixel_depth = 48; - } - - else - return; /* bad bit depth */ - - row_info->channels = 3; - - /* Finally fix the color type if it records an alpha channel */ - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - row_info->color_type = PNG_COLOR_TYPE_RGB; - } - - else - return; /* The filler channel has gone already */ - - /* Fix the rowbytes value. */ - row_info->rowbytes = dp-row; -} -#endif - -#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) -/* Swaps red and blue bytes within a pixel */ -void /* PRIVATE */ -png_do_bgr(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_bgr"); - - if ((row_info->color_type & PNG_COLOR_MASK_COLOR)) - { - png_uint_32 row_width = row_info->width; - if (row_info->bit_depth == 8) - { - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - { - png_bytep rp; - png_uint_32 i; - - for (i = 0, rp = row; i < row_width; i++, rp += 3) - { - png_byte save = *rp; - *rp = *(rp + 2); - *(rp + 2) = save; - } - } - - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - png_bytep rp; - png_uint_32 i; - - for (i = 0, rp = row; i < row_width; i++, rp += 4) - { - png_byte save = *rp; - *rp = *(rp + 2); - *(rp + 2) = save; - } - } - } - -#ifdef PNG_16BIT_SUPPORTED - else if (row_info->bit_depth == 16) - { - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - { - png_bytep rp; - png_uint_32 i; - - for (i = 0, rp = row; i < row_width; i++, rp += 6) - { - png_byte save = *rp; - *rp = *(rp + 4); - *(rp + 4) = save; - save = *(rp + 1); - *(rp + 1) = *(rp + 5); - *(rp + 5) = save; - } - } - - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - png_bytep rp; - png_uint_32 i; - - for (i = 0, rp = row; i < row_width; i++, rp += 8) - { - png_byte save = *rp; - *rp = *(rp + 4); - *(rp + 4) = save; - save = *(rp + 1); - *(rp + 1) = *(rp + 5); - *(rp + 5) = save; - } - } - } -#endif - } -} -#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */ - -#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ - defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) -/* Added at libpng-1.5.10 */ -void /* PRIVATE */ -png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info) -{ - if (png_ptr->num_palette < (1 << row_info->bit_depth) && - png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */ - { - /* Calculations moved outside switch in an attempt to stop different - * compiler warnings. 'padding' is in *bits* within the last byte, it is - * an 'int' because pixel_depth becomes an 'int' in the expression below, - * and this calculation is used because it avoids warnings that other - * forms produced on either GCC or MSVC. - */ - int padding = (-row_info->pixel_depth * row_info->width) & 7; - png_bytep rp = png_ptr->row_buf + row_info->rowbytes; - - switch (row_info->bit_depth) - { - case 1: - { - /* in this case, all bytes must be 0 so we don't need - * to unpack the pixels except for the rightmost one. - */ - for (; rp > png_ptr->row_buf; rp--) - { - if (*rp >> padding != 0) - png_ptr->num_palette_max = 1; - padding = 0; - } - - break; - } - - case 2: - { - for (; rp > png_ptr->row_buf; rp--) - { - int i = ((*rp >> padding) & 0x03); - - if (i > png_ptr->num_palette_max) - png_ptr->num_palette_max = i; - - i = (((*rp >> padding) >> 2) & 0x03); - - if (i > png_ptr->num_palette_max) - png_ptr->num_palette_max = i; - - i = (((*rp >> padding) >> 4) & 0x03); - - if (i > png_ptr->num_palette_max) - png_ptr->num_palette_max = i; - - i = (((*rp >> padding) >> 6) & 0x03); - - if (i > png_ptr->num_palette_max) - png_ptr->num_palette_max = i; - - padding = 0; - } - - break; - } - - case 4: - { - for (; rp > png_ptr->row_buf; rp--) - { - int i = ((*rp >> padding) & 0x0f); - - if (i > png_ptr->num_palette_max) - png_ptr->num_palette_max = i; - - i = (((*rp >> padding) >> 4) & 0x0f); - - if (i > png_ptr->num_palette_max) - png_ptr->num_palette_max = i; - - padding = 0; - } - - break; - } - - case 8: - { - for (; rp > png_ptr->row_buf; rp--) - { - if (*rp > png_ptr->num_palette_max) - png_ptr->num_palette_max = (int) *rp; - } - - break; - } - - default: - break; - } - } -} -#endif /* PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED */ - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) -#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED -void PNGAPI -png_set_user_transform_info(png_structrp png_ptr, png_voidp - user_transform_ptr, int user_transform_depth, int user_transform_channels) -{ - png_debug(1, "in png_set_user_transform_info"); - - if (png_ptr == NULL) - return; - png_ptr->user_transform_ptr = user_transform_ptr; - png_ptr->user_transform_depth = (png_byte)user_transform_depth; - png_ptr->user_transform_channels = (png_byte)user_transform_channels; -} -#endif - -/* This function returns a pointer to the user_transform_ptr associated with - * the user transform functions. The application should free any memory - * associated with this pointer before png_write_destroy and png_read_destroy - * are called. - */ -#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED -png_voidp PNGAPI -png_get_user_transform_ptr(png_const_structrp png_ptr) -{ - if (png_ptr == NULL) - return (NULL); - - return png_ptr->user_transform_ptr; -} -#endif - -#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED -png_uint_32 PNGAPI -png_get_current_row_number(png_const_structrp png_ptr) -{ - /* See the comments in png.h - this is the sub-image row when reading and - * interlaced image. - */ - if (png_ptr != NULL) - return png_ptr->row_number; - - return PNG_UINT_32_MAX; /* help the app not to fail silently */ -} - -png_byte PNGAPI -png_get_current_pass_number(png_const_structrp png_ptr) -{ - if (png_ptr != NULL) - return png_ptr->pass; - return 8; /* invalid */ -} -#endif /* PNG_USER_TRANSFORM_INFO_SUPPORTED */ -#endif /* PNG_READ_USER_TRANSFORM_SUPPORTED || - PNG_WRITE_USER_TRANSFORM_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pngwio.c b/source/modules/juce_graphics/image_formats/pnglib/pngwio.c deleted file mode 100644 index c5fca989c..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pngwio.c +++ /dev/null @@ -1,164 +0,0 @@ - -/* pngwio.c - functions for data output - * - * Last changed in libpng 1.6.0 [February 14, 2013] - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file provides a location for all output. Users who need - * special handling are expected to write functions that have the same - * arguments as these and perform similar functions, but that possibly - * use different output methods. Note that you shouldn't change these - * functions, but rather write replacement functions and then change - * them at run time with png_set_write_fn(...). - */ - -#include "pngpriv.h" - -#ifdef PNG_WRITE_SUPPORTED - -/* Write the data to whatever output you are using. The default routine - * writes to a file pointer. Note that this routine sometimes gets called - * with very small lengths, so you should implement some kind of simple - * buffering if you are using unbuffered writes. This should never be asked - * to write more than 64K on a 16 bit machine. - */ - -void /* PRIVATE */ -png_write_data(png_structrp png_ptr, png_const_bytep data, png_size_t length) -{ - /* NOTE: write_data_fn must not change the buffer! */ - if (png_ptr->write_data_fn != NULL ) - (*(png_ptr->write_data_fn))(png_ptr, png_constcast(png_bytep,data), - length); - - else - png_error(png_ptr, "Call to NULL write function"); -} - -#ifdef PNG_STDIO_SUPPORTED -/* This is the function that does the actual writing of data. If you are - * not writing to a standard C stream, you should create a replacement - * write_data function and use it at run time with png_set_write_fn(), rather - * than changing the library. - */ -void PNGCBAPI -png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_size_t check; - - if (png_ptr == NULL) - return; - - check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr)); - - if (check != length) - png_error(png_ptr, "Write Error"); -} -#endif - -/* This function is called to output any data pending writing (normally - * to disk). After png_flush is called, there should be no data pending - * writing in any buffers. - */ -#ifdef PNG_WRITE_FLUSH_SUPPORTED -void /* PRIVATE */ -png_flush(png_structrp png_ptr) -{ - if (png_ptr->output_flush_fn != NULL) - (*(png_ptr->output_flush_fn))(png_ptr); -} - -# ifdef PNG_STDIO_SUPPORTED -void PNGCBAPI -png_default_flush(png_structp png_ptr) -{ - png_FILE_p io_ptr; - - if (png_ptr == NULL) - return; - - io_ptr = png_voidcast(png_FILE_p, (png_ptr->io_ptr)); - fflush(io_ptr); -} -# endif -#endif - -/* This function allows the application to supply new output functions for - * libpng if standard C streams aren't being used. - * - * This function takes as its arguments: - * png_ptr - pointer to a png output data structure - * io_ptr - pointer to user supplied structure containing info about - * the output functions. May be NULL. - * write_data_fn - pointer to a new output function that takes as its - * arguments a pointer to a png_struct, a pointer to - * data to be written, and a 32-bit unsigned int that is - * the number of bytes to be written. The new write - * function should call png_error(png_ptr, "Error msg") - * to exit and output any fatal error messages. May be - * NULL, in which case libpng's default function will - * be used. - * flush_data_fn - pointer to a new flush function that takes as its - * arguments a pointer to a png_struct. After a call to - * the flush function, there should be no data in any buffers - * or pending transmission. If the output method doesn't do - * any buffering of output, a function prototype must still be - * supplied although it doesn't have to do anything. If - * PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile - * time, output_flush_fn will be ignored, although it must be - * supplied for compatibility. May be NULL, in which case - * libpng's default function will be used, if - * PNG_WRITE_FLUSH_SUPPORTED is defined. This is not - * a good idea if io_ptr does not point to a standard - * *FILE structure. - */ -void PNGAPI -png_set_write_fn(png_structrp png_ptr, png_voidp io_ptr, - png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn) -{ - if (png_ptr == NULL) - return; - - png_ptr->io_ptr = io_ptr; - -#ifdef PNG_STDIO_SUPPORTED - if (write_data_fn != NULL) - png_ptr->write_data_fn = write_data_fn; - - else - png_ptr->write_data_fn = png_default_write_data; -#else - png_ptr->write_data_fn = write_data_fn; -#endif - -#ifdef PNG_WRITE_FLUSH_SUPPORTED -# ifdef PNG_STDIO_SUPPORTED - - if (output_flush_fn != NULL) - png_ptr->output_flush_fn = output_flush_fn; - - else - png_ptr->output_flush_fn = png_default_flush; - -# else - png_ptr->output_flush_fn = output_flush_fn; -# endif -#endif /* PNG_WRITE_FLUSH_SUPPORTED */ - - /* It is an error to read while writing a png file */ - if (png_ptr->read_data_fn != NULL) - { - png_ptr->read_data_fn = NULL; - - png_warning(png_ptr, - "Can't set both read_data_fn and write_data_fn in the" - " same structure"); - } -} -#endif /* PNG_WRITE_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pngwrite.c b/source/modules/juce_graphics/image_formats/pnglib/pngwrite.c deleted file mode 100644 index 4c686824d..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pngwrite.c +++ /dev/null @@ -1,2331 +0,0 @@ - -/* pngwrite.c - general routines to write a PNG file - * - * Last changed in libpng 1.6.1 [March 28, 2013] - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - */ - -#include "pngpriv.h" -#if defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) -# include -#endif - -#ifdef PNG_WRITE_SUPPORTED - -#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED -/* Write out all the unknown chunks for the current given location */ -static void -write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, - unsigned int where) -{ - if (info_ptr->unknown_chunks_num) - { - png_const_unknown_chunkp up; - - png_debug(5, "writing extra chunks"); - - for (up = info_ptr->unknown_chunks; - up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; - ++up) - if (up->location & where) - { - /* If per-chunk unknown chunk handling is enabled use it, otherwise - * just write the chunks the application has set. - */ -#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED - int keep = png_handle_as_unknown(png_ptr, up->name); - - /* NOTE: this code is radically different from the read side in the - * matter of handling an ancillary unknown chunk. In the read side - * the default behavior is to discard it, in the code below the default - * behavior is to write it. Critical chunks are, however, only - * written if explicitly listed or if the default is set to write all - * unknown chunks. - * - * The default handling is also slightly weird - it is not possible to - * stop the writing of all unsafe-to-copy chunks! - * - * TODO: REVIEW: this would seem to be a bug. - */ - if (keep != PNG_HANDLE_CHUNK_NEVER && - ((up->name[3] & 0x20) /* safe-to-copy overrides everything */ || - keep == PNG_HANDLE_CHUNK_ALWAYS || - (keep == PNG_HANDLE_CHUNK_AS_DEFAULT && - png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS))) -#endif - { - /* TODO: review, what is wrong with a zero length unknown chunk? */ - if (up->size == 0) - png_warning(png_ptr, "Writing zero-length unknown chunk"); - - png_write_chunk(png_ptr, up->name, up->data, up->size); - } - } - } -} -#endif /* PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED */ - -/* Writes all the PNG information. This is the suggested way to use the - * library. If you have a new chunk to add, make a function to write it, - * and put it in the correct location here. If you want the chunk written - * after the image data, put it in png_write_end(). I strongly encourage - * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing - * the chunk, as that will keep the code from breaking if you want to just - * write a plain PNG file. If you have long comments, I suggest writing - * them in png_write_end(), and compressing them. - */ -void PNGAPI -png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) -{ - png_debug(1, "in png_write_info_before_PLTE"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) - { - /* Write PNG signature */ - png_write_sig(png_ptr); - -#ifdef PNG_MNG_FEATURES_SUPPORTED - if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \ - (png_ptr->mng_features_permitted)) - { - png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); - png_ptr->mng_features_permitted = 0; - } -#endif - - /* Write IHDR information. */ - png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, - info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, - info_ptr->filter_type, -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - info_ptr->interlace_type -#else - 0 -#endif - ); - - /* The rest of these check to see if the valid field has the appropriate - * flag set, and if it does, writes the chunk. - * - * 1.6.0: COLORSPACE support controls the writing of these chunks too, and - * the chunks will be written if the WRITE routine is there and information - * is available in the COLORSPACE. (See png_colorspace_sync_info in png.c - * for where the valid flags get set.) - * - * Under certain circumstances the colorspace can be invalidated without - * syncing the info_struct 'valid' flags; this happens if libpng detects and - * error and calls png_error while the color space is being set, yet the - * application continues writing the PNG. So check the 'invalid' flag here - * too. - */ -#ifdef PNG_GAMMA_SUPPORTED -# ifdef PNG_WRITE_gAMA_SUPPORTED - if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && - (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) && - (info_ptr->valid & PNG_INFO_gAMA)) - png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma); -# endif -#endif - -#ifdef PNG_COLORSPACE_SUPPORTED - /* Write only one of sRGB or an ICC profile. If a profile was supplied - * and it matches one of the known sRGB ones issue a warning. - */ -# ifdef PNG_WRITE_iCCP_SUPPORTED - if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && - (info_ptr->valid & PNG_INFO_iCCP)) - { -# ifdef PNG_WRITE_sRGB_SUPPORTED - if (info_ptr->valid & PNG_INFO_sRGB) - png_app_warning(png_ptr, - "profile matches sRGB but writing iCCP instead"); -# endif - - png_write_iCCP(png_ptr, info_ptr->iccp_name, - info_ptr->iccp_profile); - } -# ifdef PNG_WRITE_sRGB_SUPPORTED - else -# endif -# endif - -# ifdef PNG_WRITE_sRGB_SUPPORTED - if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && - (info_ptr->valid & PNG_INFO_sRGB)) - png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent); -# endif /* WRITE_sRGB */ -#endif /* COLORSPACE */ - -#ifdef PNG_WRITE_sBIT_SUPPORTED - if (info_ptr->valid & PNG_INFO_sBIT) - png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); -#endif - -#ifdef PNG_COLORSPACE_SUPPORTED -# ifdef PNG_WRITE_cHRM_SUPPORTED - if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && - (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) && - (info_ptr->valid & PNG_INFO_cHRM)) - png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy); -# endif -#endif - -#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR); -#endif - - png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; - } -} - -void PNGAPI -png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) -{ -#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) - int i; -#endif - - png_debug(1, "in png_write_info"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - png_write_info_before_PLTE(png_ptr, info_ptr); - - if (info_ptr->valid & PNG_INFO_PLTE) - png_write_PLTE(png_ptr, info_ptr->palette, - (png_uint_32)info_ptr->num_palette); - - else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - png_error(png_ptr, "Valid palette required for paletted images"); - -#ifdef PNG_WRITE_tRNS_SUPPORTED - if (info_ptr->valid & PNG_INFO_tRNS) - { -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED - /* Invert the alpha channel (in tRNS) */ - if ((png_ptr->transformations & PNG_INVERT_ALPHA) && - info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - int j; - for (j = 0; j<(int)info_ptr->num_trans; j++) - info_ptr->trans_alpha[j] = - (png_byte)(255 - info_ptr->trans_alpha[j]); - } -#endif - png_write_tRNS(png_ptr, info_ptr->trans_alpha, &(info_ptr->trans_color), - info_ptr->num_trans, info_ptr->color_type); - } -#endif -#ifdef PNG_WRITE_bKGD_SUPPORTED - if (info_ptr->valid & PNG_INFO_bKGD) - png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); -#endif - -#ifdef PNG_WRITE_hIST_SUPPORTED - if (info_ptr->valid & PNG_INFO_hIST) - png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); -#endif - -#ifdef PNG_WRITE_oFFs_SUPPORTED - if (info_ptr->valid & PNG_INFO_oFFs) - png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, - info_ptr->offset_unit_type); -#endif - -#ifdef PNG_WRITE_pCAL_SUPPORTED - if (info_ptr->valid & PNG_INFO_pCAL) - png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, - info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, - info_ptr->pcal_units, info_ptr->pcal_params); -#endif - -#ifdef PNG_WRITE_sCAL_SUPPORTED - if (info_ptr->valid & PNG_INFO_sCAL) - png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, - info_ptr->scal_s_width, info_ptr->scal_s_height); -#endif /* sCAL */ - -#ifdef PNG_WRITE_pHYs_SUPPORTED - if (info_ptr->valid & PNG_INFO_pHYs) - png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, - info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); -#endif /* pHYs */ - -#ifdef PNG_WRITE_tIME_SUPPORTED - if (info_ptr->valid & PNG_INFO_tIME) - { - png_write_tIME(png_ptr, &(info_ptr->mod_time)); - png_ptr->mode |= PNG_WROTE_tIME; - } -#endif /* tIME */ - -#ifdef PNG_WRITE_sPLT_SUPPORTED - if (info_ptr->valid & PNG_INFO_sPLT) - for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) - png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); -#endif /* sPLT */ - -#ifdef PNG_WRITE_TEXT_SUPPORTED - /* Check to see if we need to write text chunks */ - for (i = 0; i < info_ptr->num_text; i++) - { - png_debug2(2, "Writing header text chunk %d, type %d", i, - info_ptr->text[i].compression); - /* An internationalized chunk? */ - if (info_ptr->text[i].compression > 0) - { -#ifdef PNG_WRITE_iTXt_SUPPORTED - /* Write international chunk */ - png_write_iTXt(png_ptr, - info_ptr->text[i].compression, - info_ptr->text[i].key, - info_ptr->text[i].lang, - info_ptr->text[i].lang_key, - info_ptr->text[i].text); -#else - png_warning(png_ptr, "Unable to write international text"); -#endif - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; - } - - /* If we want a compressed text chunk */ - else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt) - { -#ifdef PNG_WRITE_zTXt_SUPPORTED - /* Write compressed chunk */ - png_write_zTXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, 0, - info_ptr->text[i].compression); -#else - png_warning(png_ptr, "Unable to write compressed text"); -#endif - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; - } - - else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) - { -#ifdef PNG_WRITE_tEXt_SUPPORTED - /* Write uncompressed chunk */ - png_write_tEXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, - 0); - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; -#else - /* Can't get here */ - png_warning(png_ptr, "Unable to write uncompressed text"); -#endif - } - } -#endif /* tEXt */ - -#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_PLTE); -#endif -} - -/* Writes the end of the PNG file. If you don't want to write comments or - * time information, you can pass NULL for info. If you already wrote these - * in png_write_info(), do not write them again here. If you have long - * comments, I suggest writing them here, and compressing them. - */ -void PNGAPI -png_write_end(png_structrp png_ptr, png_inforp info_ptr) -{ - png_debug(1, "in png_write_end"); - - if (png_ptr == NULL) - return; - - if (!(png_ptr->mode & PNG_HAVE_IDAT)) - png_error(png_ptr, "No IDATs written into file"); - -#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED - if (png_ptr->num_palette_max > png_ptr->num_palette) - png_benign_error(png_ptr, "Wrote palette index exceeding num_palette"); -#endif - - /* See if user wants us to write information chunks */ - if (info_ptr != NULL) - { -#ifdef PNG_WRITE_TEXT_SUPPORTED - int i; /* local index variable */ -#endif -#ifdef PNG_WRITE_tIME_SUPPORTED - /* Check to see if user has supplied a time chunk */ - if ((info_ptr->valid & PNG_INFO_tIME) && - !(png_ptr->mode & PNG_WROTE_tIME)) - png_write_tIME(png_ptr, &(info_ptr->mod_time)); - -#endif -#ifdef PNG_WRITE_TEXT_SUPPORTED - /* Loop through comment chunks */ - for (i = 0; i < info_ptr->num_text; i++) - { - png_debug2(2, "Writing trailer text chunk %d, type %d", i, - info_ptr->text[i].compression); - /* An internationalized chunk? */ - if (info_ptr->text[i].compression > 0) - { -#ifdef PNG_WRITE_iTXt_SUPPORTED - /* Write international chunk */ - png_write_iTXt(png_ptr, - info_ptr->text[i].compression, - info_ptr->text[i].key, - info_ptr->text[i].lang, - info_ptr->text[i].lang_key, - info_ptr->text[i].text); -#else - png_warning(png_ptr, "Unable to write international text"); -#endif - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; - } - - else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) - { -#ifdef PNG_WRITE_zTXt_SUPPORTED - /* Write compressed chunk */ - png_write_zTXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, 0, - info_ptr->text[i].compression); -#else - png_warning(png_ptr, "Unable to write compressed text"); -#endif - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; - } - - else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) - { -#ifdef PNG_WRITE_tEXt_SUPPORTED - /* Write uncompressed chunk */ - png_write_tEXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, 0); -#else - png_warning(png_ptr, "Unable to write uncompressed text"); -#endif - - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; - } - } -#endif -#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT); -#endif - } - - png_ptr->mode |= PNG_AFTER_IDAT; - - /* Write end of PNG file */ - png_write_IEND(png_ptr); - /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, - * and restored again in libpng-1.2.30, may cause some applications that - * do not set png_ptr->output_flush_fn to crash. If your application - * experiences a problem, please try building libpng with - * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to - * png-mng-implement at lists.sf.net . - */ -#ifdef PNG_WRITE_FLUSH_SUPPORTED -# ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED - png_flush(png_ptr); -# endif -#endif -} - -#ifdef PNG_CONVERT_tIME_SUPPORTED -void PNGAPI -png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm * ttime) -{ - png_debug(1, "in png_convert_from_struct_tm"); - - ptime->year = (png_uint_16)(1900 + ttime->tm_year); - ptime->month = (png_byte)(ttime->tm_mon + 1); - ptime->day = (png_byte)ttime->tm_mday; - ptime->hour = (png_byte)ttime->tm_hour; - ptime->minute = (png_byte)ttime->tm_min; - ptime->second = (png_byte)ttime->tm_sec; -} - -void PNGAPI -png_convert_from_time_t(png_timep ptime, time_t ttime) -{ - struct tm *tbuf; - - png_debug(1, "in png_convert_from_time_t"); - - tbuf = gmtime(&ttime); - png_convert_from_struct_tm(ptime, tbuf); -} -#endif - -/* Initialize png_ptr structure, and allocate any memory needed */ -PNG_FUNCTION(png_structp,PNGAPI -png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) -{ -#ifndef PNG_USER_MEM_SUPPORTED - png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, - error_fn, warn_fn, NULL, NULL, NULL); -#else - return png_create_write_struct_2(user_png_ver, error_ptr, error_fn, - warn_fn, NULL, NULL, NULL); -} - -/* Alternate initialize png_ptr structure, and allocate any memory needed */ -PNG_FUNCTION(png_structp,PNGAPI -png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, - png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) -{ - png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, - error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); -#endif /* PNG_USER_MEM_SUPPORTED */ - - /* Set the zlib control values to defaults; they can be overridden by the - * application after the struct has been created. - */ - png_ptr->zbuffer_size = PNG_ZBUF_SIZE; - - /* The 'zlib_strategy' setting is irrelevant because png_default_claim in - * pngwutil.c defaults it according to whether or not filters will be used, - * and ignores this setting. - */ - png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY; - png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION; - png_ptr->zlib_mem_level = 8; - png_ptr->zlib_window_bits = 15; - png_ptr->zlib_method = 8; - -#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED - png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY; - png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION; - png_ptr->zlib_text_mem_level = 8; - png_ptr->zlib_text_window_bits = 15; - png_ptr->zlib_text_method = 8; -#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */ - - /* This is a highly dubious configuration option; by default it is off, but - * it may be appropriate for private builds that are testing extensions not - * conformant to the current specification, or of applications that must not - * fail to write at all costs! - */ -# ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED - png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; - /* In stable builds only warn if an application error can be completely - * handled. - */ -# endif - - /* App warnings are warnings in release (or release candidate) builds but - * are errors during development. - */ -# if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC - png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; -# endif - - if (png_ptr != NULL) - { - /* TODO: delay this, it can be done in png_init_io() (if the app doesn't - * do it itself) avoiding setting the default function if it is not - * required. - */ - png_set_write_fn(png_ptr, NULL, NULL, NULL); - } - - return png_ptr; -} - - -/* Write a few rows of image data. If the image is interlaced, - * either you will have to write the 7 sub images, or, if you - * have called png_set_interlace_handling(), you will have to - * "write" the image seven times. - */ -void PNGAPI -png_write_rows(png_structrp png_ptr, png_bytepp row, - png_uint_32 num_rows) -{ - png_uint_32 i; /* row counter */ - png_bytepp rp; /* row pointer */ - - png_debug(1, "in png_write_rows"); - - if (png_ptr == NULL) - return; - - /* Loop through the rows */ - for (i = 0, rp = row; i < num_rows; i++, rp++) - { - png_write_row(png_ptr, *rp); - } -} - -/* Write the image. You only need to call this function once, even - * if you are writing an interlaced image. - */ -void PNGAPI -png_write_image(png_structrp png_ptr, png_bytepp image) -{ - png_uint_32 i; /* row index */ - int pass, num_pass; /* pass variables */ - png_bytepp rp; /* points to current row */ - - if (png_ptr == NULL) - return; - - png_debug(1, "in png_write_image"); - -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* Initialize interlace handling. If image is not interlaced, - * this will set pass to 1 - */ - num_pass = png_set_interlace_handling(png_ptr); -#else - num_pass = 1; -#endif - /* Loop through passes */ - for (pass = 0; pass < num_pass; pass++) - { - /* Loop through image */ - for (i = 0, rp = image; i < png_ptr->height; i++, rp++) - { - png_write_row(png_ptr, *rp); - } - } -} - -/* Called by user to write a row of image data */ -void PNGAPI -png_write_row(png_structrp png_ptr, png_const_bytep row) -{ - /* 1.5.6: moved from png_struct to be a local structure: */ - png_row_info row_info; - - if (png_ptr == NULL) - return; - - png_debug2(1, "in png_write_row (row %u, pass %d)", - png_ptr->row_number, png_ptr->pass); - - /* Initialize transformations and other stuff if first time */ - if (png_ptr->row_number == 0 && png_ptr->pass == 0) - { - /* Make sure we wrote the header info */ - if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) - png_error(png_ptr, - "png_write_info was never called before png_write_row"); - - /* Check for transforms that have been set but were defined out */ -#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) - if (png_ptr->transformations & PNG_INVERT_MONO) - png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined"); -#endif - -#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) - if (png_ptr->transformations & PNG_FILLER) - png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined"); -#endif -#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ - defined(PNG_READ_PACKSWAP_SUPPORTED) - if (png_ptr->transformations & PNG_PACKSWAP) - png_warning(png_ptr, - "PNG_WRITE_PACKSWAP_SUPPORTED is not defined"); -#endif - -#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) - if (png_ptr->transformations & PNG_PACK) - png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined"); -#endif - -#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) - if (png_ptr->transformations & PNG_SHIFT) - png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined"); -#endif - -#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) - if (png_ptr->transformations & PNG_BGR) - png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined"); -#endif - -#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) - if (png_ptr->transformations & PNG_SWAP_BYTES) - png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined"); -#endif - - png_write_start_row(png_ptr); - } - -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* If interlaced and not interested in row, return */ - if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) - { - switch (png_ptr->pass) - { - case 0: - if (png_ptr->row_number & 0x07) - { - png_write_finish_row(png_ptr); - return; - } - break; - - case 1: - if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) - { - png_write_finish_row(png_ptr); - return; - } - break; - - case 2: - if ((png_ptr->row_number & 0x07) != 4) - { - png_write_finish_row(png_ptr); - return; - } - break; - - case 3: - if ((png_ptr->row_number & 0x03) || png_ptr->width < 3) - { - png_write_finish_row(png_ptr); - return; - } - break; - - case 4: - if ((png_ptr->row_number & 0x03) != 2) - { - png_write_finish_row(png_ptr); - return; - } - break; - - case 5: - if ((png_ptr->row_number & 0x01) || png_ptr->width < 2) - { - png_write_finish_row(png_ptr); - return; - } - break; - - case 6: - if (!(png_ptr->row_number & 0x01)) - { - png_write_finish_row(png_ptr); - return; - } - break; - - default: /* error: ignore it */ - break; - } - } -#endif - - /* Set up row info for transformations */ - row_info.color_type = png_ptr->color_type; - row_info.width = png_ptr->usr_width; - row_info.channels = png_ptr->usr_channels; - row_info.bit_depth = png_ptr->usr_bit_depth; - row_info.pixel_depth = (png_byte)(row_info.bit_depth * row_info.channels); - row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); - - png_debug1(3, "row_info->color_type = %d", row_info.color_type); - png_debug1(3, "row_info->width = %u", row_info.width); - png_debug1(3, "row_info->channels = %d", row_info.channels); - png_debug1(3, "row_info->bit_depth = %d", row_info.bit_depth); - png_debug1(3, "row_info->pixel_depth = %d", row_info.pixel_depth); - png_debug1(3, "row_info->rowbytes = %lu", (unsigned long)row_info.rowbytes); - - /* Copy user's row into buffer, leaving room for filter byte. */ - memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes); - -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* Handle interlacing */ - if (png_ptr->interlaced && png_ptr->pass < 6 && - (png_ptr->transformations & PNG_INTERLACE)) - { - png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass); - /* This should always get caught above, but still ... */ - if (!(row_info.width)) - { - png_write_finish_row(png_ptr); - return; - } - } -#endif - -#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED - /* Handle other transformations */ - if (png_ptr->transformations) - png_do_write_transformations(png_ptr, &row_info); -#endif - - /* At this point the row_info pixel depth must match the 'transformed' depth, - * which is also the output depth. - */ - if (row_info.pixel_depth != png_ptr->pixel_depth || - row_info.pixel_depth != png_ptr->transformed_pixel_depth) - png_error(png_ptr, "internal write transform logic error"); - -#ifdef PNG_MNG_FEATURES_SUPPORTED - /* Write filter_method 64 (intrapixel differencing) only if - * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and - * 2. Libpng did not write a PNG signature (this filter_method is only - * used in PNG datastreams that are embedded in MNG datastreams) and - * 3. The application called png_permit_mng_features with a mask that - * included PNG_FLAG_MNG_FILTER_64 and - * 4. The filter_method is 64 and - * 5. The color_type is RGB or RGBA - */ - if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && - (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) - { - /* Intrapixel differencing */ - png_do_write_intrapixel(&row_info, png_ptr->row_buf + 1); - } -#endif - -/* Added at libpng-1.5.10 */ -#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED - /* Check for out-of-range palette index */ - if (row_info.color_type == PNG_COLOR_TYPE_PALETTE && - png_ptr->num_palette_max >= 0) - png_do_check_palette_indexes(png_ptr, &row_info); -#endif - - /* Find a filter if necessary, filter the row and write it out. */ - png_write_find_filter(png_ptr, &row_info); - - if (png_ptr->write_row_fn != NULL) - (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); -} - -#ifdef PNG_WRITE_FLUSH_SUPPORTED -/* Set the automatic flush interval or 0 to turn flushing off */ -void PNGAPI -png_set_flush(png_structrp png_ptr, int nrows) -{ - png_debug(1, "in png_set_flush"); - - if (png_ptr == NULL) - return; - - png_ptr->flush_dist = (nrows < 0 ? 0 : nrows); -} - -/* Flush the current output buffers now */ -void PNGAPI -png_write_flush(png_structrp png_ptr) -{ - png_debug(1, "in png_write_flush"); - - if (png_ptr == NULL) - return; - - /* We have already written out all of the data */ - if (png_ptr->row_number >= png_ptr->num_rows) - return; - - png_compress_IDAT(png_ptr, NULL, 0, Z_SYNC_FLUSH); - png_ptr->flush_rows = 0; - png_flush(png_ptr); -} -#endif /* PNG_WRITE_FLUSH_SUPPORTED */ - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED -static void png_reset_filter_heuristics(png_structrp png_ptr);/* forward decl */ -#endif - -/* Free any memory used in png_ptr struct without freeing the struct itself. */ -static void -png_write_destroy(png_structrp png_ptr) -{ - png_debug(1, "in png_write_destroy"); - - /* Free any memory zlib uses */ - if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) - deflateEnd(&png_ptr->zstream); - - /* Free our memory. png_free checks NULL for us. */ - png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); - png_free(png_ptr, png_ptr->row_buf); -#ifdef PNG_WRITE_FILTER_SUPPORTED - png_free(png_ptr, png_ptr->prev_row); - png_free(png_ptr, png_ptr->sub_row); - png_free(png_ptr, png_ptr->up_row); - png_free(png_ptr, png_ptr->avg_row); - png_free(png_ptr, png_ptr->paeth_row); -#endif - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - /* Use this to save a little code space, it doesn't free the filter_costs */ - png_reset_filter_heuristics(png_ptr); - png_free(png_ptr, png_ptr->filter_costs); - png_free(png_ptr, png_ptr->inv_filter_costs); -#endif - -#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED - png_free(png_ptr, png_ptr->chunk_list); -#endif - - /* The error handling and memory handling information is left intact at this - * point: the jmp_buf may still have to be freed. See png_destroy_png_struct - * for how this happens. - */ -} - -/* Free all memory used by the write. - * In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for - * *png_ptr_ptr. Prior to 1.6.0 it would accept such a value and it would free - * the passed in info_structs but it would quietly fail to free any of the data - * inside them. In 1.6.0 it quietly does nothing (it has to be quiet because it - * has no png_ptr.) - */ -void PNGAPI -png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) -{ - png_debug(1, "in png_destroy_write_struct"); - - if (png_ptr_ptr != NULL) - { - png_structrp png_ptr = *png_ptr_ptr; - - if (png_ptr != NULL) /* added in libpng 1.6.0 */ - { - png_destroy_info_struct(png_ptr, info_ptr_ptr); - - *png_ptr_ptr = NULL; - png_write_destroy(png_ptr); - png_destroy_png_struct(png_ptr); - } - } -} - -/* Allow the application to select one or more row filters to use. */ -void PNGAPI -png_set_filter(png_structrp png_ptr, int method, int filters) -{ - png_debug(1, "in png_set_filter"); - - if (png_ptr == NULL) - return; - -#ifdef PNG_MNG_FEATURES_SUPPORTED - if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && - (method == PNG_INTRAPIXEL_DIFFERENCING)) - method = PNG_FILTER_TYPE_BASE; - -#endif - if (method == PNG_FILTER_TYPE_BASE) - { - switch (filters & (PNG_ALL_FILTERS | 0x07)) - { -#ifdef PNG_WRITE_FILTER_SUPPORTED - case 5: - case 6: - case 7: png_app_error(png_ptr, "Unknown row filter for method 0"); - /* FALL THROUGH */ -#endif /* PNG_WRITE_FILTER_SUPPORTED */ - case PNG_FILTER_VALUE_NONE: - png_ptr->do_filter = PNG_FILTER_NONE; break; - -#ifdef PNG_WRITE_FILTER_SUPPORTED - case PNG_FILTER_VALUE_SUB: - png_ptr->do_filter = PNG_FILTER_SUB; break; - - case PNG_FILTER_VALUE_UP: - png_ptr->do_filter = PNG_FILTER_UP; break; - - case PNG_FILTER_VALUE_AVG: - png_ptr->do_filter = PNG_FILTER_AVG; break; - - case PNG_FILTER_VALUE_PAETH: - png_ptr->do_filter = PNG_FILTER_PAETH; break; - - default: - png_ptr->do_filter = (png_byte)filters; break; -#else - default: - png_app_error(png_ptr, "Unknown row filter for method 0"); -#endif /* PNG_WRITE_FILTER_SUPPORTED */ - } - - /* If we have allocated the row_buf, this means we have already started - * with the image and we should have allocated all of the filter buffers - * that have been selected. If prev_row isn't already allocated, then - * it is too late to start using the filters that need it, since we - * will be missing the data in the previous row. If an application - * wants to start and stop using particular filters during compression, - * it should start out with all of the filters, and then add and - * remove them after the start of compression. - */ - if (png_ptr->row_buf != NULL) - { -#ifdef PNG_WRITE_FILTER_SUPPORTED - if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL) - { - png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, - (png_ptr->rowbytes + 1)); - png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; - } - - if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL) - { - if (png_ptr->prev_row == NULL) - { - png_warning(png_ptr, "Can't add Up filter after starting"); - png_ptr->do_filter = (png_byte)(png_ptr->do_filter & - ~PNG_FILTER_UP); - } - - else - { - png_ptr->up_row = (png_bytep)png_malloc(png_ptr, - (png_ptr->rowbytes + 1)); - png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; - } - } - - if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL) - { - if (png_ptr->prev_row == NULL) - { - png_warning(png_ptr, "Can't add Average filter after starting"); - png_ptr->do_filter = (png_byte)(png_ptr->do_filter & - ~PNG_FILTER_AVG); - } - - else - { - png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, - (png_ptr->rowbytes + 1)); - png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; - } - } - - if ((png_ptr->do_filter & PNG_FILTER_PAETH) && - png_ptr->paeth_row == NULL) - { - if (png_ptr->prev_row == NULL) - { - png_warning(png_ptr, "Can't add Paeth filter after starting"); - png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH); - } - - else - { - png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, - (png_ptr->rowbytes + 1)); - png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; - } - } - - if (png_ptr->do_filter == PNG_NO_FILTERS) -#endif /* PNG_WRITE_FILTER_SUPPORTED */ - png_ptr->do_filter = PNG_FILTER_NONE; - } - } - else - png_error(png_ptr, "Unknown custom filter method"); -} - -/* This allows us to influence the way in which libpng chooses the "best" - * filter for the current scanline. While the "minimum-sum-of-absolute- - * differences metric is relatively fast and effective, there is some - * question as to whether it can be improved upon by trying to keep the - * filtered data going to zlib more consistent, hopefully resulting in - * better compression. - */ -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* GRR 970116 */ -/* Convenience reset API. */ -static void -png_reset_filter_heuristics(png_structrp png_ptr) -{ - /* Clear out any old values in the 'weights' - this must be done because if - * the app calls set_filter_heuristics multiple times with different - * 'num_weights' values we would otherwise potentially have wrong sized - * arrays. - */ - png_ptr->num_prev_filters = 0; - png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED; - if (png_ptr->prev_filters != NULL) - { - png_bytep old = png_ptr->prev_filters; - png_ptr->prev_filters = NULL; - png_free(png_ptr, old); - } - if (png_ptr->filter_weights != NULL) - { - png_uint_16p old = png_ptr->filter_weights; - png_ptr->filter_weights = NULL; - png_free(png_ptr, old); - } - - if (png_ptr->inv_filter_weights != NULL) - { - png_uint_16p old = png_ptr->inv_filter_weights; - png_ptr->inv_filter_weights = NULL; - png_free(png_ptr, old); - } - - /* Leave the filter_costs - this array is fixed size. */ -} - -static int -png_init_filter_heuristics(png_structrp png_ptr, int heuristic_method, - int num_weights) -{ - if (png_ptr == NULL) - return 0; - - /* Clear out the arrays */ - png_reset_filter_heuristics(png_ptr); - - /* Check arguments; the 'reset' function makes the correct settings for the - * unweighted case, but we must handle the weight case by initializing the - * arrays for the caller. - */ - if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int i; - - if (num_weights > 0) - { - png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, - (png_uint_32)((sizeof (png_byte)) * num_weights)); - - /* To make sure that the weighting starts out fairly */ - for (i = 0; i < num_weights; i++) - { - png_ptr->prev_filters[i] = 255; - } - - png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)((sizeof (png_uint_16)) * num_weights)); - - png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)((sizeof (png_uint_16)) * num_weights)); - - for (i = 0; i < num_weights; i++) - { - png_ptr->inv_filter_weights[i] = - png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; - } - - /* Safe to set this now */ - png_ptr->num_prev_filters = (png_byte)num_weights; - } - - /* If, in the future, there are other filter methods, this would - * need to be based on png_ptr->filter. - */ - if (png_ptr->filter_costs == NULL) - { - png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST)); - - png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST)); - } - - for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) - { - png_ptr->inv_filter_costs[i] = - png_ptr->filter_costs[i] = PNG_COST_FACTOR; - } - - /* All the arrays are inited, safe to set this: */ - png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_WEIGHTED; - - /* Return the 'ok' code. */ - return 1; - } - else if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT || - heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED) - { - return 1; - } - else - { - png_warning(png_ptr, "Unknown filter heuristic method"); - return 0; - } -} - -/* Provide floating and fixed point APIs */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -void PNGAPI -png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method, - int num_weights, png_const_doublep filter_weights, - png_const_doublep filter_costs) -{ - png_debug(1, "in png_set_filter_heuristics"); - - /* The internal API allocates all the arrays and ensures that the elements of - * those arrays are set to the default value. - */ - if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights)) - return; - - /* If using the weighted method copy in the weights. */ - if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int i; - for (i = 0; i < num_weights; i++) - { - if (filter_weights[i] <= 0.0) - { - png_ptr->inv_filter_weights[i] = - png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; - } - - else - { - png_ptr->inv_filter_weights[i] = - (png_uint_16)(PNG_WEIGHT_FACTOR*filter_weights[i]+.5); - - png_ptr->filter_weights[i] = - (png_uint_16)(PNG_WEIGHT_FACTOR/filter_weights[i]+.5); - } - } - - /* Here is where we set the relative costs of the different filters. We - * should take the desired compression level into account when setting - * the costs, so that Paeth, for instance, has a high relative cost at low - * compression levels, while it has a lower relative cost at higher - * compression settings. The filter types are in order of increasing - * relative cost, so it would be possible to do this with an algorithm. - */ - for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) if (filter_costs[i] >= 1.0) - { - png_ptr->inv_filter_costs[i] = - (png_uint_16)(PNG_COST_FACTOR / filter_costs[i] + .5); - - png_ptr->filter_costs[i] = - (png_uint_16)(PNG_COST_FACTOR * filter_costs[i] + .5); - } - } -} -#endif /* FLOATING_POINT */ - -#ifdef PNG_FIXED_POINT_SUPPORTED -void PNGAPI -png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method, - int num_weights, png_const_fixed_point_p filter_weights, - png_const_fixed_point_p filter_costs) -{ - png_debug(1, "in png_set_filter_heuristics_fixed"); - - /* The internal API allocates all the arrays and ensures that the elements of - * those arrays are set to the default value. - */ - if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights)) - return; - - /* If using the weighted method copy in the weights. */ - if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int i; - for (i = 0; i < num_weights; i++) - { - if (filter_weights[i] <= 0) - { - png_ptr->inv_filter_weights[i] = - png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; - } - - else - { - png_ptr->inv_filter_weights[i] = (png_uint_16) - ((PNG_WEIGHT_FACTOR*filter_weights[i]+PNG_FP_HALF)/PNG_FP_1); - - png_ptr->filter_weights[i] = (png_uint_16)((PNG_WEIGHT_FACTOR* - PNG_FP_1+(filter_weights[i]/2))/filter_weights[i]); - } - } - - /* Here is where we set the relative costs of the different filters. We - * should take the desired compression level into account when setting - * the costs, so that Paeth, for instance, has a high relative cost at low - * compression levels, while it has a lower relative cost at higher - * compression settings. The filter types are in order of increasing - * relative cost, so it would be possible to do this with an algorithm. - */ - for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) - if (filter_costs[i] >= PNG_FP_1) - { - png_uint_32 tmp; - - /* Use a 32 bit unsigned temporary here because otherwise the - * intermediate value will be a 32 bit *signed* integer (ANSI rules) - * and this will get the wrong answer on division. - */ - tmp = PNG_COST_FACTOR*PNG_FP_1 + (filter_costs[i]/2); - tmp /= filter_costs[i]; - - png_ptr->inv_filter_costs[i] = (png_uint_16)tmp; - - tmp = PNG_COST_FACTOR * filter_costs[i] + PNG_FP_HALF; - tmp /= PNG_FP_1; - - png_ptr->filter_costs[i] = (png_uint_16)tmp; - } - } -} -#endif /* FIXED_POINT */ -#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ - -void PNGAPI -png_set_compression_level(png_structrp png_ptr, int level) -{ - png_debug(1, "in png_set_compression_level"); - - if (png_ptr == NULL) - return; - - png_ptr->zlib_level = level; -} - -void PNGAPI -png_set_compression_mem_level(png_structrp png_ptr, int mem_level) -{ - png_debug(1, "in png_set_compression_mem_level"); - - if (png_ptr == NULL) - return; - - png_ptr->zlib_mem_level = mem_level; -} - -void PNGAPI -png_set_compression_strategy(png_structrp png_ptr, int strategy) -{ - png_debug(1, "in png_set_compression_strategy"); - - if (png_ptr == NULL) - return; - - /* The flag setting here prevents the libpng dynamic selection of strategy. - */ - png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; - png_ptr->zlib_strategy = strategy; -} - -/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a - * smaller value of window_bits if it can do so safely. - */ -void PNGAPI -png_set_compression_window_bits(png_structrp png_ptr, int window_bits) -{ - if (png_ptr == NULL) - return; - - /* Prior to 1.6.0 this would warn but then set the window_bits value, this - * meant that negative window bits values could be selected which would cause - * libpng to write a non-standard PNG file with raw deflate or gzip - * compressed IDAT or ancillary chunks. Such files can be read and there is - * no warning on read, so this seems like a very bad idea. - */ - if (window_bits > 15) - { - png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); - window_bits = 15; - } - - else if (window_bits < 8) - { - png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); - window_bits = 8; - } - - png_ptr->zlib_window_bits = window_bits; -} - -void PNGAPI -png_set_compression_method(png_structrp png_ptr, int method) -{ - png_debug(1, "in png_set_compression_method"); - - if (png_ptr == NULL) - return; - - /* This would produce an invalid PNG file if it worked, but it doesn't and - * deflate will fault it, so it is harmless to just warn here. - */ - if (method != 8) - png_warning(png_ptr, "Only compression method 8 is supported by PNG"); - - png_ptr->zlib_method = method; -} - -/* The following were added to libpng-1.5.4 */ -#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED -void PNGAPI -png_set_text_compression_level(png_structrp png_ptr, int level) -{ - png_debug(1, "in png_set_text_compression_level"); - - if (png_ptr == NULL) - return; - - png_ptr->zlib_text_level = level; -} - -void PNGAPI -png_set_text_compression_mem_level(png_structrp png_ptr, int mem_level) -{ - png_debug(1, "in png_set_text_compression_mem_level"); - - if (png_ptr == NULL) - return; - - png_ptr->zlib_text_mem_level = mem_level; -} - -void PNGAPI -png_set_text_compression_strategy(png_structrp png_ptr, int strategy) -{ - png_debug(1, "in png_set_text_compression_strategy"); - - if (png_ptr == NULL) - return; - - png_ptr->zlib_text_strategy = strategy; -} - -/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a - * smaller value of window_bits if it can do so safely. - */ -void PNGAPI -png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits) -{ - if (png_ptr == NULL) - return; - - if (window_bits > 15) - { - png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); - window_bits = 15; - } - - else if (window_bits < 8) - { - png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); - window_bits = 8; - } - - png_ptr->zlib_text_window_bits = window_bits; -} - -void PNGAPI -png_set_text_compression_method(png_structrp png_ptr, int method) -{ - png_debug(1, "in png_set_text_compression_method"); - - if (png_ptr == NULL) - return; - - if (method != 8) - png_warning(png_ptr, "Only compression method 8 is supported by PNG"); - - png_ptr->zlib_text_method = method; -} -#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ -/* end of API added to libpng-1.5.4 */ - -void PNGAPI -png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn) -{ - if (png_ptr == NULL) - return; - - png_ptr->write_row_fn = write_row_fn; -} - -#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED -void PNGAPI -png_set_write_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr - write_user_transform_fn) -{ - png_debug(1, "in png_set_write_user_transform_fn"); - - if (png_ptr == NULL) - return; - - png_ptr->transformations |= PNG_USER_TRANSFORM; - png_ptr->write_user_transform_fn = write_user_transform_fn; -} -#endif - - -#ifdef PNG_INFO_IMAGE_SUPPORTED -void PNGAPI -png_write_png(png_structrp png_ptr, png_inforp info_ptr, - int transforms, voidp params) -{ - if (png_ptr == NULL || info_ptr == NULL) - return; - - /* Write the file header information. */ - png_write_info(png_ptr, info_ptr); - - /* ------ these transformations don't touch the info structure ------- */ - -#ifdef PNG_WRITE_INVERT_SUPPORTED - /* Invert monochrome pixels */ - if (transforms & PNG_TRANSFORM_INVERT_MONO) - png_set_invert_mono(png_ptr); -#endif - -#ifdef PNG_WRITE_SHIFT_SUPPORTED - /* Shift the pixels up to a legal bit depth and fill in - * as appropriate to correctly scale the image. - */ - if ((transforms & PNG_TRANSFORM_SHIFT) - && (info_ptr->valid & PNG_INFO_sBIT)) - png_set_shift(png_ptr, &info_ptr->sig_bit); -#endif - -#ifdef PNG_WRITE_PACK_SUPPORTED - /* Pack pixels into bytes */ - if (transforms & PNG_TRANSFORM_PACKING) - png_set_packing(png_ptr); -#endif - -#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED - /* Swap location of alpha bytes from ARGB to RGBA */ - if (transforms & PNG_TRANSFORM_SWAP_ALPHA) - png_set_swap_alpha(png_ptr); -#endif - -#ifdef PNG_WRITE_FILLER_SUPPORTED - /* Pack XRGB/RGBX/ARGB/RGBA into RGB (4 channels -> 3 channels) */ - if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) - png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); - - else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) - png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); -#endif - -#ifdef PNG_WRITE_BGR_SUPPORTED - /* Flip BGR pixels to RGB */ - if (transforms & PNG_TRANSFORM_BGR) - png_set_bgr(png_ptr); -#endif - -#ifdef PNG_WRITE_SWAP_SUPPORTED - /* Swap bytes of 16-bit files to most significant byte first */ - if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) - png_set_swap(png_ptr); -#endif - -#ifdef PNG_WRITE_PACKSWAP_SUPPORTED - /* Swap bits of 1, 2, 4 bit packed pixel formats */ - if (transforms & PNG_TRANSFORM_PACKSWAP) - png_set_packswap(png_ptr); -#endif - -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED - /* Invert the alpha channel from opacity to transparency */ - if (transforms & PNG_TRANSFORM_INVERT_ALPHA) - png_set_invert_alpha(png_ptr); -#endif - - /* ----------------------- end of transformations ------------------- */ - - /* Write the bits */ - if (info_ptr->valid & PNG_INFO_IDAT) - png_write_image(png_ptr, info_ptr->row_pointers); - - /* It is REQUIRED to call this to finish writing the rest of the file */ - png_write_end(png_ptr, info_ptr); - - PNG_UNUSED(transforms) /* Quiet compiler warnings */ - PNG_UNUSED(params) -} -#endif - - -#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED -#ifdef PNG_STDIO_SUPPORTED /* currently required for png_image_write_* */ -/* Initialize the write structure - general purpose utility. */ -static int -png_image_write_init(png_imagep image) -{ - png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image, - png_safe_error, png_safe_warning); - - if (png_ptr != NULL) - { - png_infop info_ptr = png_create_info_struct(png_ptr); - - if (info_ptr != NULL) - { - png_controlp control = png_voidcast(png_controlp, - png_malloc_warn(png_ptr, (sizeof *control))); - - if (control != NULL) - { - memset(control, 0, (sizeof *control)); - - control->png_ptr = png_ptr; - control->info_ptr = info_ptr; - control->for_write = 1; - - image->opaque = control; - return 1; - } - - /* Error clean up */ - png_destroy_info_struct(png_ptr, &info_ptr); - } - - png_destroy_write_struct(&png_ptr, NULL); - } - - return png_image_error(image, "png_image_write_: out of memory"); -} - -/* Arguments to png_image_write_main: */ -typedef struct -{ - /* Arguments: */ - png_imagep image; - png_const_voidp buffer; - png_int_32 row_stride; - png_const_voidp colormap; - int convert_to_8bit; - /* Local variables: */ - png_const_voidp first_row; - ptrdiff_t row_bytes; - png_voidp local_row; -} png_image_write_control; - -/* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to - * do any necessary byte swapping. The component order is defined by the - * png_image format value. - */ -static int -png_write_image_16bit(png_voidp argument) -{ - png_image_write_control *display = png_voidcast(png_image_write_control*, - argument); - png_imagep image = display->image; - png_structrp png_ptr = image->opaque->png_ptr; - - png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, - display->first_row); - png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row); - png_uint_16p row_end; - const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1; - int aindex = 0; - png_uint_32 y = image->height; - - if (image->format & PNG_FORMAT_FLAG_ALPHA) - { - if (image->format & PNG_FORMAT_FLAG_AFIRST) - { - aindex = -1; - ++input_row; /* To point to the first component */ - ++output_row; - } - - else - aindex = channels; - } - - else - png_error(png_ptr, "png_write_image: internal call error"); - - /* Work out the output row end and count over this, note that the increment - * above to 'row' means that row_end can actually be beyond the end of the - * row; this is correct. - */ - row_end = output_row + image->width * (channels+1); - - while (y-- > 0) - { - png_const_uint_16p in_ptr = input_row; - png_uint_16p out_ptr = output_row; - - while (out_ptr < row_end) - { - const png_uint_16 alpha = in_ptr[aindex]; - png_uint_32 reciprocal = 0; - int c; - - out_ptr[aindex] = alpha; - - /* Calculate a reciprocal. The correct calculation is simply - * component/alpha*65535 << 15. (I.e. 15 bits of precision); this - * allows correct rounding by adding .5 before the shift. 'reciprocal' - * is only initialized when required. - */ - if (alpha > 0 && alpha < 65535) - reciprocal = ((0xffff<<15)+(alpha>>1))/alpha; - - c = channels; - do /* always at least one channel */ - { - png_uint_16 component = *in_ptr++; - - /* The following gives 65535 for an alpha of 0, which is fine, - * otherwise if 0/0 is represented as some other value there is more - * likely to be a discontinuity which will probably damage - * compression when moving from a fully transparent area to a - * nearly transparent one. (The assumption here is that opaque - * areas tend not to be 0 intensity.) - */ - if (component >= alpha) - component = 65535; - - /* component 0 && alpha < 65535) - { - png_uint_32 calc = component * reciprocal; - calc += 16384; /* round to nearest */ - component = (png_uint_16)(calc >> 15); - } - - *out_ptr++ = component; - } - while (--c > 0); - - /* Skip to next component (skip the intervening alpha channel) */ - ++in_ptr; - ++out_ptr; - } - - png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row)); - input_row += display->row_bytes/(sizeof (png_uint_16)); - } - - return 1; -} - -/* Given 16-bit input (1 to 4 channels) write 8-bit output. If an alpha channel - * is present it must be removed from the components, the components are then - * written in sRGB encoding. No components are added or removed. - * - * Calculate an alpha reciprocal to reverse pre-multiplication. As above the - * calculation can be done to 15 bits of accuracy; however, the output needs to - * be scaled in the range 0..255*65535, so include that scaling here. - */ -#define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+(alpha>>1))/alpha) - -static png_byte -png_unpremultiply(png_uint_32 component, png_uint_32 alpha, - png_uint_32 reciprocal/*from the above macro*/) -{ - /* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0 - * is represented as some other value there is more likely to be a - * discontinuity which will probably damage compression when moving from a - * fully transparent area to a nearly transparent one. (The assumption here - * is that opaque areas tend not to be 0 intensity.) - * - * There is a rounding problem here; if alpha is less than 128 it will end up - * as 0 when scaled to 8 bits. To avoid introducing spurious colors into the - * output change for this too. - */ - if (component >= alpha || alpha < 128) - return 255; - - /* component 0) - { - /* The test is that alpha/257 (rounded) is less than 255, the first value - * that becomes 255 is 65407. - * NOTE: this must agree with the PNG_DIV257 macro (which must, therefore, - * be exact!) [Could also test reciprocal != 0] - */ - if (alpha < 65407) - { - component *= reciprocal; - component += 64; /* round to nearest */ - component >>= 7; - } - - else - component *= 255; - - /* Convert the component to sRGB. */ - return (png_byte)PNG_sRGB_FROM_LINEAR(component); - } - - else - return 0; -} - -static int -png_write_image_8bit(png_voidp argument) -{ - png_image_write_control *display = png_voidcast(png_image_write_control*, - argument); - png_imagep image = display->image; - png_structrp png_ptr = image->opaque->png_ptr; - - png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, - display->first_row); - png_bytep output_row = png_voidcast(png_bytep, display->local_row); - png_uint_32 y = image->height; - const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1; - - if (image->format & PNG_FORMAT_FLAG_ALPHA) - { - png_bytep row_end; - int aindex; - - if (image->format & PNG_FORMAT_FLAG_AFIRST) - { - aindex = -1; - ++input_row; /* To point to the first component */ - ++output_row; - } - - else - aindex = channels; - - /* Use row_end in place of a loop counter: */ - row_end = output_row + image->width * (channels+1); - - while (y-- > 0) - { - png_const_uint_16p in_ptr = input_row; - png_bytep out_ptr = output_row; - - while (out_ptr < row_end) - { - png_uint_16 alpha = in_ptr[aindex]; - png_byte alphabyte = (png_byte)PNG_DIV257(alpha); - png_uint_32 reciprocal = 0; - int c; - - /* Scale and write the alpha channel. */ - out_ptr[aindex] = alphabyte; - - if (alphabyte > 0 && alphabyte < 255) - reciprocal = UNP_RECIPROCAL(alpha); - - c = channels; - do /* always at least one channel */ - *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal); - while (--c > 0); - - /* Skip to next component (skip the intervening alpha channel) */ - ++in_ptr; - ++out_ptr; - } /* while out_ptr < row_end */ - - png_write_row(png_ptr, png_voidcast(png_const_bytep, - display->local_row)); - input_row += display->row_bytes/(sizeof (png_uint_16)); - } /* while y */ - } - - else - { - /* No alpha channel, so the row_end really is the end of the row and it - * is sufficient to loop over the components one by one. - */ - png_bytep row_end = output_row + image->width * channels; - - while (y-- > 0) - { - png_const_uint_16p in_ptr = input_row; - png_bytep out_ptr = output_row; - - while (out_ptr < row_end) - { - png_uint_32 component = *in_ptr++; - - component *= 255; - *out_ptr++ = (png_byte)PNG_sRGB_FROM_LINEAR(component); - } - - png_write_row(png_ptr, output_row); - input_row += display->row_bytes/(sizeof (png_uint_16)); - } - } - - return 1; -} - -static void -png_image_set_PLTE(png_image_write_control *display) -{ - const png_imagep image = display->image; - const void *cmap = display->colormap; - const int entries = image->colormap_entries > 256 ? 256 : - (int)image->colormap_entries; - - /* NOTE: the caller must check for cmap != NULL and entries != 0 */ - const png_uint_32 format = image->format; - const int channels = PNG_IMAGE_SAMPLE_CHANNELS(format); - -# ifdef PNG_FORMAT_BGR_SUPPORTED - const int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 && - (format & PNG_FORMAT_FLAG_ALPHA) != 0; -# else -# define afirst 0 -# endif - -# ifdef PNG_FORMAT_BGR_SUPPORTED - const int bgr = (format & PNG_FORMAT_FLAG_BGR) ? 2 : 0; -# else -# define bgr 0 -# endif - - int i, num_trans; - png_color palette[256]; - png_byte tRNS[256]; - - memset(tRNS, 255, (sizeof tRNS)); - memset(palette, 0, (sizeof palette)); - - for (i=num_trans=0; i= 3) /* RGB */ - { - palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 * - entry[(2 ^ bgr)]); - palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 * - entry[1]); - palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 * - entry[bgr]); - } - - else /* Gray */ - palette[i].blue = palette[i].red = palette[i].green = - (png_byte)PNG_sRGB_FROM_LINEAR(255 * *entry); - } - - else /* alpha */ - { - png_uint_16 alpha = entry[afirst ? 0 : channels-1]; - png_byte alphabyte = (png_byte)PNG_DIV257(alpha); - png_uint_32 reciprocal = 0; - - /* Calculate a reciprocal, as in the png_write_image_8bit code above - * this is designed to produce a value scaled to 255*65535 when - * divided by 128 (i.e. asr 7). - */ - if (alphabyte > 0 && alphabyte < 255) - reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha; - - tRNS[i] = alphabyte; - if (alphabyte < 255) - num_trans = i+1; - - if (channels >= 3) /* RGB */ - { - palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)], - alpha, reciprocal); - palette[i].green = png_unpremultiply(entry[afirst + 1], alpha, - reciprocal); - palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha, - reciprocal); - } - - else /* gray */ - palette[i].blue = palette[i].red = palette[i].green = - png_unpremultiply(entry[afirst], alpha, reciprocal); - } - } - - else /* Color-map has sRGB values */ - { - png_const_bytep entry = png_voidcast(png_const_bytep, cmap); - - entry += i * channels; - - switch (channels) - { - case 4: - tRNS[i] = entry[afirst ? 0 : 3]; - if (tRNS[i] < 255) - num_trans = i+1; - /* FALL THROUGH */ - case 3: - palette[i].blue = entry[afirst + (2 ^ bgr)]; - palette[i].green = entry[afirst + 1]; - palette[i].red = entry[afirst + bgr]; - break; - - case 2: - tRNS[i] = entry[1 ^ afirst]; - if (tRNS[i] < 255) - num_trans = i+1; - /* FALL THROUGH */ - case 1: - palette[i].blue = palette[i].red = palette[i].green = - entry[afirst]; - break; - - default: - break; - } - } - } - -# ifdef afirst -# undef afirst -# endif -# ifdef bgr -# undef bgr -# endif - - png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette, - entries); - - if (num_trans > 0) - png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS, - num_trans, NULL); - - image->colormap_entries = entries; -} - -static int -png_image_write_main(png_voidp argument) -{ - png_image_write_control *display = png_voidcast(png_image_write_control*, - argument); - png_imagep image = display->image; - png_structrp png_ptr = image->opaque->png_ptr; - png_inforp info_ptr = image->opaque->info_ptr; - png_uint_32 format = image->format; - - int colormap = (format & PNG_FORMAT_FLAG_COLORMAP) != 0; - int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR) != 0; /* input */ - int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA) != 0; - int write_16bit = linear && !colormap && !display->convert_to_8bit; - -# ifdef PNG_BENIGN_ERRORS_SUPPORTED - /* Make sure we error out on any bad situation */ - png_set_benign_errors(png_ptr, 0/*error*/); -# endif - - /* Default the 'row_stride' parameter if required. */ - if (display->row_stride == 0) - display->row_stride = PNG_IMAGE_ROW_STRIDE(*image); - - /* Set the required transforms then write the rows in the correct order. */ - if (format & PNG_FORMAT_FLAG_COLORMAP) - { - if (display->colormap != NULL && image->colormap_entries > 0) - { - png_uint_32 entries = image->colormap_entries; - - png_set_IHDR(png_ptr, info_ptr, image->width, image->height, - entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)), - PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - png_image_set_PLTE(display); - } - - else - png_error(image->opaque->png_ptr, - "no color-map for color-mapped image"); - } - - else - png_set_IHDR(png_ptr, info_ptr, image->width, image->height, - write_16bit ? 16 : 8, - ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) + - ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0), - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - /* Counter-intuitively the data transformations must be called *after* - * png_write_info, not before as in the read code, but the 'set' functions - * must still be called before. Just set the color space information, never - * write an interlaced image. - */ - - if (write_16bit) - { - /* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */ - png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR); - - if (!(image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB)) - png_set_cHRM_fixed(png_ptr, info_ptr, - /* color x y */ - /* white */ 31270, 32900, - /* red */ 64000, 33000, - /* green */ 30000, 60000, - /* blue */ 15000, 6000 - ); - } - - else if (!(image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB)) - png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL); - - /* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit - * space must still be gamma encoded. - */ - else - png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE); - - /* Write the file header. */ - png_write_info(png_ptr, info_ptr); - - /* Now set up the data transformations (*after* the header is written), - * remove the handled transformations from the 'format' flags for checking. - * - * First check for a little endian system if writing 16 bit files. - */ - if (write_16bit) - { - PNG_CONST png_uint_16 le = 0x0001; - - if (*(png_const_bytep)&le) - png_set_swap(png_ptr); - } - -# ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED - if (format & PNG_FORMAT_FLAG_BGR) - { - if (!colormap && (format & PNG_FORMAT_FLAG_COLOR) != 0) - png_set_bgr(png_ptr); - format &= ~PNG_FORMAT_FLAG_BGR; - } -# endif - -# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED - if (format & PNG_FORMAT_FLAG_AFIRST) - { - if (!colormap && (format & PNG_FORMAT_FLAG_ALPHA) != 0) - png_set_swap_alpha(png_ptr); - format &= ~PNG_FORMAT_FLAG_AFIRST; - } -# endif - - /* If there are 16 or fewer color-map entries we wrote a lower bit depth - * above, but the application data is still byte packed. - */ - if (colormap && image->colormap_entries <= 16) - png_set_packing(png_ptr); - - /* That should have handled all (both) the transforms. */ - if ((format & ~(png_uint_32)(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR | - PNG_FORMAT_FLAG_ALPHA | PNG_FORMAT_FLAG_COLORMAP)) != 0) - png_error(png_ptr, "png_write_image: unsupported transformation"); - - { - png_const_bytep row = png_voidcast(png_const_bytep, display->buffer); - ptrdiff_t row_bytes = display->row_stride; - - if (linear) - row_bytes *= (sizeof (png_uint_16)); - - if (row_bytes < 0) - row += (image->height-1) * (-row_bytes); - - display->first_row = row; - display->row_bytes = row_bytes; - } - - /* Apply 'fast' options if the flag is set. */ - if ((image->flags & PNG_IMAGE_FLAG_FAST) != 0) - { - png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS); - /* NOTE: determined by experiment using pngstest, this reflects some - * balance between the time to write the image once and the time to read - * it about 50 times. The speed-up in pngstest was about 10-20% of the - * total (user) time on a heavily loaded system. - */ - png_set_compression_level(png_ptr, 3); - } - - /* Check for the cases that currently require a pre-transform on the row - * before it is written. This only applies when the input is 16-bit and - * either there is an alpha channel or it is converted to 8-bit. - */ - if ((linear && alpha) || (!colormap && display->convert_to_8bit)) - { - png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr, - png_get_rowbytes(png_ptr, info_ptr))); - int result; - - display->local_row = row; - if (write_16bit) - result = png_safe_execute(image, png_write_image_16bit, display); - else - result = png_safe_execute(image, png_write_image_8bit, display); - display->local_row = NULL; - - png_free(png_ptr, row); - - /* Skip the 'write_end' on error: */ - if (!result) - return 0; - } - - /* Otherwise this is the case where the input is in a format currently - * supported by the rest of the libpng write code; call it directly. - */ - else - { - png_const_bytep row = png_voidcast(png_const_bytep, display->first_row); - ptrdiff_t row_bytes = display->row_bytes; - png_uint_32 y = image->height; - - while (y-- > 0) - { - png_write_row(png_ptr, row); - row += row_bytes; - } - } - - png_write_end(png_ptr, info_ptr); - return 1; -} - -int PNGAPI -png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, - const void *buffer, png_int_32 row_stride, const void *colormap) -{ - /* Write the image to the given (FILE*). */ - if (image != NULL && image->version == PNG_IMAGE_VERSION) - { - if (file != NULL) - { - if (png_image_write_init(image)) - { - png_image_write_control display; - int result; - - /* This is slightly evil, but png_init_io doesn't do anything other - * than this and we haven't changed the standard IO functions so - * this saves a 'safe' function. - */ - image->opaque->png_ptr->io_ptr = file; - - memset(&display, 0, (sizeof display)); - display.image = image; - display.buffer = buffer; - display.row_stride = row_stride; - display.colormap = colormap; - display.convert_to_8bit = convert_to_8bit; - - result = png_safe_execute(image, png_image_write_main, &display); - png_image_free(image); - return result; - } - - else - return 0; - } - - else - return png_image_error(image, - "png_image_write_to_stdio: invalid argument"); - } - - else if (image != NULL) - return png_image_error(image, - "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION"); - - else - return 0; -} - -int PNGAPI -png_image_write_to_file(png_imagep image, const char *file_name, - int convert_to_8bit, const void *buffer, png_int_32 row_stride, - const void *colormap) -{ - /* Write the image to the named file. */ - if (image != NULL && image->version == PNG_IMAGE_VERSION) - { - if (file_name != NULL) - { - FILE *fp = fopen(file_name, "wb"); - - if (fp != NULL) - { - if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer, - row_stride, colormap)) - { - int error; /* from fflush/fclose */ - - /* Make sure the file is flushed correctly. */ - if (fflush(fp) == 0 && ferror(fp) == 0) - { - if (fclose(fp) == 0) - return 1; - - error = errno; /* from fclose */ - } - - else - { - error = errno; /* from fflush or ferror */ - (void)fclose(fp); - } - - (void)remove(file_name); - /* The image has already been cleaned up; this is just used to - * set the error (because the original write succeeded). - */ - return png_image_error(image, strerror(error)); - } - - else - { - /* Clean up: just the opened file. */ - (void)fclose(fp); - (void)remove(file_name); - return 0; - } - } - - else - return png_image_error(image, strerror(errno)); - } - - else - return png_image_error(image, - "png_image_write_to_file: invalid argument"); - } - - else if (image != NULL) - return png_image_error(image, - "png_image_write_to_file: incorrect PNG_IMAGE_VERSION"); - - else - return 0; -} -#endif /* PNG_STDIO_SUPPORTED */ -#endif /* SIMPLIFIED_WRITE */ -#endif /* PNG_WRITE_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pngwtran.c b/source/modules/juce_graphics/image_formats/pnglib/pngwtran.c deleted file mode 100644 index 2cdd7c95c..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pngwtran.c +++ /dev/null @@ -1,637 +0,0 @@ - -/* pngwtran.c - transforms the data in a row for PNG writers - * - * Last changed in libpng 1.6.0 [February 14, 2013] - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - */ - -#include "pngpriv.h" - -#ifdef PNG_WRITE_SUPPORTED - -#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED -/* Transform the data according to the user's wishes. The order of - * transformations is significant. - */ -void /* PRIVATE */ -png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info) -{ - png_debug(1, "in png_do_write_transformations"); - - if (png_ptr == NULL) - return; - -#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED - if (png_ptr->transformations & PNG_USER_TRANSFORM) - if (png_ptr->write_user_transform_fn != NULL) - (*(png_ptr->write_user_transform_fn)) /* User write transform - function */ - (png_ptr, /* png_ptr */ - row_info, /* row_info: */ - /* png_uint_32 width; width of row */ - /* png_size_t rowbytes; number of bytes in row */ - /* png_byte color_type; color type of pixels */ - /* png_byte bit_depth; bit depth of samples */ - /* png_byte channels; number of channels (1-4) */ - /* png_byte pixel_depth; bits per pixel (depth*channels) */ - png_ptr->row_buf + 1); /* start of pixel data for row */ -#endif - -#ifdef PNG_WRITE_FILLER_SUPPORTED - if (png_ptr->transformations & PNG_FILLER) - png_do_strip_channel(row_info, png_ptr->row_buf + 1, - !(png_ptr->flags & PNG_FLAG_FILLER_AFTER)); -#endif - -#ifdef PNG_WRITE_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) - png_do_packswap(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_WRITE_PACK_SUPPORTED - if (png_ptr->transformations & PNG_PACK) - png_do_pack(row_info, png_ptr->row_buf + 1, - (png_uint_32)png_ptr->bit_depth); -#endif - -#ifdef PNG_WRITE_SWAP_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_BYTES) - png_do_swap(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_WRITE_SHIFT_SUPPORTED - if (png_ptr->transformations & PNG_SHIFT) - png_do_shift(row_info, png_ptr->row_buf + 1, - &(png_ptr->shift)); -#endif - -#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_ALPHA) - png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_ALPHA) - png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_WRITE_BGR_SUPPORTED - if (png_ptr->transformations & PNG_BGR) - png_do_bgr(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_WRITE_INVERT_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_MONO) - png_do_invert(row_info, png_ptr->row_buf + 1); -#endif -} - -#ifdef PNG_WRITE_PACK_SUPPORTED -/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The - * row_info bit depth should be 8 (one pixel per byte). The channels - * should be 1 (this only happens on grayscale and paletted images). - */ -void /* PRIVATE */ -png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) -{ - png_debug(1, "in png_do_pack"); - - if (row_info->bit_depth == 8 && - row_info->channels == 1) - { - switch ((int)bit_depth) - { - case 1: - { - png_bytep sp, dp; - int mask, v; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - sp = row; - dp = row; - mask = 0x80; - v = 0; - - for (i = 0; i < row_width; i++) - { - if (*sp != 0) - v |= mask; - - sp++; - - if (mask > 1) - mask >>= 1; - - else - { - mask = 0x80; - *dp = (png_byte)v; - dp++; - v = 0; - } - } - - if (mask != 0x80) - *dp = (png_byte)v; - - break; - } - - case 2: - { - png_bytep sp, dp; - int shift, v; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - sp = row; - dp = row; - shift = 6; - v = 0; - - for (i = 0; i < row_width; i++) - { - png_byte value; - - value = (png_byte)(*sp & 0x03); - v |= (value << shift); - - if (shift == 0) - { - shift = 6; - *dp = (png_byte)v; - dp++; - v = 0; - } - - else - shift -= 2; - - sp++; - } - - if (shift != 6) - *dp = (png_byte)v; - - break; - } - - case 4: - { - png_bytep sp, dp; - int shift, v; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - sp = row; - dp = row; - shift = 4; - v = 0; - - for (i = 0; i < row_width; i++) - { - png_byte value; - - value = (png_byte)(*sp & 0x0f); - v |= (value << shift); - - if (shift == 0) - { - shift = 4; - *dp = (png_byte)v; - dp++; - v = 0; - } - - else - shift -= 4; - - sp++; - } - - if (shift != 4) - *dp = (png_byte)v; - - break; - } - - default: - break; - } - - row_info->bit_depth = (png_byte)bit_depth; - row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, - row_info->width); - } -} -#endif - -#ifdef PNG_WRITE_SHIFT_SUPPORTED -/* Shift pixel values to take advantage of whole range. Pass the - * true number of bits in bit_depth. The row should be packed - * according to row_info->bit_depth. Thus, if you had a row of - * bit depth 4, but the pixels only had values from 0 to 7, you - * would pass 3 as bit_depth, and this routine would translate the - * data to 0 to 15. - */ -void /* PRIVATE */ -png_do_shift(png_row_infop row_info, png_bytep row, - png_const_color_8p bit_depth) -{ - png_debug(1, "in png_do_shift"); - - if (row_info->color_type != PNG_COLOR_TYPE_PALETTE) - { - int shift_start[4], shift_dec[4]; - int channels = 0; - - if (row_info->color_type & PNG_COLOR_MASK_COLOR) - { - shift_start[channels] = row_info->bit_depth - bit_depth->red; - shift_dec[channels] = bit_depth->red; - channels++; - - shift_start[channels] = row_info->bit_depth - bit_depth->green; - shift_dec[channels] = bit_depth->green; - channels++; - - shift_start[channels] = row_info->bit_depth - bit_depth->blue; - shift_dec[channels] = bit_depth->blue; - channels++; - } - - else - { - shift_start[channels] = row_info->bit_depth - bit_depth->gray; - shift_dec[channels] = bit_depth->gray; - channels++; - } - - if (row_info->color_type & PNG_COLOR_MASK_ALPHA) - { - shift_start[channels] = row_info->bit_depth - bit_depth->alpha; - shift_dec[channels] = bit_depth->alpha; - channels++; - } - - /* With low row depths, could only be grayscale, so one channel */ - if (row_info->bit_depth < 8) - { - png_bytep bp = row; - png_size_t i; - unsigned int mask; - png_size_t row_bytes = row_info->rowbytes; - - if (bit_depth->gray == 1 && row_info->bit_depth == 2) - mask = 0x55; - - else if (row_info->bit_depth == 4 && bit_depth->gray == 3) - mask = 0x11; - - else - mask = 0xff; - - for (i = 0; i < row_bytes; i++, bp++) - { - int j; - unsigned int v, out; - - v = *bp; - out = 0; - - for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0]) - { - if (j > 0) - out |= v << j; - - else - out |= (v >> (-j)) & mask; - } - - *bp = (png_byte)(out & 0xff); - } - } - - else if (row_info->bit_depth == 8) - { - png_bytep bp = row; - png_uint_32 i; - png_uint_32 istop = channels * row_info->width; - - for (i = 0; i < istop; i++, bp++) - { - - const unsigned int c = i%channels; - int j; - unsigned int v, out; - - v = *bp; - out = 0; - - for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) - { - if (j > 0) - out |= v << j; - - else - out |= v >> (-j); - } - - *bp = (png_byte)(out & 0xff); - } - } - - else - { - png_bytep bp; - png_uint_32 i; - png_uint_32 istop = channels * row_info->width; - - for (bp = row, i = 0; i < istop; i++) - { - const unsigned int c = i%channels; - int j; - unsigned int value, v; - - v = png_get_uint_16(bp); - value = 0; - - for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) - { - if (j > 0) - value |= v << j; - - else - value |= v >> (-j); - } - *bp++ = (png_byte)((value >> 8) & 0xff); - *bp++ = (png_byte)(value & 0xff); - } - } - } -} -#endif - -#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED -void /* PRIVATE */ -png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_write_swap_alpha"); - - { - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - if (row_info->bit_depth == 8) - { - /* This converts from ARGB to RGBA */ - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - for (i = 0, sp = dp = row; i < row_width; i++) - { - png_byte save = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = save; - } - } - -#ifdef PNG_WRITE_16BIT_SUPPORTED - else - { - /* This converts from AARRGGBB to RRGGBBAA */ - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - for (i = 0, sp = dp = row; i < row_width; i++) - { - png_byte save[2]; - save[0] = *(sp++); - save[1] = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = save[0]; - *(dp++) = save[1]; - } - } -#endif /* PNG_WRITE_16BIT_SUPPORTED */ - } - - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - if (row_info->bit_depth == 8) - { - /* This converts from AG to GA */ - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - for (i = 0, sp = dp = row; i < row_width; i++) - { - png_byte save = *(sp++); - *(dp++) = *(sp++); - *(dp++) = save; - } - } - -#ifdef PNG_WRITE_16BIT_SUPPORTED - else - { - /* This converts from AAGG to GGAA */ - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - for (i = 0, sp = dp = row; i < row_width; i++) - { - png_byte save[2]; - save[0] = *(sp++); - save[1] = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = save[0]; - *(dp++) = save[1]; - } - } -#endif /* PNG_WRITE_16BIT_SUPPORTED */ - } - } -} -#endif - -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED -void /* PRIVATE */ -png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_write_invert_alpha"); - - { - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - if (row_info->bit_depth == 8) - { - /* This inverts the alpha channel in RGBA */ - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - for (i = 0, sp = dp = row; i < row_width; i++) - { - /* Does nothing - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - */ - sp+=3; dp = sp; - *(dp++) = (png_byte)(255 - *(sp++)); - } - } - -#ifdef PNG_WRITE_16BIT_SUPPORTED - else - { - /* This inverts the alpha channel in RRGGBBAA */ - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - for (i = 0, sp = dp = row; i < row_width; i++) - { - /* Does nothing - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - *(dp++) = *(sp++); - */ - sp+=6; dp = sp; - *(dp++) = (png_byte)(255 - *(sp++)); - *(dp++) = (png_byte)(255 - *(sp++)); - } - } -#endif /* PNG_WRITE_16BIT_SUPPORTED */ - } - - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - if (row_info->bit_depth == 8) - { - /* This inverts the alpha channel in GA */ - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - for (i = 0, sp = dp = row; i < row_width; i++) - { - *(dp++) = *(sp++); - *(dp++) = (png_byte)(255 - *(sp++)); - } - } - -#ifdef PNG_WRITE_16BIT_SUPPORTED - else - { - /* This inverts the alpha channel in GGAA */ - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - for (i = 0, sp = dp = row; i < row_width; i++) - { - /* Does nothing - *(dp++) = *(sp++); - *(dp++) = *(sp++); - */ - sp+=2; dp = sp; - *(dp++) = (png_byte)(255 - *(sp++)); - *(dp++) = (png_byte)(255 - *(sp++)); - } - } -#endif /* PNG_WRITE_16BIT_SUPPORTED */ - } - } -} -#endif -#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */ - -#ifdef PNG_MNG_FEATURES_SUPPORTED -/* Undoes intrapixel differencing */ -void /* PRIVATE */ -png_do_write_intrapixel(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_write_intrapixel"); - - if ((row_info->color_type & PNG_COLOR_MASK_COLOR)) - { - int bytes_per_pixel; - png_uint_32 row_width = row_info->width; - if (row_info->bit_depth == 8) - { - png_bytep rp; - png_uint_32 i; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 3; - - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 4; - - else - return; - - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - *(rp) = (png_byte)((*rp - *(rp + 1)) & 0xff); - *(rp + 2) = (png_byte)((*(rp + 2) - *(rp + 1)) & 0xff); - } - } - -#ifdef PNG_WRITE_16BIT_SUPPORTED - else if (row_info->bit_depth == 16) - { - png_bytep rp; - png_uint_32 i; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 6; - - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 8; - - else - return; - - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); - png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); - png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); - png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); - png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); - *(rp ) = (png_byte)((red >> 8) & 0xff); - *(rp + 1) = (png_byte)(red & 0xff); - *(rp + 4) = (png_byte)((blue >> 8) & 0xff); - *(rp + 5) = (png_byte)(blue & 0xff); - } - } -#endif /* PNG_WRITE_16BIT_SUPPORTED */ - } -} -#endif /* PNG_MNG_FEATURES_SUPPORTED */ -#endif /* PNG_WRITE_SUPPORTED */ diff --git a/source/modules/juce_graphics/image_formats/pnglib/pngwutil.c b/source/modules/juce_graphics/image_formats/pnglib/pngwutil.c deleted file mode 100644 index c90ff8bd0..000000000 --- a/source/modules/juce_graphics/image_formats/pnglib/pngwutil.c +++ /dev/null @@ -1,3020 +0,0 @@ - -/* pngwutil.c - utilities to write a PNG file - * - * Last changed in libpng 1.6.0 [February 14, 2013] - * Copyright (c) 1998-2013 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - */ - -#include "pngpriv.h" - -#ifdef PNG_WRITE_SUPPORTED - -#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED -/* Place a 32-bit number into a buffer in PNG byte order. We work - * with unsigned numbers for convenience, although one supported - * ancillary chunk uses signed (two's complement) numbers. - */ -void PNGAPI -png_save_uint_32(png_bytep buf, png_uint_32 i) -{ - buf[0] = (png_byte)((i >> 24) & 0xff); - buf[1] = (png_byte)((i >> 16) & 0xff); - buf[2] = (png_byte)((i >> 8) & 0xff); - buf[3] = (png_byte)(i & 0xff); -} - -/* Place a 16-bit number into a buffer in PNG byte order. - * The parameter is declared unsigned int, not png_uint_16, - * just to avoid potential problems on pre-ANSI C compilers. - */ -void PNGAPI -png_save_uint_16(png_bytep buf, unsigned int i) -{ - buf[0] = (png_byte)((i >> 8) & 0xff); - buf[1] = (png_byte)(i & 0xff); -} -#endif - -/* Simple function to write the signature. If we have already written - * the magic bytes of the signature, or more likely, the PNG stream is - * being embedded into another stream and doesn't need its own signature, - * we should call png_set_sig_bytes() to tell libpng how many of the - * bytes have already been written. - */ -void PNGAPI -png_write_sig(png_structrp png_ptr) -{ - png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; - -#ifdef PNG_IO_STATE_SUPPORTED - /* Inform the I/O callback that the signature is being written */ - png_ptr->io_state = PNG_IO_WRITING | PNG_IO_SIGNATURE; -#endif - - /* Write the rest of the 8 byte signature */ - png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes], - (png_size_t)(8 - png_ptr->sig_bytes)); - - if (png_ptr->sig_bytes < 3) - png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; -} - -/* Write the start of a PNG chunk. The type is the chunk type. - * The total_length is the sum of the lengths of all the data you will be - * passing in png_write_chunk_data(). - */ -static void -png_write_chunk_header(png_structrp png_ptr, png_uint_32 chunk_name, - png_uint_32 length) -{ - png_byte buf[8]; - -#if defined(PNG_DEBUG) && (PNG_DEBUG > 0) - PNG_CSTRING_FROM_CHUNK(buf, chunk_name); - png_debug2(0, "Writing %s chunk, length = %lu", buf, (unsigned long)length); -#endif - - if (png_ptr == NULL) - return; - -#ifdef PNG_IO_STATE_SUPPORTED - /* Inform the I/O callback that the chunk header is being written. - * PNG_IO_CHUNK_HDR requires a single I/O call. - */ - png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_HDR; -#endif - - /* Write the length and the chunk name */ - png_save_uint_32(buf, length); - png_save_uint_32(buf + 4, chunk_name); - png_write_data(png_ptr, buf, 8); - - /* Put the chunk name into png_ptr->chunk_name */ - png_ptr->chunk_name = chunk_name; - - /* Reset the crc and run it over the chunk name */ - png_reset_crc(png_ptr); - - png_calculate_crc(png_ptr, buf + 4, 4); - -#ifdef PNG_IO_STATE_SUPPORTED - /* Inform the I/O callback that chunk data will (possibly) be written. - * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls. - */ - png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_DATA; -#endif -} - -void PNGAPI -png_write_chunk_start(png_structrp png_ptr, png_const_bytep chunk_string, - png_uint_32 length) -{ - png_write_chunk_header(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), length); -} - -/* Write the data of a PNG chunk started with png_write_chunk_header(). - * Note that multiple calls to this function are allowed, and that the - * sum of the lengths from these calls *must* add up to the total_length - * given to png_write_chunk_header(). - */ -void PNGAPI -png_write_chunk_data(png_structrp png_ptr, png_const_bytep data, - png_size_t length) -{ - /* Write the data, and run the CRC over it */ - if (png_ptr == NULL) - return; - - if (data != NULL && length > 0) - { - png_write_data(png_ptr, data, length); - - /* Update the CRC after writing the data, - * in case that the user I/O routine alters it. - */ - png_calculate_crc(png_ptr, data, length); - } -} - -/* Finish a chunk started with png_write_chunk_header(). */ -void PNGAPI -png_write_chunk_end(png_structrp png_ptr) -{ - png_byte buf[4]; - - if (png_ptr == NULL) return; - -#ifdef PNG_IO_STATE_SUPPORTED - /* Inform the I/O callback that the chunk CRC is being written. - * PNG_IO_CHUNK_CRC requires a single I/O function call. - */ - png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_CRC; -#endif - - /* Write the crc in a single operation */ - png_save_uint_32(buf, png_ptr->crc); - - png_write_data(png_ptr, buf, (png_size_t)4); -} - -/* Write a PNG chunk all at once. The type is an array of ASCII characters - * representing the chunk name. The array must be at least 4 bytes in - * length, and does not need to be null terminated. To be safe, pass the - * pre-defined chunk names here, and if you need a new one, define it - * where the others are defined. The length is the length of the data. - * All the data must be present. If that is not possible, use the - * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end() - * functions instead. - */ -static void -png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name, - png_const_bytep data, png_size_t length) -{ - if (png_ptr == NULL) - return; - - /* On 64 bit architectures 'length' may not fit in a png_uint_32. */ - if (length > PNG_UINT_31_MAX) - png_error(png_ptr, "length exceeds PNG maxima"); - - png_write_chunk_header(png_ptr, chunk_name, (png_uint_32)length); - png_write_chunk_data(png_ptr, data, length); - png_write_chunk_end(png_ptr); -} - -/* This is the API that calls the internal function above. */ -void PNGAPI -png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string, - png_const_bytep data, png_size_t length) -{ - png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data, - length); -} - -/* This is used below to find the size of an image to pass to png_deflate_claim, - * so it only needs to be accurate if the size is less than 16384 bytes (the - * point at which a lower LZ window size can be used.) - */ -static png_alloc_size_t -png_image_size(png_structrp png_ptr) -{ - /* Only return sizes up to the maximum of a png_uint_32, do this by limiting - * the width and height used to 15 bits. - */ - png_uint_32 h = png_ptr->height; - - if (png_ptr->rowbytes < 32768 && h < 32768) - { - if (png_ptr->interlaced) - { - /* Interlacing makes the image larger because of the replication of - * both the filter byte and the padding to a byte boundary. - */ - png_uint_32 w = png_ptr->width; - unsigned int pd = png_ptr->pixel_depth; - png_alloc_size_t cb_base; - int pass; - - for (cb_base=0, pass=0; pass<=6; ++pass) - { - png_uint_32 pw = PNG_PASS_COLS(w, pass); - - if (pw > 0) - cb_base += (PNG_ROWBYTES(pd, pw)+1) * PNG_PASS_ROWS(h, pass); - } - - return cb_base; - } - - else - return (png_ptr->rowbytes+1) * h; - } - - else - return 0xffffffffU; -} - -#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED - /* This is the code to hack the first two bytes of the deflate stream (the - * deflate header) to correct the windowBits value to match the actual data - * size. Note that the second argument is the *uncompressed* size but the - * first argument is the *compressed* data (and it must be deflate - * compressed.) - */ -static void -optimize_cmf(png_bytep data, png_alloc_size_t data_size) -{ - /* Optimize the CMF field in the zlib stream. The resultant zlib stream is - * still compliant to the stream specification. - */ - if (data_size <= 16384) /* else windowBits must be 15 */ - { - unsigned int z_cmf = data[0]; /* zlib compression method and flags */ - - if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) - { - unsigned int z_cinfo; - unsigned int half_z_window_size; - - z_cinfo = z_cmf >> 4; - half_z_window_size = 1U << (z_cinfo + 7); - - if (data_size <= half_z_window_size) /* else no change */ - { - unsigned int tmp; - - do - { - half_z_window_size >>= 1; - --z_cinfo; - } - while (z_cinfo > 0 && data_size <= half_z_window_size); - - z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); - - data[0] = (png_byte)z_cmf; - tmp = data[1] & 0xe0; - tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f; - data[1] = (png_byte)tmp; - } - } - } -} -#else -# define optimize_cmf(dp,dl) ((void)0) -#endif /* PNG_WRITE_OPTIMIZE_CMF_SUPPORTED */ - -/* Initialize the compressor for the appropriate type of compression. */ -static int -png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, - png_alloc_size_t data_size) -{ - if (png_ptr->zowner != 0) - { - char msg[64]; - - PNG_STRING_FROM_CHUNK(msg, owner); - msg[4] = ':'; - msg[5] = ' '; - PNG_STRING_FROM_CHUNK(msg+6, png_ptr->zowner); - /* So the message that results is " using zstream"; this is an - * internal error, but is very useful for debugging. i18n requirements - * are minimal. - */ - (void)png_safecat(msg, (sizeof msg), 10, " using zstream"); -# if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC - png_warning(png_ptr, msg); - - /* Attempt sane error recovery */ - if (png_ptr->zowner == png_IDAT) /* don't steal from IDAT */ - { - png_ptr->zstream.msg = PNGZ_MSG_CAST("in use by IDAT"); - return Z_STREAM_ERROR; - } - - png_ptr->zowner = 0; -# else - png_error(png_ptr, msg); -# endif - } - - { - int level = png_ptr->zlib_level; - int method = png_ptr->zlib_method; - int windowBits = png_ptr->zlib_window_bits; - int memLevel = png_ptr->zlib_mem_level; - int strategy; /* set below */ - int ret; /* zlib return code */ - - if (owner == png_IDAT) - { - if (png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY) - strategy = png_ptr->zlib_strategy; - - else if (png_ptr->do_filter != PNG_FILTER_NONE) - strategy = PNG_Z_DEFAULT_STRATEGY; - - else - strategy = PNG_Z_DEFAULT_NOFILTER_STRATEGY; - } - - else - { -# ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED - level = png_ptr->zlib_text_level; - method = png_ptr->zlib_text_method; - windowBits = png_ptr->zlib_text_window_bits; - memLevel = png_ptr->zlib_text_mem_level; - strategy = png_ptr->zlib_text_strategy; -# else - /* If customization is not supported the values all come from the - * IDAT values except for the strategy, which is fixed to the - * default. (This is the pre-1.6.0 behavior too, although it was - * implemented in a very different way.) - */ - strategy = Z_DEFAULT_STRATEGY; -# endif - } - - /* Adjust 'windowBits' down if larger than 'data_size'; to stop this - * happening just pass 32768 as the data_size parameter. Notice that zlib - * requires an extra 262 bytes in the window in addition to the data to be - * able to see the whole of the data, so if data_size+262 takes us to the - * next windowBits size we need to fix up the value later. (Because even - * though deflate needs the extra window, inflate does not!) - */ - if (data_size <= 16384) - { - /* IMPLEMENTATION NOTE: this 'half_window_size' stuff is only here to - * work round a Microsoft Visual C misbehavior which, contrary to C-90, - * widens the result of the following shift to 64-bits if (and, - * apparently, only if) it is used in a test. - */ - unsigned int half_window_size = 1U << (windowBits-1); - - while (data_size + 262 <= half_window_size) - { - half_window_size >>= 1; - --windowBits; - } - } - - /* Check against the previous initialized values, if any. */ - if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) && - (png_ptr->zlib_set_level != level || - png_ptr->zlib_set_method != method || - png_ptr->zlib_set_window_bits != windowBits || - png_ptr->zlib_set_mem_level != memLevel || - png_ptr->zlib_set_strategy != strategy)) - { - if (deflateEnd(&png_ptr->zstream) != Z_OK) - png_warning(png_ptr, "deflateEnd failed (ignored)"); - - png_ptr->flags &= ~PNG_FLAG_ZSTREAM_INITIALIZED; - } - - /* For safety clear out the input and output pointers (currently zlib - * doesn't use them on Init, but it might in the future). - */ - png_ptr->zstream.next_in = NULL; - png_ptr->zstream.avail_in = 0; - png_ptr->zstream.next_out = NULL; - png_ptr->zstream.avail_out = 0; - - /* Now initialize if required, setting the new parameters, otherwise just - * to a simple reset to the previous parameters. - */ - if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) - ret = deflateReset(&png_ptr->zstream); - - else - { - ret = deflateInit2(&png_ptr->zstream, level, method, windowBits, - memLevel, strategy); - - if (ret == Z_OK) - png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; - } - - /* The return code is from either deflateReset or deflateInit2; they have - * pretty much the same set of error codes. - */ - if (ret == Z_OK) - png_ptr->zowner = owner; - - else - png_zstream_error(png_ptr, ret); - - return ret; - } -} - -/* Clean up (or trim) a linked list of compression buffers. */ -void /* PRIVATE */ -png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp) -{ - png_compression_bufferp list = *listp; - - if (list != NULL) - { - *listp = NULL; - - do - { - png_compression_bufferp next = list->next; - - png_free(png_ptr, list); - list = next; - } - while (list != NULL); - } -} - -#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED -/* This pair of functions encapsulates the operation of (a) compressing a - * text string, and (b) issuing it later as a series of chunk data writes. - * The compression_state structure is shared context for these functions - * set up by the caller to allow access to the relevant local variables. - * - * compression_buffer (new in 1.6.0) is just a linked list of zbuffer_size - * temporary buffers. From 1.6.0 it is retained in png_struct so that it will - * be correctly freed in the event of a write error (previous implementations - * just leaked memory.) - */ -typedef struct -{ - png_const_bytep input; /* The uncompressed input data */ - png_alloc_size_t input_len; /* Its length */ - png_uint_32 output_len; /* Final compressed length */ - png_byte output[1024]; /* First block of output */ -} compression_state; - -static void -png_text_compress_init(compression_state *comp, png_const_bytep input, - png_alloc_size_t input_len) -{ - comp->input = input; - comp->input_len = input_len; - comp->output_len = 0; -} - -/* Compress the data in the compression state input */ -static int -png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, - compression_state *comp, png_uint_32 prefix_len) -{ - int ret; - - /* To find the length of the output it is necessary to first compress the - * input, the result is buffered rather than using the two-pass algorithm - * that is used on the inflate side; deflate is assumed to be slower and a - * PNG writer is assumed to have more memory available than a PNG reader. - * - * IMPLEMENTATION NOTE: the zlib API deflateBound() can be used to find an - * upper limit on the output size, but it is always bigger than the input - * size so it is likely to be more efficient to use this linked-list - * approach. - */ - ret = png_deflate_claim(png_ptr, chunk_name, comp->input_len); - - if (ret != Z_OK) - return ret; - - /* Set up the compression buffers, we need a loop here to avoid overflowing a - * uInt. Use ZLIB_IO_MAX to limit the input. The output is always limited - * by the output buffer size, so there is no need to check that. Since this - * is ANSI-C we know that an 'int', hence a uInt, is always at least 16 bits - * in size. - */ - { - png_compression_bufferp *end = &png_ptr->zbuffer_list; - png_alloc_size_t input_len = comp->input_len; /* may be zero! */ - png_uint_32 output_len; - - /* zlib updates these for us: */ - png_ptr->zstream.next_in = PNGZ_INPUT_CAST(comp->input); - png_ptr->zstream.avail_in = 0; /* Set below */ - png_ptr->zstream.next_out = comp->output; - png_ptr->zstream.avail_out = (sizeof comp->output); - - output_len = png_ptr->zstream.avail_out; - - do - { - uInt avail_in = ZLIB_IO_MAX; - - if (avail_in > input_len) - avail_in = (uInt)input_len; - - input_len -= avail_in; - - png_ptr->zstream.avail_in = avail_in; - - if (png_ptr->zstream.avail_out == 0) - { - png_compression_buffer *next; - - /* Chunk data is limited to 2^31 bytes in length, so the prefix - * length must be counted here. - */ - if (output_len + prefix_len > PNG_UINT_31_MAX) - { - ret = Z_MEM_ERROR; - break; - } - - /* Need a new (malloc'ed) buffer, but there may be one present - * already. - */ - next = *end; - if (next == NULL) - { - next = png_voidcast(png_compression_bufferp, png_malloc_base - (png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); - - if (next == NULL) - { - ret = Z_MEM_ERROR; - break; - } - - /* Link in this buffer (so that it will be freed later) */ - next->next = NULL; - *end = next; - } - - png_ptr->zstream.next_out = next->output; - png_ptr->zstream.avail_out = png_ptr->zbuffer_size; - output_len += png_ptr->zstream.avail_out; - - /* Move 'end' to the next buffer pointer. */ - end = &next->next; - } - - /* Compress the data */ - ret = deflate(&png_ptr->zstream, - input_len > 0 ? Z_NO_FLUSH : Z_FINISH); - - /* Claw back input data that was not consumed (because avail_in is - * reset above every time round the loop). - */ - input_len += png_ptr->zstream.avail_in; - png_ptr->zstream.avail_in = 0; /* safety */ - } - while (ret == Z_OK); - - /* There may be some space left in the last output buffer, this needs to - * be subtracted from output_len. - */ - output_len -= png_ptr->zstream.avail_out; - png_ptr->zstream.avail_out = 0; /* safety */ - comp->output_len = output_len; - - /* Now double check the output length, put in a custom message if it is - * too long. Otherwise ensure the z_stream::msg pointer is set to - * something. - */ - if (output_len + prefix_len >= PNG_UINT_31_MAX) - { - png_ptr->zstream.msg = PNGZ_MSG_CAST("compressed data too long"); - ret = Z_MEM_ERROR; - } - - else - png_zstream_error(png_ptr, ret); - - /* Reset zlib for another zTXt/iTXt or image data */ - png_ptr->zowner = 0; - - /* The only success case is Z_STREAM_END, input_len must be 0, if not this - * is an internal error. - */ - if (ret == Z_STREAM_END && input_len == 0) - { - /* Fix up the deflate header, if required */ - optimize_cmf(comp->output, comp->input_len); - - /* But Z_OK is returned, not Z_STREAM_END; this allows the claim - * function above to return Z_STREAM_END on an error (though it never - * does in the current versions of zlib.) - */ - return Z_OK; - } - - else - return ret; - } -} - -/* Ship the compressed text out via chunk writes */ -static void -png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp) -{ - png_uint_32 output_len = comp->output_len; - png_const_bytep output = comp->output; - png_uint_32 avail = (sizeof comp->output); - png_compression_buffer *next = png_ptr->zbuffer_list; - - for (;;) - { - if (avail > output_len) - avail = output_len; - - png_write_chunk_data(png_ptr, output, avail); - - output_len -= avail; - - if (output_len == 0 || next == NULL) - break; - - avail = png_ptr->zbuffer_size; - output = next->output; - next = next->next; - } - - /* This is an internal error; 'next' must have been NULL! */ - if (output_len > 0) - png_error(png_ptr, "error writing ancillary chunked compressed data"); -} -#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */ - -#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ - defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) -/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, - * and if invalid, correct the keyword rather than discarding the entire - * chunk. The PNG 1.0 specification requires keywords 1-79 characters in - * length, forbids leading or trailing whitespace, multiple internal spaces, - * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. - * - * The 'new_key' buffer must be 80 characters in size (for the keyword plus a - * trailing '\0'). If this routine returns 0 then there was no keyword, or a - * valid one could not be generated, and the caller must png_error. - */ -static png_uint_32 -png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key) -{ - png_const_charp orig_key = key; - png_uint_32 key_len = 0; - int bad_character = 0; - int space = 1; - - png_debug(1, "in png_check_keyword"); - - if (key == NULL) - { - *new_key = 0; - return 0; - } - - while (*key && key_len < 79) - { - png_byte ch = (png_byte)(0xff & *key++); - - if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/)) - *new_key++ = ch, ++key_len, space = 0; - - else if (!space) - { - /* A space or an invalid character when one wasn't seen immediately - * before; output just a space. - */ - *new_key++ = 32, ++key_len, space = 1; - - /* If the character was not a space then it is invalid. */ - if (ch != 32) - bad_character = ch; - } - - else if (!bad_character) - bad_character = ch; /* just skip it, record the first error */ - } - - if (key_len > 0 && space) /* trailing space */ - { - --key_len, --new_key; - if (!bad_character) - bad_character = 32; - } - - /* Terminate the keyword */ - *new_key = 0; - - if (key_len == 0) - return 0; - - /* Try to only output one warning per keyword: */ - if (*key) /* keyword too long */ - png_warning(png_ptr, "keyword truncated"); - - else if (bad_character) - { - PNG_WARNING_PARAMETERS(p) - - png_warning_parameter(p, 1, orig_key); - png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character); - - png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'"); - } - - return key_len; -} -#endif - -/* Write the IHDR chunk, and update the png_struct with the necessary - * information. Note that the rest of this code depends upon this - * information being correct. - */ -void /* PRIVATE */ -png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, - int bit_depth, int color_type, int compression_type, int filter_type, - int interlace_type) -{ - png_byte buf[13]; /* Buffer to store the IHDR info */ - - png_debug(1, "in png_write_IHDR"); - - /* Check that we have valid input data from the application info */ - switch (color_type) - { - case PNG_COLOR_TYPE_GRAY: - switch (bit_depth) - { - case 1: - case 2: - case 4: - case 8: -#ifdef PNG_WRITE_16BIT_SUPPORTED - case 16: -#endif - png_ptr->channels = 1; break; - - default: - png_error(png_ptr, - "Invalid bit depth for grayscale image"); - } - break; - - case PNG_COLOR_TYPE_RGB: -#ifdef PNG_WRITE_16BIT_SUPPORTED - if (bit_depth != 8 && bit_depth != 16) -#else - if (bit_depth != 8) -#endif - png_error(png_ptr, "Invalid bit depth for RGB image"); - - png_ptr->channels = 3; - break; - - case PNG_COLOR_TYPE_PALETTE: - switch (bit_depth) - { - case 1: - case 2: - case 4: - case 8: - png_ptr->channels = 1; - break; - - default: - png_error(png_ptr, "Invalid bit depth for paletted image"); - } - break; - - case PNG_COLOR_TYPE_GRAY_ALPHA: - if (bit_depth != 8 && bit_depth != 16) - png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); - - png_ptr->channels = 2; - break; - - case PNG_COLOR_TYPE_RGB_ALPHA: -#ifdef PNG_WRITE_16BIT_SUPPORTED - if (bit_depth != 8 && bit_depth != 16) -#else - if (bit_depth != 8) -#endif - png_error(png_ptr, "Invalid bit depth for RGBA image"); - - png_ptr->channels = 4; - break; - - default: - png_error(png_ptr, "Invalid image color type specified"); - } - - if (compression_type != PNG_COMPRESSION_TYPE_BASE) - { - png_warning(png_ptr, "Invalid compression type specified"); - compression_type = PNG_COMPRESSION_TYPE_BASE; - } - - /* Write filter_method 64 (intrapixel differencing) only if - * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and - * 2. Libpng did not write a PNG signature (this filter_method is only - * used in PNG datastreams that are embedded in MNG datastreams) and - * 3. The application called png_permit_mng_features with a mask that - * included PNG_FLAG_MNG_FILTER_64 and - * 4. The filter_method is 64 and - * 5. The color_type is RGB or RGBA - */ - if ( -#ifdef PNG_MNG_FEATURES_SUPPORTED - !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && - ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) && - (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_RGB_ALPHA) && - (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && -#endif - filter_type != PNG_FILTER_TYPE_BASE) - { - png_warning(png_ptr, "Invalid filter type specified"); - filter_type = PNG_FILTER_TYPE_BASE; - } - -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - if (interlace_type != PNG_INTERLACE_NONE && - interlace_type != PNG_INTERLACE_ADAM7) - { - png_warning(png_ptr, "Invalid interlace type specified"); - interlace_type = PNG_INTERLACE_ADAM7; - } -#else - interlace_type=PNG_INTERLACE_NONE; -#endif - - /* Save the relevent information */ - png_ptr->bit_depth = (png_byte)bit_depth; - png_ptr->color_type = (png_byte)color_type; - png_ptr->interlaced = (png_byte)interlace_type; -#ifdef PNG_MNG_FEATURES_SUPPORTED - png_ptr->filter_type = (png_byte)filter_type; -#endif - png_ptr->compression_type = (png_byte)compression_type; - png_ptr->width = width; - png_ptr->height = height; - - png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels); - png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width); - /* Set the usr info, so any transformations can modify it */ - png_ptr->usr_width = png_ptr->width; - png_ptr->usr_bit_depth = png_ptr->bit_depth; - png_ptr->usr_channels = png_ptr->channels; - - /* Pack the header information into the buffer */ - png_save_uint_32(buf, width); - png_save_uint_32(buf + 4, height); - buf[8] = (png_byte)bit_depth; - buf[9] = (png_byte)color_type; - buf[10] = (png_byte)compression_type; - buf[11] = (png_byte)filter_type; - buf[12] = (png_byte)interlace_type; - - /* Write the chunk */ - png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13); - - if (!(png_ptr->do_filter)) - { - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || - png_ptr->bit_depth < 8) - png_ptr->do_filter = PNG_FILTER_NONE; - - else - png_ptr->do_filter = PNG_ALL_FILTERS; - } - - png_ptr->mode = PNG_HAVE_IHDR; /* not READY_FOR_ZTXT */ -} - -/* Write the palette. We are careful not to trust png_color to be in the - * correct order for PNG, so people can redefine it to any convenient - * structure. - */ -void /* PRIVATE */ -png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, - png_uint_32 num_pal) -{ - png_uint_32 i; - png_const_colorp pal_ptr; - png_byte buf[3]; - - png_debug(1, "in png_write_PLTE"); - - if (( -#ifdef PNG_MNG_FEATURES_SUPPORTED - !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) && -#endif - num_pal == 0) || num_pal > 256) - { - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - png_error(png_ptr, "Invalid number of colors in palette"); - } - - else - { - png_warning(png_ptr, "Invalid number of colors in palette"); - return; - } - } - - if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) - { - png_warning(png_ptr, - "Ignoring request to write a PLTE chunk in grayscale PNG"); - - return; - } - - png_ptr->num_palette = (png_uint_16)num_pal; - png_debug1(3, "num_palette = %d", png_ptr->num_palette); - - png_write_chunk_header(png_ptr, png_PLTE, (png_uint_32)(num_pal * 3)); -#ifdef PNG_POINTER_INDEXING_SUPPORTED - - for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++) - { - buf[0] = pal_ptr->red; - buf[1] = pal_ptr->green; - buf[2] = pal_ptr->blue; - png_write_chunk_data(png_ptr, buf, (png_size_t)3); - } - -#else - /* This is a little slower but some buggy compilers need to do this - * instead - */ - pal_ptr=palette; - - for (i = 0; i < num_pal; i++) - { - buf[0] = pal_ptr[i].red; - buf[1] = pal_ptr[i].green; - buf[2] = pal_ptr[i].blue; - png_write_chunk_data(png_ptr, buf, (png_size_t)3); - } - -#endif - png_write_chunk_end(png_ptr); - png_ptr->mode |= PNG_HAVE_PLTE; -} - -/* This is similar to png_text_compress, above, except that it does not require - * all of the data at once and, instead of buffering the compressed result, - * writes it as IDAT chunks. Unlike png_text_compress it *can* png_error out - * because it calls the write interface. As a result it does its own error - * reporting and does not return an error code. In the event of error it will - * just call png_error. The input data length may exceed 32-bits. The 'flush' - * parameter is exactly the same as that to deflate, with the following - * meanings: - * - * Z_NO_FLUSH: normal incremental output of compressed data - * Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush - * Z_FINISH: this is the end of the input, do a Z_FINISH and clean up - * - * The routine manages the acquire and release of the png_ptr->zstream by - * checking and (at the end) clearing png_ptr->zowner, it does some sanity - * checks on the 'mode' flags while doing this. - */ -void /* PRIVATE */ -png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, - png_alloc_size_t input_len, int flush) -{ - if (png_ptr->zowner != png_IDAT) - { - /* First time. Ensure we have a temporary buffer for compression and - * trim the buffer list if it has more than one entry to free memory. - * If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been - * created at this point, but the check here is quick and safe. - */ - if (png_ptr->zbuffer_list == NULL) - { - png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp, - png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); - png_ptr->zbuffer_list->next = NULL; - } - - else - png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list->next); - - /* It is a terminal error if we can't claim the zstream. */ - if (png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)) != Z_OK) - png_error(png_ptr, png_ptr->zstream.msg); - - /* The output state is maintained in png_ptr->zstream, so it must be - * initialized here after the claim. - */ - png_ptr->zstream.next_out = png_ptr->zbuffer_list->output; - png_ptr->zstream.avail_out = png_ptr->zbuffer_size; - } - - /* Now loop reading and writing until all the input is consumed or an error - * terminates the operation. The _out values are maintained across calls to - * this function, but the input must be reset each time. - */ - png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input); - png_ptr->zstream.avail_in = 0; /* set below */ - for (;;) - { - int ret; - - /* INPUT: from the row data */ - uInt avail = ZLIB_IO_MAX; - - if (avail > input_len) - avail = (uInt)input_len; /* safe because of the check */ - - png_ptr->zstream.avail_in = avail; - input_len -= avail; - - ret = deflate(&png_ptr->zstream, input_len > 0 ? Z_NO_FLUSH : flush); - - /* Include as-yet unconsumed input */ - input_len += png_ptr->zstream.avail_in; - png_ptr->zstream.avail_in = 0; - - /* OUTPUT: write complete IDAT chunks when avail_out drops to zero, note - * that these two zstream fields are preserved across the calls, therefore - * there is no need to set these up on entry to the loop. - */ - if (png_ptr->zstream.avail_out == 0) - { - png_bytep data = png_ptr->zbuffer_list->output; - uInt size = png_ptr->zbuffer_size; - - /* Write an IDAT containing the data then reset the buffer. The - * first IDAT may need deflate header optimization. - */ -# ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED - if (!(png_ptr->mode & PNG_HAVE_IDAT) && - png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) - optimize_cmf(data, png_image_size(png_ptr)); -# endif - - png_write_complete_chunk(png_ptr, png_IDAT, data, size); - png_ptr->mode |= PNG_HAVE_IDAT; - - png_ptr->zstream.next_out = data; - png_ptr->zstream.avail_out = size; - - /* For SYNC_FLUSH or FINISH it is essential to keep calling zlib with - * the same flush parameter until it has finished output, for NO_FLUSH - * it doesn't matter. - */ - if (ret == Z_OK && flush != Z_NO_FLUSH) - continue; - } - - /* The order of these checks doesn't matter much; it just effect which - * possible error might be detected if multiple things go wrong at once. - */ - if (ret == Z_OK) /* most likely return code! */ - { - /* If all the input has been consumed then just return. If Z_FINISH - * was used as the flush parameter something has gone wrong if we get - * here. - */ - if (input_len == 0) - { - if (flush == Z_FINISH) - png_error(png_ptr, "Z_OK on Z_FINISH with output space"); - - return; - } - } - - else if (ret == Z_STREAM_END && flush == Z_FINISH) - { - /* This is the end of the IDAT data; any pending output must be - * flushed. For small PNG files we may still be at the beginning. - */ - png_bytep data = png_ptr->zbuffer_list->output; - uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out; - -# ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED - if (!(png_ptr->mode & PNG_HAVE_IDAT) && - png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) - optimize_cmf(data, png_image_size(png_ptr)); -# endif - - png_write_complete_chunk(png_ptr, png_IDAT, data, size); - png_ptr->zstream.avail_out = 0; - png_ptr->zstream.next_out = NULL; - png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT; - - png_ptr->zowner = 0; /* Release the stream */ - return; - } - - else - { - /* This is an error condition. */ - png_zstream_error(png_ptr, ret); - png_error(png_ptr, png_ptr->zstream.msg); - } - } -} - -/* Write an IEND chunk */ -void /* PRIVATE */ -png_write_IEND(png_structrp png_ptr) -{ - png_debug(1, "in png_write_IEND"); - - png_write_complete_chunk(png_ptr, png_IEND, NULL, (png_size_t)0); - png_ptr->mode |= PNG_HAVE_IEND; -} - -#ifdef PNG_WRITE_gAMA_SUPPORTED -/* Write a gAMA chunk */ -void /* PRIVATE */ -png_write_gAMA_fixed(png_structrp png_ptr, png_fixed_point file_gamma) -{ - png_byte buf[4]; - - png_debug(1, "in png_write_gAMA"); - - /* file_gamma is saved in 1/100,000ths */ - png_save_uint_32(buf, (png_uint_32)file_gamma); - png_write_complete_chunk(png_ptr, png_gAMA, buf, (png_size_t)4); -} -#endif - -#ifdef PNG_WRITE_sRGB_SUPPORTED -/* Write a sRGB chunk */ -void /* PRIVATE */ -png_write_sRGB(png_structrp png_ptr, int srgb_intent) -{ - png_byte buf[1]; - - png_debug(1, "in png_write_sRGB"); - - if (srgb_intent >= PNG_sRGB_INTENT_LAST) - png_warning(png_ptr, - "Invalid sRGB rendering intent specified"); - - buf[0]=(png_byte)srgb_intent; - png_write_complete_chunk(png_ptr, png_sRGB, buf, (png_size_t)1); -} -#endif - -#ifdef PNG_WRITE_iCCP_SUPPORTED -/* Write an iCCP chunk */ -void /* PRIVATE */ -png_write_iCCP(png_structrp png_ptr, png_const_charp name, - png_const_bytep profile) -{ - png_uint_32 name_len; - png_uint_32 profile_len; - png_byte new_name[81]; /* 1 byte for the compression byte */ - compression_state comp; - - png_debug(1, "in png_write_iCCP"); - - /* These are all internal problems: the profile should have been checked - * before when it was stored. - */ - if (profile == NULL) - png_error(png_ptr, "No profile for iCCP chunk"); /* internal error */ - - profile_len = png_get_uint_32(profile); - - if (profile_len < 132) - png_error(png_ptr, "ICC profile too short"); - - if (profile_len & 0x03) - png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)"); - - { - png_uint_32 embedded_profile_len = png_get_uint_32(profile); - - if (profile_len != embedded_profile_len) - png_error(png_ptr, "Profile length does not match profile"); - } - - name_len = png_check_keyword(png_ptr, name, new_name); - - if (name_len == 0) - png_error(png_ptr, "iCCP: invalid keyword"); - - new_name[++name_len] = PNG_COMPRESSION_TYPE_BASE; - - /* Make sure we include the NULL after the name and the compression type */ - ++name_len; - - png_text_compress_init(&comp, profile, profile_len); - - /* Allow for keyword terminator and compression byte */ - if (png_text_compress(png_ptr, png_iCCP, &comp, name_len) != Z_OK) - png_error(png_ptr, png_ptr->zstream.msg); - - png_write_chunk_header(png_ptr, png_iCCP, name_len + comp.output_len); - - png_write_chunk_data(png_ptr, new_name, name_len); - - png_write_compressed_data_out(png_ptr, &comp); - - png_write_chunk_end(png_ptr); -} -#endif - -#ifdef PNG_WRITE_sPLT_SUPPORTED -/* Write a sPLT chunk */ -void /* PRIVATE */ -png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette) -{ - png_uint_32 name_len; - png_byte new_name[80]; - png_byte entrybuf[10]; - png_size_t entry_size = (spalette->depth == 8 ? 6 : 10); - png_size_t palette_size = entry_size * spalette->nentries; - png_sPLT_entryp ep; -#ifndef PNG_POINTER_INDEXING_SUPPORTED - int i; -#endif - - png_debug(1, "in png_write_sPLT"); - - name_len = png_check_keyword(png_ptr, spalette->name, new_name); - - if (name_len == 0) - png_error(png_ptr, "sPLT: invalid keyword"); - - /* Make sure we include the NULL after the name */ - png_write_chunk_header(png_ptr, png_sPLT, - (png_uint_32)(name_len + 2 + palette_size)); - - png_write_chunk_data(png_ptr, (png_bytep)new_name, - (png_size_t)(name_len + 1)); - - png_write_chunk_data(png_ptr, &spalette->depth, (png_size_t)1); - - /* Loop through each palette entry, writing appropriately */ -#ifdef PNG_POINTER_INDEXING_SUPPORTED - for (ep = spalette->entries; epentries + spalette->nentries; ep++) - { - if (spalette->depth == 8) - { - entrybuf[0] = (png_byte)ep->red; - entrybuf[1] = (png_byte)ep->green; - entrybuf[2] = (png_byte)ep->blue; - entrybuf[3] = (png_byte)ep->alpha; - png_save_uint_16(entrybuf + 4, ep->frequency); - } - - else - { - png_save_uint_16(entrybuf + 0, ep->red); - png_save_uint_16(entrybuf + 2, ep->green); - png_save_uint_16(entrybuf + 4, ep->blue); - png_save_uint_16(entrybuf + 6, ep->alpha); - png_save_uint_16(entrybuf + 8, ep->frequency); - } - - png_write_chunk_data(png_ptr, entrybuf, entry_size); - } -#else - ep=spalette->entries; - for (i = 0; i>spalette->nentries; i++) - { - if (spalette->depth == 8) - { - entrybuf[0] = (png_byte)ep[i].red; - entrybuf[1] = (png_byte)ep[i].green; - entrybuf[2] = (png_byte)ep[i].blue; - entrybuf[3] = (png_byte)ep[i].alpha; - png_save_uint_16(entrybuf + 4, ep[i].frequency); - } - - else - { - png_save_uint_16(entrybuf + 0, ep[i].red); - png_save_uint_16(entrybuf + 2, ep[i].green); - png_save_uint_16(entrybuf + 4, ep[i].blue); - png_save_uint_16(entrybuf + 6, ep[i].alpha); - png_save_uint_16(entrybuf + 8, ep[i].frequency); - } - - png_write_chunk_data(png_ptr, entrybuf, entry_size); - } -#endif - - png_write_chunk_end(png_ptr); -} -#endif - -#ifdef PNG_WRITE_sBIT_SUPPORTED -/* Write the sBIT chunk */ -void /* PRIVATE */ -png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type) -{ - png_byte buf[4]; - png_size_t size; - - png_debug(1, "in png_write_sBIT"); - - /* Make sure we don't depend upon the order of PNG_COLOR_8 */ - if (color_type & PNG_COLOR_MASK_COLOR) - { - png_byte maxbits; - - maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 : - png_ptr->usr_bit_depth); - - if (sbit->red == 0 || sbit->red > maxbits || - sbit->green == 0 || sbit->green > maxbits || - sbit->blue == 0 || sbit->blue > maxbits) - { - png_warning(png_ptr, "Invalid sBIT depth specified"); - return; - } - - buf[0] = sbit->red; - buf[1] = sbit->green; - buf[2] = sbit->blue; - size = 3; - } - - else - { - if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth) - { - png_warning(png_ptr, "Invalid sBIT depth specified"); - return; - } - - buf[0] = sbit->gray; - size = 1; - } - - if (color_type & PNG_COLOR_MASK_ALPHA) - { - if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) - { - png_warning(png_ptr, "Invalid sBIT depth specified"); - return; - } - - buf[size++] = sbit->alpha; - } - - png_write_complete_chunk(png_ptr, png_sBIT, buf, size); -} -#endif - -#ifdef PNG_WRITE_cHRM_SUPPORTED -/* Write the cHRM chunk */ -void /* PRIVATE */ -png_write_cHRM_fixed(png_structrp png_ptr, const png_xy *xy) -{ - png_byte buf[32]; - - png_debug(1, "in png_write_cHRM"); - - /* Each value is saved in 1/100,000ths */ - png_save_int_32(buf, xy->whitex); - png_save_int_32(buf + 4, xy->whitey); - - png_save_int_32(buf + 8, xy->redx); - png_save_int_32(buf + 12, xy->redy); - - png_save_int_32(buf + 16, xy->greenx); - png_save_int_32(buf + 20, xy->greeny); - - png_save_int_32(buf + 24, xy->bluex); - png_save_int_32(buf + 28, xy->bluey); - - png_write_complete_chunk(png_ptr, png_cHRM, buf, 32); -} -#endif - -#ifdef PNG_WRITE_tRNS_SUPPORTED -/* Write the tRNS chunk */ -void /* PRIVATE */ -png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha, - png_const_color_16p tran, int num_trans, int color_type) -{ - png_byte buf[6]; - - png_debug(1, "in png_write_tRNS"); - - if (color_type == PNG_COLOR_TYPE_PALETTE) - { - if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette) - { - png_app_warning(png_ptr, - "Invalid number of transparent colors specified"); - return; - } - - /* Write the chunk out as it is */ - png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha, - (png_size_t)num_trans); - } - - else if (color_type == PNG_COLOR_TYPE_GRAY) - { - /* One 16 bit value */ - if (tran->gray >= (1 << png_ptr->bit_depth)) - { - png_app_warning(png_ptr, - "Ignoring attempt to write tRNS chunk out-of-range for bit_depth"); - - return; - } - - png_save_uint_16(buf, tran->gray); - png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)2); - } - - else if (color_type == PNG_COLOR_TYPE_RGB) - { - /* Three 16 bit values */ - png_save_uint_16(buf, tran->red); - png_save_uint_16(buf + 2, tran->green); - png_save_uint_16(buf + 4, tran->blue); -#ifdef PNG_WRITE_16BIT_SUPPORTED - if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) -#else - if (buf[0] | buf[2] | buf[4]) -#endif - { - png_app_warning(png_ptr, - "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); - return; - } - - png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)6); - } - - else - { - png_app_warning(png_ptr, "Can't write tRNS with an alpha channel"); - } -} -#endif - -#ifdef PNG_WRITE_bKGD_SUPPORTED -/* Write the background chunk */ -void /* PRIVATE */ -png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) -{ - png_byte buf[6]; - - png_debug(1, "in png_write_bKGD"); - - if (color_type == PNG_COLOR_TYPE_PALETTE) - { - if ( -#ifdef PNG_MNG_FEATURES_SUPPORTED - (png_ptr->num_palette || - (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) && -#endif - back->index >= png_ptr->num_palette) - { - png_warning(png_ptr, "Invalid background palette index"); - return; - } - - buf[0] = back->index; - png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)1); - } - - else if (color_type & PNG_COLOR_MASK_COLOR) - { - png_save_uint_16(buf, back->red); - png_save_uint_16(buf + 2, back->green); - png_save_uint_16(buf + 4, back->blue); -#ifdef PNG_WRITE_16BIT_SUPPORTED - if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) -#else - if (buf[0] | buf[2] | buf[4]) -#endif - { - png_warning(png_ptr, - "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8"); - - return; - } - - png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)6); - } - - else - { - if (back->gray >= (1 << png_ptr->bit_depth)) - { - png_warning(png_ptr, - "Ignoring attempt to write bKGD chunk out-of-range for bit_depth"); - - return; - } - - png_save_uint_16(buf, back->gray); - png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)2); - } -} -#endif - -#ifdef PNG_WRITE_hIST_SUPPORTED -/* Write the histogram */ -void /* PRIVATE */ -png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist) -{ - int i; - png_byte buf[3]; - - png_debug(1, "in png_write_hIST"); - - if (num_hist > (int)png_ptr->num_palette) - { - png_debug2(3, "num_hist = %d, num_palette = %d", num_hist, - png_ptr->num_palette); - - png_warning(png_ptr, "Invalid number of histogram entries specified"); - return; - } - - png_write_chunk_header(png_ptr, png_hIST, (png_uint_32)(num_hist * 2)); - - for (i = 0; i < num_hist; i++) - { - png_save_uint_16(buf, hist[i]); - png_write_chunk_data(png_ptr, buf, (png_size_t)2); - } - - png_write_chunk_end(png_ptr); -} -#endif - -#ifdef PNG_WRITE_tEXt_SUPPORTED -/* Write a tEXt chunk */ -void /* PRIVATE */ -png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, - png_size_t text_len) -{ - png_uint_32 key_len; - png_byte new_key[80]; - - png_debug(1, "in png_write_tEXt"); - - key_len = png_check_keyword(png_ptr, key, new_key); - - if (key_len == 0) - png_error(png_ptr, "tEXt: invalid keyword"); - - if (text == NULL || *text == '\0') - text_len = 0; - - else - text_len = strlen(text); - - if (text_len > PNG_UINT_31_MAX - (key_len+1)) - png_error(png_ptr, "tEXt: text too long"); - - /* Make sure we include the 0 after the key */ - png_write_chunk_header(png_ptr, png_tEXt, - (png_uint_32)/*checked above*/(key_len + text_len + 1)); - /* - * We leave it to the application to meet PNG-1.0 requirements on the - * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of - * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. - * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. - */ - png_write_chunk_data(png_ptr, new_key, key_len + 1); - - if (text_len) - png_write_chunk_data(png_ptr, (png_const_bytep)text, text_len); - - png_write_chunk_end(png_ptr); -} -#endif - -#ifdef PNG_WRITE_zTXt_SUPPORTED -/* Write a compressed text chunk */ -void /* PRIVATE */ -png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, - png_size_t text_len, int compression) -{ - png_uint_32 key_len; - png_byte new_key[81]; - compression_state comp; - - png_debug(1, "in png_write_zTXt"); - PNG_UNUSED(text_len) /* Always use strlen */ - - if (compression == PNG_TEXT_COMPRESSION_NONE) - { - png_write_tEXt(png_ptr, key, text, 0); - return; - } - - if (compression != PNG_TEXT_COMPRESSION_zTXt) - png_error(png_ptr, "zTXt: invalid compression type"); - - key_len = png_check_keyword(png_ptr, key, new_key); - - if (key_len == 0) - png_error(png_ptr, "zTXt: invalid keyword"); - - /* Add the compression method and 1 for the keyword separator. */ - new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; - ++key_len; - - /* Compute the compressed data; do it now for the length */ - png_text_compress_init(&comp, (png_const_bytep)text, - text == NULL ? 0 : strlen(text)); - - if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK) - png_error(png_ptr, png_ptr->zstream.msg); - - /* Write start of chunk */ - png_write_chunk_header(png_ptr, png_zTXt, key_len + comp.output_len); - - /* Write key */ - png_write_chunk_data(png_ptr, new_key, key_len); - - /* Write the compressed data */ - png_write_compressed_data_out(png_ptr, &comp); - - /* Close the chunk */ - png_write_chunk_end(png_ptr); -} -#endif - -#ifdef PNG_WRITE_iTXt_SUPPORTED -/* Write an iTXt chunk */ -void /* PRIVATE */ -png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key, - png_const_charp lang, png_const_charp lang_key, png_const_charp text) -{ - png_uint_32 key_len, prefix_len; - png_size_t lang_len, lang_key_len; - png_byte new_key[82]; - compression_state comp; - - png_debug(1, "in png_write_iTXt"); - - key_len = png_check_keyword(png_ptr, key, new_key); - - if (key_len == 0) - png_error(png_ptr, "iTXt: invalid keyword"); - - /* Set the compression flag */ - switch (compression) - { - case PNG_ITXT_COMPRESSION_NONE: - case PNG_TEXT_COMPRESSION_NONE: - compression = new_key[++key_len] = 0; /* no compression */ - break; - - case PNG_TEXT_COMPRESSION_zTXt: - case PNG_ITXT_COMPRESSION_zTXt: - compression = new_key[++key_len] = 1; /* compressed */ - break; - - default: - png_error(png_ptr, "iTXt: invalid compression"); - } - - new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; - ++key_len; /* for the keywod separator */ - - /* We leave it to the application to meet PNG-1.0 requirements on the - * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of - * any non-Latin-1 characters except for NEWLINE. ISO PNG, however, - * specifies that the text is UTF-8 and this really doesn't require any - * checking. - * - * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. - * - * TODO: validate the language tag correctly (see the spec.) - */ - if (lang == NULL) lang = ""; /* empty language is valid */ - lang_len = strlen(lang)+1; - if (lang_key == NULL) lang_key = ""; /* may be empty */ - lang_key_len = strlen(lang_key)+1; - if (text == NULL) text = ""; /* may be empty */ - - prefix_len = key_len; - if (lang_len > PNG_UINT_31_MAX-prefix_len) - prefix_len = PNG_UINT_31_MAX; - else - prefix_len = (png_uint_32)(prefix_len + lang_len); - - if (lang_key_len > PNG_UINT_31_MAX-prefix_len) - prefix_len = PNG_UINT_31_MAX; - else - prefix_len = (png_uint_32)(prefix_len + lang_key_len); - - png_text_compress_init(&comp, (png_const_bytep)text, strlen(text)); - - if (compression) - { - if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK) - png_error(png_ptr, png_ptr->zstream.msg); - } - - else - { - if (comp.input_len > PNG_UINT_31_MAX-prefix_len) - png_error(png_ptr, "iTXt: uncompressed text too long"); - } - - png_write_chunk_header(png_ptr, png_iTXt, comp.output_len + prefix_len); - - png_write_chunk_data(png_ptr, new_key, key_len); - - png_write_chunk_data(png_ptr, (png_const_bytep)lang, lang_len); - - png_write_chunk_data(png_ptr, (png_const_bytep)lang_key, lang_key_len); - - if (compression) - png_write_compressed_data_out(png_ptr, &comp); - - else - png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.input_len); - - png_write_chunk_end(png_ptr); -} -#endif - -#ifdef PNG_WRITE_oFFs_SUPPORTED -/* Write the oFFs chunk */ -void /* PRIVATE */ -png_write_oFFs(png_structrp png_ptr, png_int_32 x_offset, png_int_32 y_offset, - int unit_type) -{ - png_byte buf[9]; - - png_debug(1, "in png_write_oFFs"); - - if (unit_type >= PNG_OFFSET_LAST) - png_warning(png_ptr, "Unrecognized unit type for oFFs chunk"); - - png_save_int_32(buf, x_offset); - png_save_int_32(buf + 4, y_offset); - buf[8] = (png_byte)unit_type; - - png_write_complete_chunk(png_ptr, png_oFFs, buf, (png_size_t)9); -} -#endif -#ifdef PNG_WRITE_pCAL_SUPPORTED -/* Write the pCAL chunk (described in the PNG extensions document) */ -void /* PRIVATE */ -png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0, - png_int_32 X1, int type, int nparams, png_const_charp units, - png_charpp params) -{ - png_uint_32 purpose_len; - png_size_t units_len, total_len; - png_size_tp params_len; - png_byte buf[10]; - png_byte new_purpose[80]; - int i; - - png_debug1(1, "in png_write_pCAL (%d parameters)", nparams); - - if (type >= PNG_EQUATION_LAST) - png_error(png_ptr, "Unrecognized equation type for pCAL chunk"); - - purpose_len = png_check_keyword(png_ptr, purpose, new_purpose); - - if (purpose_len == 0) - png_error(png_ptr, "pCAL: invalid keyword"); - - ++purpose_len; /* terminator */ - - png_debug1(3, "pCAL purpose length = %d", (int)purpose_len); - units_len = strlen(units) + (nparams == 0 ? 0 : 1); - png_debug1(3, "pCAL units length = %d", (int)units_len); - total_len = purpose_len + units_len + 10; - - params_len = (png_size_tp)png_malloc(png_ptr, - (png_alloc_size_t)(nparams * (sizeof (png_size_t)))); - - /* Find the length of each parameter, making sure we don't count the - * null terminator for the last parameter. - */ - for (i = 0; i < nparams; i++) - { - params_len[i] = strlen(params[i]) + (i == nparams - 1 ? 0 : 1); - png_debug2(3, "pCAL parameter %d length = %lu", i, - (unsigned long)params_len[i]); - total_len += params_len[i]; - } - - png_debug1(3, "pCAL total length = %d", (int)total_len); - png_write_chunk_header(png_ptr, png_pCAL, (png_uint_32)total_len); - png_write_chunk_data(png_ptr, new_purpose, purpose_len); - png_save_int_32(buf, X0); - png_save_int_32(buf + 4, X1); - buf[8] = (png_byte)type; - buf[9] = (png_byte)nparams; - png_write_chunk_data(png_ptr, buf, (png_size_t)10); - png_write_chunk_data(png_ptr, (png_const_bytep)units, (png_size_t)units_len); - - for (i = 0; i < nparams; i++) - { - png_write_chunk_data(png_ptr, (png_const_bytep)params[i], params_len[i]); - } - - png_free(png_ptr, params_len); - png_write_chunk_end(png_ptr); -} -#endif - -#ifdef PNG_WRITE_sCAL_SUPPORTED -/* Write the sCAL chunk */ -void /* PRIVATE */ -png_write_sCAL_s(png_structrp png_ptr, int unit, png_const_charp width, - png_const_charp height) -{ - png_byte buf[64]; - png_size_t wlen, hlen, total_len; - - png_debug(1, "in png_write_sCAL_s"); - - wlen = strlen(width); - hlen = strlen(height); - total_len = wlen + hlen + 2; - - if (total_len > 64) - { - png_warning(png_ptr, "Can't write sCAL (buffer too small)"); - return; - } - - buf[0] = (png_byte)unit; - memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */ - memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */ - - png_debug1(3, "sCAL total length = %u", (unsigned int)total_len); - png_write_complete_chunk(png_ptr, png_sCAL, buf, total_len); -} -#endif - -#ifdef PNG_WRITE_pHYs_SUPPORTED -/* Write the pHYs chunk */ -void /* PRIVATE */ -png_write_pHYs(png_structrp png_ptr, png_uint_32 x_pixels_per_unit, - png_uint_32 y_pixels_per_unit, - int unit_type) -{ - png_byte buf[9]; - - png_debug(1, "in png_write_pHYs"); - - if (unit_type >= PNG_RESOLUTION_LAST) - png_warning(png_ptr, "Unrecognized unit type for pHYs chunk"); - - png_save_uint_32(buf, x_pixels_per_unit); - png_save_uint_32(buf + 4, y_pixels_per_unit); - buf[8] = (png_byte)unit_type; - - png_write_complete_chunk(png_ptr, png_pHYs, buf, (png_size_t)9); -} -#endif - -#ifdef PNG_WRITE_tIME_SUPPORTED -/* Write the tIME chunk. Use either png_convert_from_struct_tm() - * or png_convert_from_time_t(), or fill in the structure yourself. - */ -void /* PRIVATE */ -png_write_tIME(png_structrp png_ptr, png_const_timep mod_time) -{ - png_byte buf[7]; - - png_debug(1, "in png_write_tIME"); - - if (mod_time->month > 12 || mod_time->month < 1 || - mod_time->day > 31 || mod_time->day < 1 || - mod_time->hour > 23 || mod_time->second > 60) - { - png_warning(png_ptr, "Invalid time specified for tIME chunk"); - return; - } - - png_save_uint_16(buf, mod_time->year); - buf[2] = mod_time->month; - buf[3] = mod_time->day; - buf[4] = mod_time->hour; - buf[5] = mod_time->minute; - buf[6] = mod_time->second; - - png_write_complete_chunk(png_ptr, png_tIME, buf, (png_size_t)7); -} -#endif - -/* Initializes the row writing capability of libpng */ -void /* PRIVATE */ -png_write_start_row(png_structrp png_ptr) -{ -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif - - png_alloc_size_t buf_size; - int usr_pixel_depth; - - png_debug(1, "in png_write_start_row"); - - usr_pixel_depth = png_ptr->usr_channels * png_ptr->usr_bit_depth; - buf_size = PNG_ROWBYTES(usr_pixel_depth, png_ptr->width) + 1; - - /* 1.5.6: added to allow checking in the row write code. */ - png_ptr->transformed_pixel_depth = png_ptr->pixel_depth; - png_ptr->maximum_pixel_depth = (png_byte)usr_pixel_depth; - - /* Set up row buffer */ - png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, buf_size); - - png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; - -#ifdef PNG_WRITE_FILTER_SUPPORTED - /* Set up filtering buffer, if using this filter */ - if (png_ptr->do_filter & PNG_FILTER_SUB) - { - png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1); - - png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; - } - - /* We only need to keep the previous row if we are using one of these. */ - if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) - { - /* Set up previous row buffer */ - png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, buf_size); - - if (png_ptr->do_filter & PNG_FILTER_UP) - { - png_ptr->up_row = (png_bytep)png_malloc(png_ptr, - png_ptr->rowbytes + 1); - - png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; - } - - if (png_ptr->do_filter & PNG_FILTER_AVG) - { - png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, - png_ptr->rowbytes + 1); - - png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; - } - - if (png_ptr->do_filter & PNG_FILTER_PAETH) - { - png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, - png_ptr->rowbytes + 1); - - png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; - } - } -#endif /* PNG_WRITE_FILTER_SUPPORTED */ - -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* If interlaced, we need to set up width and height of pass */ - if (png_ptr->interlaced) - { - if (!(png_ptr->transformations & PNG_INTERLACE)) - { - png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - - png_pass_ystart[0]) / png_pass_yinc[0]; - - png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 - - png_pass_start[0]) / png_pass_inc[0]; - } - - else - { - png_ptr->num_rows = png_ptr->height; - png_ptr->usr_width = png_ptr->width; - } - } - - else -#endif - { - png_ptr->num_rows = png_ptr->height; - png_ptr->usr_width = png_ptr->width; - } -} - -/* Internal use only. Called when finished processing a row of data. */ -void /* PRIVATE */ -png_write_finish_row(png_structrp png_ptr) -{ -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif - - png_debug(1, "in png_write_finish_row"); - - /* Next row */ - png_ptr->row_number++; - - /* See if we are done */ - if (png_ptr->row_number < png_ptr->num_rows) - return; - -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* If interlaced, go to next pass */ - if (png_ptr->interlaced) - { - png_ptr->row_number = 0; - if (png_ptr->transformations & PNG_INTERLACE) - { - png_ptr->pass++; - } - - else - { - /* Loop until we find a non-zero width or height pass */ - do - { - png_ptr->pass++; - - if (png_ptr->pass >= 7) - break; - - png_ptr->usr_width = (png_ptr->width + - png_pass_inc[png_ptr->pass] - 1 - - png_pass_start[png_ptr->pass]) / - png_pass_inc[png_ptr->pass]; - - png_ptr->num_rows = (png_ptr->height + - png_pass_yinc[png_ptr->pass] - 1 - - png_pass_ystart[png_ptr->pass]) / - png_pass_yinc[png_ptr->pass]; - - if (png_ptr->transformations & PNG_INTERLACE) - break; - - } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); - - } - - /* Reset the row above the image for the next pass */ - if (png_ptr->pass < 7) - { - if (png_ptr->prev_row != NULL) - memset(png_ptr->prev_row, 0, - (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* - png_ptr->usr_bit_depth, png_ptr->width)) + 1); - - return; - } - } -#endif - - /* If we get here, we've just written the last row, so we need - to flush the compressor */ - png_compress_IDAT(png_ptr, NULL, 0, Z_FINISH); -} - -#ifdef PNG_WRITE_INTERLACING_SUPPORTED -/* Pick out the correct pixels for the interlace pass. - * The basic idea here is to go through the row with a source - * pointer and a destination pointer (sp and dp), and copy the - * correct pixels for the pass. As the row gets compacted, - * sp will always be >= dp, so we should never overwrite anything. - * See the default: case for the easiest code to understand. - */ -void /* PRIVATE */ -png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) -{ - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - png_debug(1, "in png_do_write_interlace"); - - /* We don't have to do anything on the last pass (6) */ - if (pass < 6) - { - /* Each pixel depth is handled separately */ - switch (row_info->pixel_depth) - { - case 1: - { - png_bytep sp; - png_bytep dp; - int shift; - int d; - int value; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - dp = row; - d = 0; - shift = 7; - - for (i = png_pass_start[pass]; i < row_width; - i += png_pass_inc[pass]) - { - sp = row + (png_size_t)(i >> 3); - value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01; - d |= (value << shift); - - if (shift == 0) - { - shift = 7; - *dp++ = (png_byte)d; - d = 0; - } - - else - shift--; - - } - if (shift != 7) - *dp = (png_byte)d; - - break; - } - - case 2: - { - png_bytep sp; - png_bytep dp; - int shift; - int d; - int value; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - dp = row; - shift = 6; - d = 0; - - for (i = png_pass_start[pass]; i < row_width; - i += png_pass_inc[pass]) - { - sp = row + (png_size_t)(i >> 2); - value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03; - d |= (value << shift); - - if (shift == 0) - { - shift = 6; - *dp++ = (png_byte)d; - d = 0; - } - - else - shift -= 2; - } - if (shift != 6) - *dp = (png_byte)d; - - break; - } - - case 4: - { - png_bytep sp; - png_bytep dp; - int shift; - int d; - int value; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - dp = row; - shift = 4; - d = 0; - for (i = png_pass_start[pass]; i < row_width; - i += png_pass_inc[pass]) - { - sp = row + (png_size_t)(i >> 1); - value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f; - d |= (value << shift); - - if (shift == 0) - { - shift = 4; - *dp++ = (png_byte)d; - d = 0; - } - - else - shift -= 4; - } - if (shift != 4) - *dp = (png_byte)d; - - break; - } - - default: - { - png_bytep sp; - png_bytep dp; - png_uint_32 i; - png_uint_32 row_width = row_info->width; - png_size_t pixel_bytes; - - /* Start at the beginning */ - dp = row; - - /* Find out how many bytes each pixel takes up */ - pixel_bytes = (row_info->pixel_depth >> 3); - - /* Loop through the row, only looking at the pixels that matter */ - for (i = png_pass_start[pass]; i < row_width; - i += png_pass_inc[pass]) - { - /* Find out where the original pixel is */ - sp = row + (png_size_t)i * pixel_bytes; - - /* Move the pixel */ - if (dp != sp) - memcpy(dp, sp, pixel_bytes); - - /* Next pixel */ - dp += pixel_bytes; - } - break; - } - } - /* Set new row width */ - row_info->width = (row_info->width + - png_pass_inc[pass] - 1 - - png_pass_start[pass]) / - png_pass_inc[pass]; - - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, - row_info->width); - } -} -#endif - -/* This filters the row, chooses which filter to use, if it has not already - * been specified by the application, and then writes the row out with the - * chosen filter. - */ -static void png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, - png_size_t row_bytes); - -#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1) -#define PNG_HISHIFT 10 -#define PNG_LOMASK ((png_uint_32)0xffffL) -#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT)) -void /* PRIVATE */ -png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) -{ - png_bytep best_row; -#ifdef PNG_WRITE_FILTER_SUPPORTED - png_bytep prev_row, row_buf; - png_uint_32 mins, bpp; - png_byte filter_to_do = png_ptr->do_filter; - png_size_t row_bytes = row_info->rowbytes; -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - int num_p_filters = png_ptr->num_prev_filters; -#endif - - png_debug(1, "in png_write_find_filter"); - -#ifndef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->row_number == 0 && filter_to_do == PNG_ALL_FILTERS) - { - /* These will never be selected so we need not test them. */ - filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_PAETH); - } -#endif - - /* Find out how many bytes offset each pixel is */ - bpp = (row_info->pixel_depth + 7) >> 3; - - prev_row = png_ptr->prev_row; -#endif - best_row = png_ptr->row_buf; -#ifdef PNG_WRITE_FILTER_SUPPORTED - row_buf = best_row; - mins = PNG_MAXSUM; - - /* The prediction method we use is to find which method provides the - * smallest value when summing the absolute values of the distances - * from zero, using anything >= 128 as negative numbers. This is known - * as the "minimum sum of absolute differences" heuristic. Other - * heuristics are the "weighted minimum sum of absolute differences" - * (experimental and can in theory improve compression), and the "zlib - * predictive" method (not implemented yet), which does test compressions - * of lines using different filter methods, and then chooses the - * (series of) filter(s) that give minimum compressed data size (VERY - * computationally expensive). - * - * GRR 980525: consider also - * - * (1) minimum sum of absolute differences from running average (i.e., - * keep running sum of non-absolute differences & count of bytes) - * [track dispersion, too? restart average if dispersion too large?] - * - * (1b) minimum sum of absolute differences from sliding average, probably - * with window size <= deflate window (usually 32K) - * - * (2) minimum sum of squared differences from zero or running average - * (i.e., ~ root-mean-square approach) - */ - - - /* We don't need to test the 'no filter' case if this is the only filter - * that has been chosen, as it doesn't actually do anything to the data. - */ - if ((filter_to_do & PNG_FILTER_NONE) && filter_to_do != PNG_FILTER_NONE) - { - png_bytep rp; - png_uint_32 sum = 0; - png_size_t i; - int v; - - for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) - { - v = *rp; - sum += (v < 128) ? v : 256 - v; - } - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - png_uint_32 sumhi, sumlo; - int j; - sumlo = sum & PNG_LOMASK; - sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */ - - /* Reduce the sum if we match any of the previous rows */ - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) - { - sumlo = (sumlo * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - - sumhi = (sumhi * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - /* Factor in the cost of this filter (this is here for completeness, - * but it makes no sense to have a "cost" for the NONE filter, as - * it has the minimum possible computational cost - none). - */ - sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> - PNG_COST_SHIFT; - - sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> - PNG_COST_SHIFT; - - if (sumhi > PNG_HIMASK) - sum = PNG_MAXSUM; - - else - sum = (sumhi << PNG_HISHIFT) + sumlo; - } -#endif - mins = sum; - } - - /* Sub filter */ - if (filter_to_do == PNG_FILTER_SUB) - /* It's the only filter so no testing is needed */ - { - png_bytep rp, lp, dp; - png_size_t i; - - for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; - i++, rp++, dp++) - { - *dp = *rp; - } - - for (lp = row_buf + 1; i < row_bytes; - i++, rp++, lp++, dp++) - { - *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); - } - - best_row = png_ptr->sub_row; - } - - else if (filter_to_do & PNG_FILTER_SUB) - { - png_bytep rp, dp, lp; - png_uint_32 sum = 0, lmins = mins; - png_size_t i; - int v; - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - /* We temporarily increase the "minimum sum" by the factor we - * would reduce the sum of this filter, so that we can do the - * early exit comparison without scaling the sum each time. - */ - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int j; - png_uint_32 lmhi, lmlo; - lmlo = lmins & PNG_LOMASK; - lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; - - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) - { - lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - - lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> - PNG_COST_SHIFT; - - lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> - PNG_COST_SHIFT; - - if (lmhi > PNG_HIMASK) - lmins = PNG_MAXSUM; - - else - lmins = (lmhi << PNG_HISHIFT) + lmlo; - } -#endif - - for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; - i++, rp++, dp++) - { - v = *dp = *rp; - - sum += (v < 128) ? v : 256 - v; - } - - for (lp = row_buf + 1; i < row_bytes; - i++, rp++, lp++, dp++) - { - v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); - - sum += (v < 128) ? v : 256 - v; - - if (sum > lmins) /* We are already worse, don't continue. */ - break; - } - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int j; - png_uint_32 sumhi, sumlo; - sumlo = sum & PNG_LOMASK; - sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; - - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) - { - sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - - sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> - PNG_COST_SHIFT; - - sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> - PNG_COST_SHIFT; - - if (sumhi > PNG_HIMASK) - sum = PNG_MAXSUM; - - else - sum = (sumhi << PNG_HISHIFT) + sumlo; - } -#endif - - if (sum < mins) - { - mins = sum; - best_row = png_ptr->sub_row; - } - } - - /* Up filter */ - if (filter_to_do == PNG_FILTER_UP) - { - png_bytep rp, dp, pp; - png_size_t i; - - for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, - pp = prev_row + 1; i < row_bytes; - i++, rp++, pp++, dp++) - { - *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); - } - - best_row = png_ptr->up_row; - } - - else if (filter_to_do & PNG_FILTER_UP) - { - png_bytep rp, dp, pp; - png_uint_32 sum = 0, lmins = mins; - png_size_t i; - int v; - - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int j; - png_uint_32 lmhi, lmlo; - lmlo = lmins & PNG_LOMASK; - lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; - - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) - { - lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - - lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> - PNG_COST_SHIFT; - - lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> - PNG_COST_SHIFT; - - if (lmhi > PNG_HIMASK) - lmins = PNG_MAXSUM; - - else - lmins = (lmhi << PNG_HISHIFT) + lmlo; - } -#endif - - for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, - pp = prev_row + 1; i < row_bytes; i++) - { - v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); - - sum += (v < 128) ? v : 256 - v; - - if (sum > lmins) /* We are already worse, don't continue. */ - break; - } - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int j; - png_uint_32 sumhi, sumlo; - sumlo = sum & PNG_LOMASK; - sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; - - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) - { - sumlo = (sumlo * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - - sumhi = (sumhi * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> - PNG_COST_SHIFT; - - sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> - PNG_COST_SHIFT; - - if (sumhi > PNG_HIMASK) - sum = PNG_MAXSUM; - - else - sum = (sumhi << PNG_HISHIFT) + sumlo; - } -#endif - - if (sum < mins) - { - mins = sum; - best_row = png_ptr->up_row; - } - } - - /* Avg filter */ - if (filter_to_do == PNG_FILTER_AVG) - { - png_bytep rp, dp, pp, lp; - png_uint_32 i; - - for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, - pp = prev_row + 1; i < bpp; i++) - { - *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); - } - - for (lp = row_buf + 1; i < row_bytes; i++) - { - *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) - & 0xff); - } - best_row = png_ptr->avg_row; - } - - else if (filter_to_do & PNG_FILTER_AVG) - { - png_bytep rp, dp, pp, lp; - png_uint_32 sum = 0, lmins = mins; - png_size_t i; - int v; - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int j; - png_uint_32 lmhi, lmlo; - lmlo = lmins & PNG_LOMASK; - lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; - - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG) - { - lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - - lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> - PNG_COST_SHIFT; - - lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> - PNG_COST_SHIFT; - - if (lmhi > PNG_HIMASK) - lmins = PNG_MAXSUM; - - else - lmins = (lmhi << PNG_HISHIFT) + lmlo; - } -#endif - - for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, - pp = prev_row + 1; i < bpp; i++) - { - v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); - - sum += (v < 128) ? v : 256 - v; - } - - for (lp = row_buf + 1; i < row_bytes; i++) - { - v = *dp++ = - (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); - - sum += (v < 128) ? v : 256 - v; - - if (sum > lmins) /* We are already worse, don't continue. */ - break; - } - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int j; - png_uint_32 sumhi, sumlo; - sumlo = sum & PNG_LOMASK; - sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; - - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) - { - sumlo = (sumlo * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - - sumhi = (sumhi * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> - PNG_COST_SHIFT; - - sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> - PNG_COST_SHIFT; - - if (sumhi > PNG_HIMASK) - sum = PNG_MAXSUM; - - else - sum = (sumhi << PNG_HISHIFT) + sumlo; - } -#endif - - if (sum < mins) - { - mins = sum; - best_row = png_ptr->avg_row; - } - } - - /* Paeth filter */ - if (filter_to_do == PNG_FILTER_PAETH) - { - png_bytep rp, dp, pp, cp, lp; - png_size_t i; - - for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, - pp = prev_row + 1; i < bpp; i++) - { - *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); - } - - for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) - { - int a, b, c, pa, pb, pc, p; - - b = *pp++; - c = *cp++; - a = *lp++; - - p = b - c; - pc = a - c; - -#ifdef PNG_USE_ABS - pa = abs(p); - pb = abs(pc); - pc = abs(p + pc); -#else - pa = p < 0 ? -p : p; - pb = pc < 0 ? -pc : pc; - pc = (p + pc) < 0 ? -(p + pc) : p + pc; -#endif - - p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; - - *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); - } - best_row = png_ptr->paeth_row; - } - - else if (filter_to_do & PNG_FILTER_PAETH) - { - png_bytep rp, dp, pp, cp, lp; - png_uint_32 sum = 0, lmins = mins; - png_size_t i; - int v; - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int j; - png_uint_32 lmhi, lmlo; - lmlo = lmins & PNG_LOMASK; - lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; - - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) - { - lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - - lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> - PNG_COST_SHIFT; - - lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> - PNG_COST_SHIFT; - - if (lmhi > PNG_HIMASK) - lmins = PNG_MAXSUM; - - else - lmins = (lmhi << PNG_HISHIFT) + lmlo; - } -#endif - - for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, - pp = prev_row + 1; i < bpp; i++) - { - v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); - - sum += (v < 128) ? v : 256 - v; - } - - for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) - { - int a, b, c, pa, pb, pc, p; - - b = *pp++; - c = *cp++; - a = *lp++; - -#ifndef PNG_SLOW_PAETH - p = b - c; - pc = a - c; -#ifdef PNG_USE_ABS - pa = abs(p); - pb = abs(pc); - pc = abs(p + pc); -#else - pa = p < 0 ? -p : p; - pb = pc < 0 ? -pc : pc; - pc = (p + pc) < 0 ? -(p + pc) : p + pc; -#endif - p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; -#else /* PNG_SLOW_PAETH */ - p = a + b - c; - pa = abs(p - a); - pb = abs(p - b); - pc = abs(p - c); - - if (pa <= pb && pa <= pc) - p = a; - - else if (pb <= pc) - p = b; - - else - p = c; -#endif /* PNG_SLOW_PAETH */ - - v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); - - sum += (v < 128) ? v : 256 - v; - - if (sum > lmins) /* We are already worse, don't continue. */ - break; - } - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) - { - int j; - png_uint_32 sumhi, sumlo; - sumlo = sum & PNG_LOMASK; - sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; - - for (j = 0; j < num_p_filters; j++) - { - if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) - { - sumlo = (sumlo * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - - sumhi = (sumhi * png_ptr->filter_weights[j]) >> - PNG_WEIGHT_SHIFT; - } - } - - sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> - PNG_COST_SHIFT; - - sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> - PNG_COST_SHIFT; - - if (sumhi > PNG_HIMASK) - sum = PNG_MAXSUM; - - else - sum = (sumhi << PNG_HISHIFT) + sumlo; - } -#endif - - if (sum < mins) - { - best_row = png_ptr->paeth_row; - } - } -#endif /* PNG_WRITE_FILTER_SUPPORTED */ - - /* Do the actual writing of the filtered row data from the chosen filter. */ - png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1); - -#ifdef PNG_WRITE_FILTER_SUPPORTED -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - /* Save the type of filter we picked this time for future calculations */ - if (png_ptr->num_prev_filters > 0) - { - int j; - - for (j = 1; j < num_p_filters; j++) - { - png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1]; - } - - png_ptr->prev_filters[j] = best_row[0]; - } -#endif -#endif /* PNG_WRITE_FILTER_SUPPORTED */ -} - - -/* Do the actual writing of a previously filtered row. */ -static void -png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, - png_size_t full_row_length/*includes filter byte*/) -{ - png_debug(1, "in png_write_filtered_row"); - - png_debug1(2, "filter = %d", filtered_row[0]); - - png_compress_IDAT(png_ptr, filtered_row, full_row_length, Z_NO_FLUSH); - - /* Swap the current and previous rows */ - if (png_ptr->prev_row != NULL) - { - png_bytep tptr; - - tptr = png_ptr->prev_row; - png_ptr->prev_row = png_ptr->row_buf; - png_ptr->row_buf = tptr; - } - - /* Finish row - updates counters and flushes zlib if last row */ - png_write_finish_row(png_ptr); - -#ifdef PNG_WRITE_FLUSH_SUPPORTED - png_ptr->flush_rows++; - - if (png_ptr->flush_dist > 0 && - png_ptr->flush_rows >= png_ptr->flush_dist) - { - png_write_flush(png_ptr); - } -#endif -} -#endif /* PNG_WRITE_SUPPORTED */ diff --git a/source/modules/juce_graphics/images/juce_Image.cpp b/source/modules/juce_graphics/images/juce_Image.cpp deleted file mode 100644 index 1b206f5a2..000000000 --- a/source/modules/juce_graphics/images/juce_Image.cpp +++ /dev/null @@ -1,680 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -ImagePixelData::ImagePixelData (const Image::PixelFormat format, const int w, const int h) - : pixelFormat (format), width (w), height (h) -{ - jassert (format == Image::RGB || format == Image::ARGB || format == Image::SingleChannel); - jassert (w > 0 && h > 0); // It's illegal to create a zero-sized image! -} - -ImagePixelData::~ImagePixelData() -{ - listeners.call (&Listener::imageDataBeingDeleted, this); -} - -void ImagePixelData::sendDataChangeMessage() -{ - listeners.call (&Listener::imageDataChanged, this); -} - -int ImagePixelData::getSharedCount() const noexcept -{ - return getReferenceCount(); -} - -//============================================================================== -ImageType::ImageType() {} -ImageType::~ImageType() {} - -Image ImageType::convert (const Image& source) const -{ - if (source.isNull() || getTypeID() == (ScopedPointer (source.getPixelData()->createType())->getTypeID())) - return source; - - const Image::BitmapData src (source, Image::BitmapData::readOnly); - - Image newImage (create (src.pixelFormat, src.width, src.height, false)); - Image::BitmapData dest (newImage, Image::BitmapData::writeOnly); - - if (src.pixelStride == dest.pixelStride && src.pixelFormat == dest.pixelFormat) - { - for (int y = 0; y < dest.height; ++y) - memcpy (dest.getLinePointer (y), src.getLinePointer (y), (size_t) dest.lineStride); - } - else - { - for (int y = 0; y < dest.height; ++y) - for (int x = 0; x < dest.width; ++x) - dest.setPixelColour (x, y, src.getPixelColour (x, y)); - } - - return newImage; -} - -//============================================================================== -class SoftwarePixelData : public ImagePixelData -{ -public: - SoftwarePixelData (const Image::PixelFormat format_, const int w, const int h, const bool clearImage) - : ImagePixelData (format_, w, h), - pixelStride (format_ == Image::RGB ? 3 : ((format_ == Image::ARGB) ? 4 : 1)), - lineStride ((pixelStride * jmax (1, w) + 3) & ~3) - { - imageData.allocate ((size_t) (lineStride * jmax (1, h)), clearImage); - } - - LowLevelGraphicsContext* createLowLevelContext() override - { - sendDataChangeMessage(); - return new LowLevelGraphicsSoftwareRenderer (Image (this)); - } - - void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override - { - bitmap.data = imageData + x * pixelStride + y * lineStride; - bitmap.pixelFormat = pixelFormat; - bitmap.lineStride = lineStride; - bitmap.pixelStride = pixelStride; - - if (mode != Image::BitmapData::readOnly) - sendDataChangeMessage(); - } - - ImagePixelData::Ptr clone() override - { - SoftwarePixelData* s = new SoftwarePixelData (pixelFormat, width, height, false); - memcpy (s->imageData, imageData, (size_t) (lineStride * height)); - return s; - } - - ImageType* createType() const override { return new SoftwareImageType(); } - -private: - HeapBlock imageData; - const int pixelStride, lineStride; - - JUCE_LEAK_DETECTOR (SoftwarePixelData) -}; - -SoftwareImageType::SoftwareImageType() {} -SoftwareImageType::~SoftwareImageType() {} - -ImagePixelData::Ptr SoftwareImageType::create (Image::PixelFormat format, int width, int height, bool clearImage) const -{ - return new SoftwarePixelData (format, width, height, clearImage); -} - -int SoftwareImageType::getTypeID() const -{ - return 2; -} - -//============================================================================== -NativeImageType::NativeImageType() {} -NativeImageType::~NativeImageType() {} - -int NativeImageType::getTypeID() const -{ - return 1; -} - -#if JUCE_WINDOWS || JUCE_LINUX -ImagePixelData::Ptr NativeImageType::create (Image::PixelFormat format, int width, int height, bool clearImage) const -{ - return new SoftwarePixelData (format, width, height, clearImage); -} -#endif - -//============================================================================== -class SubsectionPixelData : public ImagePixelData -{ -public: - SubsectionPixelData (ImagePixelData* const im, const Rectangle& r) - : ImagePixelData (im->pixelFormat, r.getWidth(), r.getHeight()), - sourceImage (im), area (r) - { - } - - LowLevelGraphicsContext* createLowLevelContext() override - { - LowLevelGraphicsContext* g = sourceImage->createLowLevelContext(); - g->clipToRectangle (area); - g->setOrigin (area.getPosition()); - return g; - } - - void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override - { - sourceImage->initialiseBitmapData (bitmap, x + area.getX(), y + area.getY(), mode); - - if (mode != Image::BitmapData::readOnly) - sendDataChangeMessage(); - } - - ImagePixelData::Ptr clone() override - { - jassert (getReferenceCount() > 0); // (This method can't be used on an unowned pointer, as it will end up self-deleting) - const ScopedPointer type (createType()); - - Image newImage (type->create (pixelFormat, area.getWidth(), area.getHeight(), pixelFormat != Image::RGB)); - - { - Graphics g (newImage); - g.drawImageAt (Image (this), 0, 0); - } - - return newImage.getPixelData(); - } - - ImageType* createType() const override { return sourceImage->createType(); } - - /* as we always hold a reference to image, don't double count */ - int getSharedCount() const noexcept override { return getReferenceCount() + sourceImage->getSharedCount() - 1; } - -private: - friend class Image; - const ImagePixelData::Ptr sourceImage; - const Rectangle area; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SubsectionPixelData) -}; - -Image Image::getClippedImage (const Rectangle& area) const -{ - if (area.contains (getBounds())) - return *this; - - const Rectangle validArea (area.getIntersection (getBounds())); - return Image (validArea.isEmpty() ? nullptr : new SubsectionPixelData (image, validArea)); -} - - -//============================================================================== -Image::Image() noexcept -{ -} - -Image::Image (ImagePixelData* const instance) noexcept - : image (instance) -{ -} - -Image::Image (const PixelFormat format, int width, int height, bool clearImage) - : image (NativeImageType().create (format, width, height, clearImage)) -{ -} - -Image::Image (const PixelFormat format, int width, int height, bool clearImage, const ImageType& type) - : image (type.create (format, width, height, clearImage)) -{ -} - -Image::Image (const Image& other) noexcept - : image (other.image) -{ -} - -Image& Image::operator= (const Image& other) -{ - image = other.image; - return *this; -} - -Image::Image (Image&& other) noexcept - : image (static_cast (other.image)) -{ -} - -Image& Image::operator= (Image&& other) noexcept -{ - image = static_cast (other.image); - return *this; -} - -Image::~Image() -{ -} - -#if JUCE_ALLOW_STATIC_NULL_VARIABLES -const Image Image::null; -#endif - -int Image::getReferenceCount() const noexcept { return image == nullptr ? 0 : image->getSharedCount(); } -int Image::getWidth() const noexcept { return image == nullptr ? 0 : image->width; } -int Image::getHeight() const noexcept { return image == nullptr ? 0 : image->height; } -Rectangle Image::getBounds() const noexcept { return image == nullptr ? Rectangle() : Rectangle (image->width, image->height); } -Image::PixelFormat Image::getFormat() const noexcept { return image == nullptr ? UnknownFormat : image->pixelFormat; } -bool Image::isARGB() const noexcept { return getFormat() == ARGB; } -bool Image::isRGB() const noexcept { return getFormat() == RGB; } -bool Image::isSingleChannel() const noexcept { return getFormat() == SingleChannel; } -bool Image::hasAlphaChannel() const noexcept { return getFormat() != RGB; } - -LowLevelGraphicsContext* Image::createLowLevelContext() const -{ - return image == nullptr ? nullptr : image->createLowLevelContext(); -} - -void Image::duplicateIfShared() -{ - if (getReferenceCount() > 1) - image = image->clone(); -} - -Image Image::createCopy() const -{ - if (image != nullptr) - return Image (image->clone()); - - return Image(); -} - -Image Image::rescaled (const int newWidth, const int newHeight, const Graphics::ResamplingQuality quality) const -{ - if (image == nullptr || (image->width == newWidth && image->height == newHeight)) - return *this; - - const ScopedPointer type (image->createType()); - Image newImage (type->create (image->pixelFormat, newWidth, newHeight, hasAlphaChannel())); - - Graphics g (newImage); - g.setImageResamplingQuality (quality); - g.drawImageTransformed (*this, AffineTransform::scale (newWidth / (float) image->width, - newHeight / (float) image->height), false); - return newImage; -} - -Image Image::convertedToFormat (PixelFormat newFormat) const -{ - if (image == nullptr || newFormat == image->pixelFormat) - return *this; - - const int w = image->width, h = image->height; - - const ScopedPointer type (image->createType()); - Image newImage (type->create (newFormat, w, h, false)); - - if (newFormat == SingleChannel) - { - if (! hasAlphaChannel()) - { - newImage.clear (getBounds(), Colours::black); - } - else - { - const BitmapData destData (newImage, 0, 0, w, h, BitmapData::writeOnly); - const BitmapData srcData (*this, 0, 0, w, h); - - for (int y = 0; y < h; ++y) - { - const PixelARGB* const src = (const PixelARGB*) srcData.getLinePointer (y); - uint8* const dst = destData.getLinePointer (y); - - for (int x = 0; x < w; ++x) - dst[x] = src[x].getAlpha(); - } - } - } - else if (image->pixelFormat == SingleChannel && newFormat == Image::ARGB) - { - const BitmapData destData (newImage, 0, 0, w, h, BitmapData::writeOnly); - const BitmapData srcData (*this, 0, 0, w, h); - - for (int y = 0; y < h; ++y) - { - const PixelAlpha* const src = (const PixelAlpha*) srcData.getLinePointer (y); - PixelARGB* const dst = (PixelARGB*) destData.getLinePointer (y); - - for (int x = 0; x < w; ++x) - dst[x].set (src[x]); - } - } - else - { - if (hasAlphaChannel()) - newImage.clear (getBounds()); - - Graphics g (newImage); - g.drawImageAt (*this, 0, 0); - } - - return newImage; -} - -NamedValueSet* Image::getProperties() const -{ - return image == nullptr ? nullptr : &(image->userData); -} - -//============================================================================== -Image::BitmapData::BitmapData (Image& im, const int x, const int y, const int w, const int h, BitmapData::ReadWriteMode mode) - : width (w), height (h) -{ - // The BitmapData class must be given a valid image, and a valid rectangle within it! - jassert (im.image != nullptr); - jassert (x >= 0 && y >= 0 && w > 0 && h > 0 && x + w <= im.getWidth() && y + h <= im.getHeight()); - - im.image->initialiseBitmapData (*this, x, y, mode); - jassert (data != nullptr && pixelStride > 0 && lineStride != 0); -} - -Image::BitmapData::BitmapData (const Image& im, const int x, const int y, const int w, const int h) - : width (w), height (h) -{ - // The BitmapData class must be given a valid image, and a valid rectangle within it! - jassert (im.image != nullptr); - jassert (x >= 0 && y >= 0 && w > 0 && h > 0 && x + w <= im.getWidth() && y + h <= im.getHeight()); - - im.image->initialiseBitmapData (*this, x, y, readOnly); - jassert (data != nullptr && pixelStride > 0 && lineStride != 0); -} - -Image::BitmapData::BitmapData (const Image& im, BitmapData::ReadWriteMode mode) - : width (im.getWidth()), - height (im.getHeight()) -{ - // The BitmapData class must be given a valid image! - jassert (im.image != nullptr); - - im.image->initialiseBitmapData (*this, 0, 0, mode); - jassert (data != nullptr && pixelStride > 0 && lineStride != 0); -} - -Image::BitmapData::~BitmapData() -{ -} - -Colour Image::BitmapData::getPixelColour (const int x, const int y) const noexcept -{ - jassert (isPositiveAndBelow (x, width) && isPositiveAndBelow (y, height)); - - const uint8* const pixel = getPixelPointer (x, y); - - switch (pixelFormat) - { - case Image::ARGB: return Colour ( ((const PixelARGB*) pixel)->getUnpremultiplied()); - case Image::RGB: return Colour (*((const PixelRGB*) pixel)); - case Image::SingleChannel: return Colour (*((const PixelAlpha*) pixel)); - default: jassertfalse; break; - } - - return Colour(); -} - -void Image::BitmapData::setPixelColour (const int x, const int y, Colour colour) const noexcept -{ - jassert (isPositiveAndBelow (x, width) && isPositiveAndBelow (y, height)); - - uint8* const pixel = getPixelPointer (x, y); - const PixelARGB col (colour.getPixelARGB()); - - switch (pixelFormat) - { - case Image::ARGB: ((PixelARGB*) pixel)->set (col); break; - case Image::RGB: ((PixelRGB*) pixel)->set (col); break; - case Image::SingleChannel: ((PixelAlpha*) pixel)->set (col); break; - default: jassertfalse; break; - } -} - -//============================================================================== -void Image::clear (const Rectangle& area, Colour colourToClearTo) -{ - if (image != nullptr) - { - const ScopedPointer g (image->createLowLevelContext()); - g->setFill (colourToClearTo); - g->fillRect (area, true); - } -} - -//============================================================================== -Colour Image::getPixelAt (const int x, const int y) const -{ - if (isPositiveAndBelow (x, getWidth()) && isPositiveAndBelow (y, getHeight())) - { - const BitmapData srcData (*this, x, y, 1, 1); - return srcData.getPixelColour (0, 0); - } - - return Colour(); -} - -void Image::setPixelAt (const int x, const int y, Colour colour) -{ - if (isPositiveAndBelow (x, getWidth()) && isPositiveAndBelow (y, getHeight())) - { - const BitmapData destData (*this, x, y, 1, 1, BitmapData::writeOnly); - destData.setPixelColour (0, 0, colour); - } -} - -void Image::multiplyAlphaAt (const int x, const int y, const float multiplier) -{ - if (isPositiveAndBelow (x, getWidth()) && isPositiveAndBelow (y, getHeight()) - && hasAlphaChannel()) - { - const BitmapData destData (*this, x, y, 1, 1, BitmapData::readWrite); - - if (isARGB()) - ((PixelARGB*) destData.data)->multiplyAlpha (multiplier); - else - *(destData.data) = (uint8) (*(destData.data) * multiplier); - } -} - -template -struct PixelIterator -{ - template - static void iterate (const Image::BitmapData& data, const PixelOperation& pixelOp) - { - for (int y = 0; y < data.height; ++y) - { - uint8* p = data.getLinePointer (y); - - for (int x = 0; x < data.width; ++x) - { - pixelOp (*(PixelType*) p); - p += data.pixelStride; - } - } - } -}; - -template -static void performPixelOp (const Image::BitmapData& data, const PixelOperation& pixelOp) -{ - switch (data.pixelFormat) - { - case Image::ARGB: PixelIterator ::iterate (data, pixelOp); break; - case Image::RGB: PixelIterator ::iterate (data, pixelOp); break; - case Image::SingleChannel: PixelIterator::iterate (data, pixelOp); break; - default: jassertfalse; break; - } -} - -struct AlphaMultiplyOp -{ - float alpha; - - template - void operator() (PixelType& pixel) const - { - pixel.multiplyAlpha (alpha); - } -}; - -void Image::multiplyAllAlphas (const float amountToMultiplyBy) -{ - jassert (hasAlphaChannel()); - - const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), BitmapData::readWrite); - performPixelOp (destData, AlphaMultiplyOp { amountToMultiplyBy }); -} - -struct DesaturateOp -{ - template - void operator() (PixelType& pixel) const - { - pixel.desaturate(); - } -}; - -void Image::desaturate() -{ - if (isARGB() || isRGB()) - { - const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), BitmapData::readWrite); - performPixelOp (destData, DesaturateOp()); - } -} - -void Image::createSolidAreaMask (RectangleList& result, const float alphaThreshold) const -{ - if (hasAlphaChannel()) - { - const uint8 threshold = (uint8) jlimit (0, 255, roundToInt (alphaThreshold * 255.0f)); - SparseSet pixelsOnRow; - - const BitmapData srcData (*this, 0, 0, getWidth(), getHeight()); - - for (int y = 0; y < srcData.height; ++y) - { - pixelsOnRow.clear(); - const uint8* lineData = srcData.getLinePointer (y); - - if (isARGB()) - { - for (int x = 0; x < srcData.width; ++x) - { - if (((const PixelARGB*) lineData)->getAlpha() >= threshold) - pixelsOnRow.addRange (Range (x, x + 1)); - - lineData += srcData.pixelStride; - } - } - else - { - for (int x = 0; x < srcData.width; ++x) - { - if (*lineData >= threshold) - pixelsOnRow.addRange (Range (x, x + 1)); - - lineData += srcData.pixelStride; - } - } - - for (int i = 0; i < pixelsOnRow.getNumRanges(); ++i) - { - const Range range (pixelsOnRow.getRange (i)); - result.add (Rectangle (range.getStart(), y, range.getLength(), 1)); - } - - result.consolidate(); - } - } - else - { - result.add (0, 0, getWidth(), getHeight()); - } -} - -void Image::moveImageSection (int dx, int dy, - int sx, int sy, - int w, int h) -{ - if (dx < 0) - { - w += dx; - sx -= dx; - dx = 0; - } - - if (dy < 0) - { - h += dy; - sy -= dy; - dy = 0; - } - - if (sx < 0) - { - w += sx; - dx -= sx; - sx = 0; - } - - if (sy < 0) - { - h += sy; - dy -= sy; - sy = 0; - } - - const int minX = jmin (dx, sx); - const int minY = jmin (dy, sy); - - w = jmin (w, getWidth() - jmax (sx, dx)); - h = jmin (h, getHeight() - jmax (sy, dy)); - - if (w > 0 && h > 0) - { - const int maxX = jmax (dx, sx) + w; - const int maxY = jmax (dy, sy) + h; - - const BitmapData destData (*this, minX, minY, maxX - minX, maxY - minY, BitmapData::readWrite); - - uint8* dst = destData.getPixelPointer (dx - minX, dy - minY); - const uint8* src = destData.getPixelPointer (sx - minX, sy - minY); - - const size_t lineSize = (size_t) (destData.pixelStride * w); - - if (dy > sy) - { - while (--h >= 0) - { - const int offset = h * destData.lineStride; - memmove (dst + offset, src + offset, lineSize); - } - } - else if (dst != src) - { - while (--h >= 0) - { - memmove (dst, src, lineSize); - dst += destData.lineStride; - src += destData.lineStride; - } - } - } -} - -} // namespace juce diff --git a/source/modules/juce_graphics/images/juce_Image.h b/source/modules/juce_graphics/images/juce_Image.h deleted file mode 100644 index eefaa98d1..000000000 --- a/source/modules/juce_graphics/images/juce_Image.h +++ /dev/null @@ -1,547 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -class ImageType; -class ImagePixelData; - - -//============================================================================== -/** - Holds a fixed-size bitmap. - - The image is stored in either 24-bit RGB or 32-bit premultiplied-ARGB format. - - To draw into an image, create a Graphics object for it. - e.g. @code - - // create a transparent 500x500 image.. - Image myImage (Image::RGB, 500, 500, true); - - Graphics g (myImage); - g.setColour (Colours::red); - g.fillEllipse (20, 20, 300, 200); // draws a red ellipse in our image. - @endcode - - Other useful ways to create an image are with the ImageCache class, or the - ImageFileFormat, which provides a way to load common image files. - - @see Graphics, ImageFileFormat, ImageCache, ImageConvolutionKernel -*/ -class JUCE_API Image -{ -public: - //============================================================================== - /** - */ - enum PixelFormat - { - UnknownFormat, - RGB, /**<< each pixel is a 3-byte packed RGB colour value. For byte order, see the PixelRGB class. */ - ARGB, /**<< each pixel is a 4-byte ARGB premultiplied colour value. For byte order, see the PixelARGB class. */ - SingleChannel /**<< each pixel is a 1-byte alpha channel value. */ - }; - - //============================================================================== - /** Creates a null image. */ - Image() noexcept; - - /** Creates an image with a specified size and format. - - The image's internal type will be of the NativeImageType class - to specify a - different type, use the other constructor, which takes an ImageType to use. - - @param format the preferred pixel format. Note that this is only a *hint* which - is passed to the ImageType class - different ImageTypes may not support - all formats, so may substitute e.g. ARGB for RGB. - @param imageWidth the desired width of the image, in pixels - this value must be - greater than zero (otherwise a width of 1 will be used) - @param imageHeight the desired width of the image, in pixels - this value must be - greater than zero (otherwise a height of 1 will be used) - @param clearImage if true, the image will initially be cleared to black (if it's RGB) - or transparent black (if it's ARGB). If false, the image may contain - junk initially, so you need to make sure you overwrite it thoroughly. - */ - Image (PixelFormat format, int imageWidth, int imageHeight, bool clearImage); - - /** Creates an image with a specified size and format. - - @param format the preferred pixel format. Note that this is only a *hint* which - is passed to the ImageType class - different ImageTypes may not support - all formats, so may substitute e.g. ARGB for RGB. - @param imageWidth the desired width of the image, in pixels - this value must be - greater than zero (otherwise a width of 1 will be used) - @param imageHeight the desired width of the image, in pixels - this value must be - greater than zero (otherwise a height of 1 will be used) - @param clearImage if true, the image will initially be cleared to black (if it's RGB) - or transparent black (if it's ARGB). If false, the image may contain - junk initially, so you need to make sure you overwrite it thoroughly. - @param type the type of image - this lets you specify the internal format that will - be used to allocate and manage the image data. - */ - Image (PixelFormat format, int imageWidth, int imageHeight, bool clearImage, const ImageType& type); - - /** Creates a shared reference to another image. - - This won't create a duplicate of the image - when Image objects are copied, they simply - point to the same shared image data. To make sure that an Image object has its own unique, - unshared internal data, call duplicateIfShared(). - */ - Image (const Image&) noexcept; - - /** Makes this image refer to the same underlying image as another object. - - This won't create a duplicate of the image - when Image objects are copied, they simply - point to the same shared image data. To make sure that an Image object has its own unique, - unshared internal data, call duplicateIfShared(). - */ - Image& operator= (const Image&); - - /** Move constructor */ - Image (Image&&) noexcept; - - /** Move assignment operator */ - Image& operator= (Image&&) noexcept; - - /** Destructor. */ - ~Image(); - - /** Returns true if the two images are referring to the same internal, shared image. */ - bool operator== (const Image& other) const noexcept { return image == other.image; } - - /** Returns true if the two images are not referring to the same internal, shared image. */ - bool operator!= (const Image& other) const noexcept { return image != other.image; } - - /** Returns true if this image isn't null. - If you create an Image with the default constructor, it has no size or content, and is null - until you reassign it to an Image which contains some actual data. - The isNull() method is the opposite of isValid(). - @see isNull - */ - inline bool isValid() const noexcept { return image != nullptr; } - - /** Returns true if this image is not valid. - If you create an Image with the default constructor, it has no size or content, and is null - until you reassign it to an Image which contains some actual data. - The isNull() method is the opposite of isValid(). - @see isValid - */ - inline bool isNull() const noexcept { return image == nullptr; } - - #if JUCE_ALLOW_STATIC_NULL_VARIABLES - /** A null Image object that can be used when you need to return an invalid image. - This object is the equivalient to an Image created with the default constructor, and - you should always prefer to use Image() or {} when you need an empty image object. - */ - static const Image null; - #endif - - //============================================================================== - /** Returns the image's width (in pixels). */ - int getWidth() const noexcept; - - /** Returns the image's height (in pixels). */ - int getHeight() const noexcept; - - /** Returns a rectangle with the same size as this image. - The rectangle's origin is always (0, 0). - */ - Rectangle getBounds() const noexcept; - - /** Returns the image's pixel format. */ - PixelFormat getFormat() const noexcept; - - /** True if the image's format is ARGB. */ - bool isARGB() const noexcept; - - /** True if the image's format is RGB. */ - bool isRGB() const noexcept; - - /** True if the image's format is a single-channel alpha map. */ - bool isSingleChannel() const noexcept; - - /** True if the image contains an alpha-channel. */ - bool hasAlphaChannel() const noexcept; - - //============================================================================== - /** Clears a section of the image with a given colour. - - This won't do any alpha-blending - it just sets all pixels in the image to - the given colour (which may be non-opaque if the image has an alpha channel). - */ - void clear (const Rectangle& area, Colour colourToClearTo = Colour (0x00000000)); - - /** Returns a rescaled version of this image. - - A new image is returned which is a copy of this one, rescaled to the given size. - - Note that if the new size is identical to the existing image, this will just return - a reference to the original image, and won't actually create a duplicate. - */ - Image rescaled (int newWidth, int newHeight, - Graphics::ResamplingQuality quality = Graphics::mediumResamplingQuality) const; - - /** Creates a copy of this image. - Note that it's usually more efficient to use duplicateIfShared(), because it may not be necessary - to copy an image if nothing else is using it. - @see getReferenceCount - */ - Image createCopy() const; - - /** Returns a version of this image with a different image format. - - A new image is returned which has been converted to the specified format. - - Note that if the new format is no different to the current one, this will just return - a reference to the original image, and won't actually create a copy. - */ - Image convertedToFormat (PixelFormat newFormat) const; - - /** Makes sure that no other Image objects share the same underlying data as this one. - - If no other Image objects refer to the same shared data as this one, this method has no - effect. But if there are other references to the data, this will create a new copy of - the data internally. - - Call this if you want to draw onto the image, but want to make sure that this doesn't - affect any other code that may be sharing the same data. - - @see getReferenceCount - */ - void duplicateIfShared(); - - /** Returns an image which refers to a subsection of this image. - - This will not make a copy of the original - the new image will keep a reference to it, so that - if the original image is changed, the contents of the subsection will also change. Likewise if you - draw into the subimage, you'll also be drawing onto that area of the original image. Note that if - you use operator= to make the original Image object refer to something else, the subsection image - won't pick up this change, it'll remain pointing at the original. - - The area passed-in will be clipped to the bounds of this image, so this may return a smaller - image than the area you asked for, or even a null image if the area was out-of-bounds. - */ - Image getClippedImage (const Rectangle& area) const; - - //============================================================================== - /** Returns the colour of one of the pixels in the image. - - If the coordinates given are beyond the image's boundaries, this will - return Colours::transparentBlack. - - @see setPixelAt, Image::BitmapData::getPixelColour - */ - Colour getPixelAt (int x, int y) const; - - /** Sets the colour of one of the image's pixels. - - If the coordinates are beyond the image's boundaries, then nothing will happen. - - Note that this won't do any alpha-blending, it'll just replace the existing pixel - with the given one. The colour's opacity will be ignored if this image doesn't have - an alpha-channel. - - @see getPixelAt, Image::BitmapData::setPixelColour - */ - void setPixelAt (int x, int y, Colour colour); - - /** Changes the opacity of a pixel. - - This only has an effect if the image has an alpha channel and if the - given coordinates are inside the image's boundary. - - The multiplier must be in the range 0 to 1.0, and the current alpha - at the given coordinates will be multiplied by this value. - - @see setPixelAt - */ - void multiplyAlphaAt (int x, int y, float multiplier); - - /** Changes the overall opacity of the image. - - This will multiply the alpha value of each pixel in the image by the given - amount (limiting the resulting alpha values between 0 and 255). This allows - you to make an image more or less transparent. - - If the image doesn't have an alpha channel, this won't have any effect. - */ - void multiplyAllAlphas (float amountToMultiplyBy); - - /** Changes all the colours to be shades of grey, based on their current luminosity. - */ - void desaturate(); - - //============================================================================== - /** Retrieves a section of an image as raw pixel data, so it can be read or written to. - - You should only use this class as a last resort - messing about with the internals of - an image is only recommended for people who really know what they're doing! - - A BitmapData object should be used as a temporary, stack-based object. Don't keep one - hanging around while the image is being used elsewhere. - - Depending on the way the image class is implemented, this may create a temporary buffer - which is copied back to the image when the object is deleted, or it may just get a pointer - directly into the image's raw data. - - You can use the stride and data values in this class directly, but don't alter them! - The actual format of the pixel data depends on the image's format - see Image::getFormat(), - and the PixelRGB, PixelARGB and PixelAlpha classes for more info. - */ - class JUCE_API BitmapData - { - public: - enum ReadWriteMode - { - readOnly, - writeOnly, - readWrite - }; - - BitmapData (Image& image, int x, int y, int w, int h, ReadWriteMode mode); - BitmapData (const Image& image, int x, int y, int w, int h); - BitmapData (const Image& image, ReadWriteMode mode); - ~BitmapData(); - - /** Returns a pointer to the start of a line in the image. - The coordinate you provide here isn't checked, so it's the caller's responsibility to make - sure it's not out-of-range. - */ - inline uint8* getLinePointer (int y) const noexcept { return data + y * lineStride; } - - /** Returns a pointer to a pixel in the image. - The coordinates you give here are not checked, so it's the caller's responsibility to make sure they're - not out-of-range. - */ - inline uint8* getPixelPointer (int x, int y) const noexcept { return data + y * lineStride + x * pixelStride; } - - /** Returns the colour of a given pixel. - For performance reasons, this won't do any bounds-checking on the coordinates, so it's the caller's - repsonsibility to make sure they're within the image's size. - */ - Colour getPixelColour (int x, int y) const noexcept; - - /** Sets the colour of a given pixel. - For performance reasons, this won't do any bounds-checking on the coordinates, so it's the caller's - repsonsibility to make sure they're within the image's size. - */ - void setPixelColour (int x, int y, Colour colour) const noexcept; - - /** Returns the size of the bitmap. */ - Rectangle getBounds() const noexcept { return Rectangle (width, height); } - - uint8* data; /**< The raw pixel data, packed according to the image's pixel format. */ - PixelFormat pixelFormat; /**< The format of the data. */ - int lineStride; /**< The number of bytes between each line. */ - int pixelStride; /**< The number of bytes between each pixel. */ - int width, height; - - //============================================================================== - /** Used internally by custom image types to manage pixel data lifetime. */ - class BitmapDataReleaser - { - protected: - BitmapDataReleaser() {} - public: - virtual ~BitmapDataReleaser() {} - }; - - ScopedPointer dataReleaser; - - private: - JUCE_DECLARE_NON_COPYABLE (BitmapData) - }; - - //============================================================================== - /** Copies a section of the image to somewhere else within itself. */ - void moveImageSection (int destX, int destY, - int sourceX, int sourceY, - int width, int height); - - /** Creates a RectangleList containing rectangles for all non-transparent pixels - of the image. - - @param result the list that will have the area added to it - @param alphaThreshold for a semi-transparent image, any pixels whose alpha is - above this level will be considered opaque - */ - void createSolidAreaMask (RectangleList& result, float alphaThreshold) const; - - //============================================================================== - /** Returns a NamedValueSet that is attached to the image and which can be used for - associating custom values with it. - - If this is a null image, this will return a null pointer. - */ - NamedValueSet* getProperties() const; - - //============================================================================== - /** Creates a context suitable for drawing onto this image. - Don't call this method directly! It's used internally by the Graphics class. - */ - LowLevelGraphicsContext* createLowLevelContext() const; - - /** Returns the number of Image objects which are currently referring to the same internal - shared image data. - - @see duplicateIfShared - */ - int getReferenceCount() const noexcept; - - //============================================================================== - /** @internal */ - ImagePixelData* getPixelData() const noexcept { return image; } - - /** @internal */ - explicit Image (ImagePixelData*) noexcept; - -private: - //============================================================================== - ReferenceCountedObjectPtr image; - - JUCE_LEAK_DETECTOR (Image) -}; - - -//============================================================================== -/** - This is a base class for holding image data in implementation-specific ways. - - You may never need to use this class directly - it's used internally - by the Image class to store the actual image data. To access pixel data directly, - you should use Image::BitmapData rather than this class. - - ImagePixelData objects are created indirectly, by subclasses of ImageType. - @see Image, ImageType -*/ -class JUCE_API ImagePixelData : public ReferenceCountedObject -{ -public: - ImagePixelData (Image::PixelFormat, int width, int height); - ~ImagePixelData(); - - typedef ReferenceCountedObjectPtr Ptr; - - /** Creates a context that will draw into this image. */ - virtual LowLevelGraphicsContext* createLowLevelContext() = 0; - /** Creates a copy of this image. */ - virtual Ptr clone() = 0; - /** Creates an instance of the type of this image. */ - virtual ImageType* createType() const = 0; - /** Initialises a BitmapData object. */ - virtual void initialiseBitmapData (Image::BitmapData&, int x, int y, Image::BitmapData::ReadWriteMode) = 0; - /** Returns the number of Image objects which are currently referring to the same internal - shared image data. This is different to the reference count as an instance of ImagePixelData - can internally depend on another ImagePixelData via it's member variables. */ - virtual int getSharedCount() const noexcept; - - - /** The pixel format of the image data. */ - const Image::PixelFormat pixelFormat; - const int width, height; - - /** User-defined settings that are attached to this image. - @see Image::getProperties(). - */ - NamedValueSet userData; - - //============================================================================== - struct Listener - { - virtual ~Listener() {} - - virtual void imageDataChanged (ImagePixelData*) = 0; - virtual void imageDataBeingDeleted (ImagePixelData*) = 0; - }; - - ListenerList listeners; - - void sendDataChangeMessage(); - -private: - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ImagePixelData) -}; - -//============================================================================== -/** - This base class is for handlers that control a type of image manipulation format, - e.g. an in-memory bitmap, an OpenGL image, CoreGraphics image, etc. - - @see SoftwareImageType, NativeImageType, OpenGLImageType -*/ -class JUCE_API ImageType -{ -public: - ImageType(); - virtual ~ImageType(); - - /** Creates a new image of this type, and the specified parameters. */ - virtual ImagePixelData::Ptr create (Image::PixelFormat, int width, int height, bool shouldClearImage) const = 0; - - /** Must return a unique number to identify this type. */ - virtual int getTypeID() const = 0; - - /** Returns an image which is a copy of the source image, but using this type of storage mechanism. - For example, to make sure that an image is stored in-memory, you could use: - @code myImage = SoftwareImageType().convert (myImage); @endcode - */ - virtual Image convert (const Image& source) const; -}; - -//============================================================================== -/** - An image storage type which holds the pixels in-memory as a simple block of values. - @see ImageType, NativeImageType -*/ -class JUCE_API SoftwareImageType : public ImageType -{ -public: - SoftwareImageType(); - ~SoftwareImageType(); - - ImagePixelData::Ptr create (Image::PixelFormat, int width, int height, bool clearImage) const override; - int getTypeID() const override; -}; - -//============================================================================== -/** - An image storage type which holds the pixels using whatever is the default storage - format on the current platform. - @see ImageType, SoftwareImageType -*/ -class JUCE_API NativeImageType : public ImageType -{ -public: - NativeImageType(); - ~NativeImageType(); - - ImagePixelData::Ptr create (Image::PixelFormat, int width, int height, bool clearImage) const override; - int getTypeID() const override; -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/images/juce_ImageCache.cpp b/source/modules/juce_graphics/images/juce_ImageCache.cpp deleted file mode 100644 index e565f5e5e..000000000 --- a/source/modules/juce_graphics/images/juce_ImageCache.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -struct ImageCache::Pimpl : private Timer, - private DeletedAtShutdown -{ - Pimpl() {} - ~Pimpl() { clearSingletonInstance(); } - - juce_DeclareSingleton_SingleThreaded_Minimal (ImageCache::Pimpl) - - Image getFromHashCode (const int64 hashCode) noexcept - { - const ScopedLock sl (lock); - - for (auto& item : images) - { - if (item.hashCode == hashCode) - { - item.lastUseTime = Time::getApproximateMillisecondCounter(); - return item.image; - } - } - - return {}; - } - - void addImageToCache (const Image& image, const int64 hashCode) - { - if (image.isValid()) - { - if (! isTimerRunning()) - startTimer (2000); - - const ScopedLock sl (lock); - images.add ({ image, hashCode, Time::getApproximateMillisecondCounter() }); - } - } - - void timerCallback() override - { - auto now = Time::getApproximateMillisecondCounter(); - - const ScopedLock sl (lock); - - for (int i = images.size(); --i >= 0;) - { - auto& item = images.getReference(i); - - if (item.image.getReferenceCount() <= 1) - { - if (now > item.lastUseTime + cacheTimeout || now < item.lastUseTime - 1000) - images.remove (i); - } - else - { - item.lastUseTime = now; // multiply-referenced, so this image is still in use. - } - } - - if (images.isEmpty()) - stopTimer(); - } - - void releaseUnusedImages() - { - const ScopedLock sl (lock); - - for (int i = images.size(); --i >= 0;) - if (images.getReference(i).image.getReferenceCount() <= 1) - images.remove (i); - } - - struct Item - { - Image image; - int64 hashCode; - uint32 lastUseTime; - }; - - Array images; - CriticalSection lock; - unsigned int cacheTimeout = 5000; - - JUCE_DECLARE_NON_COPYABLE (Pimpl) -}; - -juce_ImplementSingleton_SingleThreaded (ImageCache::Pimpl) - - -//============================================================================== -Image ImageCache::getFromHashCode (const int64 hashCode) -{ - if (Pimpl::getInstanceWithoutCreating() != nullptr) - return Pimpl::getInstanceWithoutCreating()->getFromHashCode (hashCode); - - return {}; -} - -void ImageCache::addImageToCache (const Image& image, const int64 hashCode) -{ - Pimpl::getInstance()->addImageToCache (image, hashCode); -} - -Image ImageCache::getFromFile (const File& file) -{ - auto hashCode = file.hashCode64(); - auto image = getFromHashCode (hashCode); - - if (image.isNull()) - { - image = ImageFileFormat::loadFrom (file); - addImageToCache (image, hashCode); - } - - return image; -} - -Image ImageCache::getFromMemory (const void* imageData, const int dataSize) -{ - auto hashCode = (int64) (pointer_sized_int) imageData; - auto image = getFromHashCode (hashCode); - - if (image.isNull()) - { - image = ImageFileFormat::loadFrom (imageData, (size_t) dataSize); - addImageToCache (image, hashCode); - } - - return image; -} - -void ImageCache::setCacheTimeout (const int millisecs) -{ - jassert (millisecs >= 0); - Pimpl::getInstance()->cacheTimeout = (unsigned int) millisecs; -} - -void ImageCache::releaseUnusedImages() -{ - Pimpl::getInstance()->releaseUnusedImages(); -} - -} // namespace juce diff --git a/source/modules/juce_graphics/images/juce_ImageCache.h b/source/modules/juce_graphics/images/juce_ImageCache.h deleted file mode 100644 index 753ce750d..000000000 --- a/source/modules/juce_graphics/images/juce_ImageCache.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A global cache of images that have been loaded from files or memory. - - If you're loading an image and may need to use the image in more than one - place, this is used to allow the same image to be shared rather than loading - multiple copies into memory. - - Another advantage is that after images are released, they will be kept in - memory for a few seconds before it is actually deleted, so if you're repeatedly - loading/deleting the same image, it'll reduce the chances of having to reload it - each time. - - @see Image, ImageFileFormat -*/ -class JUCE_API ImageCache -{ -public: - //============================================================================== - /** Loads an image from a file, (or just returns the image if it's already cached). - - If the cache already contains an image that was loaded from this file, - that image will be returned. Otherwise, this method will try to load the - file, add it to the cache, and return it. - - Remember that the image returned is shared, so drawing into it might - affect other things that are using it! If you want to draw on it, first - call Image::duplicateIfShared() - - @param file the file to try to load - @returns the image, or null if it there was an error loading it - @see getFromMemory, getFromCache, ImageFileFormat::loadFrom - */ - static Image getFromFile (const File& file); - - /** Loads an image from an in-memory image file, (or just returns the image if it's already cached). - - If the cache already contains an image that was loaded from this block of memory, - that image will be returned. Otherwise, this method will try to load the - file, add it to the cache, and return it. - - Remember that the image returned is shared, so drawing into it might - affect other things that are using it! If you want to draw on it, first - call Image::duplicateIfShared() - - @param imageData the block of memory containing the image data - @param dataSize the data size in bytes - @returns the image, or an invalid image if it there was an error loading it - @see getFromMemory, getFromCache, ImageFileFormat::loadFrom - */ - static Image getFromMemory (const void* imageData, int dataSize); - - //============================================================================== - /** Checks the cache for an image with a particular hashcode. - - If there's an image in the cache with this hashcode, it will be returned, - otherwise it will return an invalid image. - - @param hashCode the hash code that was associated with the image by addImageToCache() - @see addImageToCache - */ - static Image getFromHashCode (int64 hashCode); - - /** Adds an image to the cache with a user-defined hash-code. - - The image passed-in will be referenced (not copied) by the cache, so it's probably - a good idea not to draw into it after adding it, otherwise this will affect all - instances of it that may be in use. - - @param image the image to add - @param hashCode the hash-code to associate with it - @see getFromHashCode - */ - static void addImageToCache (const Image& image, int64 hashCode); - - /** Changes the amount of time before an unused image will be removed from the cache. - By default this is about 5 seconds. - */ - static void setCacheTimeout (int millisecs); - - /** Releases any images in the cache that aren't being referenced by active - Image objects. - */ - static void releaseUnusedImages(); - -private: - //============================================================================== - struct Pimpl; - friend struct Pimpl; - - ImageCache(); - ~ImageCache(); - - JUCE_DECLARE_NON_COPYABLE (ImageCache) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/images/juce_ImageConvolutionKernel.cpp b/source/modules/juce_graphics/images/juce_ImageConvolutionKernel.cpp deleted file mode 100644 index e7408c2f0..000000000 --- a/source/modules/juce_graphics/images/juce_ImageConvolutionKernel.cpp +++ /dev/null @@ -1,297 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -ImageConvolutionKernel::ImageConvolutionKernel (const int size_) - : values ((size_t) (size_ * size_)), - size (size_) -{ - clear(); -} - -ImageConvolutionKernel::~ImageConvolutionKernel() -{ -} - -//============================================================================== -float ImageConvolutionKernel::getKernelValue (const int x, const int y) const noexcept -{ - if (isPositiveAndBelow (x, size) && isPositiveAndBelow (y, size)) - return values [x + y * size]; - - jassertfalse; - return 0; -} - -void ImageConvolutionKernel::setKernelValue (const int x, const int y, const float value) noexcept -{ - if (isPositiveAndBelow (x, size) && isPositiveAndBelow (y, size)) - { - values [x + y * size] = value; - } - else - { - jassertfalse; - } -} - -void ImageConvolutionKernel::clear() -{ - for (int i = size * size; --i >= 0;) - values[i] = 0; -} - -void ImageConvolutionKernel::setOverallSum (const float desiredTotalSum) -{ - double currentTotal = 0.0; - - for (int i = size * size; --i >= 0;) - currentTotal += values[i]; - - rescaleAllValues ((float) (desiredTotalSum / currentTotal)); -} - -void ImageConvolutionKernel::rescaleAllValues (const float multiplier) -{ - for (int i = size * size; --i >= 0;) - values[i] *= multiplier; -} - -//============================================================================== -void ImageConvolutionKernel::createGaussianBlur (const float radius) -{ - const double radiusFactor = -1.0 / (radius * radius * 2); - const int centre = size >> 1; - - for (int y = size; --y >= 0;) - { - for (int x = size; --x >= 0;) - { - const int cx = x - centre; - const int cy = y - centre; - - values [x + y * size] = (float) exp (radiusFactor * (cx * cx + cy * cy)); - } - } - - setOverallSum (1.0f); -} - -//============================================================================== -void ImageConvolutionKernel::applyToImage (Image& destImage, - const Image& sourceImage, - const Rectangle& destinationArea) const -{ - if (sourceImage == destImage) - { - destImage.duplicateIfShared(); - } - else - { - if (sourceImage.getWidth() != destImage.getWidth() - || sourceImage.getHeight() != destImage.getHeight() - || sourceImage.getFormat() != destImage.getFormat()) - { - jassertfalse; - return; - } - } - - const Rectangle area (destinationArea.getIntersection (destImage.getBounds())); - - if (area.isEmpty()) - return; - - const int right = area.getRight(); - const int bottom = area.getBottom(); - - const Image::BitmapData destData (destImage, area.getX(), area.getY(), area.getWidth(), area.getHeight(), - Image::BitmapData::writeOnly); - uint8* line = destData.data; - - const Image::BitmapData srcData (sourceImage, Image::BitmapData::readOnly); - - if (destData.pixelStride == 4) - { - for (int y = area.getY(); y < bottom; ++y) - { - uint8* dest = line; - line += destData.lineStride; - - for (int x = area.getX(); x < right; ++x) - { - float c1 = 0; - float c2 = 0; - float c3 = 0; - float c4 = 0; - - for (int yy = 0; yy < size; ++yy) - { - const int sy = y + yy - (size >> 1); - - if (sy >= srcData.height) - break; - - if (sy >= 0) - { - int sx = x - (size >> 1); - const uint8* src = srcData.getPixelPointer (sx, sy); - - for (int xx = 0; xx < size; ++xx) - { - if (sx >= srcData.width) - break; - - if (sx >= 0) - { - const float kernelMult = values [xx + yy * size]; - c1 += kernelMult * *src++; - c2 += kernelMult * *src++; - c3 += kernelMult * *src++; - c4 += kernelMult * *src++; - } - else - { - src += 4; - } - - ++sx; - } - } - } - - *dest++ = (uint8) jmin (0xff, roundToInt (c1)); - *dest++ = (uint8) jmin (0xff, roundToInt (c2)); - *dest++ = (uint8) jmin (0xff, roundToInt (c3)); - *dest++ = (uint8) jmin (0xff, roundToInt (c4)); - } - } - } - else if (destData.pixelStride == 3) - { - for (int y = area.getY(); y < bottom; ++y) - { - uint8* dest = line; - line += destData.lineStride; - - for (int x = area.getX(); x < right; ++x) - { - float c1 = 0; - float c2 = 0; - float c3 = 0; - - for (int yy = 0; yy < size; ++yy) - { - const int sy = y + yy - (size >> 1); - - if (sy >= srcData.height) - break; - - if (sy >= 0) - { - int sx = x - (size >> 1); - const uint8* src = srcData.getPixelPointer (sx, sy); - - for (int xx = 0; xx < size; ++xx) - { - if (sx >= srcData.width) - break; - - if (sx >= 0) - { - const float kernelMult = values [xx + yy * size]; - c1 += kernelMult * *src++; - c2 += kernelMult * *src++; - c3 += kernelMult * *src++; - } - else - { - src += 3; - } - - ++sx; - } - } - } - - *dest++ = (uint8) roundToInt (c1); - *dest++ = (uint8) roundToInt (c2); - *dest++ = (uint8) roundToInt (c3); - } - } - } - else if (destData.pixelStride == 1) - { - for (int y = area.getY(); y < bottom; ++y) - { - uint8* dest = line; - line += destData.lineStride; - - for (int x = area.getX(); x < right; ++x) - { - float c1 = 0; - - for (int yy = 0; yy < size; ++yy) - { - const int sy = y + yy - (size >> 1); - - if (sy >= srcData.height) - break; - - if (sy >= 0) - { - int sx = x - (size >> 1); - const uint8* src = srcData.getPixelPointer (sx, sy); - - for (int xx = 0; xx < size; ++xx) - { - if (sx >= srcData.width) - break; - - if (sx >= 0) - { - const float kernelMult = values [xx + yy * size]; - c1 += kernelMult * *src++; - } - else - { - src += 3; - } - - ++sx; - } - } - } - - *dest++ = (uint8) roundToInt (c1); - } - } - } -} - -} // namespace juce diff --git a/source/modules/juce_graphics/images/juce_ImageConvolutionKernel.h b/source/modules/juce_graphics/images/juce_ImageConvolutionKernel.h deleted file mode 100644 index c3495a268..000000000 --- a/source/modules/juce_graphics/images/juce_ImageConvolutionKernel.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Represents a filter kernel to use in convoluting an image. - - @see Image::applyConvolution -*/ -class JUCE_API ImageConvolutionKernel -{ -public: - //============================================================================== - /** Creates an empty convulution kernel. - - @param size the length of each dimension of the kernel, so e.g. if the size - is 5, it will create a 5x5 kernel - */ - ImageConvolutionKernel (int size); - - /** Destructor. */ - ~ImageConvolutionKernel(); - - //============================================================================== - /** Resets all values in the kernel to zero. */ - void clear(); - - /** Returns one of the kernel values. */ - float getKernelValue (int x, int y) const noexcept; - - /** Sets the value of a specific cell in the kernel. - - The x and y parameters must be in the range 0 < x < getKernelSize(). - - @see setOverallSum - */ - void setKernelValue (int x, int y, float value) noexcept; - - /** Rescales all values in the kernel to make the total add up to a fixed value. - - This will multiply all values in the kernel by (desiredTotalSum / currentTotalSum). - */ - void setOverallSum (float desiredTotalSum); - - /** Multiplies all values in the kernel by a value. */ - void rescaleAllValues (float multiplier); - - /** Intialises the kernel for a gaussian blur. - - @param blurRadius this may be larger or smaller than the kernel's actual - size but this will obviously be wasteful or clip at the - edges. Ideally the kernel should be just larger than - (blurRadius * 2). - */ - void createGaussianBlur (float blurRadius); - - //============================================================================== - /** Returns the size of the kernel. - - E.g. if it's a 3x3 kernel, this returns 3. - */ - int getKernelSize() const { return size; } - - //============================================================================== - /** Applies the kernel to an image. - - @param destImage the image that will receive the resultant convoluted pixels. - @param sourceImage the source image to read from - this can be the same image as - the destination, but if different, it must be exactly the same - size and format. - @param destinationArea the region of the image to apply the filter to - */ - void applyToImage (Image& destImage, - const Image& sourceImage, - const Rectangle& destinationArea) const; - -private: - //============================================================================== - HeapBlock values; - const int size; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ImageConvolutionKernel) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/images/juce_ImageFileFormat.cpp b/source/modules/juce_graphics/images/juce_ImageFileFormat.cpp deleted file mode 100644 index 12ad6afb2..000000000 --- a/source/modules/juce_graphics/images/juce_ImageFileFormat.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -struct DefaultImageFormats -{ - static ImageFileFormat** get() - { - static DefaultImageFormats formats; - return formats.formats; - } - -private: - DefaultImageFormats() noexcept - { - formats[0] = &png; - formats[1] = &jpg; - formats[2] = &gif; - formats[3] = nullptr; - } - - PNGImageFormat png; - JPEGImageFormat jpg; - GIFImageFormat gif; - - ImageFileFormat* formats[4]; -}; - -ImageFileFormat* ImageFileFormat::findImageFormatForStream (InputStream& input) -{ - const int64 streamPos = input.getPosition(); - - for (ImageFileFormat** i = DefaultImageFormats::get(); *i != nullptr; ++i) - { - const bool found = (*i)->canUnderstand (input); - input.setPosition (streamPos); - - if (found) - return *i; - } - - return nullptr; -} - -ImageFileFormat* ImageFileFormat::findImageFormatForFileExtension (const File& file) -{ - for (ImageFileFormat** i = DefaultImageFormats::get(); *i != nullptr; ++i) - if ((*i)->usesFileExtension (file)) - return *i; - - return nullptr; -} - -//============================================================================== -Image ImageFileFormat::loadFrom (InputStream& input) -{ - if (ImageFileFormat* format = findImageFormatForStream (input)) - return format->decodeImage (input); - - return Image(); -} - -Image ImageFileFormat::loadFrom (const File& file) -{ - FileInputStream stream (file); - - if (stream.openedOk()) - { - BufferedInputStream b (stream, 8192); - return loadFrom (b); - } - - return Image(); -} - -Image ImageFileFormat::loadFrom (const void* rawData, const size_t numBytes) -{ - if (rawData != nullptr && numBytes > 4) - { - MemoryInputStream stream (rawData, numBytes, false); - return loadFrom (stream); - } - - return Image(); -} - -} // namespace juce diff --git a/source/modules/juce_graphics/images/juce_ImageFileFormat.h b/source/modules/juce_graphics/images/juce_ImageFileFormat.h deleted file mode 100644 index ec7138836..000000000 --- a/source/modules/juce_graphics/images/juce_ImageFileFormat.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Base-class for codecs that can read and write image file formats such - as PNG, JPEG, etc. - - This class also contains static methods to make it easy to load images - from files, streams or from memory. - - @see Image, ImageCache -*/ -class JUCE_API ImageFileFormat -{ -protected: - //============================================================================== - /** Creates an ImageFormat. */ - ImageFileFormat() {} - -public: - /** Destructor. */ - virtual ~ImageFileFormat() {} - - //============================================================================== - /** Returns a description of this file format. - - E.g. "JPEG", "PNG" - */ - virtual String getFormatName() = 0; - - /** Returns true if the given stream seems to contain data that this format understands. - - The format class should only read the first few bytes of the stream and sniff - for header bytes that it understands. - - Note that this will advance the stream and leave it in a new position, so if you're - planning on re-using it, you may want to rewind it after calling this method. - - @see decodeImage - */ - virtual bool canUnderstand (InputStream& input) = 0; - - /** Returns true if this format uses the file extension of the given file. */ - virtual bool usesFileExtension (const File& possibleFile) = 0; - - /** Tries to decode and return an image from the given stream. - - This will be called for an image format after calling its canUnderStand() method - to see if it can handle the stream. - - @param input the stream to read the data from. The stream will be positioned - at the start of the image data (but this may not necessarily - be position 0) - @returns the image that was decoded, or an invalid image if it fails. - @see loadFrom - */ - virtual Image decodeImage (InputStream& input) = 0; - - //============================================================================== - /** Attempts to write an image to a stream. - - To specify extra information like encoding quality, there will be appropriate parameters - in the subclasses of the specific file types. - - @returns true if it nothing went wrong. - */ - virtual bool writeImageToStream (const Image& sourceImage, - OutputStream& destStream) = 0; - - //============================================================================== - /** Tries the built-in formats to see if it can find one to read this stream. - There are currently built-in decoders for PNG, JPEG and GIF formats. - The object that is returned should not be deleted by the caller. - @see canUnderstand, decodeImage, loadFrom - */ - static ImageFileFormat* findImageFormatForStream (InputStream& input); - - /** Looks for a format that can handle the given file extension. - There are currently built-in formats for PNG, JPEG and GIF formats. - The object that is returned should not be deleted by the caller. - */ - static ImageFileFormat* findImageFormatForFileExtension (const File& file); - - //============================================================================== - /** Tries to load an image from a stream. - - This will use the findImageFormatForStream() method to locate a suitable - codec, and use that to load the image. - - @returns the image that was decoded, or an invalid image if it fails. - */ - static Image loadFrom (InputStream& input); - - /** Tries to load an image from a file. - - This will use the findImageFormatForStream() method to locate a suitable - codec, and use that to load the image. - - @returns the image that was decoded, or an invalid image if it fails. - */ - static Image loadFrom (const File& file); - - /** Tries to load an image from a block of raw image data. - - This will use the findImageFormatForStream() method to locate a suitable - codec, and use that to load the image. - - @returns the image that was decoded, or an invalid image if it fails. - */ - static Image loadFrom (const void* rawData, - size_t numBytesOfData); -}; - -//============================================================================== -/** - A subclass of ImageFileFormat for reading and writing PNG files. - - @see ImageFileFormat, JPEGImageFormat -*/ -class JUCE_API PNGImageFormat : public ImageFileFormat -{ -public: - //============================================================================== - PNGImageFormat(); - ~PNGImageFormat(); - - //============================================================================== - String getFormatName() override; - bool usesFileExtension (const File&) override; - bool canUnderstand (InputStream&) override; - Image decodeImage (InputStream&) override; - bool writeImageToStream (const Image&, OutputStream&) override; -}; - - -//============================================================================== -/** - A subclass of ImageFileFormat for reading and writing JPEG files. - - @see ImageFileFormat, PNGImageFormat -*/ -class JUCE_API JPEGImageFormat : public ImageFileFormat -{ -public: - //============================================================================== - JPEGImageFormat(); - ~JPEGImageFormat(); - - //============================================================================== - /** Specifies the quality to be used when writing a JPEG file. - - @param newQuality a value 0 to 1.0, where 0 is low quality, 1.0 is best, or - any negative value is "default" quality - */ - void setQuality (float newQuality); - - //============================================================================== - String getFormatName() override; - bool usesFileExtension (const File&) override; - bool canUnderstand (InputStream&) override; - Image decodeImage (InputStream&) override; - bool writeImageToStream (const Image&, OutputStream&) override; - -private: - float quality; -}; - -//============================================================================== -/** - A subclass of ImageFileFormat for reading GIF files. - - @see ImageFileFormat, PNGImageFormat, JPEGImageFormat -*/ -class JUCE_API GIFImageFormat : public ImageFileFormat -{ -public: - //============================================================================== - GIFImageFormat(); - ~GIFImageFormat(); - - //============================================================================== - String getFormatName() override; - bool usesFileExtension (const File&) override; - bool canUnderstand (InputStream&) override; - Image decodeImage (InputStream&) override; - bool writeImageToStream (const Image&, OutputStream&) override; -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/juce_graphics.cpp b/source/modules/juce_graphics/juce_graphics.cpp deleted file mode 100644 index 2dcbc5e8b..000000000 --- a/source/modules/juce_graphics/juce_graphics.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -#ifdef JUCE_GRAPHICS_H_INCLUDED - /* When you add this cpp file to your project, you mustn't include it in a file where you've - already included any other headers - just put it inside a file on its own, possibly with your config - flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix - header files that the compiler may be using. - */ - #error "Incorrect use of JUCE cpp file" -#endif - -#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1 -#define JUCE_CORE_INCLUDE_COM_SMART_PTR 1 -#define JUCE_CORE_INCLUDE_JNI_HELPERS 1 -#define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1 -#define JUCE_GRAPHICS_INCLUDE_COREGRAPHICS_HELPERS 1 - -#include "juce_graphics.h" - -//============================================================================== -#if JUCE_MAC - #import - -#elif JUCE_WINDOWS - // get rid of some warnings in Window's own headers - #ifdef JUCE_MSVC - #pragma warning (push) - #pragma warning (disable : 4458) - #endif - - #if JUCE_MINGW && JUCE_USE_DIRECTWRITE - #warning "DirectWrite not currently implemented with mingw..." - #undef JUCE_USE_DIRECTWRITE - #endif - - #if JUCE_USE_DIRECTWRITE || JUCE_DIRECT2D - /* If you hit a compile error trying to include these files, you may need to update - your version of the Windows SDK to the latest one. The DirectWrite and Direct2D - headers are in the version 7 SDKs. - */ - #include - #include - #endif - - #if JUCE_MINGW - #include - #include - #endif - - #ifdef JUCE_MSVC - #pragma warning (pop) - #endif - -#elif JUCE_IOS - #import - #import - - #if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_3_2 - #error "JUCE no longer supports targets earlier than iOS 3.2" - #endif - -#elif JUCE_LINUX - #ifndef JUCE_USE_FREETYPE - #define JUCE_USE_FREETYPE 1 - #endif -#endif - -#if JUCE_USE_FREETYPE - #if JUCE_USE_FREETYPE_AMALGAMATED - #include "native/freetype/FreeTypeAmalgam.h" - #else - #include - #include FT_FREETYPE_H - #endif -#endif - -#undef SIZEOF - -#if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && JUCE_USE_COREIMAGE_LOADER - #define JUCE_USING_COREIMAGE_LOADER 1 -#else - #define JUCE_USING_COREIMAGE_LOADER 0 -#endif - -//============================================================================== -#include "colour/juce_Colour.cpp" -#include "colour/juce_ColourGradient.cpp" -#include "colour/juce_Colours.cpp" -#include "colour/juce_FillType.cpp" -#include "geometry/juce_AffineTransform.cpp" -#include "geometry/juce_EdgeTable.cpp" -#include "geometry/juce_Path.cpp" -#include "geometry/juce_PathIterator.cpp" -#include "geometry/juce_PathStrokeType.cpp" -#include "placement/juce_RectanglePlacement.cpp" -#include "contexts/juce_GraphicsContext.cpp" -#include "contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp" -#include "contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp" -#include "images/juce_Image.cpp" -#include "images/juce_ImageCache.cpp" -#include "images/juce_ImageConvolutionKernel.cpp" -#include "images/juce_ImageFileFormat.cpp" -#include "image_formats/juce_GIFLoader.cpp" -#include "image_formats/juce_JPEGLoader.cpp" -#include "image_formats/juce_PNGLoader.cpp" -#include "fonts/juce_AttributedString.cpp" -#include "fonts/juce_Typeface.cpp" -#include "fonts/juce_CustomTypeface.cpp" -#include "fonts/juce_Font.cpp" -#include "fonts/juce_GlyphArrangement.cpp" -#include "fonts/juce_TextLayout.cpp" -#include "effects/juce_DropShadowEffect.cpp" -#include "effects/juce_GlowEffect.cpp" - -#if JUCE_USE_FREETYPE - #include "native/juce_freetype_Fonts.cpp" -#endif - -//============================================================================== -#if JUCE_MAC || JUCE_IOS - #include "native/juce_mac_Fonts.mm" - #include "native/juce_mac_CoreGraphicsContext.mm" - #include "native/juce_mac_IconHelpers.cpp" - -#elif JUCE_WINDOWS - #include "native/juce_win32_DirectWriteTypeface.cpp" - #include "native/juce_win32_DirectWriteTypeLayout.cpp" - #include "native/juce_win32_Fonts.cpp" - #include "native/juce_win32_IconHelpers.cpp" - #if JUCE_DIRECT2D - #include "native/juce_win32_Direct2DGraphicsContext.cpp" - #endif - -#elif JUCE_LINUX - #include "native/juce_linux_Fonts.cpp" - #include "native/juce_linux_IconHelpers.cpp" - -#elif JUCE_ANDROID - #include "native/juce_android_GraphicsContext.cpp" - #include "native/juce_android_Fonts.cpp" - #include "native/juce_android_IconHelpers.cpp" - -#endif - -//============================================================================== -#if JUCE_USE_FREETYPE && JUCE_USE_FREETYPE_AMALGAMATED - #undef PIXEL_MASK - #undef ZLIB_VERSION - #undef Z_ASCII - #undef ZEXTERN - #undef ZEXPORT - - extern "C" - { - #include "native/freetype/FreeTypeAmalgam.c" - } -#endif diff --git a/source/modules/juce_graphics/juce_graphics.h b/source/modules/juce_graphics/juce_graphics.h deleted file mode 100644 index 41693ec5f..000000000 --- a/source/modules/juce_graphics/juce_graphics.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -/******************************************************************************* - The block below describes the properties of this module, and is read by - the Projucer to automatically generate project code that uses it. - For details about the syntax and how to create or use a module, see the - JUCE Module Format.txt file. - - - BEGIN_JUCE_MODULE_DECLARATION - - ID: juce_graphics - vendor: juce - version: 5.1.2 - name: JUCE graphics classes - description: Classes for 2D vector graphics, image loading/saving, font handling, etc. - website: http://www.juce.com/juce - license: GPL/Commercial - - dependencies: juce_events - OSXFrameworks: Cocoa QuartzCore - iOSFrameworks: CoreGraphics CoreImage CoreText QuartzCore - linuxPackages: x11 xinerama xext freetype2 - - END_JUCE_MODULE_DECLARATION - -*******************************************************************************/ - - -#pragma once -#define JUCE_GRAPHICS_H_INCLUDED - -#include -#include - -//============================================================================== -/** Config: JUCE_USE_COREIMAGE_LOADER - - On OSX, enabling this flag means that the CoreImage codecs will be used to load - PNG/JPEG/GIF files. It is enabled by default, but you may want to disable it if - you'd rather use libpng, libjpeg, etc. -*/ -#ifndef JUCE_USE_COREIMAGE_LOADER - #define JUCE_USE_COREIMAGE_LOADER 1 -#endif - -/** Config: JUCE_USE_DIRECTWRITE - - Enabling this flag means that DirectWrite will be used when available for font - management and layout. -*/ -#ifndef JUCE_USE_DIRECTWRITE - #define JUCE_USE_DIRECTWRITE 1 -#endif - -#ifndef JUCE_INCLUDE_PNGLIB_CODE - #define JUCE_INCLUDE_PNGLIB_CODE 1 -#endif - -#ifndef JUCE_INCLUDE_JPEGLIB_CODE - #define JUCE_INCLUDE_JPEGLIB_CODE 1 -#endif - -#ifndef USE_COREGRAPHICS_RENDERING - #define USE_COREGRAPHICS_RENDERING 1 -#endif - -//============================================================================== -namespace juce -{ - class Image; - class AffineTransform; - class Path; - class Font; - class Graphics; - class FillType; - class LowLevelGraphicsContext; -} - -#include "geometry/juce_AffineTransform.h" -#include "geometry/juce_Point.h" -#include "geometry/juce_Line.h" -#include "geometry/juce_Rectangle.h" -#include "placement/juce_Justification.h" -#include "geometry/juce_Path.h" -#include "geometry/juce_RectangleList.h" -#include "colour/juce_PixelFormats.h" -#include "colour/juce_Colour.h" -#include "colour/juce_ColourGradient.h" -#include "colour/juce_Colours.h" -#include "geometry/juce_BorderSize.h" -#include "geometry/juce_EdgeTable.h" -#include "geometry/juce_PathIterator.h" -#include "geometry/juce_PathStrokeType.h" -#include "placement/juce_RectanglePlacement.h" -#include "images/juce_ImageCache.h" -#include "images/juce_ImageConvolutionKernel.h" -#include "images/juce_ImageFileFormat.h" -#include "fonts/juce_Typeface.h" -#include "fonts/juce_Font.h" -#include "fonts/juce_AttributedString.h" -#include "fonts/juce_GlyphArrangement.h" -#include "fonts/juce_TextLayout.h" -#include "fonts/juce_CustomTypeface.h" -#include "contexts/juce_GraphicsContext.h" -#include "contexts/juce_LowLevelGraphicsContext.h" -#include "images/juce_Image.h" -#include "colour/juce_FillType.h" -#include "native/juce_RenderingHelpers.h" -#include "contexts/juce_LowLevelGraphicsSoftwareRenderer.h" -#include "contexts/juce_LowLevelGraphicsPostScriptRenderer.h" -#include "effects/juce_ImageEffectFilter.h" -#include "effects/juce_DropShadowEffect.h" -#include "effects/juce_GlowEffect.h" - -#if JUCE_GRAPHICS_INCLUDE_COREGRAPHICS_HELPERS && (JUCE_MAC || JUCE_IOS) - #include "native/juce_mac_CoreGraphicsHelpers.h" - #include "native/juce_mac_CoreGraphicsContext.h" -#endif - -#if JUCE_DIRECT2D && JUCE_WINDOWS -#include "native/juce_win32_Direct2DGraphicsContext.h" -#endif diff --git a/source/modules/juce_graphics/native/juce_RenderingHelpers.h b/source/modules/juce_graphics/native/juce_RenderingHelpers.h deleted file mode 100644 index e552758b2..000000000 --- a/source/modules/juce_graphics/native/juce_RenderingHelpers.h +++ /dev/null @@ -1,2690 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -#if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4127) // "expression is constant" warning -#endif - -namespace RenderingHelpers -{ - -//============================================================================== -/** Holds either a simple integer translation, or an affine transform. -*/ -class TranslationOrTransform -{ -public: - TranslationOrTransform (Point origin) noexcept - : offset (origin), isOnlyTranslated (true), isRotated (false) - { - } - - TranslationOrTransform (const TranslationOrTransform& other) noexcept - : complexTransform (other.complexTransform), offset (other.offset), - isOnlyTranslated (other.isOnlyTranslated), isRotated (other.isRotated) - { - } - - AffineTransform getTransform() const noexcept - { - return isOnlyTranslated ? AffineTransform::translation (offset) - : complexTransform; - } - - AffineTransform getTransformWith (const AffineTransform& userTransform) const noexcept - { - return isOnlyTranslated ? userTransform.translated (offset) - : userTransform.followedBy (complexTransform); - } - - void setOrigin (Point delta) noexcept - { - if (isOnlyTranslated) - offset += delta; - else - complexTransform = AffineTransform::translation (delta) - .followedBy (complexTransform); - } - - void addTransform (const AffineTransform& t) noexcept - { - if (isOnlyTranslated && t.isOnlyTranslation()) - { - const int tx = (int) (t.getTranslationX() * 256.0f); - const int ty = (int) (t.getTranslationY() * 256.0f); - - if (((tx | ty) & 0xf8) == 0) - { - offset += Point (tx >> 8, ty >> 8); - return; - } - } - - complexTransform = getTransformWith (t); - isOnlyTranslated = false; - isRotated = (complexTransform.mat01 != 0.0f || complexTransform.mat10 != 0.0f - || complexTransform.mat00 < 0 || complexTransform.mat11 < 0); - } - - float getPhysicalPixelScaleFactor() const noexcept - { - return isOnlyTranslated ? 1.0f : std::abs (complexTransform.getScaleFactor()); - } - - void moveOriginInDeviceSpace (Point delta) noexcept - { - if (isOnlyTranslated) - offset += delta; - else - complexTransform = complexTransform.translated (delta); - } - - Rectangle translated (const Rectangle& r) const noexcept - { - jassert (isOnlyTranslated); - return r + offset; - } - - Rectangle translated (const Rectangle& r) const noexcept - { - jassert (isOnlyTranslated); - return r + offset.toFloat(); - } - - template - RectangleOrPoint transformed (const RectangleOrPoint& r) const noexcept - { - jassert (! isOnlyTranslated); - return r.transformedBy (complexTransform); - } - - template - Rectangle deviceSpaceToUserSpace (const Rectangle& r) const noexcept - { - return isOnlyTranslated ? r - offset - : r.transformedBy (complexTransform.inverted()); - } - - AffineTransform complexTransform; - Point offset; - bool isOnlyTranslated, isRotated; -}; - -//============================================================================== -/** Holds a cache of recently-used glyph objects of some type. */ -template -class GlyphCache : private DeletedAtShutdown -{ -public: - GlyphCache() - { - reset(); - } - - ~GlyphCache() - { - getSingletonPointer() = nullptr; - } - - static GlyphCache& getInstance() - { - GlyphCache*& g = getSingletonPointer(); - - if (g == nullptr) - g = new GlyphCache(); - - return *g; - } - - //============================================================================== - void reset() - { - const ScopedLock sl (lock); - glyphs.clear(); - addNewGlyphSlots (120); - hits.set (0); - misses.set (0); - } - - void drawGlyph (RenderTargetType& target, const Font& font, const int glyphNumber, Point pos) - { - if (ReferenceCountedObjectPtr glyph = findOrCreateGlyph (font, glyphNumber)) - { - glyph->lastAccessCount = ++accessCounter; - glyph->draw (target, pos); - } - } - - ReferenceCountedObjectPtr findOrCreateGlyph (const Font& font, int glyphNumber) - { - const ScopedLock sl (lock); - - if (CachedGlyphType* g = findExistingGlyph (font, glyphNumber)) - { - ++hits; - return g; - } - - ++misses; - CachedGlyphType* g = getGlyphForReuse(); - jassert (g != nullptr); - g->generate (font, glyphNumber); - return g; - } - -private: - friend struct ContainerDeletePolicy; - ReferenceCountedArray glyphs; - Atomic accessCounter, hits, misses; - CriticalSection lock; - - CachedGlyphType* findExistingGlyph (const Font& font, int glyphNumber) const - { - for (int i = 0; i < glyphs.size(); ++i) - { - CachedGlyphType* const g = glyphs.getUnchecked (i); - - if (g->glyph == glyphNumber && g->font == font) - return g; - } - - return nullptr; - } - - CachedGlyphType* getGlyphForReuse() - { - if (hits.value + misses.value > glyphs.size() * 16) - { - if (misses.value * 2 > hits.value) - addNewGlyphSlots (32); - - hits.set (0); - misses.set (0); - } - - if (CachedGlyphType* g = findLeastRecentlyUsedGlyph()) - return g; - - addNewGlyphSlots (32); - return glyphs.getLast(); - } - - void addNewGlyphSlots (int num) - { - glyphs.ensureStorageAllocated (glyphs.size() + num); - - while (--num >= 0) - glyphs.add (new CachedGlyphType()); - } - - CachedGlyphType* findLeastRecentlyUsedGlyph() const noexcept - { - CachedGlyphType* oldest = nullptr; - int oldestCounter = std::numeric_limits::max(); - - for (int i = glyphs.size() - 1; --i >= 0;) - { - CachedGlyphType* const glyph = glyphs.getUnchecked(i); - - if (glyph->lastAccessCount <= oldestCounter - && glyph->getReferenceCount() == 1) - { - oldestCounter = glyph->lastAccessCount; - oldest = glyph; - } - } - - return oldest; - } - - static GlyphCache*& getSingletonPointer() noexcept - { - static GlyphCache* g = nullptr; - return g; - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GlyphCache) -}; - -//============================================================================== -/** Caches a glyph as an edge-table. */ -template -class CachedGlyphEdgeTable : public ReferenceCountedObject -{ -public: - CachedGlyphEdgeTable() : glyph (0), lastAccessCount (0) {} - - void draw (RendererType& state, Point pos) const - { - if (snapToIntegerCoordinate) - pos.x = std::floor (pos.x + 0.5f); - - if (edgeTable != nullptr) - state.fillEdgeTable (*edgeTable, pos.x, roundToInt (pos.y)); - } - - void generate (const Font& newFont, const int glyphNumber) - { - font = newFont; - Typeface* const typeface = newFont.getTypeface(); - snapToIntegerCoordinate = typeface->isHinted(); - glyph = glyphNumber; - - const float fontHeight = font.getHeight(); - edgeTable = typeface->getEdgeTableForGlyph (glyphNumber, - AffineTransform::scale (fontHeight * font.getHorizontalScale(), - fontHeight), fontHeight); - } - - Font font; - ScopedPointer edgeTable; - int glyph, lastAccessCount; - bool snapToIntegerCoordinate; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CachedGlyphEdgeTable) -}; - -//============================================================================== -/** Calculates the alpha values and positions for rendering the edges of a - non-pixel-aligned rectangle. -*/ -struct FloatRectangleRasterisingInfo -{ - FloatRectangleRasterisingInfo (const Rectangle& area) - : left (roundToInt (256.0f * area.getX())), - top (roundToInt (256.0f * area.getY())), - right (roundToInt (256.0f * area.getRight())), - bottom (roundToInt (256.0f * area.getBottom())) - { - if ((top >> 8) == (bottom >> 8)) - { - topAlpha = bottom - top; - bottomAlpha = 0; - totalTop = top >> 8; - totalBottom = bottom = top = totalTop + 1; - } - else - { - if ((top & 255) == 0) - { - topAlpha = 0; - top = totalTop = (top >> 8); - } - else - { - topAlpha = 255 - (top & 255); - totalTop = (top >> 8); - top = totalTop + 1; - } - - bottomAlpha = bottom & 255; - bottom >>= 8; - totalBottom = bottom + (bottomAlpha != 0 ? 1 : 0); - } - - if ((left >> 8) == (right >> 8)) - { - leftAlpha = right - left; - rightAlpha = 0; - totalLeft = (left >> 8); - totalRight = right = left = totalLeft + 1; - } - else - { - if ((left & 255) == 0) - { - leftAlpha = 0; - left = totalLeft = (left >> 8); - } - else - { - leftAlpha = 255 - (left & 255); - totalLeft = (left >> 8); - left = totalLeft + 1; - } - - rightAlpha = right & 255; - right >>= 8; - totalRight = right + (rightAlpha != 0 ? 1 : 0); - } - } - - template - void iterate (Callback& callback) const - { - if (topAlpha != 0) callback (totalLeft, totalTop, totalRight - totalLeft, 1, topAlpha); - if (bottomAlpha != 0) callback (totalLeft, bottom, totalRight - totalLeft, 1, bottomAlpha); - if (leftAlpha != 0) callback (totalLeft, totalTop, 1, totalBottom - totalTop, leftAlpha); - if (rightAlpha != 0) callback (right, totalTop, 1, totalBottom - totalTop, rightAlpha); - - callback (left, top, right - left, bottom - top, 255); - } - - inline bool isOnePixelWide() const noexcept { return right - left == 1 && leftAlpha + rightAlpha == 0; } - - inline int getTopLeftCornerAlpha() const noexcept { return (topAlpha * leftAlpha) >> 8; } - inline int getTopRightCornerAlpha() const noexcept { return (topAlpha * rightAlpha) >> 8; } - inline int getBottomLeftCornerAlpha() const noexcept { return (bottomAlpha * leftAlpha) >> 8; } - inline int getBottomRightCornerAlpha() const noexcept { return (bottomAlpha * rightAlpha) >> 8; } - - //============================================================================== - int left, top, right, bottom; // bounds of the solid central area, excluding anti-aliased edges - int totalTop, totalLeft, totalBottom, totalRight; // bounds of the total area, including edges - int topAlpha, leftAlpha, bottomAlpha, rightAlpha; // alpha of each anti-aliased edge -}; - -//============================================================================== -/** Contains classes for calculating the colour of pixels within various types of gradient. */ -namespace GradientPixelIterators -{ - /** Iterates the colour of pixels in a linear gradient */ - class Linear - { - public: - Linear (const ColourGradient& gradient, const AffineTransform& transform, - const PixelARGB* const colours, const int numColours) - : lookupTable (colours), - numEntries (numColours) - { - jassert (numColours >= 0); - Point p1 (gradient.point1); - Point p2 (gradient.point2); - - if (! transform.isIdentity()) - { - const Line l (p2, p1); - Point p3 = l.getPointAlongLine (0.0f, 100.0f); - - p1.applyTransform (transform); - p2.applyTransform (transform); - p3.applyTransform (transform); - - p2 = Line (p2, p3).findNearestPointTo (p1); - } - - vertical = std::abs (p1.x - p2.x) < 0.001f; - horizontal = std::abs (p1.y - p2.y) < 0.001f; - - if (vertical) - { - scale = roundToInt ((numEntries << (int) numScaleBits) / (double) (p2.y - p1.y)); - start = roundToInt (p1.y * (float) scale); - } - else if (horizontal) - { - scale = roundToInt ((numEntries << (int) numScaleBits) / (double) (p2.x - p1.x)); - start = roundToInt (p1.x * (float) scale); - } - else - { - grad = (p2.getY() - p1.y) / (double) (p1.x - p2.x); - yTerm = p1.getY() - p1.x / grad; - scale = roundToInt ((numEntries << (int) numScaleBits) / (yTerm * grad - (p2.y * grad - p2.x))); - grad *= scale; - } - } - - forcedinline void setY (const int y) noexcept - { - if (vertical) - linePix = lookupTable [jlimit (0, numEntries, (y * scale - start) >> (int) numScaleBits)]; - else if (! horizontal) - start = roundToInt ((y - yTerm) * grad); - } - - inline PixelARGB getPixel (const int x) const noexcept - { - return vertical ? linePix - : lookupTable [jlimit (0, numEntries, (x * scale - start) >> (int) numScaleBits)]; - } - - private: - const PixelARGB* const lookupTable; - const int numEntries; - PixelARGB linePix; - int start, scale; - double grad, yTerm; - bool vertical, horizontal; - enum { numScaleBits = 12 }; - - JUCE_DECLARE_NON_COPYABLE (Linear) - }; - - //============================================================================== - /** Iterates the colour of pixels in a circular radial gradient */ - class Radial - { - public: - Radial (const ColourGradient& gradient, const AffineTransform&, - const PixelARGB* const colours, const int numColours) - : lookupTable (colours), - numEntries (numColours), - gx1 (gradient.point1.x), - gy1 (gradient.point1.y) - { - jassert (numColours >= 0); - const Point diff (gradient.point1 - gradient.point2); - maxDist = diff.x * diff.x + diff.y * diff.y; - invScale = numEntries / std::sqrt (maxDist); - jassert (roundToInt (std::sqrt (maxDist) * invScale) <= numEntries); - } - - forcedinline void setY (const int y) noexcept - { - dy = y - gy1; - dy *= dy; - } - - inline PixelARGB getPixel (const int px) const noexcept - { - double x = px - gx1; - x *= x; - x += dy; - - return lookupTable [x >= maxDist ? numEntries : roundToInt (std::sqrt (x) * invScale)]; - } - - protected: - const PixelARGB* const lookupTable; - const int numEntries; - const double gx1, gy1; - double maxDist, invScale, dy; - - JUCE_DECLARE_NON_COPYABLE (Radial) - }; - - //============================================================================== - /** Iterates the colour of pixels in a skewed radial gradient */ - class TransformedRadial : public Radial - { - public: - TransformedRadial (const ColourGradient& gradient, const AffineTransform& transform, - const PixelARGB* const colours, const int numColours) - : Radial (gradient, transform, colours, numColours), - inverseTransform (transform.inverted()) - { - tM10 = inverseTransform.mat10; - tM00 = inverseTransform.mat00; - } - - forcedinline void setY (const int y) noexcept - { - const float floatY = (float) y; - lineYM01 = inverseTransform.mat01 * floatY + inverseTransform.mat02 - gx1; - lineYM11 = inverseTransform.mat11 * floatY + inverseTransform.mat12 - gy1; - } - - inline PixelARGB getPixel (const int px) const noexcept - { - double x = px; - const double y = tM10 * x + lineYM11; - x = tM00 * x + lineYM01; - x *= x; - x += y * y; - - if (x >= maxDist) - return lookupTable [numEntries]; - - return lookupTable [jmin (numEntries, roundToInt (std::sqrt (x) * invScale))]; - } - - private: - double tM10, tM00, lineYM01, lineYM11; - const AffineTransform inverseTransform; - - JUCE_DECLARE_NON_COPYABLE (TransformedRadial) - }; -} - -#define JUCE_PERFORM_PIXEL_OP_LOOP(op) \ -{ \ - const int destStride = destData.pixelStride; \ - do { dest->op; dest = addBytesToPointer (dest, destStride); } while (--width > 0); \ -} - -//============================================================================== -/** Contains classes for filling edge tables with various fill types. */ -namespace EdgeTableFillers -{ - /** Fills an edge-table with a solid colour. */ - template - class SolidColour - { - public: - SolidColour (const Image::BitmapData& image, const PixelARGB colour) - : destData (image), sourceColour (colour) - { - if (sizeof (PixelType) == 3 && destData.pixelStride == sizeof (PixelType)) - { - areRGBComponentsEqual = sourceColour.getRed() == sourceColour.getGreen() - && sourceColour.getGreen() == sourceColour.getBlue(); - filler[0].set (sourceColour); - filler[1].set (sourceColour); - filler[2].set (sourceColour); - filler[3].set (sourceColour); - } - else - { - areRGBComponentsEqual = false; - } - } - - forcedinline void setEdgeTableYPos (const int y) noexcept - { - linePixels = (PixelType*) destData.getLinePointer (y); - } - - forcedinline void handleEdgeTablePixel (const int x, const int alphaLevel) const noexcept - { - if (replaceExisting) - getPixel (x)->set (sourceColour); - else - getPixel (x)->blend (sourceColour, (uint32) alphaLevel); - } - - forcedinline void handleEdgeTablePixelFull (const int x) const noexcept - { - if (replaceExisting) - getPixel (x)->set (sourceColour); - else - getPixel (x)->blend (sourceColour); - } - - forcedinline void handleEdgeTableLine (const int x, const int width, const int alphaLevel) const noexcept - { - PixelARGB p (sourceColour); - p.multiplyAlpha (alphaLevel); - - PixelType* dest = getPixel (x); - - if (replaceExisting || p.getAlpha() >= 0xff) - replaceLine (dest, p, width); - else - blendLine (dest, p, width); - } - - forcedinline void handleEdgeTableLineFull (const int x, const int width) const noexcept - { - PixelType* dest = getPixel (x); - - if (replaceExisting || sourceColour.getAlpha() >= 0xff) - replaceLine (dest, sourceColour, width); - else - blendLine (dest, sourceColour, width); - } - - private: - const Image::BitmapData& destData; - PixelType* linePixels; - PixelARGB sourceColour; - PixelRGB filler [4]; - bool areRGBComponentsEqual; - - forcedinline PixelType* getPixel (const int x) const noexcept - { - return addBytesToPointer (linePixels, x * destData.pixelStride); - } - - inline void blendLine (PixelType* dest, const PixelARGB colour, int width) const noexcept - { - JUCE_PERFORM_PIXEL_OP_LOOP (blend (colour)) - } - - forcedinline void replaceLine (PixelRGB* dest, const PixelARGB colour, int width) const noexcept - { - if (destData.pixelStride == sizeof (*dest)) - { - if (areRGBComponentsEqual) // if all the component values are the same, we can cheat.. - { - memset (dest, colour.getRed(), (size_t) width * 3); - } - else - { - if (width >> 5) - { - const int* const intFiller = reinterpret_cast (filler); - - while (width > 8 && (((pointer_sized_int) dest) & 7) != 0) - { - dest->set (colour); - ++dest; - --width; - } - - while (width > 4) - { - int* d = reinterpret_cast (dest); - *d++ = intFiller[0]; - *d++ = intFiller[1]; - *d++ = intFiller[2]; - dest = reinterpret_cast (d); - width -= 4; - } - } - - while (--width >= 0) - { - dest->set (colour); - ++dest; - } - } - } - else - { - JUCE_PERFORM_PIXEL_OP_LOOP (set (colour)) - } - } - - forcedinline void replaceLine (PixelAlpha* dest, const PixelARGB colour, int width) const noexcept - { - if (destData.pixelStride == sizeof (*dest)) - memset (dest, colour.getAlpha(), (size_t) width); - else - JUCE_PERFORM_PIXEL_OP_LOOP (setAlpha (colour.getAlpha())) - } - - forcedinline void replaceLine (PixelARGB* dest, const PixelARGB colour, int width) const noexcept - { - JUCE_PERFORM_PIXEL_OP_LOOP (set (colour)) - } - - JUCE_DECLARE_NON_COPYABLE (SolidColour) - }; - - //============================================================================== - /** Fills an edge-table with a gradient. */ - template - class Gradient : public GradientType - { - public: - Gradient (const Image::BitmapData& dest, const ColourGradient& gradient, const AffineTransform& transform, - const PixelARGB* const colours, const int numColours) - : GradientType (gradient, transform, colours, numColours - 1), - destData (dest) - { - } - - forcedinline void setEdgeTableYPos (const int y) noexcept - { - linePixels = (PixelType*) destData.getLinePointer (y); - GradientType::setY (y); - } - - forcedinline void handleEdgeTablePixel (const int x, const int alphaLevel) const noexcept - { - getPixel (x)->blend (GradientType::getPixel (x), (uint32) alphaLevel); - } - - forcedinline void handleEdgeTablePixelFull (const int x) const noexcept - { - getPixel (x)->blend (GradientType::getPixel (x)); - } - - void handleEdgeTableLine (int x, int width, const int alphaLevel) const noexcept - { - PixelType* dest = getPixel (x); - - if (alphaLevel < 0xff) - JUCE_PERFORM_PIXEL_OP_LOOP (blend (GradientType::getPixel (x++), (uint32) alphaLevel)) - else - JUCE_PERFORM_PIXEL_OP_LOOP (blend (GradientType::getPixel (x++))) - } - - void handleEdgeTableLineFull (int x, int width) const noexcept - { - PixelType* dest = getPixel (x); - JUCE_PERFORM_PIXEL_OP_LOOP (blend (GradientType::getPixel (x++))) - } - - private: - const Image::BitmapData& destData; - PixelType* linePixels; - - forcedinline PixelType* getPixel (const int x) const noexcept - { - return addBytesToPointer (linePixels, x * destData.pixelStride); - } - - JUCE_DECLARE_NON_COPYABLE (Gradient) - }; - - //============================================================================== - /** Fills an edge-table with a non-transformed image. */ - template - class ImageFill - { - public: - ImageFill (const Image::BitmapData& dest, const Image::BitmapData& src, - const int alpha, const int x, const int y) - : destData (dest), - srcData (src), - extraAlpha (alpha + 1), - xOffset (repeatPattern ? negativeAwareModulo (x, src.width) - src.width : x), - yOffset (repeatPattern ? negativeAwareModulo (y, src.height) - src.height : y) - { - } - - forcedinline void setEdgeTableYPos (int y) noexcept - { - linePixels = (DestPixelType*) destData.getLinePointer (y); - - y -= yOffset; - if (repeatPattern) - { - jassert (y >= 0); - y %= srcData.height; - } - - sourceLineStart = (SrcPixelType*) srcData.getLinePointer (y); - } - - forcedinline void handleEdgeTablePixel (const int x, int alphaLevel) const noexcept - { - alphaLevel = (alphaLevel * extraAlpha) >> 8; - - getDestPixel (x)->blend (*getSrcPixel (repeatPattern ? ((x - xOffset) % srcData.width) : (x - xOffset)), (uint32) alphaLevel); - } - - forcedinline void handleEdgeTablePixelFull (const int x) const noexcept - { - getDestPixel (x)->blend (*getSrcPixel (repeatPattern ? ((x - xOffset) % srcData.width) : (x - xOffset)), (uint32) extraAlpha); - } - - void handleEdgeTableLine (int x, int width, int alphaLevel) const noexcept - { - DestPixelType* dest = getDestPixel (x); - alphaLevel = (alphaLevel * extraAlpha) >> 8; - x -= xOffset; - - if (repeatPattern) - { - if (alphaLevel < 0xfe) - JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width), (uint32) alphaLevel)) - else - JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width))) - } - else - { - jassert (x >= 0 && x + width <= srcData.width); - - if (alphaLevel < 0xfe) - JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++), (uint32) alphaLevel)) - else - copyRow (dest, getSrcPixel (x), width); - } - } - - void handleEdgeTableLineFull (int x, int width) const noexcept - { - DestPixelType* dest = getDestPixel (x); - x -= xOffset; - - if (repeatPattern) - { - if (extraAlpha < 0xfe) - JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width), (uint32) extraAlpha)) - else - JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width))) - } - else - { - jassert (x >= 0 && x + width <= srcData.width); - - if (extraAlpha < 0xfe) - JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++), (uint32) extraAlpha)) - else - copyRow (dest, getSrcPixel (x), width); - } - } - - void clipEdgeTableLine (EdgeTable& et, int x, int y, int width) - { - jassert (x - xOffset >= 0 && x + width - xOffset <= srcData.width); - SrcPixelType* s = (SrcPixelType*) srcData.getLinePointer (y - yOffset); - uint8* mask = (uint8*) (s + x - xOffset); - - if (sizeof (SrcPixelType) == sizeof (PixelARGB)) - mask += PixelARGB::indexA; - - et.clipLineToMask (x, y, mask, sizeof (SrcPixelType), width); - } - - private: - const Image::BitmapData& destData; - const Image::BitmapData& srcData; - const int extraAlpha, xOffset, yOffset; - DestPixelType* linePixels; - SrcPixelType* sourceLineStart; - - forcedinline DestPixelType* getDestPixel (int const x) const noexcept - { - return addBytesToPointer (linePixels, x * destData.pixelStride); - } - - forcedinline SrcPixelType const* getSrcPixel (int const x) const noexcept - { - return addBytesToPointer (sourceLineStart, x * srcData.pixelStride); - } - - forcedinline void copyRow (DestPixelType* dest, SrcPixelType const* src, int width) const noexcept - { - const int destStride = destData.pixelStride; - const int srcStride = srcData.pixelStride; - - if (destStride == srcStride - && srcData.pixelFormat == Image::RGB - && destData.pixelFormat == Image::RGB) - { - memcpy (dest, src, (size_t) (width * srcStride)); - } - else - { - do - { - dest->blend (*src); - dest = addBytesToPointer (dest, destStride); - src = addBytesToPointer (src, srcStride); - } while (--width > 0); - } - } - - JUCE_DECLARE_NON_COPYABLE (ImageFill) - }; - - //============================================================================== - /** Fills an edge-table with a transformed image. */ - template - class TransformedImageFill - { - public: - TransformedImageFill (const Image::BitmapData& dest, const Image::BitmapData& src, - const AffineTransform& transform, const int alpha, const Graphics::ResamplingQuality q) - : interpolator (transform, - q != Graphics::lowResamplingQuality ? 0.5f : 0.0f, - q != Graphics::lowResamplingQuality ? -128 : 0), - destData (dest), - srcData (src), - extraAlpha (alpha + 1), - quality (q), - maxX (src.width - 1), - maxY (src.height - 1), - scratchSize (2048) - { - scratchBuffer.malloc (scratchSize); - } - - forcedinline void setEdgeTableYPos (const int newY) noexcept - { - y = newY; - linePixels = (DestPixelType*) destData.getLinePointer (newY); - } - - forcedinline void handleEdgeTablePixel (const int x, const int alphaLevel) noexcept - { - SrcPixelType p; - generate (&p, x, 1); - - getDestPixel (x)->blend (p, (uint32) (alphaLevel * extraAlpha) >> 8); - } - - forcedinline void handleEdgeTablePixelFull (const int x) noexcept - { - SrcPixelType p; - generate (&p, x, 1); - - getDestPixel (x)->blend (p, (uint32) extraAlpha); - } - - void handleEdgeTableLine (const int x, int width, int alphaLevel) noexcept - { - if (width > (int) scratchSize) - { - scratchSize = (size_t) width; - scratchBuffer.malloc (scratchSize); - } - - SrcPixelType* span = scratchBuffer; - generate (span, x, width); - - DestPixelType* dest = getDestPixel (x); - alphaLevel *= extraAlpha; - alphaLevel >>= 8; - - if (alphaLevel < 0xfe) - JUCE_PERFORM_PIXEL_OP_LOOP (blend (*span++, (uint32) alphaLevel)) - else - JUCE_PERFORM_PIXEL_OP_LOOP (blend (*span++)) - } - - forcedinline void handleEdgeTableLineFull (const int x, int width) noexcept - { - handleEdgeTableLine (x, width, 255); - } - - void clipEdgeTableLine (EdgeTable& et, int x, int y_, int width) - { - if (width > (int) scratchSize) - { - scratchSize = (size_t) width; - scratchBuffer.malloc (scratchSize); - } - - y = y_; - generate (scratchBuffer.get(), x, width); - - et.clipLineToMask (x, y_, - reinterpret_cast (scratchBuffer.get()) + SrcPixelType::indexA, - sizeof (SrcPixelType), width); - } - - private: - forcedinline DestPixelType* getDestPixel (const int x) const noexcept - { - return addBytesToPointer (linePixels, x * destData.pixelStride); - } - - //============================================================================== - template - void generate (PixelType* dest, const int x, int numPixels) noexcept - { - this->interpolator.setStartOfLine ((float) x, (float) y, numPixels); - - do - { - int hiResX, hiResY; - this->interpolator.next (hiResX, hiResY); - - int loResX = hiResX >> 8; - int loResY = hiResY >> 8; - - if (repeatPattern) - { - loResX = negativeAwareModulo (loResX, srcData.width); - loResY = negativeAwareModulo (loResY, srcData.height); - } - - if (quality != Graphics::lowResamplingQuality) - { - if (isPositiveAndBelow (loResX, maxX)) - { - if (isPositiveAndBelow (loResY, maxY)) - { - // In the centre of the image.. - render4PixelAverage (dest, this->srcData.getPixelPointer (loResX, loResY), - hiResX & 255, hiResY & 255); - ++dest; - continue; - } - - if (! repeatPattern) - { - // At a top or bottom edge.. - if (loResY < 0) - render2PixelAverageX (dest, this->srcData.getPixelPointer (loResX, 0), hiResX & 255); - else - render2PixelAverageX (dest, this->srcData.getPixelPointer (loResX, maxY), hiResX & 255); - - ++dest; - continue; - } - } - else - { - if (isPositiveAndBelow (loResY, maxY) && ! repeatPattern) - { - // At a left or right hand edge.. - if (loResX < 0) - render2PixelAverageY (dest, this->srcData.getPixelPointer (0, loResY), hiResY & 255); - else - render2PixelAverageY (dest, this->srcData.getPixelPointer (maxX, loResY), hiResY & 255); - - ++dest; - continue; - } - } - } - - if (! repeatPattern) - { - if (loResX < 0) loResX = 0; - if (loResY < 0) loResY = 0; - if (loResX > maxX) loResX = maxX; - if (loResY > maxY) loResY = maxY; - } - - dest->set (*(const PixelType*) this->srcData.getPixelPointer (loResX, loResY)); - ++dest; - - } while (--numPixels > 0); - } - - //============================================================================== - void render4PixelAverage (PixelARGB* const dest, const uint8* src, const int subPixelX, const int subPixelY) noexcept - { - uint32 c[4] = { 256 * 128, 256 * 128, 256 * 128, 256 * 128 }; - - uint32 weight = (uint32) ((256 - subPixelX) * (256 - subPixelY)); - c[0] += weight * src[0]; - c[1] += weight * src[1]; - c[2] += weight * src[2]; - c[3] += weight * src[3]; - - src += this->srcData.pixelStride; - - weight = (uint32) (subPixelX * (256 - subPixelY)); - c[0] += weight * src[0]; - c[1] += weight * src[1]; - c[2] += weight * src[2]; - c[3] += weight * src[3]; - - src += this->srcData.lineStride; - - weight = (uint32) (subPixelX * subPixelY); - c[0] += weight * src[0]; - c[1] += weight * src[1]; - c[2] += weight * src[2]; - c[3] += weight * src[3]; - - src -= this->srcData.pixelStride; - - weight = (uint32) ((256 - subPixelX) * subPixelY); - c[0] += weight * src[0]; - c[1] += weight * src[1]; - c[2] += weight * src[2]; - c[3] += weight * src[3]; - - dest->setARGB ((uint8) (c[PixelARGB::indexA] >> 16), - (uint8) (c[PixelARGB::indexR] >> 16), - (uint8) (c[PixelARGB::indexG] >> 16), - (uint8) (c[PixelARGB::indexB] >> 16)); - } - - void render2PixelAverageX (PixelARGB* const dest, const uint8* src, const uint32 subPixelX) noexcept - { - uint32 c[4] = { 128, 128, 128, 128 }; - - uint32 weight = 256 - subPixelX; - c[0] += weight * src[0]; - c[1] += weight * src[1]; - c[2] += weight * src[2]; - c[3] += weight * src[3]; - - src += this->srcData.pixelStride; - - weight = subPixelX; - c[0] += weight * src[0]; - c[1] += weight * src[1]; - c[2] += weight * src[2]; - c[3] += weight * src[3]; - - dest->setARGB ((uint8) (c[PixelARGB::indexA] >> 8), - (uint8) (c[PixelARGB::indexR] >> 8), - (uint8) (c[PixelARGB::indexG] >> 8), - (uint8) (c[PixelARGB::indexB] >> 8)); - } - - void render2PixelAverageY (PixelARGB* const dest, const uint8* src, const uint32 subPixelY) noexcept - { - uint32 c[4] = { 128, 128, 128, 128 }; - - uint32 weight = 256 - subPixelY; - c[0] += weight * src[0]; - c[1] += weight * src[1]; - c[2] += weight * src[2]; - c[3] += weight * src[3]; - - src += this->srcData.lineStride; - - weight = subPixelY; - c[0] += weight * src[0]; - c[1] += weight * src[1]; - c[2] += weight * src[2]; - c[3] += weight * src[3]; - - dest->setARGB ((uint8) (c[PixelARGB::indexA] >> 8), - (uint8) (c[PixelARGB::indexR] >> 8), - (uint8) (c[PixelARGB::indexG] >> 8), - (uint8) (c[PixelARGB::indexB] >> 8)); - } - - //============================================================================== - void render4PixelAverage (PixelRGB* const dest, const uint8* src, const uint32 subPixelX, const uint32 subPixelY) noexcept - { - uint32 c[3] = { 256 * 128, 256 * 128, 256 * 128 }; - - uint32 weight = (256 - subPixelX) * (256 - subPixelY); - c[0] += weight * src[0]; - c[1] += weight * src[1]; - c[2] += weight * src[2]; - - src += this->srcData.pixelStride; - - weight = subPixelX * (256 - subPixelY); - c[0] += weight * src[0]; - c[1] += weight * src[1]; - c[2] += weight * src[2]; - - src += this->srcData.lineStride; - - weight = subPixelX * subPixelY; - c[0] += weight * src[0]; - c[1] += weight * src[1]; - c[2] += weight * src[2]; - - src -= this->srcData.pixelStride; - - weight = (256 - subPixelX) * subPixelY; - c[0] += weight * src[0]; - c[1] += weight * src[1]; - c[2] += weight * src[2]; - - dest->setARGB ((uint8) 255, - (uint8) (c[PixelRGB::indexR] >> 16), - (uint8) (c[PixelRGB::indexG] >> 16), - (uint8) (c[PixelRGB::indexB] >> 16)); - } - - void render2PixelAverageX (PixelRGB* const dest, const uint8* src, const uint32 subPixelX) noexcept - { - uint32 c[3] = { 128, 128, 128 }; - - const uint32 weight = 256 - subPixelX; - c[0] += weight * src[0]; - c[1] += weight * src[1]; - c[2] += weight * src[2]; - - src += this->srcData.pixelStride; - - c[0] += subPixelX * src[0]; - c[1] += subPixelX * src[1]; - c[2] += subPixelX * src[2]; - - dest->setARGB ((uint8) 255, - (uint8) (c[PixelRGB::indexR] >> 8), - (uint8) (c[PixelRGB::indexG] >> 8), - (uint8) (c[PixelRGB::indexB] >> 8)); - } - - void render2PixelAverageY (PixelRGB* const dest, const uint8* src, const uint32 subPixelY) noexcept - { - uint32 c[3] = { 128, 128, 128 }; - - const uint32 weight = 256 - subPixelY; - c[0] += weight * src[0]; - c[1] += weight * src[1]; - c[2] += weight * src[2]; - - src += this->srcData.lineStride; - - c[0] += subPixelY * src[0]; - c[1] += subPixelY * src[1]; - c[2] += subPixelY * src[2]; - - dest->setARGB ((uint8) 255, - (uint8) (c[PixelRGB::indexR] >> 8), - (uint8) (c[PixelRGB::indexG] >> 8), - (uint8) (c[PixelRGB::indexB] >> 8)); - } - - //============================================================================== - void render4PixelAverage (PixelAlpha* const dest, const uint8* src, const uint32 subPixelX, const uint32 subPixelY) noexcept - { - uint32 c = 256 * 128; - c += src[0] * ((256 - subPixelX) * (256 - subPixelY)); - src += this->srcData.pixelStride; - c += src[0] * (subPixelX * (256 - subPixelY)); - src += this->srcData.lineStride; - c += src[0] * (subPixelX * subPixelY); - src -= this->srcData.pixelStride; - - c += src[0] * ((256 - subPixelX) * subPixelY); - - *((uint8*) dest) = (uint8) (c >> 16); - } - - void render2PixelAverageX (PixelAlpha* const dest, const uint8* src, const uint32 subPixelX) noexcept - { - uint32 c = 128; - c += src[0] * (256 - subPixelX); - src += this->srcData.pixelStride; - c += src[0] * subPixelX; - *((uint8*) dest) = (uint8) (c >> 8); - } - - void render2PixelAverageY (PixelAlpha* const dest, const uint8* src, const uint32 subPixelY) noexcept - { - uint32 c = 128; - c += src[0] * (256 - subPixelY); - src += this->srcData.lineStride; - c += src[0] * subPixelY; - *((uint8*) dest) = (uint8) (c >> 8); - } - - //============================================================================== - class TransformedImageSpanInterpolator - { - public: - TransformedImageSpanInterpolator (const AffineTransform& transform, - const float offsetFloat, const int offsetInt) noexcept - : inverseTransform (transform.inverted()), - pixelOffset (offsetFloat), pixelOffsetInt (offsetInt) - {} - - void setStartOfLine (float sx, float sy, const int numPixels) noexcept - { - jassert (numPixels > 0); - - sx += pixelOffset; - sy += pixelOffset; - float x1 = sx, y1 = sy; - sx += (float) numPixels; - inverseTransform.transformPoints (x1, y1, sx, sy); - - xBresenham.set ((int) (x1 * 256.0f), (int) (sx * 256.0f), numPixels, pixelOffsetInt); - yBresenham.set ((int) (y1 * 256.0f), (int) (sy * 256.0f), numPixels, pixelOffsetInt); - } - - void next (int& px, int& py) noexcept - { - px = xBresenham.n; xBresenham.stepToNext(); - py = yBresenham.n; yBresenham.stepToNext(); - } - - private: - class BresenhamInterpolator - { - public: - BresenhamInterpolator() noexcept {} - - void set (const int n1, const int n2, const int steps, const int offsetInt) noexcept - { - numSteps = steps; - step = (n2 - n1) / numSteps; - remainder = modulo = (n2 - n1) % numSteps; - n = n1 + offsetInt; - - if (modulo <= 0) - { - modulo += numSteps; - remainder += numSteps; - --step; - } - - modulo -= numSteps; - } - - forcedinline void stepToNext() noexcept - { - modulo += remainder; - n += step; - - if (modulo > 0) - { - modulo -= numSteps; - ++n; - } - } - - int n; - - private: - int numSteps, step, modulo, remainder; - }; - - const AffineTransform inverseTransform; - BresenhamInterpolator xBresenham, yBresenham; - const float pixelOffset; - const int pixelOffsetInt; - - JUCE_DECLARE_NON_COPYABLE (TransformedImageSpanInterpolator) - }; - - //============================================================================== - TransformedImageSpanInterpolator interpolator; - const Image::BitmapData& destData; - const Image::BitmapData& srcData; - const int extraAlpha; - const Graphics::ResamplingQuality quality; - const int maxX, maxY; - int y; - DestPixelType* linePixels; - HeapBlock scratchBuffer; - size_t scratchSize; - - JUCE_DECLARE_NON_COPYABLE (TransformedImageFill) - }; - - - //============================================================================== - template - void renderImageTransformed (Iterator& iter, const Image::BitmapData& destData, const Image::BitmapData& srcData, - const int alpha, const AffineTransform& transform, Graphics::ResamplingQuality quality, bool tiledFill) - { - switch (destData.pixelFormat) - { - case Image::ARGB: - switch (srcData.pixelFormat) - { - case Image::ARGB: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - break; - case Image::RGB: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - break; - default: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - break; - } - break; - - case Image::RGB: - switch (srcData.pixelFormat) - { - case Image::ARGB: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - break; - case Image::RGB: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - break; - default: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - break; - } - break; - - default: - switch (srcData.pixelFormat) - { - case Image::ARGB: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - break; - case Image::RGB: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - break; - default: - if (tiledFill) { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - else { TransformedImageFill r (destData, srcData, transform, alpha, quality); iter.iterate (r); } - break; - } - break; - } - } - - template - void renderImageUntransformed (Iterator& iter, const Image::BitmapData& destData, const Image::BitmapData& srcData, const int alpha, int x, int y, bool tiledFill) - { - switch (destData.pixelFormat) - { - case Image::ARGB: - switch (srcData.pixelFormat) - { - case Image::ARGB: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - break; - case Image::RGB: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - break; - default: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - break; - } - break; - - case Image::RGB: - switch (srcData.pixelFormat) - { - case Image::ARGB: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - break; - case Image::RGB: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - break; - default: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - break; - } - break; - - default: - switch (srcData.pixelFormat) - { - case Image::ARGB: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - break; - case Image::RGB: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - break; - default: - if (tiledFill) { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - else { ImageFill r (destData, srcData, alpha, x, y); iter.iterate (r); } - break; - } - break; - } - } - - template - void renderSolidFill (Iterator& iter, const Image::BitmapData& destData, const PixelARGB fillColour, const bool replaceContents, DestPixelType*) - { - if (replaceContents) - { - EdgeTableFillers::SolidColour r (destData, fillColour); - iter.iterate (r); - } - else - { - EdgeTableFillers::SolidColour r (destData, fillColour); - iter.iterate (r); - } - } - - template - void renderGradient (Iterator& iter, const Image::BitmapData& destData, const ColourGradient& g, const AffineTransform& transform, - const PixelARGB* const lookupTable, const int numLookupEntries, const bool isIdentity, DestPixelType*) - { - if (g.isRadial) - { - if (isIdentity) - { - EdgeTableFillers::Gradient renderer (destData, g, transform, lookupTable, numLookupEntries); - iter.iterate (renderer); - } - else - { - EdgeTableFillers::Gradient renderer (destData, g, transform, lookupTable, numLookupEntries); - iter.iterate (renderer); - } - } - else - { - EdgeTableFillers::Gradient renderer (destData, g, transform, lookupTable, numLookupEntries); - iter.iterate (renderer); - } - } -} - -//============================================================================== -template -struct ClipRegions -{ - class Base : public SingleThreadedReferenceCountedObject - { - public: - Base() {} - virtual ~Base() {} - - typedef ReferenceCountedObjectPtr Ptr; - - virtual Ptr clone() const = 0; - virtual Ptr applyClipTo (const Ptr& target) const = 0; - - virtual Ptr clipToRectangle (const Rectangle&) = 0; - virtual Ptr clipToRectangleList (const RectangleList&) = 0; - virtual Ptr excludeClipRectangle (const Rectangle&) = 0; - virtual Ptr clipToPath (const Path&, const AffineTransform&) = 0; - virtual Ptr clipToEdgeTable (const EdgeTable& et) = 0; - virtual Ptr clipToImageAlpha (const Image&, const AffineTransform&, const Graphics::ResamplingQuality) = 0; - virtual void translate (Point delta) = 0; - - virtual bool clipRegionIntersects (const Rectangle&) const = 0; - virtual Rectangle getClipBounds() const = 0; - - virtual void fillRectWithColour (SavedStateType&, const Rectangle&, const PixelARGB colour, bool replaceContents) const = 0; - virtual void fillRectWithColour (SavedStateType&, const Rectangle&, const PixelARGB colour) const = 0; - virtual void fillAllWithColour (SavedStateType&, const PixelARGB colour, bool replaceContents) const = 0; - virtual void fillAllWithGradient (SavedStateType&, ColourGradient&, const AffineTransform&, bool isIdentity) const = 0; - virtual void renderImageTransformed (SavedStateType&, const Image&, const int alpha, const AffineTransform&, Graphics::ResamplingQuality, bool tiledFill) const = 0; - virtual void renderImageUntransformed (SavedStateType&, const Image&, const int alpha, int x, int y, bool tiledFill) const = 0; - }; - - //============================================================================== - class EdgeTableRegion : public Base - { - public: - EdgeTableRegion (const EdgeTable& e) : edgeTable (e) {} - EdgeTableRegion (const Rectangle& r) : edgeTable (r) {} - EdgeTableRegion (const Rectangle& r) : edgeTable (r) {} - EdgeTableRegion (const RectangleList& r) : edgeTable (r) {} - EdgeTableRegion (const RectangleList& r) : edgeTable (r) {} - EdgeTableRegion (const Rectangle& bounds, const Path& p, const AffineTransform& t) : edgeTable (bounds, p, t) {} - EdgeTableRegion (const EdgeTableRegion& other) : Base(), edgeTable (other.edgeTable) {} - - typedef typename Base::Ptr Ptr; - - Ptr clone() const { return new EdgeTableRegion (*this); } - Ptr applyClipTo (const Ptr& target) const { return target->clipToEdgeTable (edgeTable); } - - Ptr clipToRectangle (const Rectangle& r) - { - edgeTable.clipToRectangle (r); - return edgeTable.isEmpty() ? nullptr : this; - } - - Ptr clipToRectangleList (const RectangleList& r) - { - RectangleList inverse (edgeTable.getMaximumBounds()); - - if (inverse.subtract (r)) - for (auto& i : inverse) - edgeTable.excludeRectangle (i); - - return edgeTable.isEmpty() ? nullptr : this; - } - - Ptr excludeClipRectangle (const Rectangle& r) - { - edgeTable.excludeRectangle (r); - return edgeTable.isEmpty() ? nullptr : this; - } - - Ptr clipToPath (const Path& p, const AffineTransform& transform) - { - EdgeTable et (edgeTable.getMaximumBounds(), p, transform); - edgeTable.clipToEdgeTable (et); - return edgeTable.isEmpty() ? nullptr : this; - } - - Ptr clipToEdgeTable (const EdgeTable& et) - { - edgeTable.clipToEdgeTable (et); - return edgeTable.isEmpty() ? nullptr : this; - } - - Ptr clipToImageAlpha (const Image& image, const AffineTransform& transform, const Graphics::ResamplingQuality quality) - { - const Image::BitmapData srcData (image, Image::BitmapData::readOnly); - - if (transform.isOnlyTranslation()) - { - // If our translation doesn't involve any distortion, just use a simple blit.. - const int tx = (int) (transform.getTranslationX() * 256.0f); - const int ty = (int) (transform.getTranslationY() * 256.0f); - - if (quality == Graphics::lowResamplingQuality || ((tx | ty) & 224) == 0) - { - const int imageX = ((tx + 128) >> 8); - const int imageY = ((ty + 128) >> 8); - - if (image.getFormat() == Image::ARGB) - straightClipImage (srcData, imageX, imageY, (PixelARGB*) 0); - else - straightClipImage (srcData, imageX, imageY, (PixelAlpha*) 0); - - return edgeTable.isEmpty() ? nullptr : this; - } - } - - if (transform.isSingularity()) - return Ptr(); - - { - Path p; - p.addRectangle (0, 0, (float) srcData.width, (float) srcData.height); - EdgeTable et2 (edgeTable.getMaximumBounds(), p, transform); - edgeTable.clipToEdgeTable (et2); - } - - if (! edgeTable.isEmpty()) - { - if (image.getFormat() == Image::ARGB) - transformedClipImage (srcData, transform, quality, (PixelARGB*) 0); - else - transformedClipImage (srcData, transform, quality, (PixelAlpha*) 0); - } - - return edgeTable.isEmpty() ? nullptr : this; - } - - void translate (Point delta) - { - edgeTable.translate ((float) delta.x, delta.y); - } - - bool clipRegionIntersects (const Rectangle& r) const - { - return edgeTable.getMaximumBounds().intersects (r); - } - - Rectangle getClipBounds() const - { - return edgeTable.getMaximumBounds(); - } - - void fillRectWithColour (SavedStateType& state, const Rectangle& area, const PixelARGB colour, bool replaceContents) const - { - const Rectangle totalClip (edgeTable.getMaximumBounds()); - const Rectangle clipped (totalClip.getIntersection (area)); - - if (! clipped.isEmpty()) - { - EdgeTableRegion et (clipped); - et.edgeTable.clipToEdgeTable (edgeTable); - state.fillWithSolidColour (et.edgeTable, colour, replaceContents); - } - } - - void fillRectWithColour (SavedStateType& state, const Rectangle& area, const PixelARGB colour) const - { - const Rectangle totalClip (edgeTable.getMaximumBounds().toFloat()); - const Rectangle clipped (totalClip.getIntersection (area)); - - if (! clipped.isEmpty()) - { - EdgeTableRegion et (clipped); - et.edgeTable.clipToEdgeTable (edgeTable); - state.fillWithSolidColour (et.edgeTable, colour, false); - } - } - - void fillAllWithColour (SavedStateType& state, const PixelARGB colour, bool replaceContents) const - { - state.fillWithSolidColour (edgeTable, colour, replaceContents); - } - - void fillAllWithGradient (SavedStateType& state, ColourGradient& gradient, const AffineTransform& transform, bool isIdentity) const - { - state.fillWithGradient (edgeTable, gradient, transform, isIdentity); - } - - void renderImageTransformed (SavedStateType& state, const Image& src, const int alpha, const AffineTransform& transform, Graphics::ResamplingQuality quality, bool tiledFill) const - { - state.renderImageTransformed (edgeTable, src, alpha, transform, quality, tiledFill); - } - - void renderImageUntransformed (SavedStateType& state, const Image& src, const int alpha, int x, int y, bool tiledFill) const - { - state.renderImageUntransformed (edgeTable, src, alpha, x, y, tiledFill); - } - - EdgeTable edgeTable; - - private: - template - void transformedClipImage (const Image::BitmapData& srcData, const AffineTransform& transform, const Graphics::ResamplingQuality quality, const SrcPixelType*) - { - EdgeTableFillers::TransformedImageFill renderer (srcData, srcData, transform, 255, quality); - - for (int y = 0; y < edgeTable.getMaximumBounds().getHeight(); ++y) - renderer.clipEdgeTableLine (edgeTable, edgeTable.getMaximumBounds().getX(), y + edgeTable.getMaximumBounds().getY(), - edgeTable.getMaximumBounds().getWidth()); - } - - template - void straightClipImage (const Image::BitmapData& srcData, int imageX, int imageY, const SrcPixelType*) - { - Rectangle r (imageX, imageY, srcData.width, srcData.height); - edgeTable.clipToRectangle (r); - - EdgeTableFillers::ImageFill renderer (srcData, srcData, 255, imageX, imageY); - - for (int y = 0; y < r.getHeight(); ++y) - renderer.clipEdgeTableLine (edgeTable, r.getX(), y + r.getY(), r.getWidth()); - } - - EdgeTableRegion& operator= (const EdgeTableRegion&); - }; - - //============================================================================== - class RectangleListRegion : public Base - { - public: - RectangleListRegion (const Rectangle& r) : clip (r) {} - RectangleListRegion (const RectangleList& r) : clip (r) {} - RectangleListRegion (const RectangleListRegion& other) : Base(), clip (other.clip) {} - - typedef typename Base::Ptr Ptr; - - Ptr clone() const { return new RectangleListRegion (*this); } - Ptr applyClipTo (const Ptr& target) const { return target->clipToRectangleList (clip); } - - Ptr clipToRectangle (const Rectangle& r) - { - clip.clipTo (r); - return clip.isEmpty() ? nullptr : this; - } - - Ptr clipToRectangleList (const RectangleList& r) - { - clip.clipTo (r); - return clip.isEmpty() ? nullptr : this; - } - - Ptr excludeClipRectangle (const Rectangle& r) - { - clip.subtract (r); - return clip.isEmpty() ? nullptr : this; - } - - Ptr clipToPath (const Path& p, const AffineTransform& transform) { return toEdgeTable()->clipToPath (p, transform); } - Ptr clipToEdgeTable (const EdgeTable& et) { return toEdgeTable()->clipToEdgeTable (et); } - - Ptr clipToImageAlpha (const Image& image, const AffineTransform& transform, const Graphics::ResamplingQuality quality) - { - return toEdgeTable()->clipToImageAlpha (image, transform, quality); - } - - void translate (Point delta) { clip.offsetAll (delta); } - bool clipRegionIntersects (const Rectangle& r) const { return clip.intersects (r); } - Rectangle getClipBounds() const { return clip.getBounds(); } - - void fillRectWithColour (SavedStateType& state, const Rectangle& area, const PixelARGB colour, bool replaceContents) const - { - SubRectangleIterator iter (clip, area); - state.fillWithSolidColour (iter, colour, replaceContents); - } - - void fillRectWithColour (SavedStateType& state, const Rectangle& area, const PixelARGB colour) const - { - SubRectangleIteratorFloat iter (clip, area); - state.fillWithSolidColour (iter, colour, false); - } - - void fillAllWithColour (SavedStateType& state, const PixelARGB colour, bool replaceContents) const - { - state.fillWithSolidColour (*this, colour, replaceContents); - } - - void fillAllWithGradient (SavedStateType& state, ColourGradient& gradient, const AffineTransform& transform, bool isIdentity) const - { - state.fillWithGradient (*this, gradient, transform, isIdentity); - } - - void renderImageTransformed (SavedStateType& state, const Image& src, const int alpha, const AffineTransform& transform, Graphics::ResamplingQuality quality, bool tiledFill) const - { - state.renderImageTransformed (*this, src, alpha, transform, quality, tiledFill); - } - - void renderImageUntransformed (SavedStateType& state, const Image& src, const int alpha, int x, int y, bool tiledFill) const - { - state.renderImageUntransformed (*this, src, alpha, x, y, tiledFill); - } - - RectangleList clip; - - //============================================================================== - template - void iterate (Renderer& r) const noexcept - { - for (auto& i : clip) - { - const int x = i.getX(); - const int w = i.getWidth(); - jassert (w > 0); - const int bottom = i.getBottom(); - - for (int y = i.getY(); y < bottom; ++y) - { - r.setEdgeTableYPos (y); - r.handleEdgeTableLineFull (x, w); - } - } - } - - private: - //============================================================================== - class SubRectangleIterator - { - public: - SubRectangleIterator (const RectangleList& clipList, const Rectangle& clipBounds) - : clip (clipList), area (clipBounds) - {} - - template - void iterate (Renderer& r) const noexcept - { - for (auto& i : clip) - { - auto rect = i.getIntersection (area); - - if (! rect.isEmpty()) - { - const int x = rect.getX(); - const int w = rect.getWidth(); - const int bottom = rect.getBottom(); - - for (int y = rect.getY(); y < bottom; ++y) - { - r.setEdgeTableYPos (y); - r.handleEdgeTableLineFull (x, w); - } - } - } - } - - private: - const RectangleList& clip; - const Rectangle area; - - JUCE_DECLARE_NON_COPYABLE (SubRectangleIterator) - }; - - //============================================================================== - class SubRectangleIteratorFloat - { - public: - SubRectangleIteratorFloat (const RectangleList& clipList, const Rectangle& clipBounds) noexcept - : clip (clipList), area (clipBounds) - { - } - - template - void iterate (Renderer& r) const noexcept - { - const RenderingHelpers::FloatRectangleRasterisingInfo f (area); - - for (auto& i : clip) - { - const int clipLeft = i.getX(); - const int clipRight = i.getRight(); - const int clipTop = i.getY(); - const int clipBottom = i.getBottom(); - - if (f.totalBottom > clipTop && f.totalTop < clipBottom - && f.totalRight > clipLeft && f.totalLeft < clipRight) - { - if (f.isOnePixelWide()) - { - if (f.topAlpha != 0 && f.totalTop >= clipTop) - { - r.setEdgeTableYPos (f.totalTop); - r.handleEdgeTablePixel (f.left, f.topAlpha); - } - - const int endY = jmin (f.bottom, clipBottom); - for (int y = jmax (clipTop, f.top); y < endY; ++y) - { - r.setEdgeTableYPos (y); - r.handleEdgeTablePixelFull (f.left); - } - - if (f.bottomAlpha != 0 && f.bottom < clipBottom) - { - r.setEdgeTableYPos (f.bottom); - r.handleEdgeTablePixel (f.left, f.bottomAlpha); - } - } - else - { - const int clippedLeft = jmax (f.left, clipLeft); - const int clippedWidth = jmin (f.right, clipRight) - clippedLeft; - const bool doLeftAlpha = f.leftAlpha != 0 && f.totalLeft >= clipLeft; - const bool doRightAlpha = f.rightAlpha != 0 && f.right < clipRight; - - if (f.topAlpha != 0 && f.totalTop >= clipTop) - { - r.setEdgeTableYPos (f.totalTop); - - if (doLeftAlpha) r.handleEdgeTablePixel (f.totalLeft, f.getTopLeftCornerAlpha()); - if (clippedWidth > 0) r.handleEdgeTableLine (clippedLeft, clippedWidth, f.topAlpha); - if (doRightAlpha) r.handleEdgeTablePixel (f.right, f.getTopRightCornerAlpha()); - } - - const int endY = jmin (f.bottom, clipBottom); - for (int y = jmax (clipTop, f.top); y < endY; ++y) - { - r.setEdgeTableYPos (y); - - if (doLeftAlpha) r.handleEdgeTablePixel (f.totalLeft, f.leftAlpha); - if (clippedWidth > 0) r.handleEdgeTableLineFull (clippedLeft, clippedWidth); - if (doRightAlpha) r.handleEdgeTablePixel (f.right, f.rightAlpha); - } - - if (f.bottomAlpha != 0 && f.bottom < clipBottom) - { - r.setEdgeTableYPos (f.bottom); - - if (doLeftAlpha) r.handleEdgeTablePixel (f.totalLeft, f.getBottomLeftCornerAlpha()); - if (clippedWidth > 0) r.handleEdgeTableLine (clippedLeft, clippedWidth, f.bottomAlpha); - if (doRightAlpha) r.handleEdgeTablePixel (f.right, f.getBottomRightCornerAlpha()); - } - } - } - } - } - - private: - const RectangleList& clip; - const Rectangle& area; - - JUCE_DECLARE_NON_COPYABLE (SubRectangleIteratorFloat) - }; - - Ptr toEdgeTable() const { return new EdgeTableRegion (clip); } - - RectangleListRegion& operator= (const RectangleListRegion&); - }; -}; - -//============================================================================== -template -class SavedStateBase -{ -public: - typedef typename ClipRegions::Base BaseRegionType; - typedef typename ClipRegions::EdgeTableRegion EdgeTableRegionType; - typedef typename ClipRegions::RectangleListRegion RectangleListRegionType; - - SavedStateBase (const Rectangle& initialClip) - : clip (new RectangleListRegionType (initialClip)), transform (Point()), - interpolationQuality (Graphics::mediumResamplingQuality), transparencyLayerAlpha (1.0f) - { - } - - SavedStateBase (const RectangleList& clipList, Point origin) - : clip (new RectangleListRegionType (clipList)), transform (origin), - interpolationQuality (Graphics::mediumResamplingQuality), transparencyLayerAlpha (1.0f) - { - } - - SavedStateBase (const SavedStateBase& other) - : clip (other.clip), transform (other.transform), fillType (other.fillType), - interpolationQuality (other.interpolationQuality), - transparencyLayerAlpha (other.transparencyLayerAlpha) - { - } - - SavedStateType& getThis() noexcept { return *static_cast (this); } - - bool clipToRectangle (const Rectangle& r) - { - if (clip != nullptr) - { - if (transform.isOnlyTranslated) - { - cloneClipIfMultiplyReferenced(); - clip = clip->clipToRectangle (transform.translated (r)); - } - else if (! transform.isRotated) - { - cloneClipIfMultiplyReferenced(); - clip = clip->clipToRectangle (transform.transformed (r)); - } - else - { - Path p; - p.addRectangle (r); - clipToPath (p, AffineTransform()); - } - } - - return clip != nullptr; - } - - bool clipToRectangleList (const RectangleList& r) - { - if (clip != nullptr) - { - if (transform.isOnlyTranslated) - { - cloneClipIfMultiplyReferenced(); - RectangleList offsetList (r); - offsetList.offsetAll (transform.offset.x, transform.offset.y); - clip = clip->clipToRectangleList (offsetList); - } - else if (! transform.isRotated) - { - cloneClipIfMultiplyReferenced(); - RectangleList scaledList; - - for (auto& i : r) - scaledList.add (transform.transformed (i)); - - clip = clip->clipToRectangleList (scaledList); - } - else - { - clipToPath (r.toPath(), AffineTransform()); - } - } - - return clip != nullptr; - } - - static Rectangle getLargestIntegerWithin (Rectangle r) - { - const int x1 = (int) std::ceil (r.getX()); - const int y1 = (int) std::ceil (r.getY()); - const int x2 = (int) std::floor (r.getRight()); - const int y2 = (int) std::floor (r.getBottom()); - - return Rectangle (x1, y1, x2 - x1, y2 - y1); - } - - bool excludeClipRectangle (const Rectangle& r) - { - if (clip != nullptr) - { - cloneClipIfMultiplyReferenced(); - - if (transform.isOnlyTranslated) - { - clip = clip->excludeClipRectangle (getLargestIntegerWithin (transform.translated (r.toFloat()))); - } - else if (! transform.isRotated) - { - clip = clip->excludeClipRectangle (getLargestIntegerWithin (transform.transformed (r.toFloat()))); - } - else - { - Path p; - p.addRectangle (r.toFloat()); - p.applyTransform (transform.complexTransform); - p.addRectangle (clip->getClipBounds().toFloat()); - p.setUsingNonZeroWinding (false); - clip = clip->clipToPath (p, AffineTransform()); - } - } - - return clip != nullptr; - } - - void clipToPath (const Path& p, const AffineTransform& t) - { - if (clip != nullptr) - { - cloneClipIfMultiplyReferenced(); - clip = clip->clipToPath (p, transform.getTransformWith (t)); - } - } - - void clipToImageAlpha (const Image& sourceImage, const AffineTransform& t) - { - if (clip != nullptr) - { - if (sourceImage.hasAlphaChannel()) - { - cloneClipIfMultiplyReferenced(); - clip = clip->clipToImageAlpha (sourceImage, transform.getTransformWith (t), interpolationQuality); - } - else - { - Path p; - p.addRectangle (sourceImage.getBounds()); - clipToPath (p, t); - } - } - } - - bool clipRegionIntersects (const Rectangle& r) const - { - if (clip != nullptr) - { - if (transform.isOnlyTranslated) - return clip->clipRegionIntersects (transform.translated (r)); - - return getClipBounds().intersects (r); - } - - return false; - } - - Rectangle getClipBounds() const - { - return clip != nullptr ? transform.deviceSpaceToUserSpace (clip->getClipBounds()) - : Rectangle(); - } - - void setFillType (const FillType& newFill) - { - fillType = newFill; - } - - void fillTargetRect (const Rectangle& r, const bool replaceContents) - { - if (fillType.isColour()) - { - clip->fillRectWithColour (getThis(), r, fillType.colour.getPixelARGB(), replaceContents); - } - else - { - const Rectangle clipped (clip->getClipBounds().getIntersection (r)); - - if (! clipped.isEmpty()) - fillShape (new RectangleListRegionType (clipped), false); - } - } - - void fillTargetRect (const Rectangle& r) - { - if (fillType.isColour()) - { - clip->fillRectWithColour (getThis(), r, fillType.colour.getPixelARGB()); - } - else - { - const Rectangle clipped (clip->getClipBounds().toFloat().getIntersection (r)); - - if (! clipped.isEmpty()) - fillShape (new EdgeTableRegionType (clipped), false); - } - } - - template - void fillRectAsPath (const Rectangle& r) - { - Path p; - p.addRectangle (r); - fillPath (p, AffineTransform()); - } - - void fillRect (const Rectangle& r, const bool replaceContents) - { - if (clip != nullptr) - { - if (transform.isOnlyTranslated) - { - fillTargetRect (transform.translated (r), replaceContents); - } - else if (! transform.isRotated) - { - fillTargetRect (transform.transformed (r), replaceContents); - } - else - { - jassert (! replaceContents); // not implemented.. - fillRectAsPath (r); - } - } - } - - void fillRect (const Rectangle& r) - { - if (clip != nullptr) - { - if (transform.isOnlyTranslated) - fillTargetRect (transform.translated (r)); - else if (! transform.isRotated) - fillTargetRect (transform.transformed (r)); - else - fillRectAsPath (r); - } - } - - void fillRectList (const RectangleList& list) - { - if (clip != nullptr) - { - if (! transform.isRotated) - { - RectangleList transformed (list); - - if (transform.isOnlyTranslated) - transformed.offsetAll (transform.offset.toFloat()); - else - transformed.transformAll (transform.getTransform()); - - fillShape (new EdgeTableRegionType (transformed), false); - } - else - { - fillPath (list.toPath(), AffineTransform()); - } - } - } - - void fillPath (const Path& path, const AffineTransform& t) - { - if (clip != nullptr) - { - const AffineTransform trans (transform.getTransformWith (t)); - const Rectangle clipRect (clip->getClipBounds()); - - if (path.getBoundsTransformed (trans).getSmallestIntegerContainer().intersects (clipRect)) - fillShape (new EdgeTableRegionType (clipRect, path, trans), false); - } - } - - void fillEdgeTable (const EdgeTable& edgeTable, const float x, const int y) - { - if (clip != nullptr) - { - EdgeTableRegionType* edgeTableClip = new EdgeTableRegionType (edgeTable); - edgeTableClip->edgeTable.translate (x, y); - - if (fillType.isColour()) - { - float brightness = fillType.colour.getBrightness() - 0.5f; - - if (brightness > 0.0f) - edgeTableClip->edgeTable.multiplyLevels (1.0f + 1.6f * brightness); - } - - fillShape (edgeTableClip, false); - } - } - - void drawLine (Line line) - { - Path p; - p.addLineSegment (line, 1.0f); - fillPath (p, {}); - } - - void drawImage (const Image& sourceImage, const AffineTransform& trans) - { - if (clip != nullptr && ! fillType.colour.isTransparent()) - renderImage (sourceImage, trans, nullptr); - } - - static bool isOnlyTranslationAllowingError (const AffineTransform& t) - { - return (std::abs (t.mat01) < 0.002) - && (std::abs (t.mat10) < 0.002) - && (std::abs (t.mat00 - 1.0f) < 0.002) - && (std::abs (t.mat11 - 1.0f) < 0.002); - } - - void renderImage (const Image& sourceImage, const AffineTransform& trans, - const BaseRegionType* const tiledFillClipRegion) - { - auto t = transform.getTransformWith (trans); - - const int alpha = fillType.colour.getAlpha(); - - if (isOnlyTranslationAllowingError (t)) - { - // If our translation doesn't involve any distortion, just use a simple blit.. - int tx = (int) (t.getTranslationX() * 256.0f); - int ty = (int) (t.getTranslationY() * 256.0f); - - if (interpolationQuality == Graphics::lowResamplingQuality || ((tx | ty) & 224) == 0) - { - tx = ((tx + 128) >> 8); - ty = ((ty + 128) >> 8); - - if (tiledFillClipRegion != nullptr) - { - tiledFillClipRegion->renderImageUntransformed (getThis(), sourceImage, alpha, tx, ty, true); - } - else - { - Rectangle area (tx, ty, sourceImage.getWidth(), sourceImage.getHeight()); - area = area.getIntersection (getThis().getMaximumBounds()); - - if (! area.isEmpty()) - if (typename BaseRegionType::Ptr c = clip->applyClipTo (new EdgeTableRegionType (area))) - c->renderImageUntransformed (getThis(), sourceImage, alpha, tx, ty, false); - } - - return; - } - } - - if (! t.isSingularity()) - { - if (tiledFillClipRegion != nullptr) - { - tiledFillClipRegion->renderImageTransformed (getThis(), sourceImage, alpha, - t, interpolationQuality, true); - } - else - { - Path p; - p.addRectangle (sourceImage.getBounds()); - - if (auto c = clip->clone()->clipToPath (p, t)) - c->renderImageTransformed (getThis(), sourceImage, alpha, - t, interpolationQuality, false); - } - } - } - - void fillShape (typename BaseRegionType::Ptr shapeToFill, const bool replaceContents) - { - jassert (clip != nullptr); - - shapeToFill = clip->applyClipTo (shapeToFill); - - if (shapeToFill != nullptr) - { - if (fillType.isGradient()) - { - jassert (! replaceContents); // that option is just for solid colours - - ColourGradient g2 (*(fillType.gradient)); - g2.multiplyOpacity (fillType.getOpacity()); - auto t = transform.getTransformWith (fillType.transform).translated (-0.5f, -0.5f); - - const bool isIdentity = t.isOnlyTranslation(); - - if (isIdentity) - { - // If our translation doesn't involve any distortion, we can speed it up.. - g2.point1.applyTransform (t); - g2.point2.applyTransform (t); - t = AffineTransform(); - } - - shapeToFill->fillAllWithGradient (getThis(), g2, t, isIdentity); - } - else if (fillType.isTiledImage()) - { - renderImage (fillType.image, fillType.transform, shapeToFill); - } - else - { - shapeToFill->fillAllWithColour (getThis(), fillType.colour.getPixelARGB(), replaceContents); - } - } - } - - void cloneClipIfMultiplyReferenced() - { - if (clip->getReferenceCount() > 1) - clip = clip->clone(); - } - - typename BaseRegionType::Ptr clip; - RenderingHelpers::TranslationOrTransform transform; - FillType fillType; - Graphics::ResamplingQuality interpolationQuality; - float transparencyLayerAlpha; -}; - -//============================================================================== -class SoftwareRendererSavedState : public SavedStateBase -{ - typedef SavedStateBase BaseClass; - -public: - SoftwareRendererSavedState (const Image& im, const Rectangle& clipBounds) - : BaseClass (clipBounds), image (im) - { - } - - SoftwareRendererSavedState (const Image& im, const RectangleList& clipList, Point origin) - : BaseClass (clipList, origin), image (im) - { - } - - SoftwareRendererSavedState (const SoftwareRendererSavedState& other) - : BaseClass (other), image (other.image), font (other.font) - { - } - - SoftwareRendererSavedState* beginTransparencyLayer (float opacity) - { - SoftwareRendererSavedState* s = new SoftwareRendererSavedState (*this); - - if (clip != nullptr) - { - const Rectangle layerBounds (clip->getClipBounds()); - - s->image = Image (Image::ARGB, layerBounds.getWidth(), layerBounds.getHeight(), true); - s->transparencyLayerAlpha = opacity; - s->transform.moveOriginInDeviceSpace (-layerBounds.getPosition()); - s->cloneClipIfMultiplyReferenced(); - s->clip->translate (-layerBounds.getPosition()); - } - - return s; - } - - void endTransparencyLayer (SoftwareRendererSavedState& finishedLayerState) - { - if (clip != nullptr) - { - const Rectangle layerBounds (clip->getClipBounds()); - - const ScopedPointer g (image.createLowLevelContext()); - g->setOpacity (finishedLayerState.transparencyLayerAlpha); - g->drawImage (finishedLayerState.image, AffineTransform::translation (layerBounds.getPosition())); - } - } - - typedef GlyphCache, SoftwareRendererSavedState> GlyphCacheType; - - static void clearGlyphCache() - { - GlyphCacheType::getInstance().reset(); - } - - //============================================================================== - void drawGlyph (int glyphNumber, const AffineTransform& trans) - { - if (clip != nullptr) - { - if (trans.isOnlyTranslation() && ! transform.isRotated) - { - GlyphCacheType& cache = GlyphCacheType::getInstance(); - - Point pos (trans.getTranslationX(), trans.getTranslationY()); - - if (transform.isOnlyTranslated) - { - cache.drawGlyph (*this, font, glyphNumber, pos + transform.offset.toFloat()); - } - else - { - pos = transform.transformed (pos); - - Font f (font); - f.setHeight (font.getHeight() * transform.complexTransform.mat11); - - const float xScale = transform.complexTransform.mat00 / transform.complexTransform.mat11; - if (std::abs (xScale - 1.0f) > 0.01f) - f.setHorizontalScale (xScale); - - cache.drawGlyph (*this, f, glyphNumber, pos); - } - } - else - { - const float fontHeight = font.getHeight(); - - AffineTransform t (transform.getTransformWith (AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight) - .followedBy (trans))); - - const ScopedPointer et (font.getTypeface()->getEdgeTableForGlyph (glyphNumber, t, fontHeight)); - - if (et != nullptr) - fillShape (new EdgeTableRegionType (*et), false); - } - } - } - - Rectangle getMaximumBounds() const { return image.getBounds(); } - - //============================================================================== - template - void renderImageTransformed (IteratorType& iter, const Image& src, const int alpha, const AffineTransform& trans, Graphics::ResamplingQuality quality, bool tiledFill) const - { - Image::BitmapData destData (image, Image::BitmapData::readWrite); - const Image::BitmapData srcData (src, Image::BitmapData::readOnly); - EdgeTableFillers::renderImageTransformed (iter, destData, srcData, alpha, trans, quality, tiledFill); - } - - template - void renderImageUntransformed (IteratorType& iter, const Image& src, const int alpha, int x, int y, bool tiledFill) const - { - Image::BitmapData destData (image, Image::BitmapData::readWrite); - const Image::BitmapData srcData (src, Image::BitmapData::readOnly); - EdgeTableFillers::renderImageUntransformed (iter, destData, srcData, alpha, x, y, tiledFill); - } - - template - void fillWithSolidColour (IteratorType& iter, const PixelARGB colour, bool replaceContents) const - { - Image::BitmapData destData (image, Image::BitmapData::readWrite); - - switch (destData.pixelFormat) - { - case Image::ARGB: EdgeTableFillers::renderSolidFill (iter, destData, colour, replaceContents, (PixelARGB*) 0); break; - case Image::RGB: EdgeTableFillers::renderSolidFill (iter, destData, colour, replaceContents, (PixelRGB*) 0); break; - default: EdgeTableFillers::renderSolidFill (iter, destData, colour, replaceContents, (PixelAlpha*) 0); break; - } - } - - template - void fillWithGradient (IteratorType& iter, ColourGradient& gradient, const AffineTransform& trans, bool isIdentity) const - { - HeapBlock lookupTable; - const int numLookupEntries = gradient.createLookupTable (trans, lookupTable); - jassert (numLookupEntries > 0); - - Image::BitmapData destData (image, Image::BitmapData::readWrite); - - switch (destData.pixelFormat) - { - case Image::ARGB: EdgeTableFillers::renderGradient (iter, destData, gradient, trans, lookupTable, numLookupEntries, isIdentity, (PixelARGB*) 0); break; - case Image::RGB: EdgeTableFillers::renderGradient (iter, destData, gradient, trans, lookupTable, numLookupEntries, isIdentity, (PixelRGB*) 0); break; - default: EdgeTableFillers::renderGradient (iter, destData, gradient, trans, lookupTable, numLookupEntries, isIdentity, (PixelAlpha*) 0); break; - } - } - - //============================================================================== - Image image; - Font font; - -private: - SoftwareRendererSavedState& operator= (const SoftwareRendererSavedState&); -}; - -//============================================================================== -template -class SavedStateStack -{ -public: - SavedStateStack (StateObjectType* const initialState) noexcept - : currentState (initialState) - {} - - SavedStateStack() noexcept {} - - void initialise (StateObjectType* state) - { - currentState = state; - } - - inline StateObjectType* operator->() const noexcept { return currentState; } - inline StateObjectType& operator*() const noexcept { return *currentState; } - - void save() - { - stack.add (new StateObjectType (*currentState)); - } - - void restore() - { - if (StateObjectType* const top = stack.getLast()) - { - currentState = top; - stack.removeLast (1, false); - } - else - { - jassertfalse; // trying to pop with an empty stack! - } - } - - void beginTransparencyLayer (float opacity) - { - save(); - currentState = currentState->beginTransparencyLayer (opacity); - } - - void endTransparencyLayer() - { - const ScopedPointer finishedTransparencyLayer (currentState); - restore(); - currentState->endTransparencyLayer (*finishedTransparencyLayer); - } - -private: - ScopedPointer currentState; - OwnedArray stack; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SavedStateStack) -}; - -//============================================================================== -template -class StackBasedLowLevelGraphicsContext : public LowLevelGraphicsContext -{ -public: - bool isVectorDevice() const override { return false; } - void setOrigin (Point o) override { stack->transform.setOrigin (o); } - void addTransform (const AffineTransform& t) override { stack->transform.addTransform (t); } - float getPhysicalPixelScaleFactor() override { return stack->transform.getPhysicalPixelScaleFactor(); } - Rectangle getClipBounds() const override { return stack->getClipBounds(); } - bool isClipEmpty() const override { return stack->clip == nullptr; } - bool clipRegionIntersects (const Rectangle& r) override { return stack->clipRegionIntersects (r); } - bool clipToRectangle (const Rectangle& r) override { return stack->clipToRectangle (r); } - bool clipToRectangleList (const RectangleList& r) override { return stack->clipToRectangleList (r); } - void excludeClipRectangle (const Rectangle& r) override { stack->excludeClipRectangle (r); } - void clipToPath (const Path& path, const AffineTransform& t) override { stack->clipToPath (path, t); } - void clipToImageAlpha (const Image& im, const AffineTransform& t) override { stack->clipToImageAlpha (im, t); } - void saveState() override { stack.save(); } - void restoreState() override { stack.restore(); } - void beginTransparencyLayer (float opacity) override { stack.beginTransparencyLayer (opacity); } - void endTransparencyLayer() override { stack.endTransparencyLayer(); } - void setFill (const FillType& fillType) override { stack->setFillType (fillType); } - void setOpacity (float newOpacity) override { stack->fillType.setOpacity (newOpacity); } - void setInterpolationQuality (Graphics::ResamplingQuality quality) override { stack->interpolationQuality = quality; } - void fillRect (const Rectangle& r, bool replace) override { stack->fillRect (r, replace); } - void fillRect (const Rectangle& r) override { stack->fillRect (r); } - void fillRectList (const RectangleList& list) override { stack->fillRectList (list); } - void fillPath (const Path& path, const AffineTransform& t) override { stack->fillPath (path, t); } - void drawImage (const Image& im, const AffineTransform& t) override { stack->drawImage (im, t); } - void drawGlyph (int glyphNumber, const AffineTransform& t) override { stack->drawGlyph (glyphNumber, t); } - void drawLine (const Line& line) override { stack->drawLine (line); } - void setFont (const Font& newFont) override { stack->font = newFont; } - const Font& getFont() override { return stack->font; } - -protected: - StackBasedLowLevelGraphicsContext (SavedStateType* initialState) : stack (initialState) {} - StackBasedLowLevelGraphicsContext() {} - - RenderingHelpers::SavedStateStack stack; -}; - -} - -#if JUCE_MSVC - #pragma warning (pop) -#endif - -} // namespace juce diff --git a/source/modules/juce_graphics/native/juce_android_Fonts.cpp b/source/modules/juce_graphics/native/juce_android_Fonts.cpp deleted file mode 100644 index a5ffa6b7d..000000000 --- a/source/modules/juce_graphics/native/juce_android_Fonts.cpp +++ /dev/null @@ -1,409 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -struct DefaultFontNames -{ - DefaultFontNames() - : defaultSans ("sans"), - defaultSerif ("serif"), - defaultFixed ("monospace"), - defaultFallback ("sans") - { - } - - String getRealFontName (const String& faceName) const - { - if (faceName == Font::getDefaultSansSerifFontName()) return defaultSans; - if (faceName == Font::getDefaultSerifFontName()) return defaultSerif; - if (faceName == Font::getDefaultMonospacedFontName()) return defaultFixed; - - return faceName; - } - - String defaultSans, defaultSerif, defaultFixed, defaultFallback; -}; - -Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font) -{ - static DefaultFontNames defaultNames; - - Font f (font); - f.setTypefaceName (defaultNames.getRealFontName (font.getTypefaceName())); - return Typeface::createSystemTypefaceFor (f); -} - -//============================================================================== -#if JUCE_USE_FREETYPE - -StringArray FTTypefaceList::getDefaultFontDirectories() -{ - return StringArray ("/system/fonts"); -} - -Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font) -{ - return new FreeTypeTypeface (font); -} - -void Typeface::scanFolderForFonts (const File& folder) -{ - FTTypefaceList::getInstance()->scanFontPaths (StringArray (folder.getFullPathName())); -} - -StringArray Font::findAllTypefaceNames() -{ - return FTTypefaceList::getInstance()->findAllFamilyNames(); -} - -StringArray Font::findAllTypefaceStyles (const String& family) -{ - return FTTypefaceList::getInstance()->findAllTypefaceStyles (family); -} - -bool TextLayout::createNativeLayout (const AttributedString&) -{ - return false; -} - -#else - -//============================================================================== -#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ - STATICMETHOD (create, "create", "(Ljava/lang/String;I)Landroid/graphics/Typeface;") \ - STATICMETHOD (createFromFile, "createFromFile", "(Ljava/lang/String;)Landroid/graphics/Typeface;") \ - -DECLARE_JNI_CLASS (TypefaceClass, "android/graphics/Typeface"); -#undef JNI_CLASS_MEMBERS - -//============================================================================== -StringArray Font::findAllTypefaceNames() -{ - StringArray results; - - Array fonts; - File ("/system/fonts").findChildFiles (fonts, File::findFiles, false, "*.ttf"); - - for (int i = 0; i < fonts.size(); ++i) - results.addIfNotAlreadyThere (fonts.getReference(i).getFileNameWithoutExtension() - .upToLastOccurrenceOf ("-", false, false)); - - return results; -} - -StringArray Font::findAllTypefaceStyles (const String& family) -{ - StringArray results ("Regular"); - - Array fonts; - File ("/system/fonts").findChildFiles (fonts, File::findFiles, false, family + "-*.ttf"); - - for (int i = 0; i < fonts.size(); ++i) - results.addIfNotAlreadyThere (fonts.getReference(i).getFileNameWithoutExtension() - .fromLastOccurrenceOf ("-", false, false)); - - return results; -} - -const float referenceFontSize = 256.0f; -const float referenceFontToUnits = 1.0f / referenceFontSize; - -//============================================================================== -class AndroidTypeface : public Typeface -{ -public: - AndroidTypeface (const Font& font) - : Typeface (font.getTypefaceName(), font.getTypefaceStyle()), - ascent (0), descent (0), heightToPointsFactor (1.0f) - { - JNIEnv* const env = getEnv(); - - // First check whether there's an embedded asset with this font name: - typeface = GlobalRef (android.activity.callObjectMethod (JuceAppActivity.getTypeFaceFromAsset, - javaString ("fonts/" + name).get())); - - if (typeface.get() == nullptr) - { - const bool isBold = style.contains ("Bold"); - const bool isItalic = style.contains ("Italic"); - - File fontFile (getFontFile (name, style)); - - if (! fontFile.exists()) - fontFile = findFontFile (name, isBold, isItalic); - - if (fontFile.exists()) - typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.createFromFile, - javaString (fontFile.getFullPathName()).get())); - else - typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.create, - javaString (getName()).get(), - (isBold ? 1 : 0) + (isItalic ? 2 : 0))); - } - - initialise (env); - } - - AndroidTypeface (const void* data, size_t size) - : Typeface (String (static_cast (reinterpret_cast (data))), String()) - { - JNIEnv* const env = getEnv(); - - LocalRef bytes (env->NewByteArray ((jsize) size)); - env->SetByteArrayRegion (bytes, 0, (jsize) size, (const jbyte*) data); - - typeface = GlobalRef (android.activity.callObjectMethod (JuceAppActivity.getTypeFaceFromByteArray, bytes.get())); - - initialise (env); - } - - void initialise (JNIEnv* const env) - { - rect = GlobalRef (env->NewObject (RectClass, RectClass.constructor, 0, 0, 0, 0)); - - paint = GlobalRef (GraphicsHelpers::createPaint (Graphics::highResamplingQuality)); - const LocalRef ignored (paint.callObjectMethod (Paint.setTypeface, typeface.get())); - - paint.callVoidMethod (Paint.setTextSize, referenceFontSize); - - const float fullAscent = std::abs (paint.callFloatMethod (Paint.ascent)); - const float fullDescent = paint.callFloatMethod (Paint.descent); - const float totalHeight = fullAscent + fullDescent; - - ascent = fullAscent / totalHeight; - descent = fullDescent / totalHeight; - heightToPointsFactor = referenceFontSize / totalHeight; - } - - float getAscent() const override { return ascent; } - float getDescent() const override { return descent; } - float getHeightToPointsFactor() const override { return heightToPointsFactor; } - - float getStringWidth (const String& text) override - { - JNIEnv* env = getEnv(); - const int numChars = text.length(); - jfloatArray widths = env->NewFloatArray (numChars); - - const int numDone = paint.callIntMethod (Paint.getTextWidths, javaString (text).get(), widths); - - HeapBlock localWidths (static_cast (numDone)); - env->GetFloatArrayRegion (widths, 0, numDone, localWidths); - env->DeleteLocalRef (widths); - - float x = 0; - for (int i = 0; i < numDone; ++i) - x += localWidths[i]; - - return x * referenceFontToUnits; - } - - void getGlyphPositions (const String& text, Array& glyphs, Array& xOffsets) override - { - JNIEnv* env = getEnv(); - const int numChars = text.length(); - jfloatArray widths = env->NewFloatArray (numChars); - - const int numDone = paint.callIntMethod (Paint.getTextWidths, javaString (text).get(), widths); - - HeapBlock localWidths (static_cast (numDone)); - env->GetFloatArrayRegion (widths, 0, numDone, localWidths); - env->DeleteLocalRef (widths); - - String::CharPointerType s (text.getCharPointer()); - - xOffsets.add (0); - - float x = 0; - for (int i = 0; i < numDone; ++i) - { - const float local = localWidths[i]; - - // Android uses jchar (UTF-16) characters - jchar ch = (jchar) s.getAndAdvance(); - - // Android has no proper glyph support, so we have to do - // a hacky workaround for ligature detection - - #if JUCE_STRING_UTF_TYPE <= 16 - static_assert (sizeof (int) >= (sizeof (jchar) * 2), "Unable store two java chars in one glyph"); - - // if the width of this glyph is zero inside the string but has - // a width on it's own, then it's probably due to ligature - if (local == 0.0f && glyphs.size() > 0 && getStringWidth (String (ch)) > 0.0f) - { - // modify the previous glyph - int& glyphNumber = glyphs.getReference (glyphs.size() - 1); - - // make sure this is not a three character ligature - if (glyphNumber < std::numeric_limits::max()) - { - const unsigned int previousGlyph - = static_cast (glyphNumber) & ((1U << (sizeof (jchar) * 8U)) - 1U); - const unsigned int thisGlyph - = static_cast (ch) & ((1U << (sizeof (jchar) * 8U)) - 1U); - - glyphNumber = static_cast ((thisGlyph << (sizeof (jchar) * 8U)) | previousGlyph); - ch = 0; - } - } - #endif - - glyphs.add ((int) ch); - x += local; - xOffsets.add (x * referenceFontToUnits); - } - } - - bool getOutlineForGlyph (int /*glyphNumber*/, Path& /*destPath*/) override - { - return false; - } - - EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& t, float /*fontHeight*/) override - { - #if JUCE_STRING_UTF_TYPE <= 16 - static_assert (sizeof (int) >= (sizeof (jchar) * 2), "Unable store two jni chars in one int"); - - // glyphNumber of zero is used to indicate that the last character was a ligature - if (glyphNumber == 0) return nullptr; - - jchar ch1 = (static_cast (glyphNumber) >> 0) & ((1U << (sizeof (jchar) * 8U)) - 1U); - jchar ch2 = (static_cast (glyphNumber) >> (sizeof (jchar) * 8U)) & ((1U << (sizeof (jchar) * 8U)) - 1U); - #else - jchar ch1 = glyphNumber, ch2 = 0; - #endif - - JNIEnv* env = getEnv(); - - jobject matrix = GraphicsHelpers::createMatrix (env, AffineTransform::scale (referenceFontToUnits).followedBy (t)); - jintArray maskData = (jintArray) android.activity.callObjectMethod (JuceAppActivity.renderGlyph, ch1, ch2, paint.get(), matrix, rect.get()); - - env->DeleteLocalRef (matrix); - - const int left = env->GetIntField (rect.get(), RectClass.left); - const int top = env->GetIntField (rect.get(), RectClass.top); - const int right = env->GetIntField (rect.get(), RectClass.right); - const int bottom = env->GetIntField (rect.get(), RectClass.bottom); - - const Rectangle bounds (left, top, right - left, bottom - top); - - EdgeTable* et = nullptr; - - if (! bounds.isEmpty()) - { - et = new EdgeTable (bounds); - - jint* const maskDataElements = env->GetIntArrayElements (maskData, 0); - const jint* mask = maskDataElements; - - for (int y = top; y < bottom; ++y) - { - #if JUCE_LITTLE_ENDIAN - const uint8* const lineBytes = ((const uint8*) mask) + 3; - #else - const uint8* const lineBytes = (const uint8*) mask; - #endif - - et->clipLineToMask (left, y, lineBytes, 4, bounds.getWidth()); - mask += bounds.getWidth(); - } - - env->ReleaseIntArrayElements (maskData, maskDataElements, 0); - } - - env->DeleteLocalRef (maskData); - return et; - } - - GlobalRef typeface, paint, rect; - float ascent, descent, heightToPointsFactor; - -private: - static File findFontFile (const String& family, - const bool bold, const bool italic) - { - File file; - - if (bold || italic) - { - String suffix; - if (bold) suffix = "Bold"; - if (italic) suffix << "Italic"; - - file = getFontFile (family, suffix); - - if (file.exists()) - return file; - } - - file = getFontFile (family, "Regular"); - - if (! file.exists()) - file = getFontFile (family, String()); - - return file; - } - - static File getFontFile (const String& family, const String& style) - { - String path ("/system/fonts/" + family); - - if (style.isNotEmpty()) - path << '-' << style; - - return File (path + ".ttf"); - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidTypeface) -}; - -//============================================================================== -Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font) -{ - return new AndroidTypeface (font); -} - -Typeface::Ptr Typeface::createSystemTypefaceFor (const void* data, size_t size) -{ - return new AndroidTypeface (data, size); -} - -void Typeface::scanFolderForFonts (const File&) -{ - jassertfalse; // not available unless using FreeType -} - -bool TextLayout::createNativeLayout (const AttributedString&) -{ - return false; -} - -#endif - -} // namespace juce diff --git a/source/modules/juce_graphics/native/juce_android_GraphicsContext.cpp b/source/modules/juce_graphics/native/juce_android_GraphicsContext.cpp deleted file mode 100644 index 77dabe2e3..000000000 --- a/source/modules/juce_graphics/native/juce_android_GraphicsContext.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -namespace GraphicsHelpers -{ - jobject createPaint (Graphics::ResamplingQuality quality) - { - jint constructorFlags = 1 /*ANTI_ALIAS_FLAG*/ - | 4 /*DITHER_FLAG*/ - | 128 /*SUBPIXEL_TEXT_FLAG*/; - - if (quality > Graphics::lowResamplingQuality) - constructorFlags |= 2; /*FILTER_BITMAP_FLAG*/ - - return getEnv()->NewObject (Paint, Paint.constructor, constructorFlags); - } - - const jobject createMatrix (JNIEnv* env, const AffineTransform& t) - { - jobject m = env->NewObject (Matrix, Matrix.constructor); - - jfloat values[9] = { t.mat00, t.mat01, t.mat02, - t.mat10, t.mat11, t.mat12, - 0.0f, 0.0f, 1.0f }; - - jfloatArray javaArray = env->NewFloatArray (9); - env->SetFloatArrayRegion (javaArray, 0, 9, values); - - env->CallVoidMethod (m, Matrix.setValues, javaArray); - env->DeleteLocalRef (javaArray); - - return m; - } -} - -ImagePixelData::Ptr NativeImageType::create (Image::PixelFormat format, int width, int height, bool clearImage) const -{ - return SoftwareImageType().create (format, width, height, clearImage); -} - -} // namespace juce diff --git a/source/modules/juce_graphics/native/juce_android_IconHelpers.cpp b/source/modules/juce_graphics/native/juce_android_IconHelpers.cpp deleted file mode 100644 index 3a11f8e34..000000000 --- a/source/modules/juce_graphics/native/juce_android_IconHelpers.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - Image JUCE_API getIconFromApplication (const String&, int) { return {}; } -} diff --git a/source/modules/juce_graphics/native/juce_freetype_Fonts.cpp b/source/modules/juce_graphics/native/juce_freetype_Fonts.cpp deleted file mode 100644 index a813ec61b..000000000 --- a/source/modules/juce_graphics/native/juce_freetype_Fonts.cpp +++ /dev/null @@ -1,462 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -struct FTLibWrapper : public ReferenceCountedObject -{ - FTLibWrapper() : library (0) - { - if (FT_Init_FreeType (&library) != 0) - { - library = 0; - DBG ("Failed to initialize FreeType"); - } - } - - ~FTLibWrapper() - { - if (library != 0) - FT_Done_FreeType (library); - } - - FT_Library library; - - typedef ReferenceCountedObjectPtr Ptr; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FTLibWrapper) -}; - -//============================================================================== -struct FTFaceWrapper : public ReferenceCountedObject -{ - FTFaceWrapper (const FTLibWrapper::Ptr& ftLib, const File& file, int faceIndex) - : face (0), library (ftLib) - { - if (FT_New_Face (ftLib->library, file.getFullPathName().toUTF8(), faceIndex, &face) != 0) - face = 0; - } - - FTFaceWrapper (const FTLibWrapper::Ptr& ftLib, const void* data, size_t dataSize, int faceIndex) - : face (0), library (ftLib), savedFaceData (data, dataSize) - { - if (FT_New_Memory_Face (ftLib->library, (const FT_Byte*) savedFaceData.getData(), - (FT_Long) savedFaceData.getSize(), faceIndex, &face) != 0) - face = 0; - } - - ~FTFaceWrapper() - { - if (face != 0) - FT_Done_Face (face); - } - - FT_Face face; - FTLibWrapper::Ptr library; - MemoryBlock savedFaceData; - - typedef ReferenceCountedObjectPtr Ptr; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FTFaceWrapper) -}; - -//============================================================================== -class FTTypefaceList : private DeletedAtShutdown -{ -public: - FTTypefaceList() : library (new FTLibWrapper()) - { - scanFontPaths (getDefaultFontDirectories()); - } - - ~FTTypefaceList() - { - clearSingletonInstance(); - } - - //============================================================================== - struct KnownTypeface - { - KnownTypeface (const File& f, const int index, const FTFaceWrapper& face) - : file (f), - family (face.face->family_name), - style (face.face->style_name), - faceIndex (index), - isMonospaced ((face.face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0), - isSansSerif (isFaceSansSerif (family)) - { - } - - const File file; - const String family, style; - const int faceIndex; - const bool isMonospaced, isSansSerif; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (KnownTypeface) - }; - - //============================================================================== - static FTFaceWrapper::Ptr selectUnicodeCharmap (FTFaceWrapper* face) - { - if (face != nullptr) - if (FT_Select_Charmap (face->face, ft_encoding_unicode) != 0) - FT_Set_Charmap (face->face, face->face->charmaps[0]); - - return face; - } - - FTFaceWrapper::Ptr createFace (const void* data, size_t dataSize, int index) - { - return selectUnicodeCharmap (new FTFaceWrapper (library, data, dataSize, index)); - } - - FTFaceWrapper::Ptr createFace (const File& file, int index) - { - return selectUnicodeCharmap (new FTFaceWrapper (library, file, index)); - } - - FTFaceWrapper::Ptr createFace (const String& fontName, const String& fontStyle) - { - const KnownTypeface* ftFace = matchTypeface (fontName, fontStyle); - - if (ftFace == nullptr) ftFace = matchTypeface (fontName, "Regular"); - if (ftFace == nullptr) ftFace = matchTypeface (fontName, String()); - - if (ftFace != nullptr) - return createFace (ftFace->file, ftFace->faceIndex); - - return nullptr; - } - - //============================================================================== - StringArray findAllFamilyNames() const - { - StringArray s; - - for (int i = 0; i < faces.size(); ++i) - s.addIfNotAlreadyThere (faces.getUnchecked(i)->family); - - return s; - } - - static int indexOfRegularStyle (const StringArray& styles) - { - int i = styles.indexOf ("Regular", true); - - if (i < 0) - for (i = 0; i < styles.size(); ++i) - if (! (styles[i].containsIgnoreCase ("Bold") || styles[i].containsIgnoreCase ("Italic"))) - break; - - return i; - } - - StringArray findAllTypefaceStyles (const String& family) const - { - StringArray s; - - for (int i = 0; i < faces.size(); ++i) - { - const KnownTypeface* const face = faces.getUnchecked(i); - - if (face->family == family) - s.addIfNotAlreadyThere (face->style); - } - - // try to get a regular style to be first in the list - const int regular = indexOfRegularStyle (s); - if (regular > 0) - s.strings.swap (0, regular); - - return s; - } - - void scanFontPaths (const StringArray& paths) - { - for (int i = 0; i < paths.size(); ++i) - { - DirectoryIterator iter (File::getCurrentWorkingDirectory() - .getChildFile (paths[i]), true); - - while (iter.next()) - if (iter.getFile().hasFileExtension ("ttf;pfb;pcf;otf")) - scanFont (iter.getFile()); - } - } - - void getMonospacedNames (StringArray& monoSpaced) const - { - for (int i = 0; i < faces.size(); ++i) - if (faces.getUnchecked(i)->isMonospaced) - monoSpaced.addIfNotAlreadyThere (faces.getUnchecked(i)->family); - } - - void getSerifNames (StringArray& serif) const - { - for (int i = 0; i < faces.size(); ++i) - if (! faces.getUnchecked(i)->isSansSerif) - serif.addIfNotAlreadyThere (faces.getUnchecked(i)->family); - } - - void getSansSerifNames (StringArray& sansSerif) const - { - for (int i = 0; i < faces.size(); ++i) - if (faces.getUnchecked(i)->isSansSerif) - sansSerif.addIfNotAlreadyThere (faces.getUnchecked(i)->family); - } - - juce_DeclareSingleton_SingleThreaded_Minimal (FTTypefaceList) - -private: - FTLibWrapper::Ptr library; - OwnedArray faces; - - static StringArray getDefaultFontDirectories(); - - void scanFont (const File& file) - { - int faceIndex = 0; - int numFaces = 0; - - do - { - FTFaceWrapper face (library, file, faceIndex); - - if (face.face != 0) - { - if (faceIndex == 0) - numFaces = (int) face.face->num_faces; - - if ((face.face->face_flags & FT_FACE_FLAG_SCALABLE) != 0) - faces.add (new KnownTypeface (file, faceIndex, face)); - } - - ++faceIndex; - } - while (faceIndex < numFaces); - } - - const KnownTypeface* matchTypeface (const String& familyName, const String& style) const noexcept - { - for (int i = 0; i < faces.size(); ++i) - { - const KnownTypeface* const face = faces.getUnchecked(i); - - if (face->family == familyName - && (face->style.equalsIgnoreCase (style) || style.isEmpty())) - return face; - } - - return nullptr; - } - - static bool isFaceSansSerif (const String& family) - { - static const char* sansNames[] = { "Sans", "Verdana", "Arial", "Ubuntu" }; - - for (int i = 0; i < numElementsInArray (sansNames); ++i) - if (family.containsIgnoreCase (sansNames[i])) - return true; - - return false; - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FTTypefaceList) -}; - -juce_ImplementSingleton_SingleThreaded (FTTypefaceList) - - -//============================================================================== -class FreeTypeTypeface : public CustomTypeface -{ -public: - FreeTypeTypeface (const Font& font) - : faceWrapper (FTTypefaceList::getInstance()->createFace (font.getTypefaceName(), - font.getTypefaceStyle())) - { - if (faceWrapper != nullptr) - initialiseCharacteristics (font.getTypefaceName(), - font.getTypefaceStyle()); - } - - FreeTypeTypeface (const void* data, size_t dataSize) - : faceWrapper (FTTypefaceList::getInstance()->createFace (data, dataSize, 0)) - { - if (faceWrapper != nullptr) - initialiseCharacteristics (faceWrapper->face->family_name, - faceWrapper->face->style_name); - } - - void initialiseCharacteristics (const String& fontName, const String& fontStyle) - { - setCharacteristics (fontName, fontStyle, - faceWrapper->face->ascender / (float) (faceWrapper->face->ascender - faceWrapper->face->descender), - L' '); - } - - bool loadGlyphIfPossible (const juce_wchar character) - { - if (faceWrapper != nullptr) - { - FT_Face face = faceWrapper->face; - const unsigned int glyphIndex = FT_Get_Char_Index (face, (FT_ULong) character); - - if (FT_Load_Glyph (face, glyphIndex, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM | FT_LOAD_NO_HINTING) == 0 - && face->glyph->format == ft_glyph_format_outline) - { - const float scale = 1.0f / (float) (face->ascender - face->descender); - Path destShape; - - if (getGlyphShape (destShape, face->glyph->outline, scale)) - { - addGlyph (character, destShape, face->glyph->metrics.horiAdvance * scale); - - if ((face->face_flags & FT_FACE_FLAG_KERNING) != 0) - addKerning (face, (uint32) character, glyphIndex); - - return true; - } - } - } - - return false; - } - -private: - FTFaceWrapper::Ptr faceWrapper; - - bool getGlyphShape (Path& destShape, const FT_Outline& outline, const float scaleX) - { - const float scaleY = -scaleX; - const short* const contours = outline.contours; - const char* const tags = outline.tags; - const FT_Vector* const points = outline.points; - - for (int c = 0; c < outline.n_contours; ++c) - { - const int startPoint = (c == 0) ? 0 : contours [c - 1] + 1; - const int endPoint = contours[c]; - - for (int p = startPoint; p <= endPoint; ++p) - { - const float x = scaleX * points[p].x; - const float y = scaleY * points[p].y; - - if (p == startPoint) - { - if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Conic) - { - float x2 = scaleX * points [endPoint].x; - float y2 = scaleY * points [endPoint].y; - - if (FT_CURVE_TAG (tags[endPoint]) != FT_Curve_Tag_On) - { - x2 = (x + x2) * 0.5f; - y2 = (y + y2) * 0.5f; - } - - destShape.startNewSubPath (x2, y2); - } - else - { - destShape.startNewSubPath (x, y); - } - } - - if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_On) - { - if (p != startPoint) - destShape.lineTo (x, y); - } - else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Conic) - { - const int nextIndex = (p == endPoint) ? startPoint : p + 1; - float x2 = scaleX * points [nextIndex].x; - float y2 = scaleY * points [nextIndex].y; - - if (FT_CURVE_TAG (tags [nextIndex]) == FT_Curve_Tag_Conic) - { - x2 = (x + x2) * 0.5f; - y2 = (y + y2) * 0.5f; - } - else - { - ++p; - } - - destShape.quadraticTo (x, y, x2, y2); - } - else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Cubic) - { - const int next1 = p + 1; - const int next2 = (p == (endPoint - 1)) ? startPoint : (p + 2); - - if (p >= endPoint - || FT_CURVE_TAG (tags[next1]) != FT_Curve_Tag_Cubic - || FT_CURVE_TAG (tags[next2]) != FT_Curve_Tag_On) - return false; - - const float x2 = scaleX * points [next1].x; - const float y2 = scaleY * points [next1].y; - const float x3 = scaleX * points [next2].x; - const float y3 = scaleY * points [next2].y; - - destShape.cubicTo (x, y, x2, y2, x3, y3); - p += 2; - } - } - - destShape.closeSubPath(); - } - - return true; - } - - void addKerning (FT_Face face, const uint32 character, const uint32 glyphIndex) - { - const float height = (float) (face->ascender - face->descender); - - uint32 rightGlyphIndex; - FT_ULong rightCharCode = FT_Get_First_Char (face, &rightGlyphIndex); - - while (rightGlyphIndex != 0) - { - FT_Vector kerning; - - if (FT_Get_Kerning (face, glyphIndex, rightGlyphIndex, ft_kerning_unscaled, &kerning) == 0 - && kerning.x != 0) - addKerningPair ((juce_wchar) character, (juce_wchar) rightCharCode, kerning.x / height); - - rightCharCode = FT_Get_Next_Char (face, rightCharCode, &rightGlyphIndex); - } - } - - JUCE_DECLARE_NON_COPYABLE (FreeTypeTypeface) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/native/juce_linux_Fonts.cpp b/source/modules/juce_graphics/native/juce_linux_Fonts.cpp deleted file mode 100644 index 06cd9401a..000000000 --- a/source/modules/juce_graphics/native/juce_linux_Fonts.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -static XmlElement* findFontsConfFile() -{ - static const char* pathsToSearch[] = { "/etc/fonts/fonts.conf", - "/usr/share/fonts/fonts.conf" }; - - for (auto* path : pathsToSearch) - if (auto* xml = XmlDocument::parse (File (path))) - return xml; - - return nullptr; -} - -StringArray FTTypefaceList::getDefaultFontDirectories() -{ - StringArray fontDirs; - - fontDirs.addTokens (String (CharPointer_UTF8 (getenv ("JUCE_FONT_PATH"))), ";,", ""); - fontDirs.removeEmptyStrings (true); - - if (fontDirs.isEmpty()) - { - if (ScopedPointer fontsInfo = findFontsConfFile()) - { - forEachXmlChildElementWithTagName (*fontsInfo, e, "dir") - { - auto fontPath = e->getAllSubText().trim(); - - if (fontPath.isNotEmpty()) - { - if (e->getStringAttribute ("prefix") == "xdg") - { - auto xdgDataHome = SystemStats::getEnvironmentVariable ("XDG_DATA_HOME", {}); - - if (xdgDataHome.trimStart().isEmpty()) - xdgDataHome = "~/.local/share"; - - fontPath = File (xdgDataHome).getChildFile (fontPath).getFullPathName(); - } - - fontDirs.add (fontPath); - } - } - } - } - - if (fontDirs.isEmpty()) - fontDirs.add ("/usr/X11R6/lib/X11/fonts"); - - fontDirs.removeDuplicates (false); - return fontDirs; -} - -Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font) -{ - return new FreeTypeTypeface (font); -} - -Typeface::Ptr Typeface::createSystemTypefaceFor (const void* data, size_t dataSize) -{ - return new FreeTypeTypeface (data, dataSize); -} - -void Typeface::scanFolderForFonts (const File& folder) -{ - FTTypefaceList::getInstance()->scanFontPaths (StringArray (folder.getFullPathName())); -} - -StringArray Font::findAllTypefaceNames() -{ - return FTTypefaceList::getInstance()->findAllFamilyNames(); -} - -StringArray Font::findAllTypefaceStyles (const String& family) -{ - return FTTypefaceList::getInstance()->findAllTypefaceStyles (family); -} - -bool TextLayout::createNativeLayout (const AttributedString&) -{ - return false; -} - -//============================================================================== -struct DefaultFontNames -{ - DefaultFontNames() - : defaultSans (getDefaultSansSerifFontName()), - defaultSerif (getDefaultSerifFontName()), - defaultFixed (getDefaultMonospacedFontName()) - { - } - - String getRealFontName (const String& faceName) const - { - if (faceName == Font::getDefaultSansSerifFontName()) return defaultSans; - if (faceName == Font::getDefaultSerifFontName()) return defaultSerif; - if (faceName == Font::getDefaultMonospacedFontName()) return defaultFixed; - - return faceName; - } - - String defaultSans, defaultSerif, defaultFixed; - -private: - static String pickBestFont (const StringArray& names, const char* const* choicesArray) - { - const StringArray choices (choicesArray); - - for (auto& choice : choices) - if (names.contains (choice, true)) - return choice; - - for (auto& choice : choices) - for (auto& name : names) - if (name.startsWithIgnoreCase (choice)) - return name; - - for (auto& choice : choices) - for (auto& name : names) - if (name.containsIgnoreCase (choice)) - return name; - - return names[0]; - } - - static String getDefaultSansSerifFontName() - { - StringArray allFonts; - FTTypefaceList::getInstance()->getSansSerifNames (allFonts); - - static const char* targets[] = { "Verdana", "Bitstream Vera Sans", "Luxi Sans", - "Liberation Sans", "DejaVu Sans", "Sans", nullptr }; - return pickBestFont (allFonts, targets); - } - - static String getDefaultSerifFontName() - { - StringArray allFonts; - FTTypefaceList::getInstance()->getSerifNames (allFonts); - - static const char* targets[] = { "Bitstream Vera Serif", "Times", "Nimbus Roman", - "Liberation Serif", "DejaVu Serif", "Serif", nullptr }; - return pickBestFont (allFonts, targets); - } - - static String getDefaultMonospacedFontName() - { - StringArray allFonts; - FTTypefaceList::getInstance()->getMonospacedNames (allFonts); - - static const char* targets[] = { "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Sans Mono", - "Liberation Mono", "Courier", "DejaVu Mono", "Mono", nullptr }; - return pickBestFont (allFonts, targets); - } - - JUCE_DECLARE_NON_COPYABLE (DefaultFontNames) -}; - -Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font) -{ - static DefaultFontNames defaultNames; - - Font f (font); - f.setTypefaceName (defaultNames.getRealFontName (font.getTypefaceName())); - return Typeface::createSystemTypefaceFor (f); -} - -} // namespace juce diff --git a/source/modules/juce_graphics/native/juce_linux_IconHelpers.cpp b/source/modules/juce_graphics/native/juce_linux_IconHelpers.cpp deleted file mode 100644 index 3a11f8e34..000000000 --- a/source/modules/juce_graphics/native/juce_linux_IconHelpers.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - Image JUCE_API getIconFromApplication (const String&, int) { return {}; } -} diff --git a/source/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h b/source/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h deleted file mode 100644 index 5db040743..000000000 --- a/source/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -class CoreGraphicsContext : public LowLevelGraphicsContext -{ -public: - CoreGraphicsContext (CGContextRef context, float flipHeight, float targetScale); - ~CoreGraphicsContext(); - - //============================================================================== - bool isVectorDevice() const override { return false; } - - void setOrigin (Point) override; - void addTransform (const AffineTransform&) override; - float getPhysicalPixelScaleFactor() override; - bool clipToRectangle (const Rectangle&) override; - bool clipToRectangleList (const RectangleList&) override; - void excludeClipRectangle (const Rectangle&) override; - void clipToPath (const Path&, const AffineTransform&) override; - void clipToImageAlpha (const Image&, const AffineTransform&) override; - bool clipRegionIntersects (const Rectangle&) override; - Rectangle getClipBounds() const override; - bool isClipEmpty() const override; - - //============================================================================== - void saveState() override; - void restoreState() override; - void beginTransparencyLayer (float opacity) override; - void endTransparencyLayer() override; - - //============================================================================== - void setFill (const FillType&) override; - void setOpacity (float) override; - void setInterpolationQuality (Graphics::ResamplingQuality) override; - - //============================================================================== - void fillRect (const Rectangle&, bool replaceExistingContents) override; - void fillRect (const Rectangle&) override; - void fillRectList (const RectangleList&) override; - void fillPath (const Path&, const AffineTransform&) override; - void drawImage (const Image& sourceImage, const AffineTransform&) override; - - //============================================================================== - void drawLine (const Line&) override; - void setFont (const Font&) override; - const Font& getFont() override; - void drawGlyph (int glyphNumber, const AffineTransform&) override; - bool drawTextLayout (const AttributedString&, const Rectangle&) override; - -private: - CGContextRef context; - const CGFloat flipHeight; - float targetScale; - CGColorSpaceRef rgbColourSpace, greyColourSpace; - mutable Rectangle lastClipRect; - mutable bool lastClipRectIsValid; - - struct SavedState - { - SavedState(); - SavedState (const SavedState&); - ~SavedState(); - - void setFill (const FillType&); - - FillType fillType; - Font font; - CGFontRef fontRef; - CGAffineTransform fontTransform; - CGGradientRef gradient; - }; - - ScopedPointer state; - OwnedArray stateStack; - - void drawGradient(); - void createPath (const Path&) const; - void createPath (const Path&, const AffineTransform&) const; - void flip() const; - void applyTransform (const AffineTransform&) const; - void drawImage (const Image&, const AffineTransform&, bool fillEntireClipAsTiles); - bool clipToRectangleListWithoutTest (const RectangleList&); - void fillCGRect (const CGRect&, bool replaceExistingContents); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreGraphicsContext) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm b/source/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm deleted file mode 100644 index 63e7f8925..000000000 --- a/source/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm +++ /dev/null @@ -1,923 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -class CoreGraphicsImage : public ImagePixelData -{ -public: - CoreGraphicsImage (const Image::PixelFormat format, const int w, const int h, const bool clearImage) - : ImagePixelData (format, w, h), cachedImageRef (0) - { - pixelStride = format == Image::RGB ? 3 : ((format == Image::ARGB) ? 4 : 1); - lineStride = (pixelStride * jmax (1, width) + 3) & ~3; - - imageData.allocate ((size_t) (lineStride * jmax (1, height)), clearImage); - - CGColorSpaceRef colourSpace = (format == Image::SingleChannel) ? CGColorSpaceCreateDeviceGray() - : CGColorSpaceCreateDeviceRGB(); - - context = CGBitmapContextCreate (imageData, (size_t) width, (size_t) height, 8, (size_t) lineStride, - colourSpace, getCGImageFlags (format)); - - CGColorSpaceRelease (colourSpace); - } - - ~CoreGraphicsImage() - { - freeCachedImageRef(); - CGContextRelease (context); - } - - LowLevelGraphicsContext* createLowLevelContext() override - { - freeCachedImageRef(); - sendDataChangeMessage(); - return new CoreGraphicsContext (context, height, 1.0f); - } - - void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override - { - bitmap.data = imageData + x * pixelStride + y * lineStride; - bitmap.pixelFormat = pixelFormat; - bitmap.lineStride = lineStride; - bitmap.pixelStride = pixelStride; - - if (mode != Image::BitmapData::readOnly) - { - freeCachedImageRef(); - sendDataChangeMessage(); - } - } - - ImagePixelData::Ptr clone() override - { - CoreGraphicsImage* im = new CoreGraphicsImage (pixelFormat, width, height, false); - memcpy (im->imageData, imageData, (size_t) (lineStride * height)); - return im; - } - - ImageType* createType() const override { return new NativeImageType(); } - - //============================================================================== - static CGImageRef getCachedImageRef (const Image& juceImage, CGColorSpaceRef colourSpace) - { - CoreGraphicsImage* const cgim = dynamic_cast (juceImage.getPixelData()); - - if (cgim != nullptr && cgim->cachedImageRef != 0) - { - CGImageRetain (cgim->cachedImageRef); - return cgim->cachedImageRef; - } - - CGImageRef ref = createImage (juceImage, colourSpace, false); - - if (cgim != nullptr) - { - CGImageRetain (ref); - cgim->cachedImageRef = ref; - } - - return ref; - } - - static CGImageRef createImage (const Image& juceImage, CGColorSpaceRef colourSpace, const bool mustOutliveSource) - { - const Image::BitmapData srcData (juceImage, Image::BitmapData::readOnly); - CGDataProviderRef provider; - - if (mustOutliveSource) - { - CFDataRef data = CFDataCreate (0, (const UInt8*) srcData.data, (CFIndex) (srcData.lineStride * srcData.height)); - provider = CGDataProviderCreateWithCFData (data); - CFRelease (data); - } - else - { - provider = CGDataProviderCreateWithData (0, srcData.data, (size_t) (srcData.lineStride * srcData.height), 0); - } - - CGImageRef imageRef = CGImageCreate ((size_t) srcData.width, - (size_t) srcData.height, - 8, (size_t) srcData.pixelStride * 8, - (size_t) srcData.lineStride, - colourSpace, getCGImageFlags (juceImage.getFormat()), provider, - 0, true, kCGRenderingIntentDefault); - - CGDataProviderRelease (provider); - return imageRef; - } - - //============================================================================== - CGContextRef context; - CGImageRef cachedImageRef; - HeapBlock imageData; - int pixelStride, lineStride; - -private: - void freeCachedImageRef() - { - if (cachedImageRef != 0) - { - CGImageRelease (cachedImageRef); - cachedImageRef = 0; - } - } - - static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) - { - #if JUCE_BIG_ENDIAN - return format == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big) : kCGBitmapByteOrderDefault; - #else - return format == Image::ARGB ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little) : kCGBitmapByteOrderDefault; - #endif - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreGraphicsImage) -}; - -ImagePixelData::Ptr NativeImageType::create (Image::PixelFormat format, int width, int height, bool clearImage) const -{ - return new CoreGraphicsImage (format == Image::RGB ? Image::ARGB : format, width, height, clearImage); -} - -//============================================================================== -CoreGraphicsContext::CoreGraphicsContext (CGContextRef c, const float h, const float scale) - : context (c), - flipHeight (h), - targetScale (scale), - lastClipRectIsValid (false), - state (new SavedState()) -{ - CGContextRetain (context); - CGContextSaveGState (context); - CGContextSetShouldSmoothFonts (context, true); - CGContextSetAllowsFontSmoothing (context, true); - CGContextSetShouldAntialias (context, true); - CGContextSetBlendMode (context, kCGBlendModeNormal); - rgbColourSpace = CGColorSpaceCreateDeviceRGB(); - greyColourSpace = CGColorSpaceCreateDeviceGray(); - setFont (Font()); -} - -CoreGraphicsContext::~CoreGraphicsContext() -{ - CGContextRestoreGState (context); - CGContextRelease (context); - CGColorSpaceRelease (rgbColourSpace); - CGColorSpaceRelease (greyColourSpace); -} - -//============================================================================== -void CoreGraphicsContext::setOrigin (Point o) -{ - CGContextTranslateCTM (context, o.x, -o.y); - - if (lastClipRectIsValid) - lastClipRect.translate (-o.x, -o.y); -} - -void CoreGraphicsContext::addTransform (const AffineTransform& transform) -{ - applyTransform (AffineTransform::verticalFlip ((float) flipHeight) - .followedBy (transform) - .translated (0, (float) -flipHeight) - .scaled (1.0f, -1.0f)); - lastClipRectIsValid = false; - - jassert (getPhysicalPixelScaleFactor() > 0.0f); - jassert (getPhysicalPixelScaleFactor() > 0.0f); -} - -float CoreGraphicsContext::getPhysicalPixelScaleFactor() -{ - const CGAffineTransform t = CGContextGetCTM (context); - - return targetScale * (float) (juce_hypot (t.a, t.c) + juce_hypot (t.b, t.d)) / 2.0f; -} - -bool CoreGraphicsContext::clipToRectangle (const Rectangle& r) -{ - CGContextClipToRect (context, CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight())); - - if (lastClipRectIsValid) - { - // This is actually incorrect, because the actual clip region may be complex, and - // clipping its bounds to a rect may not be right... But, removing this shortcut - // doesn't actually fix anything because CoreGraphics also ignores complex regions - // when calculating the resultant clip bounds, and makes the same mistake! - lastClipRect = lastClipRect.getIntersection (r); - return ! lastClipRect.isEmpty(); - } - - return ! isClipEmpty(); -} - -bool CoreGraphicsContext::clipToRectangleListWithoutTest (const RectangleList& clipRegion) -{ - if (clipRegion.isEmpty()) - { - CGContextClipToRect (context, CGRectZero); - lastClipRectIsValid = true; - lastClipRect = Rectangle(); - return false; - } - - const size_t numRects = (size_t) clipRegion.getNumRectangles(); - HeapBlock rects (numRects); - - int i = 0; - for (auto& r : clipRegion) - rects[i++] = CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight()); - - CGContextClipToRects (context, rects, numRects); - lastClipRectIsValid = false; - return true; -} - -bool CoreGraphicsContext::clipToRectangleList (const RectangleList& clipRegion) -{ - return clipToRectangleListWithoutTest (clipRegion) && ! isClipEmpty(); -} - -void CoreGraphicsContext::excludeClipRectangle (const Rectangle& r) -{ - RectangleList remaining (getClipBounds()); - remaining.subtract (r); - clipToRectangleListWithoutTest (remaining); -} - -void CoreGraphicsContext::clipToPath (const Path& path, const AffineTransform& transform) -{ - createPath (path, transform); - CGContextClip (context); - lastClipRectIsValid = false; -} - -void CoreGraphicsContext::clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform) -{ - if (! transform.isSingularity()) - { - Image singleChannelImage (sourceImage); - - if (sourceImage.getFormat() != Image::SingleChannel) - singleChannelImage = sourceImage.convertedToFormat (Image::SingleChannel); - - CGImageRef image = CoreGraphicsImage::createImage (singleChannelImage, greyColourSpace, true); - - flip(); - AffineTransform t (AffineTransform::verticalFlip (sourceImage.getHeight()).followedBy (transform)); - applyTransform (t); - - CGRect r = convertToCGRect (sourceImage.getBounds()); - CGContextClipToMask (context, r, image); - - applyTransform (t.inverted()); - flip(); - - CGImageRelease (image); - lastClipRectIsValid = false; - } -} - -bool CoreGraphicsContext::clipRegionIntersects (const Rectangle& r) -{ - return getClipBounds().intersects (r); -} - -Rectangle CoreGraphicsContext::getClipBounds() const -{ - if (! lastClipRectIsValid) - { - CGRect bounds = CGRectIntegral (CGContextGetClipBoundingBox (context)); - - lastClipRectIsValid = true; - lastClipRect.setBounds (roundToInt (bounds.origin.x), - roundToInt (flipHeight - (bounds.origin.y + bounds.size.height)), - roundToInt (bounds.size.width), - roundToInt (bounds.size.height)); - } - - return lastClipRect; -} - -bool CoreGraphicsContext::isClipEmpty() const -{ - return getClipBounds().isEmpty(); -} - -//============================================================================== -void CoreGraphicsContext::saveState() -{ - CGContextSaveGState (context); - stateStack.add (new SavedState (*state)); -} - -void CoreGraphicsContext::restoreState() -{ - CGContextRestoreGState (context); - - if (SavedState* const top = stateStack.getLast()) - { - state = top; - stateStack.removeLast (1, false); - lastClipRectIsValid = false; - } - else - { - jassertfalse; // trying to pop with an empty stack! - } -} - -void CoreGraphicsContext::beginTransparencyLayer (float opacity) -{ - saveState(); - CGContextSetAlpha (context, opacity); - CGContextBeginTransparencyLayer (context, 0); -} - -void CoreGraphicsContext::endTransparencyLayer() -{ - CGContextEndTransparencyLayer (context); - restoreState(); -} - -//============================================================================== -void CoreGraphicsContext::setFill (const FillType& fillType) -{ - state->setFill (fillType); - - if (fillType.isColour()) - { - CGContextSetRGBFillColor (context, fillType.colour.getFloatRed(), fillType.colour.getFloatGreen(), - fillType.colour.getFloatBlue(), fillType.colour.getFloatAlpha()); - CGContextSetAlpha (context, 1.0f); - } -} - -void CoreGraphicsContext::setOpacity (float newOpacity) -{ - state->fillType.setOpacity (newOpacity); - setFill (state->fillType); -} - -void CoreGraphicsContext::setInterpolationQuality (Graphics::ResamplingQuality quality) -{ - switch (quality) - { - case Graphics::lowResamplingQuality: CGContextSetInterpolationQuality (context, kCGInterpolationNone); return; - case Graphics::mediumResamplingQuality: CGContextSetInterpolationQuality (context, kCGInterpolationMedium); return; - case Graphics::highResamplingQuality: CGContextSetInterpolationQuality (context, kCGInterpolationHigh); return; - default: return; - } -} - -//============================================================================== -void CoreGraphicsContext::fillRect (const Rectangle& r, const bool replaceExistingContents) -{ - fillCGRect (CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight()), replaceExistingContents); -} - -void CoreGraphicsContext::fillRect (const Rectangle& r) -{ - fillCGRect (CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight()), false); -} - -void CoreGraphicsContext::fillCGRect (const CGRect& cgRect, const bool replaceExistingContents) -{ - if (replaceExistingContents) - { - CGContextSetBlendMode (context, kCGBlendModeCopy); - fillCGRect (cgRect, false); - CGContextSetBlendMode (context, kCGBlendModeNormal); - } - else - { - if (state->fillType.isColour()) - { - CGContextFillRect (context, cgRect); - } - else if (state->fillType.isGradient()) - { - CGContextSaveGState (context); - CGContextClipToRect (context, cgRect); - drawGradient(); - CGContextRestoreGState (context); - } - else - { - CGContextSaveGState (context); - CGContextClipToRect (context, cgRect); - drawImage (state->fillType.image, state->fillType.transform, true); - CGContextRestoreGState (context); - } - } -} - -void CoreGraphicsContext::fillPath (const Path& path, const AffineTransform& transform) -{ - CGContextSaveGState (context); - - if (state->fillType.isColour()) - { - flip(); - applyTransform (transform); - createPath (path); - - if (path.isUsingNonZeroWinding()) - CGContextFillPath (context); - else - CGContextEOFillPath (context); - } - else - { - createPath (path, transform); - - if (path.isUsingNonZeroWinding()) - CGContextClip (context); - else - CGContextEOClip (context); - - if (state->fillType.isGradient()) - drawGradient(); - else - drawImage (state->fillType.image, state->fillType.transform, true); - } - - CGContextRestoreGState (context); -} - -void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTransform& transform) -{ - drawImage (sourceImage, transform, false); -} - -void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTransform& transform, const bool fillEntireClipAsTiles) -{ - const int iw = sourceImage.getWidth(); - const int ih = sourceImage.getHeight(); - CGImageRef image = CoreGraphicsImage::getCachedImageRef (sourceImage, sourceImage.getFormat() == Image::PixelFormat::SingleChannel ? greyColourSpace - : rgbColourSpace); - - CGContextSaveGState (context); - CGContextSetAlpha (context, state->fillType.getOpacity()); - - flip(); - applyTransform (AffineTransform::verticalFlip (ih).followedBy (transform)); - CGRect imageRect = CGRectMake (0, 0, iw, ih); - - if (fillEntireClipAsTiles) - { - #if JUCE_IOS - CGContextDrawTiledImage (context, imageRect, image); - #else - // There's a bug in CGContextDrawTiledImage that makes it incredibly slow - // if it's doing a transformation - it's quicker to just draw lots of images manually - if (&CGContextDrawTiledImage != 0 && transform.isOnlyTranslation()) - { - CGContextDrawTiledImage (context, imageRect, image); - } - else - { - // Fallback to manually doing a tiled fill - CGRect clip = CGRectIntegral (CGContextGetClipBoundingBox (context)); - - int x = 0, y = 0; - while (x > clip.origin.x) x -= iw; - while (y > clip.origin.y) y -= ih; - - const int right = (int) (clip.origin.x + clip.size.width); - const int bottom = (int) (clip.origin.y + clip.size.height); - - while (y < bottom) - { - for (int x2 = x; x2 < right; x2 += iw) - CGContextDrawImage (context, CGRectMake (x2, y, iw, ih), image); - - y += ih; - } - } - #endif - } - else - { - CGContextDrawImage (context, imageRect, image); - } - - CGImageRelease (image); // (This causes a memory bug in iOS sim 3.0 - try upgrading to a later version if you hit this) - CGContextRestoreGState (context); -} - -//============================================================================== -void CoreGraphicsContext::drawLine (const Line& line) -{ - if (state->fillType.isColour()) - { - CGContextSetLineCap (context, kCGLineCapSquare); - CGContextSetLineWidth (context, 1.0f); - CGContextSetRGBStrokeColor (context, - state->fillType.colour.getFloatRed(), state->fillType.colour.getFloatGreen(), - state->fillType.colour.getFloatBlue(), state->fillType.colour.getFloatAlpha()); - - CGPoint cgLine[] = { { (CGFloat) line.getStartX(), flipHeight - (CGFloat) line.getStartY() }, - { (CGFloat) line.getEndX(), flipHeight - (CGFloat) line.getEndY() } }; - - CGContextStrokeLineSegments (context, cgLine, 1); - } - else - { - Path p; - p.addLineSegment (line, 1.0f); - fillPath (p, AffineTransform()); - } -} - -void CoreGraphicsContext::fillRectList (const RectangleList& list) -{ - HeapBlock rects ((size_t) list.getNumRectangles()); - - size_t num = 0; - - for (auto& r : list) - rects[num++] = CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight()); - - if (state->fillType.isColour()) - { - CGContextFillRects (context, rects, num); - } - else if (state->fillType.isGradient()) - { - CGContextSaveGState (context); - CGContextClipToRects (context, rects, num); - drawGradient(); - CGContextRestoreGState (context); - } - else - { - CGContextSaveGState (context); - CGContextClipToRects (context, rects, num); - drawImage (state->fillType.image, state->fillType.transform, true); - CGContextRestoreGState (context); - } -} - -void CoreGraphicsContext::setFont (const Font& newFont) -{ - if (state->font != newFont) - { - state->fontRef = 0; - state->font = newFont; - - if (OSXTypeface* osxTypeface = dynamic_cast (state->font.getTypeface())) - { - state->fontRef = osxTypeface->fontRef; - CGContextSetFont (context, state->fontRef); - CGContextSetFontSize (context, state->font.getHeight() * osxTypeface->fontHeightToPointsFactor); - - state->fontTransform = osxTypeface->renderingTransform; - state->fontTransform.a *= state->font.getHorizontalScale(); - CGContextSetTextMatrix (context, state->fontTransform); - } - } -} - -const Font& CoreGraphicsContext::getFont() -{ - return state->font; -} - -void CoreGraphicsContext::drawGlyph (int glyphNumber, const AffineTransform& transform) -{ - if (state->fontRef != 0 && state->fillType.isColour()) - { - #if JUCE_CLANG - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wdeprecated-declarations" - #endif - - if (transform.isOnlyTranslation()) - { - CGContextSetTextMatrix (context, state->fontTransform); // have to set this each time, as it's not saved as part of the state - - CGGlyph g = (CGGlyph) glyphNumber; - CGContextShowGlyphsAtPoint (context, transform.getTranslationX(), - flipHeight - roundToInt (transform.getTranslationY()), &g, 1); - } - else - { - CGContextSaveGState (context); - flip(); - applyTransform (transform); - - CGAffineTransform t = state->fontTransform; - t.d = -t.d; - CGContextSetTextMatrix (context, t); - - CGGlyph g = (CGGlyph) glyphNumber; - CGContextShowGlyphsAtPoint (context, 0, 0, &g, 1); - - CGContextRestoreGState (context); - } - - #if JUCE_CLANG - #pragma clang diagnostic pop - #endif - } - else - { - Path p; - Font& f = state->font; - f.getTypeface()->getOutlineForGlyph (glyphNumber, p); - - fillPath (p, AffineTransform::scale (f.getHeight() * f.getHorizontalScale(), f.getHeight()) - .followedBy (transform)); - } -} - -bool CoreGraphicsContext::drawTextLayout (const AttributedString& text, const Rectangle& area) -{ - #if JUCE_CORETEXT_AVAILABLE - CoreTextTypeLayout::drawToCGContext (text, area, context, (float) flipHeight); - return true; - #else - ignoreUnused (text, area); - return false; - #endif -} - -CoreGraphicsContext::SavedState::SavedState() - : font (1.0f), fontRef (0), fontTransform (CGAffineTransformIdentity), gradient (0) -{ -} - -CoreGraphicsContext::SavedState::SavedState (const SavedState& other) - : fillType (other.fillType), font (other.font), fontRef (other.fontRef), - fontTransform (other.fontTransform), gradient (other.gradient) -{ - if (gradient != 0) - CGGradientRetain (gradient); -} - -CoreGraphicsContext::SavedState::~SavedState() -{ - if (gradient != 0) - CGGradientRelease (gradient); -} - -void CoreGraphicsContext::SavedState::setFill (const FillType& newFill) -{ - fillType = newFill; - - if (gradient != 0) - { - CGGradientRelease (gradient); - gradient = 0; - } -} - -static CGGradientRef createGradient (const ColourGradient& g, CGColorSpaceRef colourSpace) -{ - const int numColours = g.getNumColours(); - CGFloat* const data = (CGFloat*) alloca ((size_t) numColours * 5 * sizeof (CGFloat)); - CGFloat* const locations = data; - CGFloat* const components = data + numColours; - CGFloat* comps = components; - - for (int i = 0; i < numColours; ++i) - { - const Colour colour (g.getColour (i)); - *comps++ = (CGFloat) colour.getFloatRed(); - *comps++ = (CGFloat) colour.getFloatGreen(); - *comps++ = (CGFloat) colour.getFloatBlue(); - *comps++ = (CGFloat) colour.getFloatAlpha(); - locations[i] = (CGFloat) g.getColourPosition (i); - - // There's a bug (?) in the way the CG renderer works where it seems - // to go wrong if you have two colour stops both at position 0.. - jassert (i == 0 || locations[i] != 0); - } - - return CGGradientCreateWithColorComponents (colourSpace, components, locations, (size_t) numColours); -} - -void CoreGraphicsContext::drawGradient() -{ - flip(); - applyTransform (state->fillType.transform); - CGContextSetAlpha (context, state->fillType.getOpacity()); - - const ColourGradient& g = *state->fillType.gradient; - - CGPoint p1 (convertToCGPoint (g.point1)); - CGPoint p2 (convertToCGPoint (g.point2)); - - state->fillType.transform.transformPoints (p1.x, p1.y, p2.x, p2.y); - - if (state->gradient == 0) - state->gradient = createGradient (g, rgbColourSpace); - - if (g.isRadial) - CGContextDrawRadialGradient (context, state->gradient, p1, 0, p1, g.point1.getDistanceFrom (g.point2), - kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); - else - CGContextDrawLinearGradient (context, state->gradient, p1, p2, - kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); -} - -void CoreGraphicsContext::createPath (const Path& path) const -{ - CGContextBeginPath (context); - - for (Path::Iterator i (path); i.next();) - { - switch (i.elementType) - { - case Path::Iterator::startNewSubPath: CGContextMoveToPoint (context, i.x1, i.y1); break; - case Path::Iterator::lineTo: CGContextAddLineToPoint (context, i.x1, i.y1); break; - case Path::Iterator::quadraticTo: CGContextAddQuadCurveToPoint (context, i.x1, i.y1, i.x2, i.y2); break; - case Path::Iterator::cubicTo: CGContextAddCurveToPoint (context, i.x1, i.y1, i.x2, i.y2, i.x3, i.y3); break; - case Path::Iterator::closePath: CGContextClosePath (context); break; - default: jassertfalse; break; - } - } -} - -void CoreGraphicsContext::createPath (const Path& path, const AffineTransform& transform) const -{ - CGContextBeginPath (context); - - for (Path::Iterator i (path); i.next();) - { - switch (i.elementType) - { - case Path::Iterator::startNewSubPath: - transform.transformPoint (i.x1, i.y1); - CGContextMoveToPoint (context, i.x1, flipHeight - i.y1); - break; - case Path::Iterator::lineTo: - transform.transformPoint (i.x1, i.y1); - CGContextAddLineToPoint (context, i.x1, flipHeight - i.y1); - break; - case Path::Iterator::quadraticTo: - transform.transformPoints (i.x1, i.y1, i.x2, i.y2); - CGContextAddQuadCurveToPoint (context, i.x1, flipHeight - i.y1, i.x2, flipHeight - i.y2); - break; - case Path::Iterator::cubicTo: - transform.transformPoints (i.x1, i.y1, i.x2, i.y2, i.x3, i.y3); - CGContextAddCurveToPoint (context, i.x1, flipHeight - i.y1, i.x2, flipHeight - i.y2, i.x3, flipHeight - i.y3); - break; - case Path::Iterator::closePath: - CGContextClosePath (context); break; - default: - jassertfalse; - break; - } - } -} - -void CoreGraphicsContext::flip() const -{ - CGContextConcatCTM (context, CGAffineTransformMake (1, 0, 0, -1, 0, flipHeight)); -} - -void CoreGraphicsContext::applyTransform (const AffineTransform& transform) const -{ - CGAffineTransform t; - t.a = transform.mat00; - t.b = transform.mat10; - t.c = transform.mat01; - t.d = transform.mat11; - t.tx = transform.mat02; - t.ty = transform.mat12; - CGContextConcatCTM (context, t); -} - -//============================================================================== -#if USE_COREGRAPHICS_RENDERING && JUCE_USE_COREIMAGE_LOADER -Image juce_loadWithCoreImage (InputStream& input) -{ - MemoryBlock data; - input.readIntoMemoryBlock (data, -1); - - #if JUCE_IOS - JUCE_AUTORELEASEPOOL - #endif - { - #if JUCE_IOS - if (UIImage* uiImage = [UIImage imageWithData: [NSData dataWithBytesNoCopy: data.getData() - length: data.getSize() - freeWhenDone: NO]]) - { - CGImageRef loadedImage = uiImage.CGImage; - - #else - CGDataProviderRef provider = CGDataProviderCreateWithData (0, data.getData(), data.getSize(), 0); - CGImageSourceRef imageSource = CGImageSourceCreateWithDataProvider (provider, 0); - CGDataProviderRelease (provider); - - if (imageSource != 0) - { - CGImageRef loadedImage = CGImageSourceCreateImageAtIndex (imageSource, 0, 0); - CFRelease (imageSource); - #endif - - if (loadedImage != 0) - { - CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo (loadedImage); - const bool hasAlphaChan = (alphaInfo != kCGImageAlphaNone - && alphaInfo != kCGImageAlphaNoneSkipLast - && alphaInfo != kCGImageAlphaNoneSkipFirst); - - Image image (NativeImageType().create (Image::ARGB, // (CoreImage doesn't work with 24-bit images) - (int) CGImageGetWidth (loadedImage), - (int) CGImageGetHeight (loadedImage), - hasAlphaChan)); - - CoreGraphicsImage* const cgImage = dynamic_cast (image.getPixelData()); - jassert (cgImage != nullptr); // if USE_COREGRAPHICS_RENDERING is set, the CoreGraphicsImage class should have been used. - - CGContextDrawImage (cgImage->context, convertToCGRect (image.getBounds()), loadedImage); - CGContextFlush (cgImage->context); - - #if ! JUCE_IOS - CFRelease (loadedImage); - #endif - - // Because it's impossible to create a truly 24-bit CG image, this flag allows a user - // to find out whether the file they just loaded the image from had an alpha channel or not. - image.getProperties()->set ("originalImageHadAlpha", hasAlphaChan); - return image; - } - } - } - - return Image(); -} -#endif - -Image juce_createImageFromCIImage (CIImage*, int, int); -Image juce_createImageFromCIImage (CIImage* im, int w, int h) -{ - CoreGraphicsImage* cgImage = new CoreGraphicsImage (Image::ARGB, w, h, false); - - CIContext* cic = [CIContext contextWithCGContext: cgImage->context options: nil]; - [cic drawImage: im inRect: CGRectMake (0, 0, w, h) fromRect: CGRectMake (0, 0, w, h)]; - CGContextFlush (cgImage->context); - - return Image (cgImage); -} - -CGImageRef juce_createCoreGraphicsImage (const Image& juceImage, CGColorSpaceRef colourSpace, - const bool mustOutliveSource) -{ - return CoreGraphicsImage::createImage (juceImage, colourSpace, mustOutliveSource); -} - -CGContextRef juce_getImageContext (const Image& image) -{ - if (CoreGraphicsImage* const cgi = dynamic_cast (image.getPixelData())) - return cgi->context; - - jassertfalse; - return 0; -} - -#if JUCE_IOS -Image juce_createImageFromUIImage (UIImage* img) -{ - CGImageRef image = [img CGImage]; - - Image retval (Image::ARGB, (int) CGImageGetWidth (image), (int) CGImageGetHeight (image), true); - CGContextRef ctx = juce_getImageContext (retval); - - CGContextDrawImage (ctx, CGRectMake (0.0f, 0.0f, CGImageGetWidth (image), CGImageGetHeight (image)), image); - - return retval; -} -#endif - -} diff --git a/source/modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h b/source/modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h deleted file mode 100644 index 6d04d73ea..000000000 --- a/source/modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -namespace -{ - template - Rectangle convertToRectInt (RectType r) noexcept - { - return Rectangle ((int) r.origin.x, (int) r.origin.y, (int) r.size.width, (int) r.size.height); - } - - template - Rectangle convertToRectFloat (RectType r) noexcept - { - return Rectangle (r.origin.x, r.origin.y, r.size.width, r.size.height); - } - - template - CGRect convertToCGRect (RectType r) noexcept - { - return CGRectMake ((CGFloat) r.getX(), (CGFloat) r.getY(), (CGFloat) r.getWidth(), (CGFloat) r.getHeight()); - } - - template - CGPoint convertToCGPoint (PointType p) noexcept - { - return CGPointMake ((CGFloat) p.x, (CGFloat) p.y); - } -} - -extern CGImageRef juce_createCoreGraphicsImage (const Image&, CGColorSpaceRef, bool mustOutliveSource); -extern CGContextRef juce_getImageContext (const Image&); - -#if JUCE_IOS - extern Image juce_createImageFromUIImage (UIImage*); -#endif - -} // namespace juce diff --git a/source/modules/juce_graphics/native/juce_mac_Fonts.mm b/source/modules/juce_graphics/native/juce_mac_Fonts.mm deleted file mode 100644 index 19b3b38f3..000000000 --- a/source/modules/juce_graphics/native/juce_mac_Fonts.mm +++ /dev/null @@ -1,1252 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -#ifndef JUCE_CORETEXT_AVAILABLE - #define JUCE_CORETEXT_AVAILABLE 1 -#endif - -const float referenceFontSize = 1024.0f; - -#if JUCE_CORETEXT_AVAILABLE - -#if JUCE_MAC && MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_5 -extern "C" -{ - void CTRunGetAdvances (CTRunRef, CFRange, CGSize buffer[]); - const CGSize* CTRunGetAdvancesPtr (CTRunRef); -} -#endif - -static CTFontRef getCTFontFromTypeface (const Font& f); - -namespace CoreTextTypeLayout -{ - static String findBestAvailableStyle (const Font& font, CGAffineTransform& requiredTransform) - { - const StringArray availableStyles (Font::findAllTypefaceStyles (font.getTypefaceName())); - const String style (font.getTypefaceStyle()); - - if (! availableStyles.contains (style)) - { - if (font.isItalic()) // Fake-up an italic font if there isn't a real one. - requiredTransform = CGAffineTransformMake (1.0f, 0, 0.25f, 1.0f, 0, 0); - - return availableStyles[0]; - } - - return style; - } - - // Workaround for Apple bug in CTFontCreateWithFontDescriptor in Garageband/Logic on 10.6 - #if JUCE_MAC && ((! defined (MAC_OS_X_VERSION_10_7)) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7) - static CTFontRef getFontWithTrait (CTFontRef ctFontRef, CTFontSymbolicTraits trait) - { - if (CTFontRef newFont = CTFontCreateCopyWithSymbolicTraits (ctFontRef, 0.0f, nullptr, trait, trait)) - { - CFRelease (ctFontRef); - return newFont; - } - - return ctFontRef; - } - - static CTFontRef useStyleFallbackIfNecessary (CTFontRef ctFontRef, CFStringRef cfFontFamily, - const float fontSizePoints, const Font& font) - { - CFStringRef cfActualFontFamily = (CFStringRef) CTFontCopyAttribute (ctFontRef, kCTFontFamilyNameAttribute); - - if (CFStringCompare (cfFontFamily, cfActualFontFamily, 0) != kCFCompareEqualTo) - { - CFRelease (ctFontRef); - ctFontRef = CTFontCreateWithName (cfFontFamily, fontSizePoints, nullptr); - - if (font.isItalic()) ctFontRef = getFontWithTrait (ctFontRef, kCTFontItalicTrait); - if (font.isBold()) ctFontRef = getFontWithTrait (ctFontRef, kCTFontBoldTrait); - } - - CFRelease (cfActualFontFamily); - return ctFontRef; - } - #endif - - static float getFontTotalHeight (CTFontRef font) - { - return std::abs ((float) CTFontGetAscent (font)) + std::abs ((float) CTFontGetDescent (font)); - } - - static float getHeightToPointsFactor (CTFontRef font) - { - return referenceFontSize / getFontTotalHeight (font); - } - - static CTFontRef getFontWithPointSize (CTFontRef font, float size) - { - CTFontRef newFont = CTFontCreateCopyWithAttributes (font, size, nullptr, nullptr); - CFRelease (font); - return newFont; - } - - static CTFontRef createCTFont (const Font& font, const float fontSizePoints, CGAffineTransform& transformRequired) - { - CFStringRef cfFontFamily = FontStyleHelpers::getConcreteFamilyName (font).toCFString(); - CFStringRef cfFontStyle = findBestAvailableStyle (font, transformRequired).toCFString(); - CFStringRef keys[] = { kCTFontFamilyNameAttribute, kCTFontStyleNameAttribute }; - CFTypeRef values[] = { cfFontFamily, cfFontStyle }; - - CFDictionaryRef fontDescAttributes = CFDictionaryCreate (nullptr, (const void**) &keys, - (const void**) &values, - numElementsInArray (keys), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - CFRelease (cfFontStyle); - - CTFontDescriptorRef ctFontDescRef = CTFontDescriptorCreateWithAttributes (fontDescAttributes); - CFRelease (fontDescAttributes); - - CTFontRef ctFontRef = CTFontCreateWithFontDescriptor (ctFontDescRef, fontSizePoints, nullptr); - CFRelease (ctFontDescRef); - - #if JUCE_MAC && ((! defined (MAC_OS_X_VERSION_10_7)) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7) - ctFontRef = useStyleFallbackIfNecessary (ctFontRef, cfFontFamily, fontSizePoints, font); - #endif - - CFRelease (cfFontFamily); - - return ctFontRef; - } - - //============================================================================== - struct Advances - { - Advances (CTRunRef run, const CFIndex numGlyphs) - : advances (CTRunGetAdvancesPtr (run)) - { - if (advances == nullptr) - { - local.malloc ((size_t) numGlyphs); - CTRunGetAdvances (run, CFRangeMake (0, 0), local); - advances = local; - } - } - - const CGSize* advances; - HeapBlock local; - }; - - struct Glyphs - { - Glyphs (CTRunRef run, const size_t numGlyphs) - : glyphs (CTRunGetGlyphsPtr (run)) - { - if (glyphs == nullptr) - { - local.malloc (numGlyphs); - CTRunGetGlyphs (run, CFRangeMake (0, 0), local); - glyphs = local; - } - } - - const CGGlyph* glyphs; - HeapBlock local; - }; - - struct Positions - { - Positions (CTRunRef run, const size_t numGlyphs) - : points (CTRunGetPositionsPtr (run)) - { - if (points == nullptr) - { - local.malloc (numGlyphs); - CTRunGetPositions (run, CFRangeMake (0, 0), local); - points = local; - } - } - - const CGPoint* points; - HeapBlock local; - }; - - struct LineInfo - { - LineInfo (CTFrameRef frame, CTLineRef line, CFIndex lineIndex) - { - CTFrameGetLineOrigins (frame, CFRangeMake (lineIndex, 1), &origin); - CTLineGetTypographicBounds (line, &ascent, &descent, &leading); - } - - CGPoint origin; - CGFloat ascent, descent, leading; - }; - - static CTFontRef getOrCreateFont (const Font& f) - { - if (CTFontRef ctf = getCTFontFromTypeface (f)) - { - CFRetain (ctf); - return ctf; - } - - CGAffineTransform transform; - return createCTFont (f, referenceFontSize, transform); - } - - //============================================================================== - static CTTextAlignment getTextAlignment (const AttributedString& text) - { - switch (text.getJustification().getOnlyHorizontalFlags()) - { - #if defined (MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 - case Justification::right: return kCTTextAlignmentRight; - case Justification::horizontallyCentred: return kCTTextAlignmentCenter; - case Justification::horizontallyJustified: return kCTTextAlignmentJustified; - default: return kCTTextAlignmentLeft; - #else - case Justification::right: return kCTRightTextAlignment; - case Justification::horizontallyCentred: return kCTCenterTextAlignment; - case Justification::horizontallyJustified: return kCTJustifiedTextAlignment; - default: return kCTLeftTextAlignment; - #endif - } - } - - static CTLineBreakMode getLineBreakMode (const AttributedString& text) - { - switch (text.getWordWrap()) - { - case AttributedString::none: return kCTLineBreakByClipping; - case AttributedString::byChar: return kCTLineBreakByCharWrapping; - default: return kCTLineBreakByWordWrapping; - } - } - - static CTWritingDirection getWritingDirection (const AttributedString& text) - { - switch (text.getReadingDirection()) - { - case AttributedString::rightToLeft: return kCTWritingDirectionRightToLeft; - case AttributedString::leftToRight: return kCTWritingDirectionLeftToRight; - default: return kCTWritingDirectionNatural; - } - } - - //============================================================================== - static CFAttributedStringRef createCFAttributedString (const AttributedString& text) - { - #if JUCE_IOS - CGColorSpaceRef rgbColourSpace = CGColorSpaceCreateDeviceRGB(); - #endif - - CFMutableAttributedStringRef attribString = CFAttributedStringCreateMutable (kCFAllocatorDefault, 0); - - CFStringRef cfText = text.getText().toCFString(); - CFAttributedStringReplaceString (attribString, CFRangeMake (0, 0), cfText); - CFRelease (cfText); - - const int numCharacterAttributes = text.getNumAttributes(); - const CFIndex attribStringLen = CFAttributedStringGetLength (attribString); - - for (int i = 0; i < numCharacterAttributes; ++i) - { - const AttributedString::Attribute& attr = text.getAttribute (i); - const int rangeStart = attr.range.getStart(); - - if (rangeStart >= attribStringLen) - continue; - - CFRange range = CFRangeMake (rangeStart, jmin (attr.range.getEnd(), (int) attribStringLen) - rangeStart); - - if (CTFontRef ctFontRef = getOrCreateFont (attr.font)) - { - ctFontRef = getFontWithPointSize (ctFontRef, attr.font.getHeight() * getHeightToPointsFactor (ctFontRef)); - - CFAttributedStringSetAttribute (attribString, range, kCTFontAttributeName, ctFontRef); - - float extraKerning = attr.font.getExtraKerningFactor(); - - if (extraKerning != 0.0f) - { - extraKerning *= attr.font.getHeight(); - - CFNumberRef numberRef = CFNumberCreate (0, kCFNumberFloatType, &extraKerning); - CFAttributedStringSetAttribute (attribString, range, kCTKernAttributeName, numberRef); - CFRelease (numberRef); - } - - CFRelease (ctFontRef); - } - - { - const Colour col (attr.colour); - - #if JUCE_IOS - const CGFloat components[] = { col.getFloatRed(), - col.getFloatGreen(), - col.getFloatBlue(), - col.getFloatAlpha() }; - CGColorRef colour = CGColorCreate (rgbColourSpace, components); - #else - CGColorRef colour = CGColorCreateGenericRGB (col.getFloatRed(), - col.getFloatGreen(), - col.getFloatBlue(), - col.getFloatAlpha()); - #endif - - CFAttributedStringSetAttribute (attribString, range, kCTForegroundColorAttributeName, colour); - CGColorRelease (colour); - } - } - - // Paragraph Attributes - CTTextAlignment ctTextAlignment = getTextAlignment (text); - CTLineBreakMode ctLineBreakMode = getLineBreakMode (text); - CTWritingDirection ctWritingDirection = getWritingDirection (text); - const CGFloat ctLineSpacing = text.getLineSpacing(); - - CTParagraphStyleSetting settings[] = - { - { kCTParagraphStyleSpecifierAlignment, sizeof (CTTextAlignment), &ctTextAlignment }, - { kCTParagraphStyleSpecifierLineBreakMode, sizeof (CTLineBreakMode), &ctLineBreakMode }, - { kCTParagraphStyleSpecifierBaseWritingDirection, sizeof (CTWritingDirection), &ctWritingDirection}, - - #if defined (MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - { kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof (CGFloat), &ctLineSpacing } - #else - { kCTParagraphStyleSpecifierLineSpacing, sizeof (CGFloat), &ctLineSpacing } - #endif - }; - - CTParagraphStyleRef ctParagraphStyleRef = CTParagraphStyleCreate (settings, (size_t) numElementsInArray (settings)); - CFAttributedStringSetAttribute (attribString, CFRangeMake (0, CFAttributedStringGetLength (attribString)), - kCTParagraphStyleAttributeName, ctParagraphStyleRef); - CFRelease (ctParagraphStyleRef); - #if JUCE_IOS - CGColorSpaceRelease (rgbColourSpace); - #endif - return attribString; - } - - static CTFrameRef createCTFrame (const AttributedString& text, CGRect bounds) - { - CFAttributedStringRef attribString = createCFAttributedString (text); - CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString (attribString); - CFRelease (attribString); - - CGMutablePathRef path = CGPathCreateMutable(); - CGPathAddRect (path, nullptr, bounds); - - CTFrameRef frame = CTFramesetterCreateFrame (framesetter, CFRangeMake (0, 0), path, nullptr); - CFRelease (framesetter); - CGPathRelease (path); - - return frame; - } - - static Range getLineVerticalRange (CTFrameRef frame, CFArrayRef lines, int lineIndex) - { - LineInfo info (frame, (CTLineRef) CFArrayGetValueAtIndex (lines, lineIndex), lineIndex); - return Range ((float) (info.origin.y - info.descent), - (float) (info.origin.y + info.ascent)); - } - - static float findCTFrameHeight (CTFrameRef frame) - { - CFArrayRef lines = CTFrameGetLines (frame); - const CFIndex numLines = CFArrayGetCount (lines); - - if (numLines == 0) - return 0; - - Range range (getLineVerticalRange (frame, lines, 0)); - - if (numLines > 1) - range = range.getUnionWith (getLineVerticalRange (frame, lines, (int) numLines - 1)); - - return range.getLength(); - } - - static void drawToCGContext (const AttributedString& text, const Rectangle& area, - const CGContextRef& context, const float flipHeight) - { - Rectangle ctFrameArea; - - const int verticalJustification = text.getJustification().getOnlyVerticalFlags(); - - // Ugly hack to fix a bug in OS X Sierra where the CTFrame needs to be slightly - // larger than the font height - otherwise the CTFrame will be invalid - if (verticalJustification == Justification::verticallyCentred) - ctFrameArea = area.withSizeKeepingCentre (area.getWidth(), area.getHeight() * 1.1f); - else if (verticalJustification == Justification::bottom) - ctFrameArea = area.withTop (area.getY() - (area.getHeight() * 0.1f)); - else - ctFrameArea = area.withHeight (area.getHeight() * 1.1f); - - CTFrameRef frame = createCTFrame (text, CGRectMake ((CGFloat) ctFrameArea.getX(), flipHeight - (CGFloat) ctFrameArea.getBottom(), - (CGFloat) ctFrameArea.getWidth(), (CGFloat) ctFrameArea.getHeight())); - - if (verticalJustification == Justification::verticallyCentred - || verticalJustification == Justification::bottom) - { - float adjust = ctFrameArea.getHeight() - findCTFrameHeight (frame); - - if (verticalJustification == Justification::verticallyCentred) - adjust *= 0.5f; - - CGContextSaveGState (context); - CGContextTranslateCTM (context, 0, -adjust); - CTFrameDraw (frame, context); - CGContextRestoreGState (context); - } - else - { - CTFrameDraw (frame, context); - } - - CFRelease (frame); - } - - static void createLayout (TextLayout& glyphLayout, const AttributedString& text) - { - const CGFloat boundsHeight = glyphLayout.getHeight(); - CTFrameRef frame = createCTFrame (text, CGRectMake (0, 0, glyphLayout.getWidth(), boundsHeight)); - - CFArrayRef lines = CTFrameGetLines (frame); - const CFIndex numLines = CFArrayGetCount (lines); - - glyphLayout.ensureStorageAllocated ((int) numLines); - - for (CFIndex i = 0; i < numLines; ++i) - { - CTLineRef line = (CTLineRef) CFArrayGetValueAtIndex (lines, i); - - CFArrayRef runs = CTLineGetGlyphRuns (line); - const CFIndex numRuns = CFArrayGetCount (runs); - - const CFRange cfrlineStringRange = CTLineGetStringRange (line); - const CFIndex lineStringEnd = cfrlineStringRange.location + cfrlineStringRange.length - 1; - const Range lineStringRange ((int) cfrlineStringRange.location, (int) lineStringEnd); - - LineInfo lineInfo (frame, line, i); - - TextLayout::Line* const glyphLine = new TextLayout::Line (lineStringRange, - Point ((float) lineInfo.origin.x, - (float) (boundsHeight - lineInfo.origin.y)), - (float) lineInfo.ascent, - (float) lineInfo.descent, - (float) lineInfo.leading, - (int) numRuns); - glyphLayout.addLine (glyphLine); - - for (CFIndex j = 0; j < numRuns; ++j) - { - CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (runs, j); - const CFIndex numGlyphs = CTRunGetGlyphCount (run); - const CFRange runStringRange = CTRunGetStringRange (run); - - TextLayout::Run* const glyphRun = new TextLayout::Run (Range ((int) runStringRange.location, - (int) (runStringRange.location + runStringRange.length - 1)), - (int) numGlyphs); - glyphLine->runs.add (glyphRun); - - CFDictionaryRef runAttributes = CTRunGetAttributes (run); - - CTFontRef ctRunFont; - if (CFDictionaryGetValueIfPresent (runAttributes, kCTFontAttributeName, (const void**) &ctRunFont)) - { - CFStringRef cfsFontName = CTFontCopyPostScriptName (ctRunFont); - CTFontRef ctFontRef = CTFontCreateWithName (cfsFontName, referenceFontSize, nullptr); - CFRelease (cfsFontName); - - const float fontHeightToPointsFactor = getHeightToPointsFactor (ctFontRef); - CFRelease (ctFontRef); - - CFStringRef cfsFontFamily = (CFStringRef) CTFontCopyAttribute (ctRunFont, kCTFontFamilyNameAttribute); - CFStringRef cfsFontStyle = (CFStringRef) CTFontCopyAttribute (ctRunFont, kCTFontStyleNameAttribute); - - glyphRun->font = Font (String::fromCFString (cfsFontFamily), - String::fromCFString (cfsFontStyle), - (float) (CTFontGetSize (ctRunFont) / fontHeightToPointsFactor)); - - CFRelease (cfsFontStyle); - CFRelease (cfsFontFamily); - } - - CGColorRef cgRunColor; - if (CFDictionaryGetValueIfPresent (runAttributes, kCTForegroundColorAttributeName, (const void**) &cgRunColor) - && CGColorGetNumberOfComponents (cgRunColor) == 4) - { - const CGFloat* const components = CGColorGetComponents (cgRunColor); - - glyphRun->colour = Colour::fromFloatRGBA ((float) components[0], - (float) components[1], - (float) components[2], - (float) components[3]); - } - - const Glyphs glyphs (run, (size_t) numGlyphs); - const Advances advances (run, numGlyphs); - const Positions positions (run, (size_t) numGlyphs); - - for (CFIndex k = 0; k < numGlyphs; ++k) - glyphRun->glyphs.add (TextLayout::Glyph (glyphs.glyphs[k], Point ((float) positions.points[k].x, - (float) positions.points[k].y), - (float) advances.advances[k].width)); - } - } - - CFRelease (frame); - } -} - - -//============================================================================== -class OSXTypeface : public Typeface -{ -public: - OSXTypeface (const Font& font) - : Typeface (font.getTypefaceName(), - font.getTypefaceStyle()), - fontRef (nullptr), - ctFontRef (nullptr), - fontHeightToPointsFactor (1.0f), - renderingTransform (CGAffineTransformIdentity), - isMemoryFont (false), - attributedStringAtts (nullptr), - ascent (0.0f), - unitsToHeightScaleFactor (0.0f) - { - ctFontRef = CoreTextTypeLayout::createCTFont (font, referenceFontSize, renderingTransform); - - if (ctFontRef != nullptr) - { - fontRef = CTFontCopyGraphicsFont (ctFontRef, nullptr); - initialiseMetrics(); - } - } - - OSXTypeface (const void* data, size_t dataSize) - : Typeface (String(), String()), - fontRef (nullptr), - ctFontRef (nullptr), - fontHeightToPointsFactor (1.0f), - renderingTransform (CGAffineTransformIdentity), - isMemoryFont (true), - dataCopy (data, dataSize), - attributedStringAtts (nullptr), - ascent (0.0f), - unitsToHeightScaleFactor (0.0f) - { - // We can't use CFDataCreate here as this triggers a false positive in ASAN - // so copy the data manually and use CFDataCreateWithBytesNoCopy - CFDataRef cfData = CFDataCreateWithBytesNoCopy (kCFAllocatorDefault, (const UInt8*) dataCopy.getData(), - (CFIndex) dataCopy.getSize(), kCFAllocatorNull); - CGDataProviderRef provider = CGDataProviderCreateWithCFData (cfData); - CFRelease (cfData); - - #if JUCE_IOS - // Workaround for a an obscure iOS bug which can cause the app to dead-lock - // when loading custom type faces. See: http://www.openradar.me/18778790 and - // http://stackoverflow.com/questions/40242370/app-hangs-in-simulator - [UIFont systemFontOfSize: 12]; - #endif - - fontRef = CGFontCreateWithDataProvider (provider); - CGDataProviderRelease (provider); - - if (fontRef != nullptr) - { - ctFontRef = CTFontCreateWithGraphicsFont (fontRef, referenceFontSize, nullptr, nullptr); - - if (ctFontRef != nullptr) - { - if (CFStringRef fontName = CTFontCopyName (ctFontRef, kCTFontFamilyNameKey)) - { - name = String::fromCFString (fontName); - CFRelease (fontName); - } - - if (CFStringRef fontStyle = CTFontCopyName (ctFontRef, kCTFontStyleNameKey)) - { - style = String::fromCFString (fontStyle); - CFRelease (fontStyle); - } - - initialiseMetrics(); - } - } - } - - void initialiseMetrics() - { - const float ctAscent = std::abs ((float) CTFontGetAscent (ctFontRef)); - const float ctDescent = std::abs ((float) CTFontGetDescent (ctFontRef)); - const float ctTotalHeight = ctAscent + ctDescent; - - ascent = ctAscent / ctTotalHeight; - unitsToHeightScaleFactor = 1.0f / ctTotalHeight; - pathTransform = AffineTransform::scale (unitsToHeightScaleFactor); - - fontHeightToPointsFactor = referenceFontSize / ctTotalHeight; - - const short zero = 0; - CFNumberRef numberRef = CFNumberCreate (0, kCFNumberShortType, &zero); - - CFStringRef keys[] = { kCTFontAttributeName, kCTLigatureAttributeName }; - CFTypeRef values[] = { ctFontRef, numberRef }; - attributedStringAtts = CFDictionaryCreate (nullptr, (const void**) &keys, (const void**) &values, numElementsInArray (keys), - &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFRelease (numberRef); - } - - ~OSXTypeface() - { - if (attributedStringAtts != nullptr) - CFRelease (attributedStringAtts); - - if (fontRef != nullptr) - CGFontRelease (fontRef); - - if (ctFontRef != nullptr) - CFRelease (ctFontRef); - } - - float getAscent() const override { return ascent; } - float getDescent() const override { return 1.0f - ascent; } - float getHeightToPointsFactor() const override { return fontHeightToPointsFactor; } - - float getStringWidth (const String& text) override - { - float x = 0; - - if (ctFontRef != nullptr && text.isNotEmpty()) - { - CFStringRef cfText = text.toCFString(); - CFAttributedStringRef attribString = CFAttributedStringCreate (kCFAllocatorDefault, cfText, attributedStringAtts); - CFRelease (cfText); - - CTLineRef line = CTLineCreateWithAttributedString (attribString); - CFArrayRef runArray = CTLineGetGlyphRuns (line); - - for (CFIndex i = 0; i < CFArrayGetCount (runArray); ++i) - { - CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (runArray, i); - CFIndex length = CTRunGetGlyphCount (run); - - const CoreTextTypeLayout::Advances advances (run, length); - - for (int j = 0; j < length; ++j) - x += (float) advances.advances[j].width; - } - - CFRelease (line); - CFRelease (attribString); - - x *= unitsToHeightScaleFactor; - } - - return x; - } - - void getGlyphPositions (const String& text, Array& resultGlyphs, Array& xOffsets) override - { - xOffsets.add (0); - - if (ctFontRef != nullptr && text.isNotEmpty()) - { - float x = 0; - - CFStringRef cfText = text.toCFString(); - CFAttributedStringRef attribString = CFAttributedStringCreate (kCFAllocatorDefault, cfText, attributedStringAtts); - CFRelease (cfText); - - CTLineRef line = CTLineCreateWithAttributedString (attribString); - CFArrayRef runArray = CTLineGetGlyphRuns (line); - - for (CFIndex i = 0; i < CFArrayGetCount (runArray); ++i) - { - CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (runArray, i); - CFIndex length = CTRunGetGlyphCount (run); - - const CoreTextTypeLayout::Advances advances (run, length); - const CoreTextTypeLayout::Glyphs glyphs (run, (size_t) length); - - for (int j = 0; j < length; ++j) - { - x += (float) advances.advances[j].width; - xOffsets.add (x * unitsToHeightScaleFactor); - resultGlyphs.add (glyphs.glyphs[j]); - } - } - - CFRelease (line); - CFRelease (attribString); - } - } - - bool getOutlineForGlyph (int glyphNumber, Path& path) override - { - jassert (path.isEmpty()); // we might need to apply a transform to the path, so this must be empty - - CGPathRef pathRef = CTFontCreatePathForGlyph (ctFontRef, (CGGlyph) glyphNumber, &renderingTransform); - if (pathRef == 0) - return false; - - CGPathApply (pathRef, &path, pathApplier); - CFRelease (pathRef); - - if (! pathTransform.isIdentity()) - path.applyTransform (pathTransform); - - return true; - } - - //============================================================================== - CGFontRef fontRef; - CTFontRef ctFontRef; - - float fontHeightToPointsFactor; - CGAffineTransform renderingTransform; - - bool isMemoryFont; - -private: - MemoryBlock dataCopy; - CFDictionaryRef attributedStringAtts; - float ascent, unitsToHeightScaleFactor; - AffineTransform pathTransform; - - static void pathApplier (void* info, const CGPathElement* const element) - { - Path& path = *static_cast (info); - const CGPoint* const p = element->points; - - switch (element->type) - { - case kCGPathElementMoveToPoint: path.startNewSubPath ((float) p[0].x, (float) -p[0].y); break; - case kCGPathElementAddLineToPoint: path.lineTo ((float) p[0].x, (float) -p[0].y); break; - case kCGPathElementAddQuadCurveToPoint: path.quadraticTo ((float) p[0].x, (float) -p[0].y, - (float) p[1].x, (float) -p[1].y); break; - case kCGPathElementAddCurveToPoint: path.cubicTo ((float) p[0].x, (float) -p[0].y, - (float) p[1].x, (float) -p[1].y, - (float) p[2].x, (float) -p[2].y); break; - case kCGPathElementCloseSubpath: path.closeSubPath(); break; - default: jassertfalse; break; - } - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSXTypeface) -}; - -CTFontRef getCTFontFromTypeface (const Font& f) -{ - if (OSXTypeface* tf = dynamic_cast (f.getTypeface())) - return tf->ctFontRef; - - return 0; -} - -StringArray Font::findAllTypefaceNames() -{ - StringArray names; - - #if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5 && ! JUCE_IOS - // CTFontManager only exists on OS X 10.6 and later, it does not exist on iOS - CFArrayRef fontFamilyArray = CTFontManagerCopyAvailableFontFamilyNames(); - - for (CFIndex i = 0; i < CFArrayGetCount (fontFamilyArray); ++i) - { - const String family (String::fromCFString ((CFStringRef) CFArrayGetValueAtIndex (fontFamilyArray, i))); - - if (! family.startsWithChar ('.')) // ignore fonts that start with a '.' - names.addIfNotAlreadyThere (family); - } - - CFRelease (fontFamilyArray); - #else - CTFontCollectionRef fontCollectionRef = CTFontCollectionCreateFromAvailableFonts (nullptr); - CFArrayRef fontDescriptorArray = CTFontCollectionCreateMatchingFontDescriptors (fontCollectionRef); - CFRelease (fontCollectionRef); - - for (CFIndex i = 0; i < CFArrayGetCount (fontDescriptorArray); ++i) - { - CTFontDescriptorRef ctFontDescriptorRef = (CTFontDescriptorRef) CFArrayGetValueAtIndex (fontDescriptorArray, i); - CFStringRef cfsFontFamily = (CFStringRef) CTFontDescriptorCopyAttribute (ctFontDescriptorRef, kCTFontFamilyNameAttribute); - - names.addIfNotAlreadyThere (String::fromCFString (cfsFontFamily)); - - CFRelease (cfsFontFamily); - } - - CFRelease (fontDescriptorArray); - #endif - - names.sort (true); - return names; -} - -StringArray Font::findAllTypefaceStyles (const String& family) -{ - if (FontStyleHelpers::isPlaceholderFamilyName (family)) - return findAllTypefaceStyles (FontStyleHelpers::getConcreteFamilyNameFromPlaceholder (family)); - - StringArray results; - - CFStringRef cfsFontFamily = family.toCFString(); - CFStringRef keys[] = { kCTFontFamilyNameAttribute }; - CFTypeRef values[] = { cfsFontFamily }; - - CFDictionaryRef fontDescAttributes = CFDictionaryCreate (nullptr, (const void**) &keys, (const void**) &values, numElementsInArray (keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFRelease (cfsFontFamily); - - CTFontDescriptorRef ctFontDescRef = CTFontDescriptorCreateWithAttributes (fontDescAttributes); - CFRelease (fontDescAttributes); - - CFArrayRef fontFamilyArray = CFArrayCreate (kCFAllocatorDefault, (const void**) &ctFontDescRef, 1, &kCFTypeArrayCallBacks); - CFRelease (ctFontDescRef); - - CTFontCollectionRef fontCollectionRef = CTFontCollectionCreateWithFontDescriptors (fontFamilyArray, nullptr); - CFRelease (fontFamilyArray); - - CFArrayRef fontDescriptorArray = CTFontCollectionCreateMatchingFontDescriptors (fontCollectionRef); - CFRelease (fontCollectionRef); - - if (fontDescriptorArray != nullptr) - { - for (CFIndex i = 0; i < CFArrayGetCount (fontDescriptorArray); ++i) - { - CTFontDescriptorRef ctFontDescriptorRef = (CTFontDescriptorRef) CFArrayGetValueAtIndex (fontDescriptorArray, i); - CFStringRef cfsFontStyle = (CFStringRef) CTFontDescriptorCopyAttribute (ctFontDescriptorRef, kCTFontStyleNameAttribute); - results.add (String::fromCFString (cfsFontStyle)); - CFRelease (cfsFontStyle); - } - - CFRelease (fontDescriptorArray); - } - - return results; -} - -#else - -//============================================================================== -class OSXTypeface : public Typeface -{ -public: - OSXTypeface (const Font& font) - : Typeface (font.getTypefaceName(), font.getTypefaceStyle()) - { - JUCE_AUTORELEASEPOOL - { - renderingTransform = CGAffineTransformIdentity; - - NSDictionary* nsDict = [NSDictionary dictionaryWithObjectsAndKeys: - juceStringToNS (name), NSFontFamilyAttribute, - juceStringToNS (style), NSFontFaceAttribute, nil]; - - NSFontDescriptor* nsFontDesc = [NSFontDescriptor fontDescriptorWithFontAttributes: nsDict]; - nsFont = [NSFont fontWithDescriptor: nsFontDesc size: referenceFontSize]; - - [nsFont retain]; - - fontRef = CGFontCreateWithFontName ((CFStringRef) [nsFont fontName]); - - const float absAscent = std::abs ((float) CGFontGetAscent (fontRef)); - const float totalHeight = absAscent + std::abs ((float) CGFontGetDescent (fontRef)); - - ascent = absAscent / totalHeight; - unitsToHeightScaleFactor = 1.0f / totalHeight; - - const float nsFontAscent = std::abs ([nsFont ascender]); - const float nsFontDescent = std::abs ([nsFont descender]); - - fontHeightToPointsFactor = referenceFontSize / (nsFontAscent + nsFontDescent); - - pathTransform = AffineTransform::scale (unitsToHeightScaleFactor); - } - } - - ~OSXTypeface() - { - #if ! JUCE_IOS - [nsFont release]; - #endif - - if (fontRef != 0) - CGFontRelease (fontRef); - } - - float getAscent() const override { return ascent; } - float getDescent() const override { return 1.0f - ascent; } - float getHeightToPointsFactor() const override { return fontHeightToPointsFactor; } - - float getStringWidth (const String& text) override - { - if (fontRef == 0 || text.isEmpty()) - return 0; - - const int length = text.length(); - HeapBlock glyphs; - createGlyphsForString (text.getCharPointer(), length, glyphs); - - float x = 0; - - HeapBlock advances (length); - - if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances)) - for (int i = 0; i < length; ++i) - x += advances[i]; - - return x * unitsToHeightScaleFactor; - } - - void getGlyphPositions (const String& text, Array& resultGlyphs, Array& xOffsets) override - { - xOffsets.add (0); - - if (fontRef == 0 || text.isEmpty()) - return; - - const int length = text.length(); - HeapBlock glyphs; - createGlyphsForString (text.getCharPointer(), length, glyphs); - - HeapBlock advances (length); - - if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances)) - { - int x = 0; - for (int i = 0; i < length; ++i) - { - x += advances [i]; - xOffsets.add (x * unitsToHeightScaleFactor); - resultGlyphs.add (glyphs[i]); - } - } - } - - bool getOutlineForGlyph (int glyphNumber, Path& path) override - { - #if JUCE_IOS - return false; - #else - if (nsFont == nil) - return false; - - // we might need to apply a transform to the path, so it mustn't have anything else in it - jassert (path.isEmpty()); - - JUCE_AUTORELEASEPOOL - { - NSBezierPath* bez = [NSBezierPath bezierPath]; - [bez moveToPoint: NSMakePoint (0, 0)]; - [bez appendBezierPathWithGlyph: (NSGlyph) glyphNumber - inFont: nsFont]; - - for (int i = 0; i < [bez elementCount]; ++i) - { - NSPoint p[3]; - switch ([bez elementAtIndex: i associatedPoints: p]) - { - case NSMoveToBezierPathElement: path.startNewSubPath ((float) p[0].x, (float) -p[0].y); break; - case NSLineToBezierPathElement: path.lineTo ((float) p[0].x, (float) -p[0].y); break; - case NSCurveToBezierPathElement: path.cubicTo ((float) p[0].x, (float) -p[0].y, - (float) p[1].x, (float) -p[1].y, - (float) p[2].x, (float) -p[2].y); break; - case NSClosePathBezierPathElement: path.closeSubPath(); break; - default: jassertfalse; break; - } - } - - path.applyTransform (pathTransform); - } - return true; - #endif - } - - //============================================================================== - CGFontRef fontRef; - float fontHeightToPointsFactor; - CGAffineTransform renderingTransform; - -private: - float ascent, unitsToHeightScaleFactor; - - #if ! JUCE_IOS - NSFont* nsFont; - AffineTransform pathTransform; - #endif - - void createGlyphsForString (String::CharPointerType text, const int length, HeapBlock& glyphs) - { - if (charToGlyphMapper == nullptr) - charToGlyphMapper = new CharToGlyphMapper (fontRef); - - glyphs.malloc (length); - - for (int i = 0; i < length; ++i) - glyphs[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text.getAndAdvance()); - } - - // Reads a CGFontRef's character map table to convert unicode into glyph numbers - class CharToGlyphMapper - { - public: - CharToGlyphMapper (CGFontRef cgFontRef) - : segCount (0), endCode (0), startCode (0), idDelta (0), - idRangeOffset (0), glyphIndexes (0) - { - CFDataRef cmapTable = CGFontCopyTableForTag (cgFontRef, 'cmap'); - - if (cmapTable != 0) - { - const int numSubtables = getValue16 (cmapTable, 2); - - for (int i = 0; i < numSubtables; ++i) - { - if (getValue16 (cmapTable, i * 8 + 4) == 0) // check for platform ID of 0 - { - const int offset = getValue32 (cmapTable, i * 8 + 8); - - if (getValue16 (cmapTable, offset) == 4) // check that it's format 4.. - { - const int length = getValue16 (cmapTable, offset + 2); - const int segCountX2 = getValue16 (cmapTable, offset + 6); - segCount = segCountX2 / 2; - const int endCodeOffset = offset + 14; - const int startCodeOffset = endCodeOffset + 2 + segCountX2; - const int idDeltaOffset = startCodeOffset + segCountX2; - const int idRangeOffsetOffset = idDeltaOffset + segCountX2; - const int glyphIndexesOffset = idRangeOffsetOffset + segCountX2; - - endCode = CFDataCreate (kCFAllocatorDefault, CFDataGetBytePtr (cmapTable) + endCodeOffset, segCountX2); - startCode = CFDataCreate (kCFAllocatorDefault, CFDataGetBytePtr (cmapTable) + startCodeOffset, segCountX2); - idDelta = CFDataCreate (kCFAllocatorDefault, CFDataGetBytePtr (cmapTable) + idDeltaOffset, segCountX2); - idRangeOffset = CFDataCreate (kCFAllocatorDefault, CFDataGetBytePtr (cmapTable) + idRangeOffsetOffset, segCountX2); - glyphIndexes = CFDataCreate (kCFAllocatorDefault, CFDataGetBytePtr (cmapTable) + glyphIndexesOffset, offset + length - glyphIndexesOffset); - } - - break; - } - } - - CFRelease (cmapTable); - } - } - - ~CharToGlyphMapper() - { - if (endCode != 0) - { - CFRelease (endCode); - CFRelease (startCode); - CFRelease (idDelta); - CFRelease (idRangeOffset); - CFRelease (glyphIndexes); - } - } - - int getGlyphForCharacter (const juce_wchar c) const - { - for (int i = 0; i < segCount; ++i) - { - if (getValue16 (endCode, i * 2) >= c) - { - const int start = getValue16 (startCode, i * 2); - if (start > c) - break; - - const int delta = getValue16 (idDelta, i * 2); - const int rangeOffset = getValue16 (idRangeOffset, i * 2); - - if (rangeOffset == 0) - return delta + c; - - return getValue16 (glyphIndexes, 2 * ((rangeOffset / 2) + (c - start) - (segCount - i))); - } - } - - // If we failed to find it "properly", this dodgy fall-back seems to do the trick for most fonts! - return jmax (-1, (int) c - 29); - } - - private: - int segCount; - CFDataRef endCode, startCode, idDelta, idRangeOffset, glyphIndexes; - - static uint16 getValue16 (CFDataRef data, const int index) - { - return CFSwapInt16BigToHost (*(UInt16*) (CFDataGetBytePtr (data) + index)); - } - - static uint32 getValue32 (CFDataRef data, const int index) - { - return CFSwapInt32BigToHost (*(UInt32*) (CFDataGetBytePtr (data) + index)); - } - }; - - ScopedPointer charToGlyphMapper; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSXTypeface) -}; - -StringArray Font::findAllTypefaceNames() -{ - StringArray names; - - JUCE_AUTORELEASEPOOL - { - #if JUCE_IOS - for (NSString* name in [UIFont familyNames]) - #else - for (NSString* name in [[NSFontManager sharedFontManager] availableFontFamilies]) - #endif - names.add (nsStringToJuce (name)); - - names.sort (true); - } - - return names; -} - -StringArray Font::findAllTypefaceStyles (const String& family) -{ - if (FontStyleHelpers::isPlaceholderFamilyName (family)) - return findAllTypefaceStyles (FontStyleHelpers::getConcreteFamilyNameFromPlaceholder (family)); - - StringArray results; - - JUCE_AUTORELEASEPOOL - { - for (NSArray* style in [[NSFontManager sharedFontManager] availableMembersOfFontFamily: juceStringToNS (family)]) - results.add (nsStringToJuce ((NSString*) [style objectAtIndex: 1])); - } - - return results; -} - -#endif - -//============================================================================== -Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font) -{ - return new OSXTypeface (font); -} - -Typeface::Ptr Typeface::createSystemTypefaceFor (const void* data, size_t dataSize) -{ - #if JUCE_CORETEXT_AVAILABLE - return new OSXTypeface (data, dataSize); - #else - jassertfalse; // You need CoreText enabled to use this feature! - return nullptr; - #endif -} - -void Typeface::scanFolderForFonts (const File&) -{ - jassertfalse; // not implemented on this platform -} - -struct DefaultFontNames -{ - DefaultFontNames() - #if JUCE_IOS - : defaultSans ("Helvetica"), - defaultSerif ("Times New Roman"), - defaultFixed ("Courier New"), - #else - : defaultSans ("Lucida Grande"), - defaultSerif ("Times New Roman"), - defaultFixed ("Menlo"), - #endif - defaultFallback ("Arial Unicode MS") - { - } - - String defaultSans, defaultSerif, defaultFixed, defaultFallback; -}; - -Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font) -{ - static DefaultFontNames defaultNames; - - Font newFont (font); - const String& faceName = font.getTypefaceName(); - - if (faceName == getDefaultSansSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSans); - else if (faceName == getDefaultSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSerif); - else if (faceName == getDefaultMonospacedFontName()) newFont.setTypefaceName (defaultNames.defaultFixed); - - if (font.getTypefaceStyle() == getDefaultStyle()) - newFont.setTypefaceStyle ("Regular"); - - return Typeface::createSystemTypefaceFor (newFont); -} - -#if JUCE_CORETEXT_AVAILABLE -static bool canAllTypefacesBeUsedInLayout (const AttributedString& text) -{ - const int numCharacterAttributes = text.getNumAttributes(); - - for (int i = 0; i < numCharacterAttributes; ++i) - { - Typeface* t = text.getAttribute(i).font.getTypeface(); - - if (OSXTypeface* tf = dynamic_cast (t)) - { - if (tf->isMemoryFont) - return false; - } - else if (dynamic_cast (t) != nullptr) - { - return false; - } - } - - return true; -} -#endif - -bool TextLayout::createNativeLayout (const AttributedString& text) -{ - #if JUCE_CORETEXT_AVAILABLE - // Seems to be an unfathomable bug in CoreText which prevents the layout working with - // typefaces that were loaded from memory, so have to fallback if we hit any of those.. - if (canAllTypefacesBeUsedInLayout (text)) - { - CoreTextTypeLayout::createLayout (*this, text); - return true; - } - #endif - - ignoreUnused (text); - return false; -} - -} // namespace juce diff --git a/source/modules/juce_graphics/native/juce_mac_IconHelpers.cpp b/source/modules/juce_graphics/native/juce_mac_IconHelpers.cpp deleted file mode 100644 index 03aa559c5..000000000 --- a/source/modules/juce_graphics/native/juce_mac_IconHelpers.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -Image getIconFromIcnsFile (const File& icnsFile, const int size) -{ - FileInputStream stream (icnsFile); - - if (! stream.openedOk()) - return {}; - - const int numHeaderSectionBytes = 4; - char headerSection [numHeaderSectionBytes]; - - if (stream.read (headerSection, numHeaderSectionBytes) != numHeaderSectionBytes - || headerSection[0] != 'i' - || headerSection[1] != 'c' - || headerSection[2] != 'n' - || headerSection[3] != 's') - return {}; - - if (stream.read (headerSection, numHeaderSectionBytes) != numHeaderSectionBytes) - return {}; - - const auto dataSize = juce::ByteOrder::bigEndianInt (headerSection); - - if (dataSize <= 0) - return {}; - - OwnedArray internalFormats; - internalFormats.add (new PNGImageFormat()); - internalFormats.add (new JPEGImageFormat()); - - Array images; - auto maxWidth = 0; - auto maxWidthIndex = -1; - - while (stream.getPosition() < dataSize) - { - const auto sectionStart = stream.getPosition(); - - if (! stream.setPosition (sectionStart + 4)) - break; - - if (stream.read (headerSection, numHeaderSectionBytes) != numHeaderSectionBytes) - break; - - const auto sectionSize = ByteOrder::bigEndianInt (headerSection); - - if (sectionSize <= 0) - break; - - const auto sectionDataStart = stream.getPosition(); - - for (auto* fmt : internalFormats) - { - if (fmt->canUnderstand (stream)) - { - stream.setPosition (sectionDataStart); - - images.add (fmt->decodeImage (stream)); - - const auto lastImageIndex = images.size() - 1; - const auto lastWidth = images.getReference (lastImageIndex).getWidth(); - - if (lastWidth > maxWidth) - { - maxWidthIndex = lastImageIndex; - maxWidth = lastWidth; - } - } - - stream.setPosition (sectionDataStart); - } - - stream.setPosition (sectionStart + sectionSize); - } - - return maxWidthIndex == -1 ? juce::Image() - : images.getReference (maxWidthIndex).rescaled (size, size, Graphics::ResamplingQuality::highResamplingQuality); -} - -Image JUCE_API getIconFromApplication (const String& applicationPath, const int size) -{ - Image hostIcon; - - if (CFStringRef pathCFString = CFStringCreateWithCString (kCFAllocatorDefault, applicationPath.toRawUTF8(), kCFStringEncodingUTF8)) - { - if (CFURLRef url = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, pathCFString, kCFURLPOSIXPathStyle, 1)) - { - if (CFBundleRef appBundle = CFBundleCreate (kCFAllocatorDefault, url)) - { - if (CFTypeRef infoValue = CFBundleGetValueForInfoDictionaryKey (appBundle, CFSTR("CFBundleIconFile"))) - { - if (CFGetTypeID (infoValue) == CFStringGetTypeID()) - { - CFStringRef iconFilename = reinterpret_cast (infoValue); - CFStringRef resourceURLSuffix = CFStringHasSuffix (iconFilename, CFSTR(".icns")) ? nullptr : CFSTR("icns"); - if (CFURLRef iconURL = CFBundleCopyResourceURL (appBundle, iconFilename, resourceURLSuffix, nullptr)) - { - if (CFStringRef iconPath = CFURLCopyFileSystemPath (iconURL, kCFURLPOSIXPathStyle)) - { - File icnsFile (CFStringGetCStringPtr (iconPath, CFStringGetSystemEncoding())); - hostIcon = getIconFromIcnsFile (icnsFile, size); - CFRelease (iconPath); - } - - CFRelease (iconURL); - } - } - } - - CFRelease (appBundle); - } - - CFRelease (url); - } - - CFRelease (pathCFString); - } - - return hostIcon; -} - -} // namespace juce diff --git a/source/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp b/source/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp deleted file mode 100644 index b9f7d592f..000000000 --- a/source/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp +++ /dev/null @@ -1,830 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -template -D2D1_RECT_F rectangleToRectF (const Rectangle& r) -{ - return D2D1::RectF ((float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom()); -} - -static D2D1_COLOR_F colourToD2D (Colour c) -{ - return D2D1::ColorF::ColorF (c.getFloatRed(), c.getFloatGreen(), c.getFloatBlue(), c.getFloatAlpha()); -} - -static void pathToGeometrySink (const Path& path, ID2D1GeometrySink* sink, const AffineTransform& transform) -{ - Path::Iterator it (path); - - while (it.next()) - { - switch (it.elementType) - { - case Path::Iterator::cubicTo: - { - D2D1_BEZIER_SEGMENT seg; - - transform.transformPoint (it.x1, it.y1); - seg.point1 = D2D1::Point2F (it.x1, it.y1); - - transform.transformPoint (it.x2, it.y2); - seg.point2 = D2D1::Point2F (it.x2, it.y2); - - transform.transformPoint (it.x3, it.y3); - seg.point3 = D2D1::Point2F (it.x3, it.y3); - - sink->AddBezier (seg); - break; - } - - case Path::Iterator::lineTo: - { - transform.transformPoint (it.x1, it.y1); - sink->AddLine (D2D1::Point2F (it.x1, it.y1)); - break; - } - - case Path::Iterator::quadraticTo: - { - D2D1_QUADRATIC_BEZIER_SEGMENT seg; - - transform.transformPoint (it.x1, it.y1); - seg.point1 = D2D1::Point2F (it.x1, it.y1); - - transform.transformPoint (it.x2, it.y2); - seg.point2 = D2D1::Point2F (it.x2, it.y2); - - sink->AddQuadraticBezier (seg); - break; - } - - case Path::Iterator::closePath: - { - sink->EndFigure (D2D1_FIGURE_END_CLOSED); - break; - } - - case Path::Iterator::startNewSubPath: - { - transform.transformPoint (it.x1, it.y1); - sink->BeginFigure (D2D1::Point2F (it.x1, it.y1), D2D1_FIGURE_BEGIN_FILLED); - break; - } - } - } -} - -static D2D1::Matrix3x2F transformToMatrix (const AffineTransform& transform) -{ - D2D1::Matrix3x2F matrix; - matrix._11 = transform.mat00; - matrix._12 = transform.mat10; - matrix._21 = transform.mat01; - matrix._22 = transform.mat11; - matrix._31 = transform.mat02; - matrix._32 = transform.mat12; - return matrix; -} - -static D2D1_POINT_2F pointTransformed (int x, int y, const AffineTransform& transform) -{ - transform.transformPoint (x, y); - return D2D1::Point2F ((FLOAT) x, (FLOAT) y); -} - -static void rectToGeometrySink (const Rectangle& rect, ID2D1GeometrySink* sink, const AffineTransform& transform) -{ - sink->BeginFigure (pointTransformed (rect.getX(), rect.getY(), transform), D2D1_FIGURE_BEGIN_FILLED); - sink->AddLine (pointTransformed (rect.getRight(), rect.getY(), transform)); - sink->AddLine (pointTransformed (rect.getRight(), rect.getBottom(), transform)); - sink->AddLine (pointTransformed (rect.getX(), rect.getBottom(), transform)); - sink->EndFigure (D2D1_FIGURE_END_CLOSED); -} - -//============================================================================== -struct Direct2DLowLevelGraphicsContext::Pimpl -{ - ID2D1PathGeometry* rectListToPathGeometry (const RectangleList& clipRegion) - { - ID2D1PathGeometry* p = nullptr; - factories->d2dFactory->CreatePathGeometry (&p); - - ComSmartPtr sink; - HRESULT hr = p->Open (sink.resetAndGetPointerAddress()); // xxx handle error - sink->SetFillMode (D2D1_FILL_MODE_WINDING); - - for (int i = clipRegion.getNumRectangles(); --i >= 0;) - rectToGeometrySink (clipRegion.getRectangle(i), sink, AffineTransform()); - - hr = sink->Close(); - return p; - } - - ID2D1PathGeometry* pathToPathGeometry (const Path& path, const AffineTransform& transform) - { - ID2D1PathGeometry* p = nullptr; - factories->d2dFactory->CreatePathGeometry (&p); - - ComSmartPtr sink; - HRESULT hr = p->Open (sink.resetAndGetPointerAddress()); - sink->SetFillMode (D2D1_FILL_MODE_WINDING); // xxx need to check Path::isUsingNonZeroWinding() - - pathToGeometrySink (path, sink, transform); - - hr = sink->Close(); - return p; - } - - SharedResourcePointer factories; - - ComSmartPtr renderingTarget; - ComSmartPtr colourBrush; -}; - -//============================================================================== -struct Direct2DLowLevelGraphicsContext::SavedState -{ -public: - SavedState (Direct2DLowLevelGraphicsContext& owner_) - : owner (owner_) - { - if (owner.currentState != nullptr) - { - // xxx seems like a very slow way to create one of these, and this is a performance - // bottleneck.. Can the same internal objects be shared by multiple state objects, maybe using copy-on-write? - setFill (owner.currentState->fillType); - currentBrush = owner.currentState->currentBrush; - clipRect = owner.currentState->clipRect; - transform = owner.currentState->transform; - - font = owner.currentState->font; - currentFontFace = owner.currentState->currentFontFace; - } - else - { - const D2D1_SIZE_U size (owner.pimpl->renderingTarget->GetPixelSize()); - clipRect.setSize (size.width, size.height); - setFill (FillType (Colours::black)); - } - } - - ~SavedState() - { - clearClip(); - clearFont(); - clearFill(); - clearPathClip(); - clearImageClip(); - complexClipLayer = nullptr; - bitmapMaskLayer = nullptr; - } - - void clearClip() - { - popClips(); - shouldClipRect = false; - } - - void clipToRectangle (const Rectangle& r) - { - clearClip(); - clipRect = r.toFloat().transformed (transform).getSmallestIntegerContainer(); - shouldClipRect = true; - pushClips(); - } - - void clearPathClip() - { - popClips(); - - if (shouldClipComplex) - { - complexClipGeometry = nullptr; - shouldClipComplex = false; - } - } - - void Direct2DLowLevelGraphicsContext::SavedState::clipToPath (ID2D1Geometry* geometry) - { - clearPathClip(); - - if (complexClipLayer == nullptr) - owner.pimpl->renderingTarget->CreateLayer (complexClipLayer.resetAndGetPointerAddress()); - - complexClipGeometry = geometry; - shouldClipComplex = true; - pushClips(); - } - - void clearRectListClip() - { - popClips(); - - if (shouldClipRectList) - { - rectListGeometry = nullptr; - shouldClipRectList = false; - } - } - - void clipToRectList (ID2D1Geometry* geometry) - { - clearRectListClip(); - - if (rectListLayer == nullptr) - owner.pimpl->renderingTarget->CreateLayer (rectListLayer.resetAndGetPointerAddress()); - - rectListGeometry = geometry; - shouldClipRectList = true; - pushClips(); - } - - void clearImageClip() - { - popClips(); - - if (shouldClipBitmap) - { - maskBitmap = nullptr; - bitmapMaskBrush = nullptr; - shouldClipBitmap = false; - } - } - - void clipToImage (const Image& clipImage, const AffineTransform& clipTransform) - { - clearImageClip(); - - if (bitmapMaskLayer == nullptr) - owner.pimpl->renderingTarget->CreateLayer (bitmapMaskLayer.resetAndGetPointerAddress()); - - D2D1_BRUSH_PROPERTIES brushProps; - brushProps.opacity = 1; - brushProps.transform = transformToMatrix (clipTransform); - - D2D1_BITMAP_BRUSH_PROPERTIES bmProps = D2D1::BitmapBrushProperties (D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP); - - D2D1_SIZE_U size; - size.width = clipImage.getWidth(); - size.height = clipImage.getHeight(); - - D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties(); - - maskImage = clipImage.convertedToFormat (Image::ARGB); - Image::BitmapData bd (maskImage, Image::BitmapData::readOnly); // xxx should be maskImage? - bp.pixelFormat = owner.pimpl->renderingTarget->GetPixelFormat(); - bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; - - HRESULT hr = owner.pimpl->renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, maskBitmap.resetAndGetPointerAddress()); - hr = owner.pimpl->renderingTarget->CreateBitmapBrush (maskBitmap, bmProps, brushProps, bitmapMaskBrush.resetAndGetPointerAddress()); - - imageMaskLayerParams = D2D1::LayerParameters(); - imageMaskLayerParams.opacityBrush = bitmapMaskBrush; - - shouldClipBitmap = true; - pushClips(); - } - - void popClips() - { - if (clipsBitmap) - { - owner.pimpl->renderingTarget->PopLayer(); - clipsBitmap = false; - } - - if (clipsComplex) - { - owner.pimpl->renderingTarget->PopLayer(); - clipsComplex = false; - } - - if (clipsRectList) - { - owner.pimpl->renderingTarget->PopLayer(); - clipsRectList = false; - } - - if (clipsRect) - { - owner.pimpl->renderingTarget->PopAxisAlignedClip(); - clipsRect = false; - } - } - - void pushClips() - { - if (shouldClipRect && !clipsRect) - { - owner.pimpl->renderingTarget->PushAxisAlignedClip (rectangleToRectF (clipRect), D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); - clipsRect = true; - } - - if (shouldClipRectList && !clipsRectList) - { - D2D1_LAYER_PARAMETERS layerParams = D2D1::LayerParameters(); - rectListGeometry->GetBounds (D2D1::IdentityMatrix(), &layerParams.contentBounds); - layerParams.geometricMask = rectListGeometry; - owner.pimpl->renderingTarget->PushLayer (layerParams, rectListLayer); - clipsRectList = true; - } - - if (shouldClipComplex && !clipsComplex) - { - D2D1_LAYER_PARAMETERS layerParams = D2D1::LayerParameters(); - complexClipGeometry->GetBounds (D2D1::IdentityMatrix(), &layerParams.contentBounds); - layerParams.geometricMask = complexClipGeometry; - owner.pimpl->renderingTarget->PushLayer (layerParams, complexClipLayer); - clipsComplex = true; - } - - if (shouldClipBitmap && !clipsBitmap) - { - owner.pimpl->renderingTarget->PushLayer (imageMaskLayerParams, bitmapMaskLayer); - clipsBitmap = true; - } - } - - void setFill (const FillType& newFillType) - { - if (fillType != newFillType) - { - fillType = newFillType; - clearFill(); - } - } - - void clearFont() - { - currentFontFace = localFontFace = nullptr; - } - - void setFont (const Font& newFont) - { - if (font != newFont) - { - font = newFont; - clearFont(); - } - } - - void createFont() - { - if (currentFontFace == nullptr) - { - WindowsDirectWriteTypeface* typeface = dynamic_cast (font.getTypeface()); - currentFontFace = typeface->getIDWriteFontFace(); - fontHeightToEmSizeFactor = typeface->getUnitsToHeightScaleFactor(); - } - } - - void setOpacity (float newOpacity) - { - fillType.setOpacity (newOpacity); - - if (currentBrush != nullptr) - currentBrush->SetOpacity (newOpacity); - } - - void clearFill() - { - gradientStops = nullptr; - linearGradient = nullptr; - radialGradient = nullptr; - bitmap = nullptr; - bitmapBrush = nullptr; - currentBrush = nullptr; - } - - void createBrush() - { - if (currentBrush == nullptr) - { - if (fillType.isColour()) - { - D2D1_COLOR_F colour = colourToD2D (fillType.colour); - owner.pimpl->colourBrush->SetColor (colour); - currentBrush = owner.pimpl->colourBrush; - } - else if (fillType.isTiledImage()) - { - D2D1_BRUSH_PROPERTIES brushProps; - brushProps.opacity = fillType.getOpacity(); - brushProps.transform = transformToMatrix (fillType.transform); - - D2D1_BITMAP_BRUSH_PROPERTIES bmProps = D2D1::BitmapBrushProperties (D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP); - - image = fillType.image; - - D2D1_SIZE_U size; - size.width = image.getWidth(); - size.height = image.getHeight(); - - D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties(); - - this->image = image.convertedToFormat (Image::ARGB); - Image::BitmapData bd (this->image, Image::BitmapData::readOnly); - bp.pixelFormat = owner.pimpl->renderingTarget->GetPixelFormat(); - bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; - - HRESULT hr = owner.pimpl->renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, bitmap.resetAndGetPointerAddress()); - hr = owner.pimpl->renderingTarget->CreateBitmapBrush (bitmap, bmProps, brushProps, bitmapBrush.resetAndGetPointerAddress()); - - currentBrush = bitmapBrush; - } - else if (fillType.isGradient()) - { - gradientStops = nullptr; - - D2D1_BRUSH_PROPERTIES brushProps; - brushProps.opacity = fillType.getOpacity(); - brushProps.transform = transformToMatrix (fillType.transform.followedBy (transform)); - - const int numColors = fillType.gradient->getNumColours(); - - HeapBlock stops (numColors); - - for (int i = fillType.gradient->getNumColours(); --i >= 0;) - { - stops[i].color = colourToD2D (fillType.gradient->getColour (i)); - stops[i].position = (FLOAT) fillType.gradient->getColourPosition (i); - } - - owner.pimpl->renderingTarget->CreateGradientStopCollection (stops.getData(), numColors, gradientStops.resetAndGetPointerAddress()); - - if (fillType.gradient->isRadial) - { - radialGradient = nullptr; - - const Point p1 = fillType.gradient->point1; - const Point p2 = fillType.gradient->point2; - float r = p1.getDistanceFrom(p2); - - D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES props = - D2D1::RadialGradientBrushProperties(D2D1::Point2F(p1.x, p1.y), - D2D1::Point2F(0, 0), - r, r); - - owner.pimpl->renderingTarget->CreateRadialGradientBrush(props, brushProps, gradientStops, radialGradient.resetAndGetPointerAddress()); - currentBrush = radialGradient; - } - else - { - linearGradient = 0; - - const Point p1 = fillType.gradient->point1; - const Point p2 = fillType.gradient->point2; - - D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES props = - D2D1::LinearGradientBrushProperties(D2D1::Point2F(p1.x, p1.y), - D2D1::Point2F(p2.x, p2.y)); - - owner.pimpl->renderingTarget->CreateLinearGradientBrush (props, brushProps, gradientStops, linearGradient.resetAndGetPointerAddress()); - - currentBrush = linearGradient; - } - } - } - } - - Direct2DLowLevelGraphicsContext& owner; - - AffineTransform transform; - - Font font; - float fontHeightToEmSizeFactor = 1.0; - - IDWriteFontFace* currentFontFace = nullptr; - ComSmartPtr localFontFace; - - Rectangle clipRect; - bool clipsRect = false, shouldClipRect = false; - - Image image; - ComSmartPtr bitmap; // xxx needs a better name - what is this for?? - bool clipsBitmap = false, shouldClipBitmap = false; - - ComSmartPtr complexClipGeometry; - D2D1_LAYER_PARAMETERS complexClipLayerParams; - ComSmartPtr complexClipLayer; - bool clipsComplex = false, shouldClipComplex = false; - - ComSmartPtr rectListGeometry; - D2D1_LAYER_PARAMETERS rectListLayerParams; - ComSmartPtr rectListLayer; - bool clipsRectList = false, shouldClipRectList = false; - - Image maskImage; - D2D1_LAYER_PARAMETERS imageMaskLayerParams; - ComSmartPtr bitmapMaskLayer; - ComSmartPtr maskBitmap; - ComSmartPtr bitmapMaskBrush; - - ID2D1Brush* currentBrush = nullptr; - ComSmartPtr bitmapBrush; - ComSmartPtr linearGradient; - ComSmartPtr radialGradient; - ComSmartPtr gradientStops; - - FillType fillType; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SavedState) -}; - -//============================================================================== -Direct2DLowLevelGraphicsContext::Direct2DLowLevelGraphicsContext (HWND hwnd_) - : hwnd (hwnd_), - currentState (nullptr), - pimpl (new Pimpl()) -{ - RECT windowRect; - GetClientRect (hwnd, &windowRect); - D2D1_SIZE_U size = { (UINT32) (windowRect.right - windowRect.left), (UINT32) (windowRect.bottom - windowRect.top) }; - bounds.setSize (size.width, size.height); - - D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(); - D2D1_HWND_RENDER_TARGET_PROPERTIES propsHwnd = D2D1::HwndRenderTargetProperties (hwnd, size); - - if (pimpl->factories->d2dFactory != nullptr) - { - HRESULT hr = pimpl->factories->d2dFactory->CreateHwndRenderTarget (props, propsHwnd, pimpl->renderingTarget.resetAndGetPointerAddress()); - jassert (SUCCEEDED (hr)); ignoreUnused (hr); - hr = pimpl->renderingTarget->CreateSolidColorBrush (D2D1::ColorF::ColorF (0.0f, 0.0f, 0.0f, 1.0f), pimpl->colourBrush.resetAndGetPointerAddress()); - } -} - -Direct2DLowLevelGraphicsContext::~Direct2DLowLevelGraphicsContext() -{ - states.clear(); -} - -void Direct2DLowLevelGraphicsContext::resized() -{ - RECT windowRect; - GetClientRect (hwnd, &windowRect); - D2D1_SIZE_U size = { (UINT32) (windowRect.right - windowRect.left), (UINT32) (windowRect.bottom - windowRect.top) }; - - pimpl->renderingTarget->Resize (size); - bounds.setSize (size.width, size.height); -} - -void Direct2DLowLevelGraphicsContext::clear() -{ - pimpl->renderingTarget->Clear (D2D1::ColorF (D2D1::ColorF::White, 0.0f)); // xxx why white and not black? -} - -void Direct2DLowLevelGraphicsContext::start() -{ - pimpl->renderingTarget->BeginDraw(); - saveState(); -} - -void Direct2DLowLevelGraphicsContext::end() -{ - states.clear(); - currentState = 0; - pimpl->renderingTarget->EndDraw(); - pimpl->renderingTarget->CheckWindowState(); -} - -void Direct2DLowLevelGraphicsContext::setOrigin (Point o) -{ - addTransform (AffineTransform::translation ((float) o.x, (float) o.y)); -} - -void Direct2DLowLevelGraphicsContext::addTransform (const AffineTransform& transform) -{ - currentState->transform = transform.followedBy (currentState->transform); -} - -float Direct2DLowLevelGraphicsContext::getPhysicalPixelScaleFactor() -{ - return currentState->transform.getScaleFactor(); -} - -bool Direct2DLowLevelGraphicsContext::clipToRectangle (const Rectangle& r) -{ - currentState->clipToRectangle (r); - return ! isClipEmpty(); -} - -bool Direct2DLowLevelGraphicsContext::clipToRectangleList (const RectangleList& clipRegion) -{ - currentState->clipToRectList (pimpl->rectListToPathGeometry (clipRegion)); - return ! isClipEmpty(); -} - -void Direct2DLowLevelGraphicsContext::excludeClipRectangle (const Rectangle&) -{ - //xxx -} - -void Direct2DLowLevelGraphicsContext::clipToPath (const Path& path, const AffineTransform& transform) -{ - currentState->clipToPath (pimpl->pathToPathGeometry (path, transform)); -} - -void Direct2DLowLevelGraphicsContext::clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform) -{ - currentState->clipToImage (sourceImage, transform); -} - -bool Direct2DLowLevelGraphicsContext::clipRegionIntersects (const Rectangle& r) -{ - return currentState->clipRect.intersects (r.toFloat().transformed (currentState->transform).getSmallestIntegerContainer()); -} - -Rectangle Direct2DLowLevelGraphicsContext::getClipBounds() const -{ - // xxx could this take into account complex clip regions? - return currentState->clipRect.toFloat().transformed (currentState->transform.inverted()).getSmallestIntegerContainer(); -} - -bool Direct2DLowLevelGraphicsContext::isClipEmpty() const -{ - return currentState->clipRect.isEmpty(); -} - -void Direct2DLowLevelGraphicsContext::saveState() -{ - states.add (new SavedState (*this)); - currentState = states.getLast(); -} - -void Direct2DLowLevelGraphicsContext::restoreState() -{ - jassert (states.size() > 1); //you should never pop the last state! - states.removeLast (1); - currentState = states.getLast(); -} - -void Direct2DLowLevelGraphicsContext::beginTransparencyLayer (float /*opacity*/) -{ - jassertfalse; //xxx todo -} - -void Direct2DLowLevelGraphicsContext::endTransparencyLayer() -{ - jassertfalse; //xxx todo -} - -void Direct2DLowLevelGraphicsContext::setFill (const FillType& fillType) -{ - currentState->setFill (fillType); -} - -void Direct2DLowLevelGraphicsContext::setOpacity (float newOpacity) -{ - currentState->setOpacity (newOpacity); -} - -void Direct2DLowLevelGraphicsContext::setInterpolationQuality (Graphics::ResamplingQuality /*quality*/) -{ -} - -void Direct2DLowLevelGraphicsContext::fillRect (const Rectangle& r, bool /*replaceExistingContents*/) -{ - fillRect (r.toFloat()); -} - -void Direct2DLowLevelGraphicsContext::fillRect (const Rectangle& r) -{ - pimpl->renderingTarget->SetTransform (transformToMatrix (currentState->transform)); - currentState->createBrush(); - pimpl->renderingTarget->FillRectangle (rectangleToRectF (r), currentState->currentBrush); - pimpl->renderingTarget->SetTransform (D2D1::IdentityMatrix()); -} - -void Direct2DLowLevelGraphicsContext::fillRectList (const RectangleList& list) -{ - for (auto& r : list) - fillRect (r); -} - -void Direct2DLowLevelGraphicsContext::fillPath (const Path& p, const AffineTransform& transform) -{ - currentState->createBrush(); - ComSmartPtr geometry (pimpl->pathToPathGeometry (p, transform.followedBy (currentState->transform))); - - if (pimpl->renderingTarget != nullptr) - pimpl->renderingTarget->FillGeometry (geometry, currentState->currentBrush); -} - -void Direct2DLowLevelGraphicsContext::drawImage (const Image& image, const AffineTransform& transform) -{ - pimpl->renderingTarget->SetTransform (transformToMatrix (transform.followedBy (currentState->transform))); - - D2D1_SIZE_U size; - size.width = image.getWidth(); - size.height = image.getHeight(); - - D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties(); - - Image img (image.convertedToFormat (Image::ARGB)); - Image::BitmapData bd (img, Image::BitmapData::readOnly); - bp.pixelFormat = pimpl->renderingTarget->GetPixelFormat(); - bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; - - { - ComSmartPtr tempBitmap; - pimpl->renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, tempBitmap.resetAndGetPointerAddress()); - if (tempBitmap != nullptr) - pimpl->renderingTarget->DrawBitmap (tempBitmap); - } - - pimpl->renderingTarget->SetTransform (D2D1::IdentityMatrix()); -} - -void Direct2DLowLevelGraphicsContext::drawLine (const Line & line) -{ - // xxx doesn't seem to be correctly aligned, may need nudging by 0.5 to match the software renderer's behaviour - pimpl->renderingTarget->SetTransform (transformToMatrix (currentState->transform)); - currentState->createBrush(); - - pimpl->renderingTarget->DrawLine (D2D1::Point2F (line.getStartX(), line.getStartY()), - D2D1::Point2F (line.getEndX(), line.getEndY()), - currentState->currentBrush); - pimpl->renderingTarget->SetTransform (D2D1::IdentityMatrix()); -} - -void Direct2DLowLevelGraphicsContext::setFont (const Font& newFont) -{ - currentState->setFont (newFont); -} - -const Font& Direct2DLowLevelGraphicsContext::getFont() -{ - return currentState->font; -} - -void Direct2DLowLevelGraphicsContext::drawGlyph (int glyphNumber, const AffineTransform& transform) -{ - currentState->createBrush(); - currentState->createFont(); - - float hScale = currentState->font.getHorizontalScale(); - - pimpl->renderingTarget->SetTransform (transformToMatrix (AffineTransform::scale (hScale, 1.0f) - .followedBy (transform) - .followedBy (currentState->transform))); - - const UINT16 glyphIndices = (UINT16) glyphNumber; - const FLOAT glyphAdvances = 0; - DWRITE_GLYPH_OFFSET offset; - offset.advanceOffset = 0; - offset.ascenderOffset = 0; - - DWRITE_GLYPH_RUN glyphRun; - glyphRun.fontFace = currentState->currentFontFace; - glyphRun.fontEmSize = (FLOAT) (currentState->font.getHeight() * currentState->fontHeightToEmSizeFactor); - glyphRun.glyphCount = 1; - glyphRun.glyphIndices = &glyphIndices; - glyphRun.glyphAdvances = &glyphAdvances; - glyphRun.glyphOffsets = &offset; - glyphRun.isSideways = FALSE; - glyphRun.bidiLevel = 0; - - pimpl->renderingTarget->DrawGlyphRun (D2D1::Point2F (0, 0), &glyphRun, currentState->currentBrush); - pimpl->renderingTarget->SetTransform (D2D1::IdentityMatrix()); -} - -bool Direct2DLowLevelGraphicsContext::drawTextLayout (const AttributedString& text, const Rectangle& area) -{ - pimpl->renderingTarget->SetTransform (transformToMatrix (currentState->transform)); - - DirectWriteTypeLayout::drawToD2DContext (text, area, - *(pimpl->renderingTarget), - *(pimpl->factories->directWriteFactory), - *(pimpl->factories->systemFonts)); - - pimpl->renderingTarget->SetTransform (D2D1::IdentityMatrix()); - return true; -} - -} // namespace juce diff --git a/source/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.h b/source/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.h deleted file mode 100644 index fb8714dbf..000000000 --- a/source/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -#ifndef _WINDEF_ -class HWND__; // Forward or never -typedef HWND__* HWND; -#endif - -class Direct2DLowLevelGraphicsContext : public LowLevelGraphicsContext -{ -public: - Direct2DLowLevelGraphicsContext (HWND); - ~Direct2DLowLevelGraphicsContext(); - - //============================================================================== - bool isVectorDevice() const override { return false; } - - void setOrigin (Point) override; - void addTransform (const AffineTransform&) override; - float getPhysicalPixelScaleFactor() override; - bool clipToRectangle (const Rectangle&) override; - bool clipToRectangleList (const RectangleList&) override; - void excludeClipRectangle (const Rectangle&) override; - void clipToPath (const Path&, const AffineTransform&) override; - void clipToImageAlpha (const Image&, const AffineTransform&) override; - bool clipRegionIntersects (const Rectangle&) override; - Rectangle getClipBounds() const override; - bool isClipEmpty() const override; - - //============================================================================== - void saveState() override; - void restoreState() override; - void beginTransparencyLayer (float opacity) override; - void endTransparencyLayer() override; - - //============================================================================== - void setFill (const FillType&) override; - void setOpacity (float) override; - void setInterpolationQuality (Graphics::ResamplingQuality) override; - - //============================================================================== - void fillRect (const Rectangle&, bool replaceExistingContents) override; - void fillRect (const Rectangle&) override; - void fillRectList (const RectangleList&) override; - void fillPath (const Path&, const AffineTransform&) override; - void drawImage (const Image& sourceImage, const AffineTransform&) override; - - //============================================================================== - void drawLine (const Line&) override; - void setFont (const Font&) override; - const Font& getFont() override; - void drawGlyph (int glyphNumber, const AffineTransform&) override; - bool drawTextLayout (const AttributedString&, const Rectangle&) override; - - void resized(); - void clear(); - - void start(); - void end(); - - //============================================================================== -private: - struct SavedState; - - HWND hwnd; - - SavedState* currentState; - OwnedArray states; - - Rectangle bounds; - - struct Pimpl; - friend struct Pimpl; - friend struct ContainerDeletePolicy; - ScopedPointer pimpl; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Direct2DLowLevelGraphicsContext) -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp b/source/modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp deleted file mode 100644 index d007ebb6b..000000000 --- a/source/modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp +++ /dev/null @@ -1,460 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -#if JUCE_USE_DIRECTWRITE -namespace DirectWriteTypeLayout -{ - class CustomDirectWriteTextRenderer : public ComBaseClassHelper - { - public: - CustomDirectWriteTextRenderer (IDWriteFontCollection& fonts, const AttributedString& as) - : ComBaseClassHelper (0), - attributedString (as), - fontCollection (fonts), - currentLine (-1), - lastOriginY (-10000.0f) - { - } - - JUCE_COMRESULT QueryInterface (REFIID refId, void** result) override - { - if (refId == __uuidof (IDWritePixelSnapping)) - return castToType (result); - - return ComBaseClassHelper::QueryInterface (refId, result); - } - - JUCE_COMRESULT IsPixelSnappingDisabled (void* /*clientDrawingContext*/, BOOL* isDisabled) override - { - *isDisabled = FALSE; - return S_OK; - } - - JUCE_COMRESULT GetCurrentTransform (void*, DWRITE_MATRIX* matrix) override - { - matrix->m11 = 1.0f; matrix->m12 = 0.0f; - matrix->m21 = 0.0f; matrix->m22 = 1.0f; - matrix->dx = 0.0f; matrix->dy = 0.0f; - return S_OK; - } - - JUCE_COMRESULT GetPixelsPerDip (void*, FLOAT* pixelsPerDip) override - { - *pixelsPerDip = 1.0f; - return S_OK; - } - - JUCE_COMRESULT DrawUnderline (void*, FLOAT, FLOAT, DWRITE_UNDERLINE const*, IUnknown*) override - { - return E_NOTIMPL; - } - - JUCE_COMRESULT DrawStrikethrough (void*, FLOAT, FLOAT, DWRITE_STRIKETHROUGH const*, IUnknown*) override - { - return E_NOTIMPL; - } - - JUCE_COMRESULT DrawInlineObject (void*, FLOAT, FLOAT, IDWriteInlineObject*, BOOL, BOOL, IUnknown*) override - { - return E_NOTIMPL; - } - - JUCE_COMRESULT DrawGlyphRun (void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE, - DWRITE_GLYPH_RUN const* glyphRun, DWRITE_GLYPH_RUN_DESCRIPTION const* runDescription, - IUnknown* clientDrawingEffect) override - { - TextLayout* const layout = static_cast (clientDrawingContext); - - if (! (baselineOriginY >= -1.0e10f && baselineOriginY <= 1.0e10f)) - baselineOriginY = 0; // DirectWrite sometimes sends NaNs in this parameter - - if (baselineOriginY != lastOriginY) - { - lastOriginY = baselineOriginY; - ++currentLine; - - if (currentLine >= layout->getNumLines()) - { - jassert (currentLine == layout->getNumLines()); - TextLayout::Line* const line = new TextLayout::Line(); - layout->addLine (line); - - line->lineOrigin = Point (baselineOriginX, baselineOriginY); - } - } - - TextLayout::Line& glyphLine = layout->getLine (currentLine); - - DWRITE_FONT_METRICS dwFontMetrics; - glyphRun->fontFace->GetMetrics (&dwFontMetrics); - - glyphLine.ascent = jmax (glyphLine.ascent, scaledFontSize (dwFontMetrics.ascent, dwFontMetrics, *glyphRun)); - glyphLine.descent = jmax (glyphLine.descent, scaledFontSize (dwFontMetrics.descent, dwFontMetrics, *glyphRun)); - - TextLayout::Run* const glyphRunLayout = new TextLayout::Run (Range (runDescription->textPosition, - runDescription->textPosition + runDescription->stringLength), - glyphRun->glyphCount); - glyphLine.runs.add (glyphRunLayout); - - glyphRun->fontFace->GetMetrics (&dwFontMetrics); - const float totalHeight = std::abs ((float) dwFontMetrics.ascent) + std::abs ((float) dwFontMetrics.descent); - const float fontHeightToEmSizeFactor = (float) dwFontMetrics.designUnitsPerEm / totalHeight; - - glyphRunLayout->font = getFontForRun (*glyphRun, glyphRun->fontEmSize / fontHeightToEmSizeFactor); - glyphRunLayout->colour = getColourOf (static_cast (clientDrawingEffect)); - - const Point lineOrigin (layout->getLine (currentLine).lineOrigin); - float x = baselineOriginX - lineOrigin.x; - - const float extraKerning = glyphRunLayout->font.getExtraKerningFactor() - * glyphRunLayout->font.getHeight(); - - for (UINT32 i = 0; i < glyphRun->glyphCount; ++i) - { - const float advance = glyphRun->glyphAdvances[i]; - - if ((glyphRun->bidiLevel & 1) != 0) - x -= advance + extraKerning; // RTL text - - glyphRunLayout->glyphs.add (TextLayout::Glyph (glyphRun->glyphIndices[i], - Point (x, baselineOriginY - lineOrigin.y), - advance)); - - if ((glyphRun->bidiLevel & 1) == 0) - x += advance + extraKerning; // LTR text - } - - return S_OK; - } - - private: - const AttributedString& attributedString; - IDWriteFontCollection& fontCollection; - int currentLine; - float lastOriginY; - - static float scaledFontSize (int n, const DWRITE_FONT_METRICS& metrics, const DWRITE_GLYPH_RUN& glyphRun) noexcept - { - return (std::abs ((float) n) / (float) metrics.designUnitsPerEm) * glyphRun.fontEmSize; - } - - static Colour getColourOf (ID2D1SolidColorBrush* d2dBrush) noexcept - { - if (d2dBrush == nullptr) - return Colours::black; - - const D2D1_COLOR_F colour (d2dBrush->GetColor()); - return Colour::fromFloatRGBA (colour.r, colour.g, colour.b, colour.a); - } - - Font getFontForRun (const DWRITE_GLYPH_RUN& glyphRun, float fontHeight) - { - for (int i = 0; i < attributedString.getNumAttributes(); ++i) - { - const Font& font = attributedString.getAttribute(i).font; - - if (WindowsDirectWriteTypeface* wt = dynamic_cast (font.getTypeface())) - if (wt->getIDWriteFontFace() == glyphRun.fontFace) - return font.withHeight (fontHeight); - } - - ComSmartPtr dwFont; - HRESULT hr = fontCollection.GetFontFromFontFace (glyphRun.fontFace, dwFont.resetAndGetPointerAddress()); - jassert (dwFont != nullptr); - - ComSmartPtr dwFontFamily; - hr = dwFont->GetFontFamily (dwFontFamily.resetAndGetPointerAddress()); - - return Font (getFontFamilyName (dwFontFamily), getFontFaceName (dwFont), fontHeight); - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomDirectWriteTextRenderer) - }; - - //============================================================================== - static float getFontHeightToEmSizeFactor (IDWriteFont& dwFont) - { - ComSmartPtr dwFontFace; - dwFont.CreateFontFace (dwFontFace.resetAndGetPointerAddress()); - - if (dwFontFace == nullptr) - return 1.0f; - - DWRITE_FONT_METRICS dwFontMetrics; - dwFontFace->GetMetrics (&dwFontMetrics); - - const float totalHeight = (float) (std::abs (dwFontMetrics.ascent) + std::abs (dwFontMetrics.descent)); - return dwFontMetrics.designUnitsPerEm / totalHeight; - } - - void setTextFormatProperties (const AttributedString& text, IDWriteTextFormat& format) - { - DWRITE_TEXT_ALIGNMENT alignment = DWRITE_TEXT_ALIGNMENT_LEADING; - DWRITE_WORD_WRAPPING wrapType = DWRITE_WORD_WRAPPING_WRAP; - - switch (text.getJustification().getOnlyHorizontalFlags()) - { - case Justification::left: break; - case Justification::right: alignment = DWRITE_TEXT_ALIGNMENT_TRAILING; break; - case Justification::horizontallyCentred: alignment = DWRITE_TEXT_ALIGNMENT_CENTER; break; - case Justification::horizontallyJustified: break; // DirectWrite cannot justify text, default to left alignment - default: jassertfalse; break; // Illegal justification flags - } - - switch (text.getWordWrap()) - { - case AttributedString::none: wrapType = DWRITE_WORD_WRAPPING_NO_WRAP; break; - case AttributedString::byWord: break; - case AttributedString::byChar: break; // DirectWrite doesn't support wrapping by character, default to word-wrap - default: jassertfalse; break; // Illegal flags! - } - - // DirectWrite does not automatically set reading direction - // This must be set correctly and manually when using RTL Scripts (Hebrew, Arabic) - if (text.getReadingDirection() == AttributedString::rightToLeft) - { - format.SetReadingDirection (DWRITE_READING_DIRECTION_RIGHT_TO_LEFT); - - switch (text.getJustification().getOnlyHorizontalFlags()) - { - case Justification::left: alignment = DWRITE_TEXT_ALIGNMENT_TRAILING; break; - case Justification::right: alignment = DWRITE_TEXT_ALIGNMENT_LEADING; break; - default: break; - } - } - - format.SetTextAlignment (alignment); - format.SetWordWrapping (wrapType); - } - - void addAttributedRange (const AttributedString::Attribute& attr, IDWriteTextLayout& textLayout, - const int textLen, ID2D1RenderTarget& renderTarget, IDWriteFontCollection& fontCollection) - { - DWRITE_TEXT_RANGE range; - range.startPosition = attr.range.getStart(); - range.length = jmin (attr.range.getLength(), textLen - attr.range.getStart()); - - { - const String familyName (FontStyleHelpers::getConcreteFamilyName (attr.font)); - - BOOL fontFound = false; - uint32 fontIndex; - fontCollection.FindFamilyName (familyName.toWideCharPointer(), &fontIndex, &fontFound); - - if (! fontFound) - fontIndex = 0; - - ComSmartPtr fontFamily; - HRESULT hr = fontCollection.GetFontFamily (fontIndex, fontFamily.resetAndGetPointerAddress()); - - ComSmartPtr dwFont; - uint32 fontFacesCount = 0; - fontFacesCount = fontFamily->GetFontCount(); - - for (int i = fontFacesCount; --i >= 0;) - { - hr = fontFamily->GetFont (i, dwFont.resetAndGetPointerAddress()); - - if (attr.font.getTypefaceStyle() == getFontFaceName (dwFont)) - break; - } - - textLayout.SetFontFamilyName (familyName.toWideCharPointer(), range); - textLayout.SetFontWeight (dwFont->GetWeight(), range); - textLayout.SetFontStretch (dwFont->GetStretch(), range); - textLayout.SetFontStyle (dwFont->GetStyle(), range); - - const float fontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (*dwFont); - textLayout.SetFontSize (attr.font.getHeight() * fontHeightToEmSizeFactor, range); - } - - { - const Colour col (attr.colour); - ComSmartPtr d2dBrush; - renderTarget.CreateSolidColorBrush (D2D1::ColorF (col.getFloatRed(), - col.getFloatGreen(), - col.getFloatBlue(), - col.getFloatAlpha()), - d2dBrush.resetAndGetPointerAddress()); - - // We need to call SetDrawingEffect with a legimate brush to get DirectWrite to break text based on colours - textLayout.SetDrawingEffect (d2dBrush, range); - } - } - - bool setupLayout (const AttributedString& text, const float maxWidth, const float maxHeight, - ID2D1RenderTarget& renderTarget, IDWriteFactory& directWriteFactory, - IDWriteFontCollection& fontCollection, ComSmartPtr& textLayout) - { - // To add color to text, we need to create a D2D render target - // Since we are not actually rendering to a D2D context we create a temporary GDI render target - - Font defaultFont; - BOOL fontFound = false; - uint32 fontIndex; - fontCollection.FindFamilyName (defaultFont.getTypeface()->getName().toWideCharPointer(), &fontIndex, &fontFound); - - if (! fontFound) - fontIndex = 0; - - ComSmartPtr dwFontFamily; - HRESULT hr = fontCollection.GetFontFamily (fontIndex, dwFontFamily.resetAndGetPointerAddress()); - - ComSmartPtr dwFont; - hr = dwFontFamily->GetFirstMatchingFont (DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, - dwFont.resetAndGetPointerAddress()); - jassert (dwFont != nullptr); - - const float defaultFontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (*dwFont); - - ComSmartPtr dwTextFormat; - hr = directWriteFactory.CreateTextFormat (defaultFont.getTypefaceName().toWideCharPointer(), &fontCollection, - DWRITE_FONT_WEIGHT_REGULAR, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, - defaultFont.getHeight() * defaultFontHeightToEmSizeFactor, - L"en-us", dwTextFormat.resetAndGetPointerAddress()); - - setTextFormatProperties (text, *dwTextFormat); - - { - DWRITE_TRIMMING trimming = { DWRITE_TRIMMING_GRANULARITY_CHARACTER, 0, 0 }; - ComSmartPtr trimmingSign; - hr = directWriteFactory.CreateEllipsisTrimmingSign (dwTextFormat, trimmingSign.resetAndGetPointerAddress()); - hr = dwTextFormat->SetTrimming (&trimming, trimmingSign); - } - - const int textLen = text.getText().length(); - - hr = directWriteFactory.CreateTextLayout (text.getText().toWideCharPointer(), textLen, dwTextFormat, - maxWidth, maxHeight, textLayout.resetAndGetPointerAddress()); - - if (FAILED (hr) || textLayout == nullptr) - return false; - - const int numAttributes = text.getNumAttributes(); - - for (int i = 0; i < numAttributes; ++i) - addAttributedRange (text.getAttribute (i), *textLayout, textLen, renderTarget, fontCollection); - - return true; - } - - void createLayout (TextLayout& layout, const AttributedString& text, - IDWriteFactory& directWriteFactory, - IDWriteFontCollection& fontCollection, - ID2D1DCRenderTarget& renderTarget) - { - ComSmartPtr dwTextLayout; - - if (! setupLayout (text, layout.getWidth(), layout.getHeight(), renderTarget, - directWriteFactory, fontCollection, dwTextLayout)) - return; - - UINT32 actualLineCount = 0; - HRESULT hr = dwTextLayout->GetLineMetrics (nullptr, 0, &actualLineCount); - - layout.ensureStorageAllocated (actualLineCount); - - { - ComSmartPtr textRenderer (new CustomDirectWriteTextRenderer (fontCollection, text)); - hr = dwTextLayout->Draw (&layout, textRenderer, 0, 0); - } - - HeapBlock dwLineMetrics (actualLineCount); - hr = dwTextLayout->GetLineMetrics (dwLineMetrics, actualLineCount, &actualLineCount); - int lastLocation = 0; - const int numLines = jmin ((int) actualLineCount, layout.getNumLines()); - float yAdjustment = 0; - const float extraLineSpacing = text.getLineSpacing(); - - for (int i = 0; i < numLines; ++i) - { - TextLayout::Line& line = layout.getLine (i); - line.stringRange = Range (lastLocation, (int) lastLocation + dwLineMetrics[i].length); - line.lineOrigin.y += yAdjustment; - yAdjustment += extraLineSpacing; - lastLocation += dwLineMetrics[i].length; - } - } - - void drawToD2DContext (const AttributedString& text, const Rectangle& area, ID2D1RenderTarget& renderTarget, - IDWriteFactory& directWriteFactory, IDWriteFontCollection& fontCollection) - { - ComSmartPtr dwTextLayout; - - if (setupLayout (text, area.getWidth(), area.getHeight(), renderTarget, - directWriteFactory, fontCollection, dwTextLayout)) - { - ComSmartPtr d2dBrush; - renderTarget.CreateSolidColorBrush (D2D1::ColorF (0.0f, 0.0f, 0.0f, 1.0f), - d2dBrush.resetAndGetPointerAddress()); - - renderTarget.DrawTextLayout (D2D1::Point2F ((float) area.getX(), (float) area.getY()), - dwTextLayout, d2dBrush, D2D1_DRAW_TEXT_OPTIONS_CLIP); - } - } -} - -static bool canAllTypefacesBeUsedInLayout (const AttributedString& text) -{ - const int numCharacterAttributes = text.getNumAttributes(); - - for (int i = 0; i < numCharacterAttributes; ++i) - if (dynamic_cast (text.getAttribute(i).font.getTypeface()) == nullptr) - return false; - - return true; -} - -#endif - -bool TextLayout::createNativeLayout (const AttributedString& text) -{ - #if JUCE_USE_DIRECTWRITE - if (! canAllTypefacesBeUsedInLayout (text)) - return false; - - SharedResourcePointer factories; - - if (factories->d2dFactory != nullptr && factories->systemFonts != nullptr) - { - DirectWriteTypeLayout::createLayout (*this, text, - *factories->directWriteFactory, - *factories->systemFonts, - *factories->directWriteRenderTarget); - - return true; - } - #else - ignoreUnused (text); - #endif - - return false; -} - -} // namespace juce diff --git a/source/modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp b/source/modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp deleted file mode 100644 index 2643d1a16..000000000 --- a/source/modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp +++ /dev/null @@ -1,327 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -#if JUCE_USE_DIRECTWRITE -namespace -{ - static String getLocalisedName (IDWriteLocalizedStrings* names) - { - jassert (names != nullptr); - - uint32 index = 0; - BOOL exists = false; - HRESULT hr = names->FindLocaleName (L"en-us", &index, &exists); - if (! exists) - index = 0; - - uint32 length = 0; - hr = names->GetStringLength (index, &length); - - HeapBlock name (length + 1); - hr = names->GetString (index, name, length + 1); - - return static_cast (name); - } - - static String getFontFamilyName (IDWriteFontFamily* family) - { - jassert (family != nullptr); - ComSmartPtr familyNames; - HRESULT hr = family->GetFamilyNames (familyNames.resetAndGetPointerAddress()); - jassert (SUCCEEDED (hr)); ignoreUnused (hr); - return getLocalisedName (familyNames); - } - - static String getFontFaceName (IDWriteFont* font) - { - jassert (font != nullptr); - ComSmartPtr faceNames; - HRESULT hr = font->GetFaceNames (faceNames.resetAndGetPointerAddress()); - jassert (SUCCEEDED (hr)); ignoreUnused (hr); - return getLocalisedName (faceNames); - } - - inline Point convertPoint (D2D1_POINT_2F p) noexcept { return Point ((float) p.x, (float) p.y); } -} - -class Direct2DFactories -{ -public: - Direct2DFactories() - { - if (direct2dDll.open ("d2d1.dll")) - { - JUCE_LOAD_WINAPI_FUNCTION (direct2dDll, D2D1CreateFactory, d2d1CreateFactory, - HRESULT, (D2D1_FACTORY_TYPE, REFIID, D2D1_FACTORY_OPTIONS*, void**)) - - if (d2d1CreateFactory != nullptr) - { - D2D1_FACTORY_OPTIONS options; - options.debugLevel = D2D1_DEBUG_LEVEL_NONE; - - d2d1CreateFactory (D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof (ID2D1Factory), &options, - (void**) d2dFactory.resetAndGetPointerAddress()); - } - } - - if (directWriteDll.open ("DWrite.dll")) - { - JUCE_LOAD_WINAPI_FUNCTION (directWriteDll, DWriteCreateFactory, dWriteCreateFactory, - HRESULT, (DWRITE_FACTORY_TYPE, REFIID, IUnknown**)) - - if (dWriteCreateFactory != nullptr) - { - dWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory), - (IUnknown**) directWriteFactory.resetAndGetPointerAddress()); - - if (directWriteFactory != nullptr) - directWriteFactory->GetSystemFontCollection (systemFonts.resetAndGetPointerAddress()); - } - - if (d2dFactory != nullptr) - { - D2D1_RENDER_TARGET_PROPERTIES d2dRTProp = D2D1::RenderTargetProperties (D2D1_RENDER_TARGET_TYPE_SOFTWARE, - D2D1::PixelFormat (DXGI_FORMAT_B8G8R8A8_UNORM, - D2D1_ALPHA_MODE_IGNORE), - 0, 0, - D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE, - D2D1_FEATURE_LEVEL_DEFAULT); - - d2dFactory->CreateDCRenderTarget (&d2dRTProp, directWriteRenderTarget.resetAndGetPointerAddress()); - } - } - } - - ~Direct2DFactories() - { - d2dFactory = nullptr; // (need to make sure these are released before deleting the DynamicLibrary objects) - directWriteFactory = nullptr; - systemFonts = nullptr; - directWriteRenderTarget = nullptr; - } - - ComSmartPtr d2dFactory; - ComSmartPtr directWriteFactory; - ComSmartPtr systemFonts; - ComSmartPtr directWriteRenderTarget; - -private: - DynamicLibrary direct2dDll, directWriteDll; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Direct2DFactories) -}; - -//============================================================================== -class WindowsDirectWriteTypeface : public Typeface -{ -public: - WindowsDirectWriteTypeface (const Font& font, IDWriteFontCollection* fontCollection) - : Typeface (font.getTypefaceName(), font.getTypefaceStyle()), - unitsToHeightScaleFactor (1.0f), heightToPointsFactor (1.0f), ascent (0.0f) - { - jassert (fontCollection != nullptr); - - BOOL fontFound = false; - uint32 fontIndex = 0; - HRESULT hr = fontCollection->FindFamilyName (font.getTypefaceName().toWideCharPointer(), &fontIndex, &fontFound); - if (! fontFound) - fontIndex = 0; - - // Get the font family using the search results - // Fonts like: Times New Roman, Times New Roman Bold, Times New Roman Italic are all in the same font family - ComSmartPtr dwFontFamily; - hr = fontCollection->GetFontFamily (fontIndex, dwFontFamily.resetAndGetPointerAddress()); - - // Get a specific font in the font family using typeface style - { - ComSmartPtr dwFont; - - for (int i = (int) dwFontFamily->GetFontCount(); --i >= 0;) - { - hr = dwFontFamily->GetFont (i, dwFont.resetAndGetPointerAddress()); - - if (i == 0) - break; - - ComSmartPtr faceNames; - hr = dwFont->GetFaceNames (faceNames.resetAndGetPointerAddress()); - - if (font.getTypefaceStyle() == getLocalisedName (faceNames)) - break; - } - - jassert (dwFont != nullptr); - hr = dwFont->CreateFontFace (dwFontFace.resetAndGetPointerAddress()); - } - - if (dwFontFace != nullptr) - { - DWRITE_FONT_METRICS dwFontMetrics; - dwFontFace->GetMetrics (&dwFontMetrics); - - // All Font Metrics are in design units so we need to get designUnitsPerEm value - // to get the metrics into Em/Design Independent Pixels - designUnitsPerEm = dwFontMetrics.designUnitsPerEm; - - ascent = std::abs ((float) dwFontMetrics.ascent); - const float totalSize = ascent + std::abs ((float) dwFontMetrics.descent); - ascent /= totalSize; - unitsToHeightScaleFactor = designUnitsPerEm / totalSize; - - HDC tempDC = GetDC (0); - float dpi = (GetDeviceCaps (tempDC, LOGPIXELSX) + GetDeviceCaps (tempDC, LOGPIXELSY)) / 2.0f; - heightToPointsFactor = (dpi / GetDeviceCaps (tempDC, LOGPIXELSY)) * unitsToHeightScaleFactor; - ReleaseDC (0, tempDC); - - const float pathAscent = (1024.0f * dwFontMetrics.ascent) / designUnitsPerEm; - const float pathDescent = (1024.0f * dwFontMetrics.descent) / designUnitsPerEm; - const float pathScale = 1.0f / (std::abs (pathAscent) + std::abs (pathDescent)); - pathTransform = AffineTransform::scale (pathScale); - } - } - - bool loadedOk() const noexcept { return dwFontFace != nullptr; } - - float getAscent() const { return ascent; } - float getDescent() const { return 1.0f - ascent; } - float getHeightToPointsFactor() const { return heightToPointsFactor; } - - float getStringWidth (const String& text) - { - const CharPointer_UTF32 textUTF32 (text.toUTF32()); - const size_t len = textUTF32.length(); - - HeapBlock glyphIndices (len); - dwFontFace->GetGlyphIndices (textUTF32, (UINT32) len, glyphIndices); - - HeapBlock dwGlyphMetrics (len); - dwFontFace->GetDesignGlyphMetrics (glyphIndices, (UINT32) len, dwGlyphMetrics, false); - - float x = 0; - for (size_t i = 0; i < len; ++i) - x += (float) dwGlyphMetrics[i].advanceWidth / designUnitsPerEm; - - return x * unitsToHeightScaleFactor; - } - - void getGlyphPositions (const String& text, Array& resultGlyphs, Array& xOffsets) - { - xOffsets.add (0); - - const CharPointer_UTF32 textUTF32 (text.toUTF32()); - const size_t len = textUTF32.length(); - - HeapBlock glyphIndices (len); - dwFontFace->GetGlyphIndices (textUTF32, (UINT32) len, glyphIndices); - HeapBlock dwGlyphMetrics (len); - dwFontFace->GetDesignGlyphMetrics (glyphIndices, (UINT32) len, dwGlyphMetrics, false); - - float x = 0; - for (size_t i = 0; i < len; ++i) - { - x += (float) dwGlyphMetrics[i].advanceWidth / designUnitsPerEm; - xOffsets.add (x * unitsToHeightScaleFactor); - resultGlyphs.add (glyphIndices[i]); - } - } - - bool getOutlineForGlyph (int glyphNumber, Path& path) - { - jassert (path.isEmpty()); // we might need to apply a transform to the path, so this must be empty - UINT16 glyphIndex = (UINT16) glyphNumber; - ComSmartPtr pathGeometrySink (new PathGeometrySink()); - - dwFontFace->GetGlyphRunOutline (1024.0f, &glyphIndex, nullptr, nullptr, 1, false, false, pathGeometrySink); - path = pathGeometrySink->path; - - if (! pathTransform.isIdentity()) - path.applyTransform (pathTransform); - - return true; - } - - IDWriteFontFace* getIDWriteFontFace() const noexcept { return dwFontFace; } - - float getUnitsToHeightScaleFactor() const noexcept { return unitsToHeightScaleFactor; } - -private: - SharedResourcePointer factories; - ComSmartPtr dwFontFace; - float unitsToHeightScaleFactor, heightToPointsFactor, ascent; - int designUnitsPerEm; - AffineTransform pathTransform; - - struct PathGeometrySink : public ComBaseClassHelper - { - PathGeometrySink() : ComBaseClassHelper (0) {} - - void __stdcall AddBeziers (const D2D1_BEZIER_SEGMENT* beziers, UINT beziersCount) override - { - for (UINT i = 0; i < beziersCount; ++i) - path.cubicTo (convertPoint (beziers[i].point1), - convertPoint (beziers[i].point2), - convertPoint (beziers[i].point3)); - } - - void __stdcall AddLines (const D2D1_POINT_2F* points, UINT pointsCount) override - { - for (UINT i = 0; i < pointsCount; ++i) - path.lineTo (convertPoint (points[i])); - } - - void __stdcall BeginFigure (D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN) override - { - path.startNewSubPath (convertPoint (startPoint)); - } - - void __stdcall EndFigure (D2D1_FIGURE_END figureEnd) override - { - if (figureEnd == D2D1_FIGURE_END_CLOSED) - path.closeSubPath(); - } - - void __stdcall SetFillMode (D2D1_FILL_MODE fillMode) override - { - path.setUsingNonZeroWinding (fillMode == D2D1_FILL_MODE_WINDING); - } - - void __stdcall SetSegmentFlags (D2D1_PATH_SEGMENT) override {} - JUCE_COMRESULT Close() override { return S_OK; } - - Path path; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PathGeometrySink) - }; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsDirectWriteTypeface) -}; - -#endif - -} // namespace juce diff --git a/source/modules/juce_graphics/native/juce_win32_Fonts.cpp b/source/modules/juce_graphics/native/juce_win32_Fonts.cpp deleted file mode 100644 index b6159c3f9..000000000 --- a/source/modules/juce_graphics/native/juce_win32_Fonts.cpp +++ /dev/null @@ -1,651 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -/* This is some quick-and-dirty code to extract the typeface name from a lump of TTF file data. - It's needed because although win32 will happily load a TTF file from in-memory data, it won't - tell you the name of the damned font that it just loaded.. and in order to actually use the font, - you need to know its name!! Anyway, this awful hack seems to work for most fonts. -*/ -namespace TTFNameExtractor -{ - struct OffsetTable - { - uint32 version; - uint16 numTables, searchRange, entrySelector, rangeShift; - }; - - struct TableDirectory - { - char tag[4]; - uint32 checkSum, offset, length; - }; - - struct NamingTable - { - uint16 formatSelector; - uint16 numberOfNameRecords; - uint16 offsetStartOfStringStorage; - }; - - struct NameRecord - { - uint16 platformID, encodingID, languageID; - uint16 nameID, stringLength, offsetFromStorageArea; - }; - - static String parseNameRecord (MemoryInputStream& input, const NameRecord& nameRecord, - const int64 directoryOffset, const int64 offsetOfStringStorage) - { - String result; - const int64 oldPos = input.getPosition(); - input.setPosition (directoryOffset + offsetOfStringStorage + ByteOrder::swapIfLittleEndian (nameRecord.offsetFromStorageArea)); - const int stringLength = (int) ByteOrder::swapIfLittleEndian (nameRecord.stringLength); - const int platformID = ByteOrder::swapIfLittleEndian (nameRecord.platformID); - - if (platformID == 0 || platformID == 3) - { - const int numChars = stringLength / 2 + 1; - HeapBlock buffer; - buffer.calloc (numChars + 1); - input.read (buffer, stringLength); - - for (int i = 0; i < numChars; ++i) - buffer[i] = ByteOrder::swapIfLittleEndian (buffer[i]); - - static_assert (sizeof (CharPointer_UTF16::CharType) == sizeof (uint16), "Sanity check UTF-16 type"); - result = CharPointer_UTF16 ((CharPointer_UTF16::CharType*) buffer.getData()); - } - else - { - HeapBlock buffer; - buffer.calloc (stringLength + 1); - input.read (buffer, stringLength); - result = CharPointer_UTF8 (buffer.getData()); - } - - input.setPosition (oldPos); - return result; - } - - static String parseNameTable (MemoryInputStream& input, int64 directoryOffset) - { - input.setPosition (directoryOffset); - - NamingTable namingTable = { 0 }; - input.read (&namingTable, sizeof (namingTable)); - - for (int i = 0; i < (int) ByteOrder::swapIfLittleEndian (namingTable.numberOfNameRecords); ++i) - { - NameRecord nameRecord = { 0 }; - input.read (&nameRecord, sizeof (nameRecord)); - - if (ByteOrder::swapIfLittleEndian (nameRecord.nameID) == 4) - { - const String result (parseNameRecord (input, nameRecord, directoryOffset, - ByteOrder::swapIfLittleEndian (namingTable.offsetStartOfStringStorage))); - - if (result.isNotEmpty()) - return result; - } - } - - return {}; - } - - static String getTypefaceNameFromFile (MemoryInputStream& input) - { - OffsetTable offsetTable = { 0 }; - input.read (&offsetTable, sizeof (offsetTable)); - - for (int i = 0; i < (int) ByteOrder::swapIfLittleEndian (offsetTable.numTables); ++i) - { - TableDirectory tableDirectory; - zerostruct (tableDirectory); - input.read (&tableDirectory, sizeof (tableDirectory)); - - if (String (tableDirectory.tag, sizeof (tableDirectory.tag)).equalsIgnoreCase ("name")) - return parseNameTable (input, ByteOrder::swapIfLittleEndian (tableDirectory.offset)); - } - - return {}; - } -} - -namespace FontEnumerators -{ - static int CALLBACK fontEnum2 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam) - { - if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0) - { - const String fontName (lpelfe->elfLogFont.lfFaceName); - ((StringArray*) lParam)->addIfNotAlreadyThere (fontName.removeCharacters ("@")); - } - - return 1; - } - - static int CALLBACK fontEnum1 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam) - { - if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0) - { - LOGFONTW lf = { 0 }; - lf.lfWeight = FW_DONTCARE; - lf.lfOutPrecision = OUT_OUTLINE_PRECIS; - lf.lfQuality = DEFAULT_QUALITY; - lf.lfCharSet = DEFAULT_CHARSET; - lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; - lf.lfPitchAndFamily = FF_DONTCARE; - - const String fontName (lpelfe->elfLogFont.lfFaceName); - fontName.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName)); - - HDC dc = CreateCompatibleDC (0); - EnumFontFamiliesEx (dc, &lf, - (FONTENUMPROCW) &fontEnum2, - lParam, 0); - DeleteDC (dc); - } - - return 1; - } -} - -StringArray Font::findAllTypefaceNames() -{ - StringArray results; - - #if JUCE_USE_DIRECTWRITE - SharedResourcePointer factories; - - if (factories->systemFonts != nullptr) - { - ComSmartPtr fontFamily; - uint32 fontFamilyCount = 0; - fontFamilyCount = factories->systemFonts->GetFontFamilyCount(); - - for (uint32 i = 0; i < fontFamilyCount; ++i) - { - HRESULT hr = factories->systemFonts->GetFontFamily (i, fontFamily.resetAndGetPointerAddress()); - - if (SUCCEEDED (hr)) - results.addIfNotAlreadyThere (getFontFamilyName (fontFamily)); - } - } - else - #endif - { - HDC dc = CreateCompatibleDC (0); - - { - LOGFONTW lf = { 0 }; - lf.lfWeight = FW_DONTCARE; - lf.lfOutPrecision = OUT_OUTLINE_PRECIS; - lf.lfQuality = DEFAULT_QUALITY; - lf.lfCharSet = DEFAULT_CHARSET; - lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; - lf.lfPitchAndFamily = FF_DONTCARE; - - EnumFontFamiliesEx (dc, &lf, - (FONTENUMPROCW) &FontEnumerators::fontEnum1, - (LPARAM) &results, 0); - } - - DeleteDC (dc); - } - - results.sort (true); - return results; -} - -StringArray Font::findAllTypefaceStyles (const String& family) -{ - if (FontStyleHelpers::isPlaceholderFamilyName (family)) - return findAllTypefaceStyles (FontStyleHelpers::getConcreteFamilyNameFromPlaceholder (family)); - - StringArray results; - - #if JUCE_USE_DIRECTWRITE - SharedResourcePointer factories; - - if (factories->systemFonts != nullptr) - { - BOOL fontFound = false; - uint32 fontIndex = 0; - HRESULT hr = factories->systemFonts->FindFamilyName (family.toWideCharPointer(), &fontIndex, &fontFound); - if (! fontFound) - fontIndex = 0; - - // Get the font family using the search results - // Fonts like: Times New Roman, Times New Roman Bold, Times New Roman Italic are all in the same font family - ComSmartPtr fontFamily; - hr = factories->systemFonts->GetFontFamily (fontIndex, fontFamily.resetAndGetPointerAddress()); - - // Get the font faces - ComSmartPtr dwFont; - uint32 fontFacesCount = 0; - fontFacesCount = fontFamily->GetFontCount(); - - for (uint32 i = 0; i < fontFacesCount; ++i) - { - hr = fontFamily->GetFont (i, dwFont.resetAndGetPointerAddress()); - - // Ignore any algorithmically generated bold and oblique styles.. - if (dwFont->GetSimulations() == DWRITE_FONT_SIMULATIONS_NONE) - results.addIfNotAlreadyThere (getFontFaceName (dwFont)); - } - } - else - #endif - { - results.add ("Regular"); - results.add ("Italic"); - results.add ("Bold"); - results.add ("Bold Italic"); - } - - return results; -} - -extern bool juce_isRunningInWine(); - -struct DefaultFontNames -{ - DefaultFontNames() - { - if (juce_isRunningInWine()) - { - // If we're running in Wine, then use fonts that might be available on Linux.. - defaultSans = "Bitstream Vera Sans"; - defaultSerif = "Bitstream Vera Serif"; - defaultFixed = "Bitstream Vera Sans Mono"; - } - else - { - defaultSans = "Verdana"; - defaultSerif = "Times New Roman"; - defaultFixed = "Lucida Console"; - defaultFallback = "Tahoma"; // (contains plenty of unicode characters) - } - } - - String defaultSans, defaultSerif, defaultFixed, defaultFallback; -}; - -Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font) -{ - static DefaultFontNames defaultNames; - - Font newFont (font); - const String& faceName = font.getTypefaceName(); - - if (faceName == getDefaultSansSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSans); - else if (faceName == getDefaultSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSerif); - else if (faceName == getDefaultMonospacedFontName()) newFont.setTypefaceName (defaultNames.defaultFixed); - - if (font.getTypefaceStyle() == getDefaultStyle()) - newFont.setTypefaceStyle ("Regular"); - - return Typeface::createSystemTypefaceFor (newFont); -} - -//============================================================================== -class WindowsTypeface : public Typeface -{ -public: - WindowsTypeface (const Font& font) - : Typeface (font.getTypefaceName(), font.getTypefaceStyle()), - fontH (0), previousFontH (0), - dc (CreateCompatibleDC (0)), memoryFont (0), - ascent (1.0f), heightToPointsFactor (1.0f), - defaultGlyph (-1) - { - loadFont(); - } - - WindowsTypeface (const void* data, size_t dataSize) - : Typeface (String(), String()), - fontH (0), previousFontH (0), - dc (CreateCompatibleDC (0)), memoryFont (0), - ascent (1.0f), heightToPointsFactor (1.0f), - defaultGlyph (-1) - { - DWORD numInstalled = 0; - memoryFont = AddFontMemResourceEx (const_cast (data), (DWORD) dataSize, - nullptr, &numInstalled); - - MemoryInputStream m (data, dataSize, false); - name = TTFNameExtractor::getTypefaceNameFromFile (m); - loadFont(); - } - - ~WindowsTypeface() - { - SelectObject (dc, previousFontH); // Replacing the previous font before deleting the DC avoids a warning in BoundsChecker - DeleteDC (dc); - - if (fontH != 0) - DeleteObject (fontH); - - if (memoryFont != 0) - RemoveFontMemResourceEx (memoryFont); - } - - float getAscent() const { return ascent; } - float getDescent() const { return 1.0f - ascent; } - float getHeightToPointsFactor() const { return heightToPointsFactor; } - - float getStringWidth (const String& text) - { - const CharPointer_UTF16 utf16 (text.toUTF16()); - const size_t numChars = utf16.length(); - HeapBlock results (numChars + 1); - results[numChars] = -1; - float x = 0; - - if (GetGlyphIndices (dc, utf16, (int) numChars, reinterpret_cast (results.getData()), - GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR) - { - for (size_t i = 0; i < numChars; ++i) - x += getKerning (dc, results[i], results[i + 1]); - } - - return x; - } - - void getGlyphPositions (const String& text, Array & resultGlyphs, Array & xOffsets) - { - const CharPointer_UTF16 utf16 (text.toUTF16()); - const size_t numChars = utf16.length(); - HeapBlock results (numChars + 1); - results[numChars] = -1; - float x = 0; - - if (GetGlyphIndices (dc, utf16, (int) numChars, reinterpret_cast (results.getData()), - GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR) - { - resultGlyphs.ensureStorageAllocated ((int) numChars); - xOffsets.ensureStorageAllocated ((int) numChars + 1); - - for (size_t i = 0; i < numChars; ++i) - { - resultGlyphs.add (results[i]); - xOffsets.add (x); - x += getKerning (dc, results[i], results[i + 1]); - } - } - - xOffsets.add (x); - } - - bool getOutlineForGlyph (int glyphNumber, Path& glyphPath) - { - if (glyphNumber < 0) - glyphNumber = defaultGlyph; - - GLYPHMETRICS gm; - // (although GetGlyphOutline returns a DWORD, it may be -1 on failure, so treat it as signed int..) - const int bufSize = (int) GetGlyphOutline (dc, (UINT) glyphNumber, GGO_NATIVE | GGO_GLYPH_INDEX, - &gm, 0, 0, &identityMatrix); - - if (bufSize > 0) - { - HeapBlock data (bufSize); - GetGlyphOutline (dc, (UINT) glyphNumber, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, - bufSize, data, &identityMatrix); - - const TTPOLYGONHEADER* pheader = reinterpret_cast (data.getData()); - - const float scaleX = 1.0f / tm.tmHeight; - const float scaleY = -scaleX; - - while ((char*) pheader < data + bufSize) - { - glyphPath.startNewSubPath (scaleX * pheader->pfxStart.x.value, - scaleY * pheader->pfxStart.y.value); - - const TTPOLYCURVE* curve = (const TTPOLYCURVE*) ((const char*) pheader + sizeof (TTPOLYGONHEADER)); - const char* const curveEnd = ((const char*) pheader) + pheader->cb; - - while ((const char*) curve < curveEnd) - { - if (curve->wType == TT_PRIM_LINE) - { - for (int i = 0; i < curve->cpfx; ++i) - glyphPath.lineTo (scaleX * curve->apfx[i].x.value, - scaleY * curve->apfx[i].y.value); - } - else if (curve->wType == TT_PRIM_QSPLINE) - { - for (int i = 0; i < curve->cpfx - 1; ++i) - { - const float x2 = scaleX * curve->apfx[i].x.value; - const float y2 = scaleY * curve->apfx[i].y.value; - float x3 = scaleX * curve->apfx[i + 1].x.value; - float y3 = scaleY * curve->apfx[i + 1].y.value; - - if (i < curve->cpfx - 2) - { - x3 = 0.5f * (x2 + x3); - y3 = 0.5f * (y2 + y3); - } - - glyphPath.quadraticTo (x2, y2, x3, y3); - } - } - - curve = (const TTPOLYCURVE*) &(curve->apfx [curve->cpfx]); - } - - pheader = (const TTPOLYGONHEADER*) curve; - - glyphPath.closeSubPath(); - } - } - - return true; - } - -private: - static const MAT2 identityMatrix; - HFONT fontH; - HGDIOBJ previousFontH; - HDC dc; - TEXTMETRIC tm; - HANDLE memoryFont; - float ascent, heightToPointsFactor; - int defaultGlyph, heightInPoints; - - struct KerningPair - { - int glyph1, glyph2; - float kerning; - - bool operator== (const KerningPair& other) const noexcept - { - return glyph1 == other.glyph1 && glyph2 == other.glyph2; - } - - bool operator< (const KerningPair& other) const noexcept - { - return glyph1 < other.glyph1 - || (glyph1 == other.glyph1 && glyph2 < other.glyph2); - } - }; - - SortedSet kerningPairs; - - void loadFont() - { - SetMapperFlags (dc, 0); - SetMapMode (dc, MM_TEXT); - - LOGFONTW lf = { 0 }; - lf.lfCharSet = DEFAULT_CHARSET; - lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; - lf.lfOutPrecision = OUT_OUTLINE_PRECIS; - lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; - lf.lfQuality = PROOF_QUALITY; - lf.lfItalic = (BYTE) (style.contains ("Italic") ? TRUE : FALSE); - lf.lfWeight = style.contains ("Bold") ? FW_BOLD : FW_NORMAL; - lf.lfHeight = -256; - name.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName)); - - HFONT standardSizedFont = CreateFontIndirect (&lf); - - if (standardSizedFont != 0) - { - if ((previousFontH = SelectObject (dc, standardSizedFont)) != 0) - { - fontH = standardSizedFont; - - OUTLINETEXTMETRIC otm; - if (GetOutlineTextMetrics (dc, sizeof (otm), &otm) != 0) - { - heightInPoints = otm.otmEMSquare; - lf.lfHeight = -(int) heightInPoints; - fontH = CreateFontIndirect (&lf); - - SelectObject (dc, fontH); - DeleteObject (standardSizedFont); - } - } - } - - if (GetTextMetrics (dc, &tm)) - { - float dpi = (GetDeviceCaps (dc, LOGPIXELSX) + GetDeviceCaps (dc, LOGPIXELSY)) / 2.0f; - heightToPointsFactor = (dpi / GetDeviceCaps (dc, LOGPIXELSY)) * heightInPoints / (float) tm.tmHeight; - ascent = tm.tmAscent / (float) tm.tmHeight; - defaultGlyph = getGlyphForChar (dc, tm.tmDefaultChar); - createKerningPairs (dc, (float) tm.tmHeight); - } - } - - void createKerningPairs (HDC hdc, const float height) - { - HeapBlock rawKerning; - const DWORD numKPs = GetKerningPairs (hdc, 0, 0); - rawKerning.calloc (numKPs); - GetKerningPairs (hdc, numKPs, rawKerning); - - kerningPairs.ensureStorageAllocated ((int) numKPs); - - for (DWORD i = 0; i < numKPs; ++i) - { - KerningPair kp; - kp.glyph1 = getGlyphForChar (hdc, rawKerning[i].wFirst); - kp.glyph2 = getGlyphForChar (hdc, rawKerning[i].wSecond); - - const int standardWidth = getGlyphWidth (hdc, kp.glyph1); - kp.kerning = (standardWidth + rawKerning[i].iKernAmount) / height; - kerningPairs.add (kp); - - kp.glyph2 = -1; // add another entry for the standard width version.. - kp.kerning = standardWidth / height; - kerningPairs.add (kp); - } - } - - static int getGlyphForChar (HDC dc, juce_wchar character) - { - const WCHAR charToTest[] = { (WCHAR) character, 0 }; - WORD index = 0; - - if (GetGlyphIndices (dc, charToTest, 1, &index, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR - || index == 0xffff) - return -1; - - return index; - } - - static int getGlyphWidth (HDC dc, int glyphNumber) - { - GLYPHMETRICS gm; - gm.gmCellIncX = 0; - GetGlyphOutline (dc, (UINT) glyphNumber, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, 0, &identityMatrix); - return gm.gmCellIncX; - } - - float getKerning (HDC hdc, const int glyph1, const int glyph2) - { - KerningPair kp; - kp.glyph1 = glyph1; - kp.glyph2 = glyph2; - int index = kerningPairs.indexOf (kp); - - if (index < 0) - { - kp.glyph2 = -1; - index = kerningPairs.indexOf (kp); - - if (index < 0) - { - kp.glyph2 = -1; - kp.kerning = getGlyphWidth (hdc, kp.glyph1) / (float) tm.tmHeight; - kerningPairs.add (kp); - return kp.kerning; - } - } - - return kerningPairs.getReference (index).kerning; - } - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsTypeface) -}; - -const MAT2 WindowsTypeface::identityMatrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } }; - -Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font) -{ - #if JUCE_USE_DIRECTWRITE - SharedResourcePointer factories; - - if (factories->systemFonts != nullptr) - { - ScopedPointer wtf (new WindowsDirectWriteTypeface (font, factories->systemFonts)); - - if (wtf->loadedOk()) - return wtf.release(); - } - #endif - - return new WindowsTypeface (font); -} - -Typeface::Ptr Typeface::createSystemTypefaceFor (const void* data, size_t dataSize) -{ - return new WindowsTypeface (data, dataSize); -} - -void Typeface::scanFolderForFonts (const File&) -{ - jassertfalse; // not implemented on this platform -} - -} // namespace juce diff --git a/source/modules/juce_graphics/native/juce_win32_IconHelpers.cpp b/source/modules/juce_graphics/native/juce_win32_IconHelpers.cpp deleted file mode 100644 index 3a11f8e34..000000000 --- a/source/modules/juce_graphics/native/juce_win32_IconHelpers.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - Image JUCE_API getIconFromApplication (const String&, int) { return {}; } -} diff --git a/source/modules/juce_graphics/placement/juce_Justification.h b/source/modules/juce_graphics/placement/juce_Justification.h deleted file mode 100644 index 8c8fb8362..000000000 --- a/source/modules/juce_graphics/placement/juce_Justification.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Represents a type of justification to be used when positioning graphical items. - - e.g. it indicates whether something should be placed top-left, top-right, - centred, etc. - - It is used in various places wherever this kind of information is needed. -*/ -class Justification -{ -public: - //============================================================================== - /** Creates a Justification object using a combination of flags from the Flags enum. */ - Justification (int justificationFlags) noexcept : flags (justificationFlags) {} - - /** Creates a copy of another Justification object. */ - Justification (const Justification& other) noexcept : flags (other.flags) {} - - /** Copies another Justification object. */ - Justification& operator= (const Justification& other) noexcept - { - flags = other.flags; - return *this; - } - - bool operator== (const Justification& other) const noexcept { return flags == other.flags; } - bool operator!= (const Justification& other) const noexcept { return flags != other.flags; } - - //============================================================================== - /** Returns the raw flags that are set for this Justification object. */ - inline int getFlags() const noexcept { return flags; } - - /** Tests a set of flags for this object. - @returns true if any of the flags passed in are set on this object. - */ - inline bool testFlags (int flagsToTest) const noexcept { return (flags & flagsToTest) != 0; } - - /** Returns just the flags from this object that deal with vertical layout. */ - int getOnlyVerticalFlags() const noexcept { return flags & (top | bottom | verticallyCentred); } - - /** Returns just the flags from this object that deal with horizontal layout. */ - int getOnlyHorizontalFlags() const noexcept { return flags & (left | right | horizontallyCentred | horizontallyJustified); } - - //============================================================================== - /** Adjusts the position of a rectangle to fit it into a space. - - The (x, y) position of the rectangle will be updated to position it inside the - given space according to the justification flags. - */ - template - void applyToRectangle (ValueType& x, ValueType& y, ValueType w, ValueType h, - ValueType spaceX, ValueType spaceY, ValueType spaceW, ValueType spaceH) const noexcept - { - x = spaceX; - if ((flags & horizontallyCentred) != 0) x += (spaceW - w) / (ValueType) 2; - else if ((flags & right) != 0) x += spaceW - w; - - y = spaceY; - if ((flags & verticallyCentred) != 0) y += (spaceH - h) / (ValueType) 2; - else if ((flags & bottom) != 0) y += spaceH - h; - } - - /** Returns the new position of a rectangle that has been justified to fit within a given space. - */ - template - const Rectangle appliedToRectangle (const Rectangle& areaToAdjust, - const Rectangle& targetSpace) const noexcept - { - ValueType x = areaToAdjust.getX(), y = areaToAdjust.getY(); - applyToRectangle (x, y, areaToAdjust.getWidth(), areaToAdjust.getHeight(), - targetSpace.getX(), targetSpace.getY(), targetSpace.getWidth(), targetSpace.getHeight()); - return areaToAdjust.withPosition (x, y); - } - - //============================================================================== - /** Flag values that can be combined and used in the constructor. */ - enum Flags - { - //============================================================================== - /** Indicates that the item should be aligned against the left edge of the available space. */ - left = 1, - - /** Indicates that the item should be aligned against the right edge of the available space. */ - right = 2, - - /** Indicates that the item should be placed in the centre between the left and right - sides of the available space. */ - horizontallyCentred = 4, - - //============================================================================== - /** Indicates that the item should be aligned against the top edge of the available space. */ - top = 8, - - /** Indicates that the item should be aligned against the bottom edge of the available space. */ - bottom = 16, - - /** Indicates that the item should be placed in the centre between the top and bottom - sides of the available space. */ - verticallyCentred = 32, - - //============================================================================== - /** Indicates that lines of text should be spread out to fill the maximum width - available, so that both margins are aligned vertically. - */ - horizontallyJustified = 64, - - //============================================================================== - /** Indicates that the item should be centred vertically and horizontally. - This is equivalent to (horizontallyCentred | verticallyCentred) - */ - centred = 36, - - /** Indicates that the item should be centred vertically but placed on the left hand side. - This is equivalent to (left | verticallyCentred) - */ - centredLeft = 33, - - /** Indicates that the item should be centred vertically but placed on the right hand side. - This is equivalent to (right | verticallyCentred) - */ - centredRight = 34, - - /** Indicates that the item should be centred horizontally and placed at the top. - This is equivalent to (horizontallyCentred | top) - */ - centredTop = 12, - - /** Indicates that the item should be centred horizontally and placed at the bottom. - This is equivalent to (horizontallyCentred | bottom) - */ - centredBottom = 20, - - /** Indicates that the item should be placed in the top-left corner. - This is equivalent to (left | top) - */ - topLeft = 9, - - /** Indicates that the item should be placed in the top-right corner. - This is equivalent to (right | top) - */ - topRight = 10, - - /** Indicates that the item should be placed in the bottom-left corner. - This is equivalent to (left | bottom) - */ - bottomLeft = 17, - - /** Indicates that the item should be placed in the bottom-left corner. - This is equivalent to (right | bottom) - */ - bottomRight = 18 - }; - - -private: - //============================================================================== - int flags; -}; - -} // namespace juce diff --git a/source/modules/juce_graphics/placement/juce_RectanglePlacement.cpp b/source/modules/juce_graphics/placement/juce_RectanglePlacement.cpp deleted file mode 100644 index 6f718c094..000000000 --- a/source/modules/juce_graphics/placement/juce_RectanglePlacement.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -RectanglePlacement::RectanglePlacement (const RectanglePlacement& other) noexcept - : flags (other.flags) -{ -} - -RectanglePlacement& RectanglePlacement::operator= (const RectanglePlacement& other) noexcept -{ - flags = other.flags; - return *this; -} - -bool RectanglePlacement::operator== (const RectanglePlacement& other) const noexcept -{ - return flags == other.flags; -} - -bool RectanglePlacement::operator!= (const RectanglePlacement& other) const noexcept -{ - return flags != other.flags; -} - -void RectanglePlacement::applyTo (double& x, double& y, double& w, double& h, - const double dx, const double dy, const double dw, const double dh) const noexcept -{ - if (w == 0.0 || h == 0.0) - return; - - if ((flags & stretchToFit) != 0) - { - x = dx; - y = dy; - w = dw; - h = dh; - } - else - { - double scale = (flags & fillDestination) != 0 ? jmax (dw / w, dh / h) - : jmin (dw / w, dh / h); - - if ((flags & onlyReduceInSize) != 0) - scale = jmin (scale, 1.0); - - if ((flags & onlyIncreaseInSize) != 0) - scale = jmax (scale, 1.0); - - w *= scale; - h *= scale; - - if ((flags & xLeft) != 0) - x = dx; - else if ((flags & xRight) != 0) - x = dx + dw - w; - else - x = dx + (dw - w) * 0.5; - - if ((flags & yTop) != 0) - y = dy; - else if ((flags & yBottom) != 0) - y = dy + dh - h; - else - y = dy + (dh - h) * 0.5; - } -} - -AffineTransform RectanglePlacement::getTransformToFit (const Rectangle& source, const Rectangle& destination) const noexcept -{ - if (source.isEmpty()) - return AffineTransform(); - - float newX = destination.getX(); - float newY = destination.getY(); - - float scaleX = destination.getWidth() / source.getWidth(); - float scaleY = destination.getHeight() / source.getHeight(); - - if ((flags & stretchToFit) == 0) - { - scaleX = (flags & fillDestination) != 0 ? jmax (scaleX, scaleY) - : jmin (scaleX, scaleY); - - if ((flags & onlyReduceInSize) != 0) - scaleX = jmin (scaleX, 1.0f); - - if ((flags & onlyIncreaseInSize) != 0) - scaleX = jmax (scaleX, 1.0f); - - scaleY = scaleX; - - if ((flags & xRight) != 0) - newX += destination.getWidth() - source.getWidth() * scaleX; // right - else if ((flags & xLeft) == 0) - newX += (destination.getWidth() - source.getWidth() * scaleX) / 2.0f; // centre - - if ((flags & yBottom) != 0) - newY += destination.getHeight() - source.getHeight() * scaleX; // bottom - else if ((flags & yTop) == 0) - newY += (destination.getHeight() - source.getHeight() * scaleX) / 2.0f; // centre - } - - return AffineTransform::translation (-source.getX(), -source.getY()) - .scaled (scaleX, scaleY) - .translated (newX, newY); -} - -} // namespace juce diff --git a/source/modules/juce_graphics/placement/juce_RectanglePlacement.h b/source/modules/juce_graphics/placement/juce_RectanglePlacement.h deleted file mode 100644 index 84eec1db0..000000000 --- a/source/modules/juce_graphics/placement/juce_RectanglePlacement.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Defines the method used to position some kind of rectangular object within - a rectangular viewport. - - Although similar to Justification, this is more specific, and has some extra - options. -*/ -class JUCE_API RectanglePlacement -{ -public: - //============================================================================== - /** Creates a RectanglePlacement object using a combination of flags from the Flags enum. */ - inline RectanglePlacement (int placementFlags) noexcept : flags (placementFlags) {} - - /** Creates a default RectanglePlacement object, which is equivalent to using the 'centred' flag. */ - inline RectanglePlacement() noexcept : flags (centred) {} - - /** Creates a copy of another RectanglePlacement object. */ - RectanglePlacement (const RectanglePlacement&) noexcept; - - /** Copies another RectanglePlacement object. */ - RectanglePlacement& operator= (const RectanglePlacement&) noexcept; - - bool operator== (const RectanglePlacement&) const noexcept; - bool operator!= (const RectanglePlacement&) const noexcept; - - //============================================================================== - /** Flag values that can be combined and used in the constructor. */ - enum Flags - { - //============================================================================== - /** Indicates that the source rectangle's left edge should be aligned with the left edge of the target rectangle. */ - xLeft = 1, - - /** Indicates that the source rectangle's right edge should be aligned with the right edge of the target rectangle. */ - xRight = 2, - - /** Indicates that the source should be placed in the centre between the left and right - sides of the available space. */ - xMid = 4, - - //============================================================================== - /** Indicates that the source's top edge should be aligned with the top edge of the - destination rectangle. */ - yTop = 8, - - /** Indicates that the source's bottom edge should be aligned with the bottom edge of the - destination rectangle. */ - yBottom = 16, - - /** Indicates that the source should be placed in the centre between the top and bottom - sides of the available space. */ - yMid = 32, - - //============================================================================== - /** If this flag is set, then the source rectangle will be resized to completely fill - the destination rectangle, and all other flags are ignored. - */ - stretchToFit = 64, - - //============================================================================== - /** If this flag is set, then the source rectangle will be resized so that it is the - minimum size to completely fill the destination rectangle, without changing its - aspect ratio. This means that some of the source rectangle may fall outside - the destination. - - If this flag is not set, the source will be given the maximum size at which none - of it falls outside the destination rectangle. - */ - fillDestination = 128, - - /** Indicates that the source rectangle can be reduced in size if required, but should - never be made larger than its original size. - */ - onlyReduceInSize = 256, - - /** Indicates that the source rectangle can be enlarged if required, but should - never be made smaller than its original size. - */ - onlyIncreaseInSize = 512, - - /** Indicates that the source rectangle's size should be left unchanged. - */ - doNotResize = (onlyIncreaseInSize | onlyReduceInSize), - - //============================================================================== - /** A shorthand value that is equivalent to (xMid | yMid). */ - centred = 4 + 32 - }; - - //============================================================================== - /** Returns the raw flags that are set for this object. */ - inline int getFlags() const noexcept { return flags; } - - /** Tests a set of flags for this object. - - @returns true if any of the flags passed in are set on this object. - */ - inline bool testFlags (int flagsToTest) const noexcept { return (flags & flagsToTest) != 0; } - - - //============================================================================== - /** Adjusts the position and size of a rectangle to fit it into a space. - - The source rectangle coordinates will be adjusted so that they fit into - the destination rectangle based on this object's flags. - */ - void applyTo (double& sourceX, - double& sourceY, - double& sourceW, - double& sourceH, - double destinationX, - double destinationY, - double destinationW, - double destinationH) const noexcept; - - /** Returns the rectangle that should be used to fit the given source rectangle - into the destination rectangle using the current flags. - */ - template - Rectangle appliedTo (const Rectangle& source, - const Rectangle& destination) const noexcept - { - double x = source.getX(), y = source.getY(), w = source.getWidth(), h = source.getHeight(); - applyTo (x, y, w, h, static_cast (destination.getX()), static_cast (destination.getY()), - static_cast (destination.getWidth()), static_cast (destination.getHeight())); - return Rectangle (static_cast (x), static_cast (y), - static_cast (w), static_cast (h)); - } - - /** Returns the transform that should be applied to these source coordinates to fit them - into the destination rectangle using the current flags. - */ - AffineTransform getTransformToFit (const Rectangle& source, - const Rectangle& destination) const noexcept; - - -private: - //============================================================================== - int flags; -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/Makefile b/source/modules/juce_gui_basics/Makefile deleted file mode 100644 index 3af84b2b7..000000000 --- a/source/modules/juce_gui_basics/Makefile +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/make -f -# Makefile for juce_gui_basics # -# ---------------------------- # -# Created by falkTX -# - -CWD=../.. -MODULENAME=juce_gui_basics -include ../Makefile.mk - -# ---------------------------------------------------------------------------------------------------------------------------- - -BUILD_CXX_FLAGS += $(JUCE_GUI_BASICS_FLAGS) -I.. - -ifeq ($(WIN32),true) -BUILD_CXX_FLAGS += -Wno-missing-field-initializers -Wno-strict-aliasing -Wno-strict-overflow -endif - -# ---------------------------------------------------------------------------------------------------------------------------- - -ifeq ($(MACOS),true) -OBJS = $(OBJDIR)/$(MODULENAME).mm.o -OBJS_posix32 = $(OBJDIR)/$(MODULENAME).mm.posix32.o -OBJS_posix64 = $(OBJDIR)/$(MODULENAME).mm.posix64.o -else -OBJS = $(OBJDIR)/$(MODULENAME).cpp.o -OBJS_posix32 = $(OBJDIR)/$(MODULENAME).cpp.posix32.o -OBJS_posix64 = $(OBJDIR)/$(MODULENAME).cpp.posix64.o -endif -OBJS_win32 = $(OBJDIR)/$(MODULENAME).cpp.win32.o -OBJS_win64 = $(OBJDIR)/$(MODULENAME).cpp.win64.o - -# ---------------------------------------------------------------------------------------------------------------------------- - -all: $(MODULEDIR)/$(MODULENAME).a -posix32: $(MODULEDIR)/$(MODULENAME).posix32.a -posix64: $(MODULEDIR)/$(MODULENAME).posix64.a -win32: $(MODULEDIR)/$(MODULENAME).win32.a -win64: $(MODULEDIR)/$(MODULENAME).win64.a - -# ---------------------------------------------------------------------------------------------------------------------------- - -clean: - rm -f $(OBJDIR)/*.o $(MODULEDIR)/$(MODULENAME)*.a - -debug: - $(MAKE) DEBUG=true - -# ---------------------------------------------------------------------------------------------------------------------------- - -$(MODULEDIR)/$(MODULENAME).a: $(OBJS) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).posix32.a: $(OBJS_posix32) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).posix32.a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).posix64.a: $(OBJS_posix64) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).posix64.a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).win32.a: $(OBJS_win32) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).win32.a" - @rm -f $@ - @$(AR) crs $@ $^ - -$(MODULEDIR)/$(MODULENAME).win64.a: $(OBJS_win64) - -@mkdir -p $(MODULEDIR) - @echo "Creating $(MODULENAME).win64.a" - @rm -f $@ - @$(AR) crs $@ $^ - -# ---------------------------------------------------------------------------------------------------------------------------- - -$(OBJDIR)/$(MODULENAME).cpp.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $<" - @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ - -$(OBJDIR)/$(MODULENAME).cpp.%32.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (32bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -c -o $@ - -$(OBJDIR)/$(MODULENAME).cpp.%64.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (64bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -c -o $@ - -# ---------------------------------------------------------------------------------------------------------------------------- - -$(OBJDIR)/$(MODULENAME).mm.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $<" - @$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ - -$(OBJDIR)/$(MODULENAME).mm.%32.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (32bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -ObjC++ -c -o $@ - -$(OBJDIR)/$(MODULENAME).mm.%64.o: $(MODULENAME).cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling $< (64bit)" - @$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -ObjC++ -c -o $@ - -# ---------------------------------------------------------------------------------------------------------------------------- - --include $(OBJS:%.o=%.d) --include $(OBJS_posix32:%.o=%.d) --include $(OBJS_posix64:%.o=%.d) --include $(OBJS_win32:%.o=%.d) --include $(OBJS_win64:%.o=%.d) - -# ---------------------------------------------------------------------------------------------------------------------------- diff --git a/source/modules/juce_gui_basics/application/juce_Application.cpp b/source/modules/juce_gui_basics/application/juce_Application.cpp deleted file mode 100644 index efa5242bb..000000000 --- a/source/modules/juce_gui_basics/application/juce_Application.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -JUCEApplication::JUCEApplication() {} -JUCEApplication::~JUCEApplication() {} - -//============================================================================== -JUCEApplication* JUCE_CALLTYPE JUCEApplication::getInstance() noexcept -{ - return dynamic_cast (JUCEApplicationBase::getInstance()); -} - -bool JUCEApplication::moreThanOneInstanceAllowed() { return true; } -void JUCEApplication::anotherInstanceStarted (const String&) {} - -void JUCEApplication::suspended() {} -void JUCEApplication::resumed() {} - -void JUCEApplication::systemRequestedQuit() { quit(); } - -void JUCEApplication::unhandledException (const std::exception*, const String&, int) -{ - jassertfalse; -} - -//============================================================================== -ApplicationCommandTarget* JUCEApplication::getNextCommandTarget() -{ - return nullptr; -} - -void JUCEApplication::getAllCommands (Array& commands) -{ - commands.add (StandardApplicationCommandIDs::quit); -} - -void JUCEApplication::getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result) -{ - if (commandID == StandardApplicationCommandIDs::quit) - { - result.setInfo (TRANS("Quit"), - TRANS("Quits the application"), - "Application", 0); - - result.defaultKeypresses.add (KeyPress ('q', ModifierKeys::commandModifier, 0)); - } -} - -bool JUCEApplication::perform (const InvocationInfo& info) -{ - if (info.commandID == StandardApplicationCommandIDs::quit) - { - systemRequestedQuit(); - return true; - } - - return false; -} - -//============================================================================== -#if JUCE_MAC - extern void juce_initialiseMacMainMenu(); -#endif - -bool JUCEApplication::initialiseApp() -{ - if (JUCEApplicationBase::initialiseApp()) - { - #if JUCE_MAC - juce_initialiseMacMainMenu(); // (needs to get the app's name) - #endif - - return true; - } - - return false; -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/application/juce_Application.h b/source/modules/juce_gui_basics/application/juce_Application.h deleted file mode 100644 index 423f8ce5c..000000000 --- a/source/modules/juce_gui_basics/application/juce_Application.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - An instance of this class is used to specify initialisation and shutdown - code for the application. - - Any application that wants to run an event loop must declare a subclass of - JUCEApplicationBase or JUCEApplication, and implement its various pure virtual - methods. - - It then needs to use the START_JUCE_APPLICATION macro somewhere in a CPP file - to declare an instance of this class and generate suitable platform-specific - boilerplate code to launch the app. - - Note that this class is derived from JUCEApplicationBase, which contains most - of the useful methods and functionality. This derived class is here simply as - a convenient way to also inherit from an ApplicationCommandTarget, and to implement - default versions of some of the pure virtual base class methods. But you can derive - your app object directly from JUCEApplicationBase if you want to, and by doing so - can avoid having a dependency on the juce_gui_basics module. - - e.g. @code - class MyJUCEApp : public JUCEApplication - { - public: - MyJUCEApp() {} - ~MyJUCEApp() {} - - void initialise (const String& commandLine) override - { - myMainWindow = new MyApplicationWindow(); - myMainWindow->setBounds (100, 100, 400, 500); - myMainWindow->setVisible (true); - } - - void shutdown() override - { - myMainWindow = nullptr; - } - - const String getApplicationName() override - { - return "Super JUCE-o-matic"; - } - - const String getApplicationVersion() override - { - return "1.0"; - } - - private: - ScopedPointer myMainWindow; - }; - - // this generates boilerplate code to launch our app class: - START_JUCE_APPLICATION (MyJUCEApp) - @endcode - - @see JUCEApplicationBase, START_JUCE_APPLICATION -*/ -class JUCE_API JUCEApplication : public JUCEApplicationBase, - public ApplicationCommandTarget -{ -public: - //============================================================================== - /** Constructs a JUCE app object. - - If subclasses implement a constructor or destructor, they shouldn't call any - JUCE code in there - put your startup/shutdown code in initialise() and - shutdown() instead. - */ - JUCEApplication(); - - /** Destructor. - - If subclasses implement a constructor or destructor, they shouldn't call any - JUCE code in there - put your startup/shutdown code in initialise() and - shutdown() instead. - */ - ~JUCEApplication(); - - //============================================================================== - /** Returns the global instance of the application object being run. */ - static JUCEApplication* JUCE_CALLTYPE getInstance() noexcept; - - //============================================================================== - #if DOXYGEN - /** Returns the application's name. */ - virtual const String getApplicationName() = 0; - - /** Returns the application's version number. */ - virtual const String getApplicationVersion() = 0; - #endif - - /** Checks whether multiple instances of the app are allowed. - - If you application class returns true for this, more than one instance is - permitted to run (except on OSX where the OS automatically stops you launching - a second instance of an app without explicitly starting it from the command-line). - - If it's false, the second instance won't start, but it you will still get a - callback to anotherInstanceStarted() to tell you about this - which - gives you a chance to react to what the user was trying to do. - */ - bool moreThanOneInstanceAllowed() override; - - /** Indicates that the user has tried to start up another instance of the app. - This will get called even if moreThanOneInstanceAllowed() is false. - */ - void anotherInstanceStarted (const String& commandLine) override; - - /** Called when the operating system is trying to close the application. - - The default implementation of this method is to call quit(), but it may - be overloaded to ignore the request or do some other special behaviour - instead. For example, you might want to offer the user the chance to save - their changes before quitting, and give them the chance to cancel. - - If you want to send a quit signal to your app, this is the correct method - to call, because it means that requests that come from the system get handled - in the same way as those from your own application code. So e.g. you'd - call this method from a "quit" item on a menu bar. - */ - void systemRequestedQuit() override; - - /** This method is called when the application is being put into background mode - by the operating system. - */ - void suspended() override; - - /** This method is called when the application is being woken from background mode - by the operating system. - */ - void resumed() override; - - /** If any unhandled exceptions make it through to the message dispatch loop, this - callback will be triggered, in case you want to log them or do some other - type of error-handling. - - If the type of exception is derived from the std::exception class, the pointer - passed-in will be valid. If the exception is of unknown type, this pointer - will be null. - */ - void unhandledException (const std::exception* e, - const String& sourceFilename, - int lineNumber) override; - - //============================================================================== - /** @internal */ - ApplicationCommandTarget* getNextCommandTarget() override; - /** @internal */ - void getCommandInfo (CommandID, ApplicationCommandInfo&) override; - /** @internal */ - void getAllCommands (Array&) override; - /** @internal */ - bool perform (const InvocationInfo&) override; - -private: - bool initialiseApp() override; - - JUCE_DECLARE_NON_COPYABLE (JUCEApplication) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_ArrowButton.cpp b/source/modules/juce_gui_basics/buttons/juce_ArrowButton.cpp deleted file mode 100644 index fa76bc1d3..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_ArrowButton.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -ArrowButton::ArrowButton (const String& name, float arrowDirectionInRadians, Colour arrowColour) - : Button (name), colour (arrowColour) -{ - path.addTriangle (0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.5f); - path.applyTransform (AffineTransform::rotation (float_Pi * 2.0f * arrowDirectionInRadians, 0.5f, 0.5f)); -} - -ArrowButton::~ArrowButton() {} - -void ArrowButton::paintButton (Graphics& g, bool /*isMouseOverButton*/, bool isButtonDown) -{ - Path p (path); - - const float offset = isButtonDown ? 1.0f : 0.0f; - p.applyTransform (path.getTransformToScaleToFit (offset, offset, getWidth() - 3.0f, getHeight() - 3.0f, false)); - - DropShadow (Colours::black.withAlpha (0.3f), isButtonDown ? 2 : 4, Point()).drawForPath (g, p); - - g.setColour (colour); - g.fillPath (p); -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_ArrowButton.h b/source/modules/juce_gui_basics/buttons/juce_ArrowButton.h deleted file mode 100644 index 8ff4d7f47..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_ArrowButton.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A button with an arrow in it. - - @see Button -*/ -class JUCE_API ArrowButton : public Button -{ -public: - //============================================================================== - /** Creates an ArrowButton. - - @param buttonName the name to give the button - @param arrowDirection the direction the arrow should point in, where 0.0 is - pointing right, 0.25 is down, 0.5 is left, 0.75 is up - @param arrowColour the colour to use for the arrow - */ - ArrowButton (const String& buttonName, - float arrowDirection, - Colour arrowColour); - - /** Destructor. */ - ~ArrowButton(); - - /** @internal */ - void paintButton (Graphics&, bool isMouseOverButton, bool isButtonDown) override; - -private: - Colour colour; - Path path; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ArrowButton) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_Button.cpp b/source/modules/juce_gui_basics/buttons/juce_Button.cpp deleted file mode 100644 index e82b83897..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_Button.cpp +++ /dev/null @@ -1,699 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -class Button::CallbackHelper : public Timer, - public ApplicationCommandManagerListener, - public Value::Listener, - public KeyListener -{ -public: - CallbackHelper (Button& b) : button (b) {} - - void timerCallback() override - { - button.repeatTimerCallback(); - } - - bool keyStateChanged (bool, Component*) override - { - return button.keyStateChangedCallback(); - } - - void valueChanged (Value& value) override - { - if (value.refersToSameSourceAs (button.isOn)) - button.setToggleState (button.isOn.getValue(), sendNotification); - } - - bool keyPressed (const KeyPress&, Component*) override - { - // returning true will avoid forwarding events for keys that we're using as shortcuts - return button.isShortcutPressed(); - } - - void applicationCommandInvoked (const ApplicationCommandTarget::InvocationInfo& info) override - { - if (info.commandID == button.commandID - && (info.commandFlags & ApplicationCommandInfo::dontTriggerVisualFeedback) == 0) - button.flashButtonState(); - } - - void applicationCommandListChanged() override - { - button.applicationCommandListChangeCallback(); - } - -private: - Button& button; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallbackHelper) -}; - -//============================================================================== -Button::Button (const String& name) - : Component (name), - text (name), - buttonPressTime (0), - lastRepeatTime (0), - commandManagerToUse (nullptr), - autoRepeatDelay (-1), - autoRepeatSpeed (0), - autoRepeatMinimumDelay (-1), - radioGroupId (0), - connectedEdgeFlags (0), - commandID(), - buttonState (buttonNormal), - lastStatePainted (buttonNormal), - lastToggleState (false), - clickTogglesState (false), - needsToRelease (false), - needsRepainting (false), - isKeyDown (false), - triggerOnMouseDown (false), - generateTooltip (false) -{ - callbackHelper = new CallbackHelper (*this); - - setWantsKeyboardFocus (true); - isOn.addListener (callbackHelper); -} - -Button::~Button() -{ - clearShortcuts(); - - if (commandManagerToUse != nullptr) - commandManagerToUse->removeListener (callbackHelper); - - isOn.removeListener (callbackHelper); - callbackHelper = nullptr; -} - -//============================================================================== -void Button::setButtonText (const String& newText) -{ - if (text != newText) - { - text = newText; - repaint(); - } -} - -void Button::setTooltip (const String& newTooltip) -{ - SettableTooltipClient::setTooltip (newTooltip); - generateTooltip = false; -} - -void Button::updateAutomaticTooltip (const ApplicationCommandInfo& info) -{ - if (generateTooltip && commandManagerToUse != nullptr) - { - String tt (info.description.isNotEmpty() ? info.description - : info.shortName); - - Array keyPresses (commandManagerToUse->getKeyMappings()->getKeyPressesAssignedToCommand (commandID)); - - for (int i = 0; i < keyPresses.size(); ++i) - { - const String key (keyPresses.getReference(i).getTextDescription()); - - tt << " ["; - - if (key.length() == 1) - tt << TRANS("shortcut") << ": '" << key << "']"; - else - tt << key << ']'; - } - - SettableTooltipClient::setTooltip (tt); - } -} - -void Button::setConnectedEdges (const int newFlags) -{ - if (connectedEdgeFlags != newFlags) - { - connectedEdgeFlags = newFlags; - repaint(); - } -} - -//============================================================================== -void Button::setToggleState (const bool shouldBeOn, const NotificationType notification) -{ - if (shouldBeOn != lastToggleState) - { - WeakReference deletionWatcher (this); - - if (shouldBeOn) - { - turnOffOtherButtonsInGroup (notification); - - if (deletionWatcher == nullptr) - return; - } - - // This test is done so that if the value is void rather than explicitly set to - // false, the value won't be changed unless the required value is true. - if (getToggleState() != shouldBeOn) - { - isOn = shouldBeOn; - - if (deletionWatcher == nullptr) - return; - } - - lastToggleState = shouldBeOn; - repaint(); - - if (notification != dontSendNotification) - { - // async callbacks aren't possible here - jassert (notification != sendNotificationAsync); - - sendClickMessage (ModifierKeys::getCurrentModifiers()); - - if (deletionWatcher == nullptr) - return; - } - - if (notification != dontSendNotification) - sendStateMessage(); - else - buttonStateChanged(); - } -} - -void Button::setToggleState (const bool shouldBeOn, bool sendChange) -{ - setToggleState (shouldBeOn, sendChange ? sendNotification : dontSendNotification); -} - -void Button::setClickingTogglesState (const bool shouldToggle) noexcept -{ - clickTogglesState = shouldToggle; - - // if you've got clickTogglesState turned on, you shouldn't also connect the button - // up to be a command invoker. Instead, your command handler must flip the state of whatever - // it is that this button represents, and the button will update its state to reflect this - // in the applicationCommandListChanged() method. - jassert (commandManagerToUse == nullptr || ! clickTogglesState); -} - -bool Button::getClickingTogglesState() const noexcept -{ - return clickTogglesState; -} - -void Button::setRadioGroupId (const int newGroupId, NotificationType notification) -{ - if (radioGroupId != newGroupId) - { - radioGroupId = newGroupId; - - if (lastToggleState) - turnOffOtherButtonsInGroup (notification); - } -} - -void Button::turnOffOtherButtonsInGroup (const NotificationType notification) -{ - if (auto* p = getParentComponent()) - { - if (radioGroupId != 0) - { - WeakReference deletionWatcher (this); - - for (auto* c : p->getChildren()) - { - if (c != this) - { - if (auto b = dynamic_cast (c)) - { - if (b->getRadioGroupId() == radioGroupId) - { - b->setToggleState (false, notification); - - if (deletionWatcher == nullptr) - return; - } - } - } - } - } - } -} - -//============================================================================== -void Button::enablementChanged() -{ - updateState(); - repaint(); -} - -Button::ButtonState Button::updateState() -{ - return updateState (isMouseOver (true), isMouseButtonDown()); -} - -Button::ButtonState Button::updateState (const bool over, const bool down) -{ - ButtonState newState = buttonNormal; - - if (isEnabled() && isVisible() && ! isCurrentlyBlockedByAnotherModalComponent()) - { - if ((down && (over || (triggerOnMouseDown && buttonState == buttonDown))) || isKeyDown) - newState = buttonDown; - else if (over) - newState = buttonOver; - } - - setState (newState); - return newState; -} - -void Button::setState (const ButtonState newState) -{ - if (buttonState != newState) - { - buttonState = newState; - repaint(); - - if (buttonState == buttonDown) - { - buttonPressTime = Time::getApproximateMillisecondCounter(); - lastRepeatTime = 0; - } - - sendStateMessage(); - } -} - -bool Button::isDown() const noexcept { return buttonState == buttonDown; } -bool Button::isOver() const noexcept { return buttonState != buttonNormal; } - -void Button::buttonStateChanged() {} - -uint32 Button::getMillisecondsSinceButtonDown() const noexcept -{ - const uint32 now = Time::getApproximateMillisecondCounter(); - return now > buttonPressTime ? now - buttonPressTime : 0; -} - -void Button::setTriggeredOnMouseDown (const bool isTriggeredOnMouseDown) noexcept -{ - triggerOnMouseDown = isTriggeredOnMouseDown; -} - -bool Button::getTriggeredOnMouseDown() const noexcept -{ - return triggerOnMouseDown; -} - -//============================================================================== -void Button::clicked() -{ -} - -void Button::clicked (const ModifierKeys&) -{ - clicked(); -} - -enum { clickMessageId = 0x2f3f4f99 }; - -void Button::triggerClick() -{ - postCommandMessage (clickMessageId); -} - -void Button::internalClickCallback (const ModifierKeys& modifiers) -{ - if (clickTogglesState) - { - const bool shouldBeOn = (radioGroupId != 0 || ! lastToggleState); - - if (shouldBeOn != getToggleState()) - { - setToggleState (shouldBeOn, sendNotification); - return; - } - } - - sendClickMessage (modifiers); -} - -void Button::flashButtonState() -{ - if (isEnabled()) - { - needsToRelease = true; - setState (buttonDown); - callbackHelper->startTimer (100); - } -} - -void Button::handleCommandMessage (int commandId) -{ - if (commandId == clickMessageId) - { - if (isEnabled()) - { - flashButtonState(); - internalClickCallback (ModifierKeys::getCurrentModifiers()); - } - } - else - { - Component::handleCommandMessage (commandId); - } -} - -//============================================================================== -void Button::addListener (Listener* l) { buttonListeners.add (l); } -void Button::removeListener (Listener* l) { buttonListeners.remove (l); } - -void Button::sendClickMessage (const ModifierKeys& modifiers) -{ - Component::BailOutChecker checker (this); - - if (commandManagerToUse != nullptr && commandID != 0) - { - ApplicationCommandTarget::InvocationInfo info (commandID); - info.invocationMethod = ApplicationCommandTarget::InvocationInfo::fromButton; - info.originatingComponent = this; - - commandManagerToUse->invoke (info, true); - } - - clicked (modifiers); - - if (! checker.shouldBailOut()) - buttonListeners.callChecked (checker, &Button::Listener::buttonClicked, this); -} - -void Button::sendStateMessage() -{ - Component::BailOutChecker checker (this); - - buttonStateChanged(); - - if (! checker.shouldBailOut()) - buttonListeners.callChecked (checker, &Button::Listener::buttonStateChanged, this); -} - -//============================================================================== -void Button::paint (Graphics& g) -{ - if (needsToRelease && isEnabled()) - { - needsToRelease = false; - needsRepainting = true; - } - - paintButton (g, isOver(), isDown()); - lastStatePainted = buttonState; -} - -//============================================================================== -void Button::mouseEnter (const MouseEvent&) { updateState (true, false); } -void Button::mouseExit (const MouseEvent&) { updateState (false, false); } - -void Button::mouseDown (const MouseEvent& e) -{ - updateState (true, true); - - if (isDown()) - { - if (autoRepeatDelay >= 0) - callbackHelper->startTimer (autoRepeatDelay); - - if (triggerOnMouseDown) - internalClickCallback (e.mods); - } -} - -void Button::mouseUp (const MouseEvent& e) -{ - const bool wasDown = isDown(); - const bool wasOver = isOver(); - updateState (isMouseOrTouchOver (e), false); - - if (wasDown && wasOver && ! triggerOnMouseDown) - { - if (lastStatePainted != buttonDown) - flashButtonState(); - - internalClickCallback (e.mods); - } -} - -void Button::mouseDrag (const MouseEvent& e) -{ - const ButtonState oldState = buttonState; - updateState (isMouseOrTouchOver (e), true); - - if (autoRepeatDelay >= 0 && buttonState != oldState && isDown()) - callbackHelper->startTimer (autoRepeatSpeed); -} - -bool Button::isMouseOrTouchOver (const MouseEvent& e) -{ - if (e.source.isTouch()) - return getLocalBounds().toFloat().contains (e.position); - - return isMouseOver(); -} - -void Button::focusGained (FocusChangeType) -{ - updateState(); - repaint(); -} - -void Button::focusLost (FocusChangeType) -{ - updateState(); - repaint(); -} - -void Button::visibilityChanged() -{ - needsToRelease = false; - updateState(); -} - -void Button::parentHierarchyChanged() -{ - Component* const newKeySource = (shortcuts.size() == 0) ? nullptr : getTopLevelComponent(); - - if (newKeySource != keySource.get()) - { - if (keySource != nullptr) - keySource->removeKeyListener (callbackHelper); - - keySource = newKeySource; - - if (keySource != nullptr) - keySource->addKeyListener (callbackHelper); - } -} - -//============================================================================== -void Button::setCommandToTrigger (ApplicationCommandManager* const newCommandManager, - const CommandID newCommandID, const bool generateTip) -{ - commandID = newCommandID; - generateTooltip = generateTip; - - if (commandManagerToUse != newCommandManager) - { - if (commandManagerToUse != nullptr) - commandManagerToUse->removeListener (callbackHelper); - - commandManagerToUse = newCommandManager; - - if (commandManagerToUse != nullptr) - commandManagerToUse->addListener (callbackHelper); - - // if you've got clickTogglesState turned on, you shouldn't also connect the button - // up to be a command invoker. Instead, your command handler must flip the state of whatever - // it is that this button represents, and the button will update its state to reflect this - // in the applicationCommandListChanged() method. - jassert (commandManagerToUse == nullptr || ! clickTogglesState); - } - - if (commandManagerToUse != nullptr) - applicationCommandListChangeCallback(); - else - setEnabled (true); -} - -void Button::applicationCommandListChangeCallback() -{ - if (commandManagerToUse != nullptr) - { - ApplicationCommandInfo info (0); - - if (commandManagerToUse->getTargetForCommand (commandID, info) != nullptr) - { - updateAutomaticTooltip (info); - setEnabled ((info.flags & ApplicationCommandInfo::isDisabled) == 0); - setToggleState ((info.flags & ApplicationCommandInfo::isTicked) != 0, dontSendNotification); - } - else - { - setEnabled (false); - } - } -} - -//============================================================================== -void Button::addShortcut (const KeyPress& key) -{ - if (key.isValid()) - { - jassert (! isRegisteredForShortcut (key)); // already registered! - - shortcuts.add (key); - parentHierarchyChanged(); - } -} - -void Button::clearShortcuts() -{ - shortcuts.clear(); - parentHierarchyChanged(); -} - -bool Button::isShortcutPressed() const -{ - if (isShowing() && ! isCurrentlyBlockedByAnotherModalComponent()) - for (int i = shortcuts.size(); --i >= 0;) - if (shortcuts.getReference(i).isCurrentlyDown()) - return true; - - return false; -} - -bool Button::isRegisteredForShortcut (const KeyPress& key) const -{ - for (int i = shortcuts.size(); --i >= 0;) - if (key == shortcuts.getReference(i)) - return true; - - return false; -} - -bool Button::keyStateChangedCallback() -{ - if (! isEnabled()) - return false; - - const bool wasDown = isKeyDown; - isKeyDown = isShortcutPressed(); - - if (autoRepeatDelay >= 0 && (isKeyDown && ! wasDown)) - callbackHelper->startTimer (autoRepeatDelay); - - updateState(); - - if (isEnabled() && wasDown && ! isKeyDown) - { - internalClickCallback (ModifierKeys::getCurrentModifiers()); - - // (return immediately - this button may now have been deleted) - return true; - } - - return wasDown || isKeyDown; -} - -bool Button::keyPressed (const KeyPress& key) -{ - if (isEnabled() && key.isKeyCode (KeyPress::returnKey)) - { - triggerClick(); - return true; - } - - return false; -} - -//============================================================================== -void Button::setRepeatSpeed (const int initialDelayMillisecs, - const int repeatMillisecs, - const int minimumDelayInMillisecs) noexcept -{ - autoRepeatDelay = initialDelayMillisecs; - autoRepeatSpeed = repeatMillisecs; - autoRepeatMinimumDelay = jmin (autoRepeatSpeed, minimumDelayInMillisecs); -} - -void Button::repeatTimerCallback() -{ - if (needsRepainting) - { - callbackHelper->stopTimer(); - updateState(); - needsRepainting = false; - } - else if (autoRepeatSpeed > 0 && (isKeyDown || (updateState() == buttonDown))) - { - int repeatSpeed = autoRepeatSpeed; - - if (autoRepeatMinimumDelay >= 0) - { - double timeHeldDown = jmin (1.0, getMillisecondsSinceButtonDown() / 4000.0); - timeHeldDown *= timeHeldDown; - - repeatSpeed = repeatSpeed + (int) (timeHeldDown * (autoRepeatMinimumDelay - repeatSpeed)); - } - - repeatSpeed = jmax (1, repeatSpeed); - - const uint32 now = Time::getMillisecondCounter(); - - // if we've been blocked from repeating often enough, speed up the repeat timer to compensate.. - if (lastRepeatTime != 0 && (int) (now - lastRepeatTime) > repeatSpeed * 2) - repeatSpeed = jmax (1, repeatSpeed / 2); - - lastRepeatTime = now; - callbackHelper->startTimer (repeatSpeed); - - internalClickCallback (ModifierKeys::getCurrentModifiers()); - } - else if (! needsToRelease) - { - callbackHelper->stopTimer(); - } -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_Button.h b/source/modules/juce_gui_basics/buttons/juce_Button.h deleted file mode 100644 index 79de48cc2..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_Button.h +++ /dev/null @@ -1,522 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A base class for buttons. - - This contains all the logic for button behaviours such as enabling/disabling, - responding to shortcut keystrokes, auto-repeating when held down, toggle-buttons - and radio groups, etc. - - @see TextButton, DrawableButton, ToggleButton -*/ -class JUCE_API Button : public Component, - public SettableTooltipClient -{ -protected: - //============================================================================== - /** Creates a button. - - @param buttonName the text to put in the button (the component's name is also - initially set to this string, but these can be changed later - using the setName() and setButtonText() methods) - */ - explicit Button (const String& buttonName); - -public: - /** Destructor. */ - virtual ~Button(); - - //============================================================================== - /** Changes the button's text. - @see getButtonText - */ - void setButtonText (const String& newText); - - /** Returns the text displayed in the button. - @see setButtonText - */ - const String& getButtonText() const { return text; } - - //============================================================================== - /** Returns true if the button is currently being held down. - @see isOver - */ - bool isDown() const noexcept; - - /** Returns true if the mouse is currently over the button. - This will be also be true if the button is being held down. - @see isDown - */ - bool isOver() const noexcept; - - //============================================================================== - /** A button has an on/off state associated with it, and this changes that. - - By default buttons are 'off' and for simple buttons that you click to perform - an action you won't change this. Toggle buttons, however will want to - change their state when turned on or off. - - @param shouldBeOn whether to set the button's toggle state to be on or - off. If it's a member of a button group, this will - always try to turn it on, and to turn off any other - buttons in the group - @param notification determines the behaviour if the value changes - this - can invoke a synchronous call to clicked(), but - sendNotificationAsync is not supported - @see getToggleState, setRadioGroupId - */ - void setToggleState (bool shouldBeOn, NotificationType notification); - - /** Returns true if the button is 'on'. - - By default buttons are 'off' and for simple buttons that you click to perform - an action you won't change this. Toggle buttons, however will want to - change their state when turned on or off. - - @see setToggleState - */ - bool getToggleState() const noexcept { return isOn.getValue(); } - - /** Returns the Value object that represents the botton's toggle state. - You can use this Value object to connect the button's state to external values or setters, - either by taking a copy of the Value, or by using Value::referTo() to make it point to - your own Value object. - @see getToggleState, Value - */ - Value& getToggleStateValue() noexcept { return isOn; } - - /** This tells the button to automatically flip the toggle state when - the button is clicked. - - If set to true, then before the clicked() callback occurs, the toggle-state - of the button is flipped. - */ - void setClickingTogglesState (bool shouldAutoToggleOnClick) noexcept; - - /** Returns true if this button is set to be an automatic toggle-button. - This returns the last value that was passed to setClickingTogglesState(). - */ - bool getClickingTogglesState() const noexcept; - - //============================================================================== - /** Enables the button to act as a member of a mutually-exclusive group - of 'radio buttons'. - - If the group ID is set to a non-zero number, then this button will - act as part of a group of buttons with the same ID, only one of - which can be 'on' at the same time. Note that when it's part of - a group, clicking a toggle-button that's 'on' won't turn it off. - - To find other buttons with the same ID, this button will search through - its sibling components for ToggleButtons, so all the buttons for a - particular group must be placed inside the same parent component. - - Set the group ID back to zero if you want it to act as a normal toggle - button again. - - The notification argument lets you specify how other buttons should react - to being turned on or off in response to this call. - - @see getRadioGroupId - */ - void setRadioGroupId (int newGroupId, NotificationType notification = sendNotification); - - /** Returns the ID of the group to which this button belongs. - (See setRadioGroupId() for an explanation of this). - */ - int getRadioGroupId() const noexcept { return radioGroupId; } - - //============================================================================== - /** - Used to receive callbacks when a button is clicked. - - @see Button::addListener, Button::removeListener - */ - class JUCE_API Listener - { - public: - /** Destructor. */ - virtual ~Listener() {} - - /** Called when the button is clicked. */ - virtual void buttonClicked (Button*) = 0; - - /** Called when the button's state changes. */ - virtual void buttonStateChanged (Button*) {} - }; - - /** Registers a listener to receive events when this button's state changes. - If the listener is already registered, this will not register it again. - @see removeListener - */ - void addListener (Listener* newListener); - - /** Removes a previously-registered button listener - @see addListener - */ - void removeListener (Listener* listener); - - //============================================================================== - /** Causes the button to act as if it's been clicked. - - This will asynchronously make the button draw itself going down and up, and - will then call back the clicked() method as if mouse was clicked on it. - - @see clicked - */ - virtual void triggerClick(); - - //============================================================================== - /** Sets a command ID for this button to automatically invoke when it's clicked. - - When the button is pressed, it will use the given manager to trigger the - command ID. - - Obviously be careful that the ApplicationCommandManager doesn't get deleted - before this button is. To disable the command triggering, call this method and - pass nullptr as the command manager. - - If generateTooltip is true, then the button's tooltip will be automatically - generated based on the name of this command and its current shortcut key. - - @see addShortcut, getCommandID - */ - void setCommandToTrigger (ApplicationCommandManager* commandManagerToUse, - CommandID commandID, - bool generateTooltip); - - /** Returns the command ID that was set by setCommandToTrigger(). */ - CommandID getCommandID() const noexcept { return commandID; } - - //============================================================================== - /** Assigns a shortcut key to trigger the button. - - The button registers itself with its top-level parent component for keypresses. - - Note that a different way of linking buttons to keypresses is by using the - setCommandToTrigger() method to invoke a command. - - @see clearShortcuts - */ - void addShortcut (const KeyPress&); - - /** Removes all key shortcuts that had been set for this button. - @see addShortcut - */ - void clearShortcuts(); - - /** Returns true if the given keypress is a shortcut for this button. - @see addShortcut - */ - bool isRegisteredForShortcut (const KeyPress&) const; - - //============================================================================== - /** Sets an auto-repeat speed for the button when it is held down. - - (Auto-repeat is disabled by default). - - @param initialDelayInMillisecs how long to wait after the mouse is pressed before - triggering the next click. If this is zero, auto-repeat - is disabled - @param repeatDelayInMillisecs the frequently subsequent repeated clicks should be - triggered - @param minimumDelayInMillisecs if this is greater than 0, the auto-repeat speed will - get faster, the longer the button is held down, up to the - minimum interval specified here - */ - void setRepeatSpeed (int initialDelayInMillisecs, - int repeatDelayInMillisecs, - int minimumDelayInMillisecs = -1) noexcept; - - /** Sets whether the button click should happen when the mouse is pressed or released. - - By default the button is only considered to have been clicked when the mouse is - released, but setting this to true will make it call the clicked() method as soon - as the button is pressed. - - This is useful if the button is being used to show a pop-up menu, as it allows - the click to be used as a drag onto the menu. - */ - void setTriggeredOnMouseDown (bool isTriggeredOnMouseDown) noexcept; - - /** Returns whether the button click happens when the mouse is pressed or released. - @see setTriggeredOnMouseDown - */ - bool getTriggeredOnMouseDown() const noexcept; - - /** Returns the number of milliseconds since the last time the button - went into the 'down' state. - */ - uint32 getMillisecondsSinceButtonDown() const noexcept; - - //============================================================================== - /** Sets the tooltip for this button. - @see TooltipClient, TooltipWindow - */ - void setTooltip (const String& newTooltip) override; - - //============================================================================== - /** A combination of these flags are used by setConnectedEdges(). */ - enum ConnectedEdgeFlags - { - ConnectedOnLeft = 1, - ConnectedOnRight = 2, - ConnectedOnTop = 4, - ConnectedOnBottom = 8 - }; - - /** Hints about which edges of the button might be connected to adjoining buttons. - - The value passed in is a bitwise combination of any of the values in the - ConnectedEdgeFlags enum. - - E.g. if you are placing two buttons adjacent to each other, you could use this to - indicate which edges are touching, and the LookAndFeel might choose to drawn them - without rounded corners on the edges that connect. It's only a hint, so the - LookAndFeel can choose to ignore it if it's not relevant for this type of - button. - */ - void setConnectedEdges (int connectedEdgeFlags); - - /** Returns the set of flags passed into setConnectedEdges(). */ - int getConnectedEdgeFlags() const noexcept { return connectedEdgeFlags; } - - /** Indicates whether the button adjoins another one on its left edge. - @see setConnectedEdges - */ - bool isConnectedOnLeft() const noexcept { return (connectedEdgeFlags & ConnectedOnLeft) != 0; } - - /** Indicates whether the button adjoins another one on its right edge. - @see setConnectedEdges - */ - bool isConnectedOnRight() const noexcept { return (connectedEdgeFlags & ConnectedOnRight) != 0; } - - /** Indicates whether the button adjoins another one on its top edge. - @see setConnectedEdges - */ - bool isConnectedOnTop() const noexcept { return (connectedEdgeFlags & ConnectedOnTop) != 0; } - - /** Indicates whether the button adjoins another one on its bottom edge. - @see setConnectedEdges - */ - bool isConnectedOnBottom() const noexcept { return (connectedEdgeFlags & ConnectedOnBottom) != 0; } - - - //============================================================================== - /** Used by setState(). */ - enum ButtonState - { - buttonNormal, - buttonOver, - buttonDown - }; - - /** Can be used to force the button into a particular state. - - This only changes the button's appearance, it won't trigger a click, or stop any mouse-clicks - from happening. - - The state that you set here will only last until it is automatically changed when the mouse - enters or exits the button, or the mouse-button is pressed or released. - */ - void setState (ButtonState newState); - - /** Returns the button's current over/down/up state. */ - ButtonState getState() const noexcept { return buttonState; } - - // This method's parameters have changed - see the new version. - JUCE_DEPRECATED (void setToggleState (bool, bool)); - - //============================================================================== - /** This abstract base class is implemented by LookAndFeel classes to provide - button-drawing functionality. - */ - struct JUCE_API LookAndFeelMethods - { - virtual ~LookAndFeelMethods() {} - - virtual void drawButtonBackground (Graphics&, Button&, const Colour& backgroundColour, - bool isMouseOverButton, bool isButtonDown) = 0; - - virtual Font getTextButtonFont (TextButton&, int buttonHeight) = 0; - virtual int getTextButtonWidthToFitText (TextButton&, int buttonHeight) = 0; - - /** Draws the text for a TextButton. */ - virtual void drawButtonText (Graphics&, TextButton&, bool isMouseOverButton, bool isButtonDown) = 0; - - /** Draws the contents of a standard ToggleButton. */ - virtual void drawToggleButton (Graphics&, ToggleButton&, bool isMouseOverButton, bool isButtonDown) = 0; - - virtual void changeToggleButtonWidthToFitText (ToggleButton&) = 0; - - virtual void drawTickBox (Graphics&, Component&, float x, float y, float w, float h, - bool ticked, bool isEnabled, bool isMouseOverButton, bool isButtonDown) = 0; - - virtual void drawDrawableButton (Graphics&, DrawableButton&, bool isMouseOverButton, bool isButtonDown) = 0; - - private: - #if JUCE_CATCH_DEPRECATED_CODE_MISUSE - // These method have been deprecated: see their replacements above. - virtual int getTextButtonFont (TextButton&) { return 0; } - virtual int changeTextButtonWidthToFitText (TextButton&, int) { return 0; } - #endif - }; - -protected: - //============================================================================== - /** This method is called when the button has been clicked. - - Subclasses can override this to perform whatever they actions they need - to do. - - Alternatively, a Button::Listener can be added to the button, and these listeners - will be called when the click occurs. - - @see triggerClick - */ - virtual void clicked(); - - /** This method is called when the button has been clicked. - - By default it just calls clicked(), but you might want to override it to handle - things like clicking when a modifier key is pressed, etc. - - @see ModifierKeys - */ - virtual void clicked (const ModifierKeys& modifiers); - - /** Subclasses should override this to actually paint the button's contents. - - It's better to use this than the paint method, because it gives you information - about the over/down state of the button. - - @param g the graphics context to use - @param isMouseOverButton true if the button is either in the 'over' or - 'down' state - @param isButtonDown true if the button should be drawn in the 'down' position - */ - virtual void paintButton (Graphics& g, - bool isMouseOverButton, - bool isButtonDown) = 0; - - /** Called when the button's up/down/over state changes. - - Subclasses can override this if they need to do something special when the button - goes up or down. - - @see isDown, isOver - */ - virtual void buttonStateChanged(); - - //============================================================================== - /** @internal */ - virtual void internalClickCallback (const ModifierKeys&); - /** @internal */ - void handleCommandMessage (int commandId) override; - /** @internal */ - void mouseEnter (const MouseEvent&) override; - /** @internal */ - void mouseExit (const MouseEvent&) override; - /** @internal */ - void mouseDown (const MouseEvent&) override; - /** @internal */ - void mouseDrag (const MouseEvent&) override; - /** @internal */ - void mouseUp (const MouseEvent&) override; - /** @internal */ - bool keyPressed (const KeyPress&) override; - /** @internal */ - using Component::keyStateChanged; - /** @internal */ - void paint (Graphics&) override; - /** @internal */ - void parentHierarchyChanged() override; - /** @internal */ - void visibilityChanged() override; - /** @internal */ - void focusGained (FocusChangeType) override; - /** @internal */ - void focusLost (FocusChangeType) override; - /** @internal */ - void enablementChanged() override; - -private: - //============================================================================== - Array shortcuts; - WeakReference keySource; - String text; - ListenerList buttonListeners; - - class CallbackHelper; - friend class CallbackHelper; - friend struct ContainerDeletePolicy; - ScopedPointer callbackHelper; - uint32 buttonPressTime, lastRepeatTime; - ApplicationCommandManager* commandManagerToUse; - int autoRepeatDelay, autoRepeatSpeed, autoRepeatMinimumDelay; - int radioGroupId, connectedEdgeFlags; - CommandID commandID; - ButtonState buttonState, lastStatePainted; - - Value isOn; - bool lastToggleState; - bool clickTogglesState; - bool needsToRelease; - bool needsRepainting; - bool isKeyDown; - bool triggerOnMouseDown; - bool generateTooltip; - - void repeatTimerCallback(); - bool keyStateChangedCallback(); - void applicationCommandListChangeCallback(); - void updateAutomaticTooltip (const ApplicationCommandInfo&); - - ButtonState updateState(); - ButtonState updateState (bool isOver, bool isDown); - bool isShortcutPressed() const; - void turnOffOtherButtonsInGroup (NotificationType); - - void flashButtonState(); - void sendClickMessage (const ModifierKeys&); - void sendStateMessage(); - - bool isMouseOrTouchOver (const MouseEvent& e); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Button) -}; - -#ifndef DOXYGEN - /** This typedef is just for compatibility with old code and VC6 - newer code should use Button::Listener instead. */ - typedef Button::Listener ButtonListener; -#endif - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_DrawableButton.cpp b/source/modules/juce_gui_basics/buttons/juce_DrawableButton.cpp deleted file mode 100644 index f4b01ef3e..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_DrawableButton.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -DrawableButton::DrawableButton (const String& name, const DrawableButton::ButtonStyle buttonStyle) - : Button (name), style (buttonStyle) -{ -} - -DrawableButton::~DrawableButton() -{ -} - -//============================================================================== -static Drawable* copyDrawableIfNotNull (const Drawable* const d) -{ - return d != nullptr ? d->createCopy() : nullptr; -} - -void DrawableButton::setImages (const Drawable* normal, - const Drawable* over, - const Drawable* down, - const Drawable* disabled, - const Drawable* normalOn, - const Drawable* overOn, - const Drawable* downOn, - const Drawable* disabledOn) -{ - jassert (normal != nullptr); // you really need to give it at least a normal image.. - - normalImage = copyDrawableIfNotNull (normal); - overImage = copyDrawableIfNotNull (over); - downImage = copyDrawableIfNotNull (down); - disabledImage = copyDrawableIfNotNull (disabled); - normalImageOn = copyDrawableIfNotNull (normalOn); - overImageOn = copyDrawableIfNotNull (overOn); - downImageOn = copyDrawableIfNotNull (downOn); - disabledImageOn = copyDrawableIfNotNull (disabledOn); - currentImage = nullptr; - - buttonStateChanged(); -} - -//============================================================================== -void DrawableButton::setButtonStyle (const DrawableButton::ButtonStyle newStyle) -{ - if (style != newStyle) - { - style = newStyle; - buttonStateChanged(); - } -} - -void DrawableButton::setEdgeIndent (const int numPixelsIndent) -{ - edgeIndent = numPixelsIndent; - repaint(); - resized(); -} - -Rectangle DrawableButton::getImageBounds() const -{ - auto r = getLocalBounds(); - - if (style != ImageStretched) - { - auto indentX = jmin (edgeIndent, proportionOfWidth (0.3f)); - auto indentY = jmin (edgeIndent, proportionOfHeight (0.3f)); - - if (style == ImageOnButtonBackground) - { - indentX = jmax (getWidth() / 4, indentX); - indentY = jmax (getHeight() / 4, indentY); - } - else if (style == ImageAboveTextLabel) - { - r = r.withTrimmedBottom (jmin (16, proportionOfHeight (0.25f))); - } - - r = r.reduced (indentX, indentY); - } - - return r.toFloat(); -} - -void DrawableButton::resized() -{ - Button::resized(); - - if (currentImage != nullptr) - { - if (style == ImageRaw) - currentImage->setOriginWithOriginalSize (Point()); - else - currentImage->setTransformToFit (getImageBounds(), - style == ImageStretched ? RectanglePlacement::stretchToFit - : RectanglePlacement::centred); - } -} - -void DrawableButton::buttonStateChanged() -{ - repaint(); - - Drawable* imageToDraw = nullptr; - float opacity = 1.0f; - - if (isEnabled()) - { - imageToDraw = getCurrentImage(); - } - else - { - imageToDraw = getToggleState() ? disabledImageOn - : disabledImage; - - if (imageToDraw == nullptr) - { - opacity = 0.4f; - imageToDraw = getNormalImage(); - } - } - - if (imageToDraw != currentImage) - { - removeChildComponent (currentImage); - currentImage = imageToDraw; - - if (currentImage != nullptr) - { - currentImage->setInterceptsMouseClicks (false, false); - addAndMakeVisible (currentImage); - resized(); - } - } - - if (currentImage != nullptr) - currentImage->setAlpha (opacity); -} - -void DrawableButton::enablementChanged() -{ - Button::enablementChanged(); - buttonStateChanged(); -} - -void DrawableButton::colourChanged() -{ - repaint(); -} - -void DrawableButton::paintButton (Graphics& g, - const bool isMouseOverButton, - const bool isButtonDown) -{ - auto& lf = getLookAndFeel(); - - if (style == ImageOnButtonBackground) - lf.drawButtonBackground (g, *this, - findColour (getToggleState() ? TextButton::buttonOnColourId - : TextButton::buttonColourId), - isMouseOverButton, isButtonDown); - else - lf.drawDrawableButton (g, *this, isMouseOverButton, isButtonDown); -} - -//============================================================================== -Drawable* DrawableButton::getCurrentImage() const noexcept -{ - if (isDown()) return getDownImage(); - if (isOver()) return getOverImage(); - - return getNormalImage(); -} - -Drawable* DrawableButton::getNormalImage() const noexcept -{ - return (getToggleState() && normalImageOn != nullptr) ? normalImageOn - : normalImage; -} - -Drawable* DrawableButton::getOverImage() const noexcept -{ - if (getToggleState()) - { - if (overImageOn != nullptr) return overImageOn; - if (normalImageOn != nullptr) return normalImageOn; - } - - return overImage != nullptr ? overImage : normalImage; -} - -Drawable* DrawableButton::getDownImage() const noexcept -{ - if (auto* d = getToggleState() ? downImageOn.get() : downImage.get()) - return d; - - return getOverImage(); -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_DrawableButton.h b/source/modules/juce_gui_basics/buttons/juce_DrawableButton.h deleted file mode 100644 index 8e261373c..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_DrawableButton.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A button that displays a Drawable. - - Up to three Drawable objects can be given to this button, to represent the - 'normal', 'over' and 'down' states. - - @see Button -*/ -class JUCE_API DrawableButton : public Button -{ -public: - //============================================================================== - enum ButtonStyle - { - ImageFitted, /**< The button will just display the images, but will resize and centre them to fit inside it. */ - ImageRaw, /**< The button will just display the images in their normal size and position. - This leaves it up to the caller to make sure the images are the correct size and position for the button. */ - ImageAboveTextLabel, /**< Draws the button as a text label across the bottom with the image resized and scaled to fit above it. */ - ImageOnButtonBackground, /**< Draws the button as a standard rounded-rectangle button with the image on top. - Note that if you use this style, the colour IDs that control the button colour are - TextButton::buttonColourId and TextButton::buttonOnColourId. */ - ImageStretched /**< Fills the button with a stretched version of the image. */ - }; - - //============================================================================== - /** Creates a DrawableButton. - - After creating one of these, use setImages() to specify the drawables to use. - - @param buttonName the name to give the component - @param buttonStyle the layout to use - - @see ButtonStyle, setButtonStyle, setImages - */ - DrawableButton (const String& buttonName, - ButtonStyle buttonStyle); - - /** Destructor. */ - ~DrawableButton(); - - //============================================================================== - /** Sets up the images to draw for the various button states. - - The button will keep its own internal copies of these drawables. - - @param normalImage the thing to draw for the button's 'normal' state. An internal copy - will be made of the object passed-in if it is non-null. - @param overImage the thing to draw for the button's 'over' state - if this is - null, the button's normal image will be used when the mouse is - over it. An internal copy will be made of the object passed-in - if it is non-null. - @param downImage the thing to draw for the button's 'down' state - if this is - null, the 'over' image will be used instead (or the normal image - as a last resort). An internal copy will be made of the object - passed-in if it is non-null. - @param disabledImage an image to draw when the button is disabled. If this is null, - the normal image will be drawn with a reduced opacity instead. - An internal copy will be made of the object passed-in if it is - non-null. - @param normalImageOn same as the normalImage, but this is used when the button's toggle - state is 'on'. If this is nullptr, the normal image is used instead - @param overImageOn same as the overImage, but this is used when the button's toggle - state is 'on'. If this is nullptr, the normalImageOn is drawn instead - @param downImageOn same as the downImage, but this is used when the button's toggle - state is 'on'. If this is nullptr, the overImageOn is drawn instead - @param disabledImageOn same as the disabledImage, but this is used when the button's toggle - state is 'on'. If this is nullptr, the normal image will be drawn instead - with a reduced opacity - */ - void setImages (const Drawable* normalImage, - const Drawable* overImage = nullptr, - const Drawable* downImage = nullptr, - const Drawable* disabledImage = nullptr, - const Drawable* normalImageOn = nullptr, - const Drawable* overImageOn = nullptr, - const Drawable* downImageOn = nullptr, - const Drawable* disabledImageOn = nullptr); - - - //============================================================================== - /** Changes the button's style. - @see ButtonStyle - */ - void setButtonStyle (ButtonStyle newStyle); - - /** Returns the current style. */ - ButtonStyle getStyle() const noexcept { return style; } - - //============================================================================== - /** Gives the button an optional amount of space around the edge of the drawable. - By default there's a gap of about 3 pixels. - */ - void setEdgeIndent (int numPixelsIndent); - - /** Returns the current edge indent size. */ - int getEdgeIndent() const noexcept { return edgeIndent; } - - //============================================================================== - /** Returns the image that the button is currently displaying. */ - Drawable* getCurrentImage() const noexcept; - - /** Returns the image that the button will use for its normal state. */ - Drawable* getNormalImage() const noexcept; - /** Returns the image that the button will use when the mouse is over it. */ - Drawable* getOverImage() const noexcept; - /** Returns the image that the button will use when the mouse is held down on it. */ - Drawable* getDownImage() const noexcept; - - /** Can be overridden to specify a custom position for the image within the button. */ - virtual Rectangle getImageBounds() const; - - //============================================================================== - /** A set of colour IDs to use to change the colour of various aspects of the link. - - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. - - Note that when the ImageOnButtonBackground style is used, the colour IDs that control - the button colour are TextButton::buttonColourId and TextButton::buttonOnColourId. - - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour - */ - enum ColourIds - { - textColourId = 0x1004010, /**< The colour to use for the button's text label. */ - textColourOnId = 0x1004013, /**< The colour to use for the button's text when the button's toggle state is "on". */ - - backgroundColourId = 0x1004011, /**< The colour used to fill the button's background (when - the button is toggled 'off'). Note that if you use the - ImageOnButtonBackground style, you should use TextButton::buttonColourId - to change the button's colour. */ - backgroundOnColourId = 0x1004012, /**< The colour used to fill the button's background (when - the button is toggled 'on'). Note that if you use the - ImageOnButtonBackground style, you should use TextButton::buttonOnColourId - to change the button's colour. */ - }; - - //============================================================================== - /** @internal */ - void paintButton (Graphics&, bool isMouseOverButton, bool isButtonDown) override; - /** @internal */ - void buttonStateChanged() override; - /** @internal */ - void resized() override; - /** @internal */ - void enablementChanged() override; - /** @internal */ - void colourChanged() override; - -private: - //============================================================================== - ButtonStyle style; - ScopedPointer normalImage, overImage, downImage, disabledImage, - normalImageOn, overImageOn, downImageOn, disabledImageOn; - Drawable* currentImage = nullptr; - int edgeIndent = 3; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DrawableButton) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_HyperlinkButton.cpp b/source/modules/juce_gui_basics/buttons/juce_HyperlinkButton.cpp deleted file mode 100644 index acafad1ac..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_HyperlinkButton.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -HyperlinkButton::HyperlinkButton (const String& linkText, - const URL& linkURL) - : Button (linkText), - url (linkURL), - font (14.0f, Font::underlined), - resizeFont (true), - justification (Justification::centred) -{ - setMouseCursor (MouseCursor::PointingHandCursor); - setTooltip (linkURL.toString (false)); -} - -HyperlinkButton::HyperlinkButton() - : Button (String()), - font (14.0f, Font::underlined), - resizeFont (true), - justification (Justification::centred) -{ - setMouseCursor (MouseCursor::PointingHandCursor); -} - -HyperlinkButton::~HyperlinkButton() -{ -} - -//============================================================================== -void HyperlinkButton::setFont (const Font& newFont, - const bool resizeToMatchComponentHeight, - Justification justificationType) -{ - font = newFont; - resizeFont = resizeToMatchComponentHeight; - justification = justificationType; - repaint(); -} - -void HyperlinkButton::setURL (const URL& newURL) noexcept -{ - url = newURL; - setTooltip (newURL.toString (false)); -} - -Font HyperlinkButton::getFontToUse() const -{ - if (resizeFont) - return font.withHeight (getHeight() * 0.7f); - - return font; -} - -void HyperlinkButton::changeWidthToFitText() -{ - setSize (getFontToUse().getStringWidth (getButtonText()) + 6, getHeight()); -} - -void HyperlinkButton::colourChanged() -{ - repaint(); -} - -//============================================================================== -void HyperlinkButton::clicked() -{ - if (url.isWellFormed()) - url.launchInDefaultBrowser(); -} - -void HyperlinkButton::paintButton (Graphics& g, - bool isMouseOverButton, - bool isButtonDown) -{ - const Colour textColour (findColour (textColourId)); - - if (isEnabled()) - g.setColour ((isMouseOverButton) ? textColour.darker ((isButtonDown) ? 1.3f : 0.4f) - : textColour); - else - g.setColour (textColour.withMultipliedAlpha (0.4f)); - - g.setFont (getFontToUse()); - - g.drawText (getButtonText(), getLocalBounds().reduced (1, 0), - justification.getOnlyHorizontalFlags() | Justification::verticallyCentred, - true); -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_HyperlinkButton.h b/source/modules/juce_gui_basics/buttons/juce_HyperlinkButton.h deleted file mode 100644 index 1b67e17d0..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_HyperlinkButton.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A button showing an underlined weblink, that will launch the link - when it's clicked. - - @see Button -*/ -class JUCE_API HyperlinkButton : public Button -{ -public: - //============================================================================== - /** Creates a HyperlinkButton. - - @param linkText the text that will be displayed in the button - this is - also set as the Component's name, but the text can be - changed later with the Button::getButtonText() method - @param linkURL the URL to launch when the user clicks the button - */ - HyperlinkButton (const String& linkText, - const URL& linkURL); - - /** Creates a HyperlinkButton. */ - HyperlinkButton(); - - /** Destructor. */ - ~HyperlinkButton(); - - //============================================================================== - /** Changes the font to use for the text. - - If resizeToMatchComponentHeight is true, the font's height will be adjusted - to match the size of the component. - */ - void setFont (const Font& newFont, - bool resizeToMatchComponentHeight, - Justification justificationType = Justification::horizontallyCentred); - - //============================================================================== - /** A set of colour IDs to use to change the colour of various aspects of the link. - - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. - - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour - */ - enum ColourIds - { - textColourId = 0x1001f00, /**< The colour to use for the URL text. */ - }; - - //============================================================================== - /** Changes the URL that the button will trigger. */ - void setURL (const URL& newURL) noexcept; - - /** Returns the URL that the button will trigger. */ - const URL& getURL() const noexcept { return url; } - - //============================================================================== - /** Resizes the button horizontally to fit snugly around the text. - - This won't affect the button's height. - */ - void changeWidthToFitText(); - -protected: - //============================================================================== - /** @internal */ - void clicked() override; - /** @internal */ - void colourChanged() override; - /** @internal */ - void paintButton (Graphics&, bool isMouseOver, bool isButtonDown) override; - -private: - //============================================================================== - URL url; - Font font; - bool resizeFont; - Justification justification; - - Font getFontToUse() const; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HyperlinkButton) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_ImageButton.cpp b/source/modules/juce_gui_basics/buttons/juce_ImageButton.cpp deleted file mode 100644 index e89f5736d..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_ImageButton.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -ImageButton::ImageButton (const String& text_) - : Button (text_), - scaleImageToFit (true), - preserveProportions (true), - alphaThreshold (0) -{ -} - -ImageButton::~ImageButton() -{ -} - -void ImageButton::setImages (const bool resizeButtonNowToFitThisImage, - const bool rescaleImagesWhenButtonSizeChanges, - const bool preserveImageProportions, - const Image& normalImage_, - const float imageOpacityWhenNormal, - Colour overlayColourWhenNormal, - const Image& overImage_, - const float imageOpacityWhenOver, - Colour overlayColourWhenOver, - const Image& downImage_, - const float imageOpacityWhenDown, - Colour overlayColourWhenDown, - const float hitTestAlphaThreshold) -{ - normalImage = normalImage_; - overImage = overImage_; - downImage = downImage_; - - if (resizeButtonNowToFitThisImage && normalImage.isValid()) - { - imageBounds.setSize (normalImage.getWidth(), - normalImage.getHeight()); - - setSize (imageBounds.getWidth(), imageBounds.getHeight()); - } - - scaleImageToFit = rescaleImagesWhenButtonSizeChanges; - preserveProportions = preserveImageProportions; - - normalOpacity = imageOpacityWhenNormal; - normalOverlay = overlayColourWhenNormal; - overOpacity = imageOpacityWhenOver; - overOverlay = overlayColourWhenOver; - downOpacity = imageOpacityWhenDown; - downOverlay = overlayColourWhenDown; - - alphaThreshold = (uint8) jlimit (0, 0xff, roundToInt (255.0f * hitTestAlphaThreshold)); - - repaint(); -} - -Image ImageButton::getCurrentImage() const -{ - if (isDown() || getToggleState()) - return getDownImage(); - - if (isOver()) - return getOverImage(); - - return getNormalImage(); -} - -Image ImageButton::getNormalImage() const -{ - return normalImage; -} - -Image ImageButton::getOverImage() const -{ - return overImage.isValid() ? overImage - : normalImage; -} - -Image ImageButton::getDownImage() const -{ - return downImage.isValid() ? downImage - : getOverImage(); -} - -void ImageButton::paintButton (Graphics& g, - bool isMouseOverButton, - bool isButtonDown) -{ - if (! isEnabled()) - { - isMouseOverButton = false; - isButtonDown = false; - } - - Image im (getCurrentImage()); - - if (im.isValid()) - { - const int iw = im.getWidth(); - const int ih = im.getHeight(); - int w = getWidth(); - int h = getHeight(); - int x = (w - iw) / 2; - int y = (h - ih) / 2; - - if (scaleImageToFit) - { - if (preserveProportions) - { - int newW, newH; - const float imRatio = ih / (float) iw; - const float destRatio = h / (float) w; - - if (imRatio > destRatio) - { - newW = roundToInt (h / imRatio); - newH = h; - } - else - { - newW = w; - newH = roundToInt (w * imRatio); - } - - x = (w - newW) / 2; - y = (h - newH) / 2; - w = newW; - h = newH; - } - else - { - x = 0; - y = 0; - } - } - - if (! scaleImageToFit) - { - w = iw; - h = ih; - } - - imageBounds.setBounds (x, y, w, h); - - const bool useDownImage = isButtonDown || getToggleState(); - - getLookAndFeel().drawImageButton (g, &im, x, y, w, h, - useDownImage ? downOverlay - : (isMouseOverButton ? overOverlay - : normalOverlay), - useDownImage ? downOpacity - : (isMouseOverButton ? overOpacity - : normalOpacity), - *this); - } -} - -bool ImageButton::hitTest (int x, int y) -{ - if (! Component::hitTest (x, y)) // handle setInterceptsMouseClicks - return false; - - if (alphaThreshold == 0) - return true; - - Image im (getCurrentImage()); - - return im.isNull() || ((! imageBounds.isEmpty()) - && alphaThreshold < im.getPixelAt (((x - imageBounds.getX()) * im.getWidth()) / imageBounds.getWidth(), - ((y - imageBounds.getY()) * im.getHeight()) / imageBounds.getHeight()).getAlpha()); -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_ImageButton.h b/source/modules/juce_gui_basics/buttons/juce_ImageButton.h deleted file mode 100644 index c867973d7..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_ImageButton.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - As the title suggests, this is a button containing an image. - - The colour and transparency of the image can be set to vary when the - button state changes. - - @see Button, ShapeButton, TextButton -*/ -class JUCE_API ImageButton : public Button -{ -public: - //============================================================================== - /** Creates an ImageButton. - - Use setImage() to specify the image to use. The colours and opacities that - are specified here can be changed later using setImages(). - - @param name the name to give the component - */ - explicit ImageButton (const String& name = String()); - - /** Destructor. */ - ~ImageButton(); - - //============================================================================== - /** Sets up the images to draw in various states. - - @param resizeButtonNowToFitThisImage if true, the button will be immediately - resized to the same dimensions as the normal image - @param rescaleImagesWhenButtonSizeChanges if true, the image will be rescaled to fit the - button when the button's size changes - @param preserveImageProportions if true then any rescaling of the image to fit - the button will keep the image's x and y proportions - correct - i.e. it won't distort its shape, although - this might create gaps around the edges - @param normalImage the image to use when the button is in its normal state. - button no longer needs it. - @param imageOpacityWhenNormal the opacity to use when drawing the normal image. - @param overlayColourWhenNormal an overlay colour to use to fill the alpha channel of the - normal image - if this colour is transparent, no overlay - will be drawn. The overlay will be drawn over the top of the - image, so you can basically add a solid or semi-transparent - colour to the image to brighten or darken it - @param overImage the image to use when the mouse is over the button. If - you want to use the same image as was set in the normalImage - parameter, this value can be a null image. - @param imageOpacityWhenOver the opacity to use when drawing the image when the mouse - is over the button - @param overlayColourWhenOver an overlay colour to use to fill the alpha channel of the - image when the mouse is over - if this colour is transparent, - no overlay will be drawn - @param downImage an image to use when the button is pressed down. If set - to a null image, the 'over' image will be drawn instead (or the - normal image if there isn't an 'over' image either). - @param imageOpacityWhenDown the opacity to use when drawing the image when the button - is pressed - @param overlayColourWhenDown an overlay colour to use to fill the alpha channel of the - image when the button is pressed down - if this colour is - transparent, no overlay will be drawn - @param hitTestAlphaThreshold if set to zero, the mouse is considered to be over the button - whenever it's inside the button's bounding rectangle. If - set to values higher than 0, the mouse will only be - considered to be over the image when the value of the - image's alpha channel at that position is greater than - this level. - */ - void setImages (bool resizeButtonNowToFitThisImage, - bool rescaleImagesWhenButtonSizeChanges, - bool preserveImageProportions, - const Image& normalImage, - float imageOpacityWhenNormal, - Colour overlayColourWhenNormal, - const Image& overImage, - float imageOpacityWhenOver, - Colour overlayColourWhenOver, - const Image& downImage, - float imageOpacityWhenDown, - Colour overlayColourWhenDown, - float hitTestAlphaThreshold = 0.0f); - - /** Returns the currently set 'normal' image. */ - Image getNormalImage() const; - - /** Returns the image that's drawn when the mouse is over the button. - - If a valid 'over' image has been set, this will return it; otherwise it'll - just return the normal image. - */ - Image getOverImage() const; - - /** Returns the image that's drawn when the button is held down. - - If a valid 'down' image has been set, this will return it; otherwise it'll - return the 'over' image or normal image, depending on what's available. - */ - Image getDownImage() const; - - //============================================================================== - /** This abstract base class is implemented by LookAndFeel classes. */ - struct JUCE_API LookAndFeelMethods - { - virtual ~LookAndFeelMethods() {} - - virtual void drawImageButton (Graphics&, Image*, - int imageX, int imageY, int imageW, int imageH, - const Colour& overlayColour, float imageOpacity, ImageButton&) = 0; - }; - -protected: - //============================================================================== - /** @internal */ - bool hitTest (int x, int y) override; - /** @internal */ - void paintButton (Graphics&, bool isMouseOver, bool isButtonDown) override; - -private: - //============================================================================== - bool scaleImageToFit, preserveProportions; - uint8 alphaThreshold; - Rectangle imageBounds; - Image normalImage, overImage, downImage; - float normalOpacity, overOpacity, downOpacity; - Colour normalOverlay, overOverlay, downOverlay; - - Image getCurrentImage() const; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ImageButton) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_ShapeButton.cpp b/source/modules/juce_gui_basics/buttons/juce_ShapeButton.cpp deleted file mode 100644 index 3e7f91a59..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_ShapeButton.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -ShapeButton::ShapeButton (const String& t, Colour n, Colour o, Colour d) - : Button (t), - normalColour (n), overColour (o), downColour (d), - normalColourOn (n), overColourOn (o), downColourOn (d), - useOnColours(false), - maintainShapeProportions (false), - outlineWidth (0.0f) -{ -} - -ShapeButton::~ShapeButton() {} - -void ShapeButton::setColours (Colour newNormalColour, Colour newOverColour, Colour newDownColour) -{ - normalColour = newNormalColour; - overColour = newOverColour; - downColour = newDownColour; -} - -void ShapeButton::setOnColours (Colour newNormalColourOn, Colour newOverColourOn, Colour newDownColourOn) -{ - normalColourOn = newNormalColourOn; - overColourOn = newOverColourOn; - downColourOn = newDownColourOn; -} - -void ShapeButton::shouldUseOnColours (bool shouldUse) -{ - useOnColours = shouldUse; -} - -void ShapeButton::setOutline (Colour newOutlineColour, const float newOutlineWidth) -{ - outlineColour = newOutlineColour; - outlineWidth = newOutlineWidth; -} - -void ShapeButton::setBorderSize (BorderSize newBorder) -{ - border = newBorder; -} - -void ShapeButton::setShape (const Path& newShape, - const bool resizeNowToFitThisShape, - const bool maintainShapeProportions_, - const bool hasShadow) -{ - shape = newShape; - maintainShapeProportions = maintainShapeProportions_; - - shadow.setShadowProperties (DropShadow (Colours::black.withAlpha (0.5f), 3, Point())); - setComponentEffect (hasShadow ? &shadow : nullptr); - - if (resizeNowToFitThisShape) - { - Rectangle newBounds (shape.getBounds()); - - if (hasShadow) - newBounds = newBounds.expanded (4.0f); - - shape.applyTransform (AffineTransform::translation (-newBounds.getX(), - -newBounds.getY())); - - setSize (1 + (int) (newBounds.getWidth() + outlineWidth) + border.getLeftAndRight(), - 1 + (int) (newBounds.getHeight() + outlineWidth) + border.getTopAndBottom()); - } - - repaint(); -} - -void ShapeButton::paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown) -{ - if (! isEnabled()) - { - isMouseOverButton = false; - isButtonDown = false; - } - - Rectangle r (border.subtractedFrom (getLocalBounds()).toFloat().reduced (outlineWidth * 0.5f)); - - if (getComponentEffect() != nullptr) - r = r.reduced (2.0f); - - if (isButtonDown) - { - const float sizeReductionWhenPressed = 0.04f; - - r = r.reduced (sizeReductionWhenPressed * r.getWidth(), - sizeReductionWhenPressed * r.getHeight()); - } - - const AffineTransform trans (shape.getTransformToScaleToFit (r, maintainShapeProportions)); - - if (isButtonDown) g.setColour (getToggleState() && useOnColours ? downColourOn : downColour); - else if (isMouseOverButton) g.setColour (getToggleState() && useOnColours ? overColourOn : overColour); - else g.setColour (getToggleState() && useOnColours ? normalColourOn : normalColour); - - g.fillPath (shape, trans); - - if (outlineWidth > 0.0f) - { - g.setColour (outlineColour); - g.strokePath (shape, PathStrokeType (outlineWidth), trans); - } -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_ShapeButton.h b/source/modules/juce_gui_basics/buttons/juce_ShapeButton.h deleted file mode 100644 index 193d886fd..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_ShapeButton.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A button that contains a filled shape. - - @see Button, ImageButton, TextButton, ArrowButton -*/ -class JUCE_API ShapeButton : public Button -{ -public: - //============================================================================== - /** Creates a ShapeButton. - - @param name a name to give the component - see Component::setName() - @param normalColour the colour to fill the shape with when the mouse isn't over - @param overColour the colour to use when the mouse is over the shape - @param downColour the colour to use when the button is in the pressed-down state - */ - ShapeButton (const String& name, - Colour normalColour, - Colour overColour, - Colour downColour); - - /** Destructor. */ - ~ShapeButton(); - - //============================================================================== - /** Sets the shape to use. - - @param newShape the shape to use - @param resizeNowToFitThisShape if true, the button will be resized to fit the shape's bounds - @param maintainShapeProportions if true, the shape's proportions will be kept fixed when - the button is resized - @param hasDropShadow if true, the button will be given a drop-shadow effect - */ - void setShape (const Path& newShape, - bool resizeNowToFitThisShape, - bool maintainShapeProportions, - bool hasDropShadow); - - /** Set the colours to use for drawing the shape. - - @param normalColour the colour to fill the shape with when the mouse isn't over - @param overColour the colour to use when the mouse is over the shape - @param downColour the colour to use when the button is in the pressed-down state - */ - void setColours (Colour normalColour, - Colour overColour, - Colour downColour); - - /** Sets the colours to use for drawing the shape when the button's toggle state is 'on'. To enable this behaviour, use the - shouldUseOnColours() method. - - @param normalColourOn the colour to fill the shape with when the mouse isn't over and the button's toggle state is 'on' - @param overColourOn the colour to use when the mouse is over the shape and the button's toggle state is 'on' - @param downColourOn the colour to use when the button is in the pressed-down state and the button's toggle state is 'on' - */ - void setOnColours (Colour normalColourOn, - Colour overColourOn, - Colour downColourOn); - - /** Set whether the button should use the 'on' set of colours when its toggle state is 'on'. - By default these will be the same as the normal colours but the setOnColours method can be - used to provide a different set of colours. - */ - void shouldUseOnColours (bool shouldUse); - - /** Sets up an outline to draw around the shape. - - @param outlineColour the colour to use - @param outlineStrokeWidth the thickness of line to draw - */ - void setOutline (Colour outlineColour, float outlineStrokeWidth); - - /** This lets you specify a border to be left around the edge of the button when - drawing the shape. - */ - void setBorderSize (BorderSize border); - - /** @internal */ - void paintButton (Graphics&, bool isMouseOverButton, bool isButtonDown) override; - -private: - //============================================================================== - Colour normalColour, overColour, downColour, - normalColourOn, overColourOn, downColourOn, outlineColour; - bool useOnColours; - DropShadowEffect shadow; - Path shape; - BorderSize border; - bool maintainShapeProportions; - float outlineWidth; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ShapeButton) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_TextButton.cpp b/source/modules/juce_gui_basics/buttons/juce_TextButton.cpp deleted file mode 100644 index d7d4fb46c..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_TextButton.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -TextButton::TextButton() : Button (String()) -{ -} - -TextButton::TextButton (const String& name) : Button (name) -{ -} - -TextButton::TextButton (const String& name, const String& toolTip) : Button (name) -{ - setTooltip (toolTip); -} - -TextButton::~TextButton() -{ -} - -void TextButton::paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown) -{ - LookAndFeel& lf = getLookAndFeel(); - - lf.drawButtonBackground (g, *this, - findColour (getToggleState() ? buttonOnColourId : buttonColourId), - isMouseOverButton, isButtonDown); - - lf.drawButtonText (g, *this, isMouseOverButton, isButtonDown); -} - -void TextButton::colourChanged() -{ - repaint(); -} - -void TextButton::changeWidthToFitText() -{ - changeWidthToFitText (getHeight()); -} - -void TextButton::changeWidthToFitText (const int newHeight) -{ - setSize (getBestWidthForHeight (newHeight), newHeight); -} - -int TextButton::getBestWidthForHeight (int buttonHeight) -{ - return getLookAndFeel().getTextButtonWidthToFitText (*this, buttonHeight); -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_TextButton.h b/source/modules/juce_gui_basics/buttons/juce_TextButton.h deleted file mode 100644 index 1631af52c..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_TextButton.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A button that uses the standard lozenge-shaped background with a line of - text on it. - - @see Button, DrawableButton -*/ -class JUCE_API TextButton : public Button -{ -public: - //============================================================================== - /** Creates a TextButton. */ - TextButton(); - - /** Creates a TextButton. - @param buttonName the text to put in the button (the component's name is also - initially set to this string, but these can be changed later - using the setName() and setButtonText() methods) - */ - explicit TextButton (const String& buttonName); - - /** Creates a TextButton. - @param buttonName the text to put in the button (the component's name is also - initially set to this string, but these can be changed later - using the setName() and setButtonText() methods) - @param toolTip an optional string to use as a toolip - */ - TextButton (const String& buttonName, const String& toolTip); - - /** Destructor. */ - ~TextButton(); - - //============================================================================== - /** A set of colour IDs to use to change the colour of various aspects of the button. - - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. - - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour - */ - enum ColourIds - { - buttonColourId = 0x1000100, /**< The colour used to fill the button shape (when the button is toggled - 'off'). The look-and-feel class might re-interpret this to add - effects, etc. */ - buttonOnColourId = 0x1000101, /**< The colour used to fill the button shape (when the button is toggled - 'on'). The look-and-feel class might re-interpret this to add - effects, etc. */ - textColourOffId = 0x1000102, /**< The colour to use for the button's text when the button's toggle state is "off". */ - textColourOnId = 0x1000103 /**< The colour to use for the button's text.when the button's toggle state is "on". */ - }; - - //============================================================================== - /** Changes this button's width to fit neatly around its current text, without - changing its height. - */ - void changeWidthToFitText(); - - /** Resizes the button's width to fit neatly around its current text, and gives it - the specified height. - */ - void changeWidthToFitText (int newHeight); - - /** Returns the width that the LookAndFeel suggests would be best for this button if it - had the given height. - */ - int getBestWidthForHeight (int buttonHeight); - - //============================================================================== - /** @internal */ - void paintButton (Graphics&, bool isMouseOverButton, bool isButtonDown) override; - /** @internal */ - void colourChanged() override; - -private: - #if JUCE_CATCH_DEPRECATED_CODE_MISUSE - // Note that this method has been removed - instead, see LookAndFeel::getTextButtonFont() - virtual int getFont() { return 0; } - #endif - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TextButton) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_ToggleButton.cpp b/source/modules/juce_gui_basics/buttons/juce_ToggleButton.cpp deleted file mode 100644 index a43e45d1e..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_ToggleButton.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -ToggleButton::ToggleButton() - : Button (String()) -{ - setClickingTogglesState (true); -} - -ToggleButton::ToggleButton (const String& buttonText) - : Button (buttonText) -{ - setClickingTogglesState (true); -} - -ToggleButton::~ToggleButton() -{ -} - -void ToggleButton::paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown) -{ - getLookAndFeel().drawToggleButton (g, *this, isMouseOverButton, isButtonDown); -} - -void ToggleButton::changeWidthToFitText() -{ - getLookAndFeel().changeToggleButtonWidthToFitText (*this); -} - -void ToggleButton::colourChanged() -{ - repaint(); -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_ToggleButton.h b/source/modules/juce_gui_basics/buttons/juce_ToggleButton.h deleted file mode 100644 index afe3dcf2a..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_ToggleButton.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A button that can be toggled on/off. - - All buttons can be toggle buttons, but this lets you create one of the - standard ones which has a tick-box and a text label next to it. - - @see Button, DrawableButton, TextButton -*/ -class JUCE_API ToggleButton : public Button -{ -public: - //============================================================================== - /** Creates a ToggleButton. */ - ToggleButton(); - - /** Creates a ToggleButton. - - @param buttonText the text to put in the button (the component's name is also - initially set to this string, but these can be changed later - using the setName() and setButtonText() methods) - */ - explicit ToggleButton (const String& buttonText); - - /** Destructor. */ - ~ToggleButton(); - - //============================================================================== - /** Resizes the button to fit neatly around its current text. - The button's height won't be affected, only its width. - */ - void changeWidthToFitText(); - - //============================================================================== - /** A set of colour IDs to use to change the colour of various aspects of the button. - - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. - - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour - */ - enum ColourIds - { - textColourId = 0x1006501, /**< The colour to use for the button's text. */ - tickColourId = 0x1006502, /**< The colour to use for the tick mark. */ - tickDisabledColourId = 0x1006503 /**< The colour to use for the disabled tick mark. */ - }; - -protected: - //============================================================================== - /** @internal */ - void paintButton (Graphics&, bool isMouseOverButton, bool isButtonDown) override; - /** @internal */ - void colourChanged() override; - -private: - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ToggleButton) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_ToolbarButton.cpp b/source/modules/juce_gui_basics/buttons/juce_ToolbarButton.cpp deleted file mode 100644 index d4f60ac8c..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_ToolbarButton.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -ToolbarButton::ToolbarButton (const int iid, const String& buttonText, - Drawable* const normalIm, Drawable* const toggledOnIm) - : ToolbarItemComponent (iid, buttonText, true), - normalImage (normalIm), - toggledOnImage (toggledOnIm), - currentImage (nullptr) -{ - jassert (normalImage != nullptr); -} - -ToolbarButton::~ToolbarButton() -{ -} - -//============================================================================== -bool ToolbarButton::getToolbarItemSizes (int toolbarDepth, bool /*isToolbarVertical*/, int& preferredSize, int& minSize, int& maxSize) -{ - preferredSize = minSize = maxSize = toolbarDepth; - return true; -} - -void ToolbarButton::paintButtonArea (Graphics&, int /*width*/, int /*height*/, bool /*isMouseOver*/, bool /*isMouseDown*/) -{ -} - -void ToolbarButton::contentAreaChanged (const Rectangle&) -{ - buttonStateChanged(); -} - -void ToolbarButton::setCurrentImage (Drawable* const newImage) -{ - if (newImage != currentImage) - { - removeChildComponent (currentImage); - currentImage = newImage; - - if (currentImage != nullptr) - { - enablementChanged(); - addAndMakeVisible (currentImage); - updateDrawable(); - } - } -} - -void ToolbarButton::updateDrawable() -{ - if (currentImage != nullptr) - { - currentImage->setInterceptsMouseClicks (false, false); - currentImage->setTransformToFit (getContentArea().toFloat(), RectanglePlacement::centred); - currentImage->setAlpha (isEnabled() ? 1.0f : 0.5f); - } -} - -void ToolbarButton::resized() -{ - ToolbarItemComponent::resized(); - updateDrawable(); -} - -void ToolbarButton::enablementChanged() -{ - ToolbarItemComponent::enablementChanged(); - updateDrawable(); -} - -Drawable* ToolbarButton::getImageToUse() const -{ - if (getStyle() == Toolbar::textOnly) - return nullptr; - - if (getToggleState() && toggledOnImage != nullptr) - return toggledOnImage; - - return normalImage; -} - -void ToolbarButton::buttonStateChanged() -{ - setCurrentImage (getImageToUse()); -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/buttons/juce_ToolbarButton.h b/source/modules/juce_gui_basics/buttons/juce_ToolbarButton.h deleted file mode 100644 index ce2190e03..000000000 --- a/source/modules/juce_gui_basics/buttons/juce_ToolbarButton.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A type of button designed to go on a toolbar. - - This simple button can have two Drawable objects specified - one for normal - use and another one (optionally) for the button's "on" state if it's a - toggle button. - - @see Toolbar, ToolbarItemFactory, ToolbarItemComponent, Drawable, Button -*/ -class JUCE_API ToolbarButton : public ToolbarItemComponent -{ -public: - //============================================================================== - /** Creates a ToolbarButton. - - @param itemId the ID for this toolbar item type. This is passed through to the - ToolbarItemComponent constructor - @param labelText the text to display on the button (if the toolbar is using a style - that shows text labels). This is passed through to the - ToolbarItemComponent constructor - @param normalImage a drawable object that the button should use as its icon. The object - that is passed-in here will be kept by this object and will be - deleted when no longer needed or when this button is deleted. - @param toggledOnImage a drawable object that the button can use as its icon if the button - is in a toggled-on state (see the Button::getToggleState() method). If - nullptr is passed-in here, then the normal image will be used instead, - regardless of the toggle state. The object that is passed-in here will be - owned by this object and will be deleted when no longer needed or when - this button is deleted. - */ - ToolbarButton (int itemId, - const String& labelText, - Drawable* normalImage, - Drawable* toggledOnImage); - - /** Destructor. */ - ~ToolbarButton(); - - - //============================================================================== - /** @internal */ - bool getToolbarItemSizes (int toolbarDepth, bool isToolbarVertical, int& preferredSize, - int& minSize, int& maxSize) override; - /** @internal */ - void paintButtonArea (Graphics&, int width, int height, bool isMouseOver, bool isMouseDown) override; - /** @internal */ - void contentAreaChanged (const Rectangle&) override; - /** @internal */ - void buttonStateChanged() override; - /** @internal */ - void resized() override; - /** @internal */ - void enablementChanged() override; - -private: - //============================================================================== - ScopedPointer normalImage, toggledOnImage; - Drawable* currentImage; - - void updateDrawable(); - Drawable* getImageToUse() const; - void setCurrentImage (Drawable*); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ToolbarButton) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/commands/juce_ApplicationCommandID.h b/source/modules/juce_gui_basics/commands/juce_ApplicationCommandID.h deleted file mode 100644 index cae26668d..000000000 --- a/source/modules/juce_gui_basics/commands/juce_ApplicationCommandID.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** A type used to hold the unique ID for an application command. - - This is a numeric type, so it can be stored as an integer. - - @see ApplicationCommandInfo, ApplicationCommandManager, - ApplicationCommandTarget, KeyPressMappingSet -*/ -typedef int CommandID; - - -//============================================================================== -/** A set of general-purpose application command IDs. - - Because these commands are likely to be used in most apps, they're defined - here to help different apps to use the same numeric values for them. - - Of course you don't have to use these, but some of them are used internally by - Juce - e.g. the quit ID is recognised as a command by the JUCEApplication class. - - @see ApplicationCommandInfo, ApplicationCommandManager, - ApplicationCommandTarget, KeyPressMappingSet -*/ -namespace StandardApplicationCommandIDs -{ - enum - { - /** This command ID should be used to send a "Quit the App" command. - - This command is recognised by the JUCEApplication class, so if it is invoked - and no other ApplicationCommandTarget handles the event first, the JUCEApplication - object will catch it and call JUCEApplicationBase::systemRequestedQuit(). - */ - quit = 0x1001, - - /** The command ID that should be used to send a "Delete" command. */ - del = 0x1002, - - /** The command ID that should be used to send a "Cut" command. */ - cut = 0x1003, - - /** The command ID that should be used to send a "Copy to clipboard" command. */ - copy = 0x1004, - - /** The command ID that should be used to send a "Paste from clipboard" command. */ - paste = 0x1005, - - /** The command ID that should be used to send a "Select all" command. */ - selectAll = 0x1006, - - /** The command ID that should be used to send a "Deselect all" command. */ - deselectAll = 0x1007, - - /** The command ID that should be used to send a "undo" command. */ - undo = 0x1008, - - /** The command ID that should be used to send a "redo" command. */ - redo = 0x1009 - }; -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/commands/juce_ApplicationCommandInfo.cpp b/source/modules/juce_gui_basics/commands/juce_ApplicationCommandInfo.cpp deleted file mode 100644 index 6599fdd9f..000000000 --- a/source/modules/juce_gui_basics/commands/juce_ApplicationCommandInfo.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -ApplicationCommandInfo::ApplicationCommandInfo (const CommandID cid) noexcept - : commandID (cid), flags (0) -{ -} - -void ApplicationCommandInfo::setInfo (const String& shortName_, - const String& description_, - const String& categoryName_, - const int flags_) noexcept -{ - shortName = shortName_; - description = description_; - categoryName = categoryName_; - flags = flags_; -} - -void ApplicationCommandInfo::setActive (const bool b) noexcept -{ - if (b) - flags &= ~isDisabled; - else - flags |= isDisabled; -} - -void ApplicationCommandInfo::setTicked (const bool b) noexcept -{ - if (b) - flags |= isTicked; - else - flags &= ~isTicked; -} - -void ApplicationCommandInfo::addDefaultKeypress (const int keyCode, ModifierKeys modifiers) noexcept -{ - defaultKeypresses.add (KeyPress (keyCode, modifiers, 0)); -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/commands/juce_ApplicationCommandInfo.h b/source/modules/juce_gui_basics/commands/juce_ApplicationCommandInfo.h deleted file mode 100644 index 63358df6a..000000000 --- a/source/modules/juce_gui_basics/commands/juce_ApplicationCommandInfo.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Holds information describing an application command. - - This object is used to pass information about a particular command, such as its - name, description and other usage flags. - - When an ApplicationCommandTarget is asked to provide information about the commands - it can perform, this is the structure gets filled-in to describe each one. - - @see ApplicationCommandTarget, ApplicationCommandTarget::getCommandInfo(), - ApplicationCommandManager -*/ -struct JUCE_API ApplicationCommandInfo -{ - //============================================================================== - explicit ApplicationCommandInfo (CommandID commandID) noexcept; - - //============================================================================== - /** Sets a number of the structures values at once. - - The meanings of each of the parameters is described below, in the appropriate - member variable's description. - */ - void setInfo (const String& shortName, - const String& description, - const String& categoryName, - int flags) noexcept; - - /** An easy way to set or remove the isDisabled bit in the structure's flags field. - - If isActive is true, the flags member has the isDisabled bit cleared; if isActive - is false, the bit is set. - */ - void setActive (bool isActive) noexcept; - - /** An easy way to set or remove the isTicked bit in the structure's flags field. - */ - void setTicked (bool isTicked) noexcept; - - /** Handy method for adding a keypress to the defaultKeypresses array. - - This is just so you can write things like: - @code - myinfo.addDefaultKeypress ('s', ModifierKeys::commandModifier); - @endcode - instead of - @code - myinfo.defaultKeypresses.add (KeyPress ('s', ModifierKeys::commandModifier)); - @endcode - */ - void addDefaultKeypress (int keyCode, ModifierKeys modifiers) noexcept; - - //============================================================================== - /** The command's unique ID number. - */ - CommandID commandID; - - /** A short name to describe the command. - - This should be suitable for use in menus, on buttons that trigger the command, etc. - - You can use the setInfo() method to quickly set this and some of the command's - other properties. - */ - String shortName; - - /** A longer description of the command. - - This should be suitable for use in contexts such as a KeyMappingEditorComponent or - pop-up tooltip describing what the command does. - - You can use the setInfo() method to quickly set this and some of the command's - other properties. - */ - String description; - - /** A named category that the command fits into. - - You can give your commands any category you like, and these will be displayed in - contexts such as the KeyMappingEditorComponent, where the category is used to group - commands together. - - You can use the setInfo() method to quickly set this and some of the command's - other properties. - */ - String categoryName; - - /** A list of zero or more keypresses that should be used as the default keys for - this command. - - Methods such as KeyPressMappingSet::resetToDefaultMappings() will use the keypresses in - this list to initialise the default set of key-to-command mappings. - - @see addDefaultKeypress - */ - Array defaultKeypresses; - - //============================================================================== - /** Flags describing the ways in which this command should be used. - - A bitwise-OR of these values is stored in the ApplicationCommandInfo::flags - variable. - */ - enum CommandFlags - { - /** Indicates that the command can't currently be performed. - - The ApplicationCommandTarget::getCommandInfo() method must set this flag if it's - not currently permissible to perform the command. If the flag is set, then - components that trigger the command, e.g. PopupMenu, may choose to grey-out the - command or show themselves as not being enabled. - - @see ApplicationCommandInfo::setActive - */ - isDisabled = 1 << 0, - - /** Indicates that the command should have a tick next to it on a menu. - - If your command is shown on a menu and this is set, it'll show a tick next to - it. Other components such as buttons may also use this flag to indicate that it - is a value that can be toggled, and is currently in the 'on' state. - - @see ApplicationCommandInfo::setTicked - */ - isTicked = 1 << 1, - - /** If this flag is present, then when a KeyPressMappingSet invokes the command, - it will call the command twice, once on key-down and again on key-up. - - @see ApplicationCommandTarget::InvocationInfo - */ - wantsKeyUpDownCallbacks = 1 << 2, - - /** If this flag is present, then a KeyMappingEditorComponent will not display the - command in its list. - */ - hiddenFromKeyEditor = 1 << 3, - - /** If this flag is present, then a KeyMappingEditorComponent will display the - command in its list, but won't allow the assigned keypress to be changed. - */ - readOnlyInKeyEditor = 1 << 4, - - /** If this flag is present and the command is invoked from a keypress, then any - buttons or menus that are also connected to the command will not flash to - indicate that they've been triggered. - */ - dontTriggerVisualFeedback = 1 << 5 - }; - - /** A bitwise-OR of the values specified in the CommandFlags enum. - - You can use the setInfo() method to quickly set this and some of the command's - other properties. - */ - int flags; -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp b/source/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp deleted file mode 100644 index acd785a36..000000000 --- a/source/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp +++ /dev/null @@ -1,319 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -ApplicationCommandManager::ApplicationCommandManager() - : firstTarget (nullptr) -{ - keyMappings = new KeyPressMappingSet (*this); - Desktop::getInstance().addFocusChangeListener (this); -} - -ApplicationCommandManager::~ApplicationCommandManager() -{ - Desktop::getInstance().removeFocusChangeListener (this); - keyMappings = nullptr; -} - -//============================================================================== -void ApplicationCommandManager::clearCommands() -{ - commands.clear(); - keyMappings->clearAllKeyPresses(); - triggerAsyncUpdate(); -} - -void ApplicationCommandManager::registerCommand (const ApplicationCommandInfo& newCommand) -{ - // zero isn't a valid command ID! - jassert (newCommand.commandID != 0); - - // the name isn't optional! - jassert (newCommand.shortName.isNotEmpty()); - - if (auto* command = getMutableCommandForID (newCommand.commandID)) - { - // Trying to re-register the same command ID with different parameters can often indicate a typo. - // This assertion is here because I've found it useful catching some mistakes, but it may also cause - // false alarms if you're deliberately updating some flags for a command. - jassert (newCommand.shortName == getCommandForID (newCommand.commandID)->shortName - && newCommand.categoryName == getCommandForID (newCommand.commandID)->categoryName - && newCommand.defaultKeypresses == getCommandForID (newCommand.commandID)->defaultKeypresses - && (newCommand.flags & (ApplicationCommandInfo::wantsKeyUpDownCallbacks | ApplicationCommandInfo::hiddenFromKeyEditor | ApplicationCommandInfo::readOnlyInKeyEditor)) - == (getCommandForID (newCommand.commandID)->flags & (ApplicationCommandInfo::wantsKeyUpDownCallbacks | ApplicationCommandInfo::hiddenFromKeyEditor | ApplicationCommandInfo::readOnlyInKeyEditor))); - - *command = newCommand; - } - else - { - ApplicationCommandInfo* const newInfo = new ApplicationCommandInfo (newCommand); - newInfo->flags &= ~ApplicationCommandInfo::isTicked; - commands.add (newInfo); - - keyMappings->resetToDefaultMapping (newCommand.commandID); - - triggerAsyncUpdate(); - } -} - -void ApplicationCommandManager::registerAllCommandsForTarget (ApplicationCommandTarget* target) -{ - if (target != nullptr) - { - Array commandIDs; - target->getAllCommands (commandIDs); - - for (int i = 0; i < commandIDs.size(); ++i) - { - ApplicationCommandInfo info (commandIDs.getUnchecked(i)); - target->getCommandInfo (info.commandID, info); - - registerCommand (info); - } - } -} - -void ApplicationCommandManager::removeCommand (const CommandID commandID) -{ - for (int i = commands.size(); --i >= 0;) - { - if (commands.getUnchecked (i)->commandID == commandID) - { - commands.remove (i); - triggerAsyncUpdate(); - - const Array keys (keyMappings->getKeyPressesAssignedToCommand (commandID)); - - for (int j = keys.size(); --j >= 0;) - keyMappings->removeKeyPress (keys.getReference (j)); - } - } -} - -void ApplicationCommandManager::commandStatusChanged() -{ - triggerAsyncUpdate(); -} - -//============================================================================== -ApplicationCommandInfo* ApplicationCommandManager::getMutableCommandForID (CommandID commandID) const noexcept -{ - for (int i = commands.size(); --i >= 0;) - if (commands.getUnchecked(i)->commandID == commandID) - return commands.getUnchecked(i); - - return nullptr; -} - -const ApplicationCommandInfo* ApplicationCommandManager::getCommandForID (const CommandID commandID) const noexcept -{ - return getMutableCommandForID (commandID); -} - -String ApplicationCommandManager::getNameOfCommand (const CommandID commandID) const noexcept -{ - if (auto* ci = getCommandForID (commandID)) - return ci->shortName; - - return {}; -} - -String ApplicationCommandManager::getDescriptionOfCommand (const CommandID commandID) const noexcept -{ - if (auto* ci = getCommandForID (commandID)) - return ci->description.isNotEmpty() ? ci->description - : ci->shortName; - - return {}; -} - -StringArray ApplicationCommandManager::getCommandCategories() const -{ - StringArray s; - - for (int i = 0; i < commands.size(); ++i) - s.addIfNotAlreadyThere (commands.getUnchecked(i)->categoryName, false); - - return s; -} - -Array ApplicationCommandManager::getCommandsInCategory (const String& categoryName) const -{ - Array results; - - for (int i = 0; i < commands.size(); ++i) - if (commands.getUnchecked(i)->categoryName == categoryName) - results.add (commands.getUnchecked(i)->commandID); - - return results; -} - -//============================================================================== -bool ApplicationCommandManager::invokeDirectly (const CommandID commandID, const bool asynchronously) -{ - ApplicationCommandTarget::InvocationInfo info (commandID); - info.invocationMethod = ApplicationCommandTarget::InvocationInfo::direct; - - return invoke (info, asynchronously); -} - -bool ApplicationCommandManager::invoke (const ApplicationCommandTarget::InvocationInfo& inf, const bool asynchronously) -{ - // This call isn't thread-safe for use from a non-UI thread without locking the message - // manager first.. - jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); - - bool ok = false; - ApplicationCommandInfo commandInfo (0); - - if (auto* target = getTargetForCommand (inf.commandID, commandInfo)) - { - ApplicationCommandTarget::InvocationInfo info (inf); - info.commandFlags = commandInfo.flags; - - sendListenerInvokeCallback (info); - ok = target->invoke (info, asynchronously); - commandStatusChanged(); - } - - return ok; -} - -//============================================================================== -ApplicationCommandTarget* ApplicationCommandManager::getFirstCommandTarget (const CommandID) -{ - return firstTarget != nullptr ? firstTarget - : findDefaultComponentTarget(); -} - -void ApplicationCommandManager::setFirstCommandTarget (ApplicationCommandTarget* const newTarget) noexcept -{ - firstTarget = newTarget; -} - -ApplicationCommandTarget* ApplicationCommandManager::getTargetForCommand (const CommandID commandID, - ApplicationCommandInfo& upToDateInfo) -{ - ApplicationCommandTarget* target = getFirstCommandTarget (commandID); - - if (target == nullptr) - target = JUCEApplication::getInstance(); - - if (target != nullptr) - target = target->getTargetForCommand (commandID); - - if (target != nullptr) - { - upToDateInfo.commandID = commandID; - target->getCommandInfo (commandID, upToDateInfo); - } - - return target; -} - -//============================================================================== -ApplicationCommandTarget* ApplicationCommandManager::findTargetForComponent (Component* c) -{ - ApplicationCommandTarget* target = dynamic_cast (c); - - if (target == nullptr && c != nullptr) - target = c->findParentComponentOfClass(); - - return target; -} - -ApplicationCommandTarget* ApplicationCommandManager::findDefaultComponentTarget() -{ - Component* c = Component::getCurrentlyFocusedComponent(); - - if (c == nullptr) - { - if (auto* activeWindow = TopLevelWindow::getActiveTopLevelWindow()) - { - c = activeWindow->getPeer()->getLastFocusedSubcomponent(); - - if (c == nullptr) - c = activeWindow; - } - } - - if (c == nullptr && Process::isForegroundProcess()) - { - auto& desktop = Desktop::getInstance(); - - // getting a bit desperate now: try all desktop comps.. - for (int i = desktop.getNumComponents(); --i >= 0;) - if (auto* peer = desktop.getComponent(i)->getPeer()) - if (auto* target = findTargetForComponent (peer->getLastFocusedSubcomponent())) - return target; - } - - if (c != nullptr) - { - // if we're focused on a ResizableWindow, chances are that it's the content - // component that really should get the event. And if not, the event will - // still be passed up to the top level window anyway, so let's send it to the - // content comp. - if (auto* resizableWindow = dynamic_cast (c)) - if (auto* content = resizableWindow->getContentComponent()) - c = content; - - if (auto* target = findTargetForComponent (c)) - return target; - } - - return JUCEApplication::getInstance(); -} - -//============================================================================== -void ApplicationCommandManager::addListener (ApplicationCommandManagerListener* const listener) -{ - listeners.add (listener); -} - -void ApplicationCommandManager::removeListener (ApplicationCommandManagerListener* const listener) -{ - listeners.remove (listener); -} - -void ApplicationCommandManager::sendListenerInvokeCallback (const ApplicationCommandTarget::InvocationInfo& info) -{ - listeners.call (&ApplicationCommandManagerListener::applicationCommandInvoked, info); -} - -void ApplicationCommandManager::handleAsyncUpdate() -{ - listeners.call (&ApplicationCommandManagerListener::applicationCommandListChanged); -} - -void ApplicationCommandManager::globalFocusChanged (Component*) -{ - commandStatusChanged(); -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.h b/source/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.h deleted file mode 100644 index 396002134..000000000 --- a/source/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.h +++ /dev/null @@ -1,352 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - One of these objects holds a list of all the commands your app can perform, - and despatches these commands when needed. - - Application commands are a good way to trigger actions in your app, e.g. "Quit", - "Copy", "Paste", etc. Menus, buttons and keypresses can all be given commands - to invoke automatically, which means you don't have to handle the result of a menu - or button click manually. Commands are despatched to ApplicationCommandTarget objects - which can choose which events they want to handle. - - This architecture also allows for nested ApplicationCommandTargets, so that for example - you could have two different objects, one inside the other, both of which can respond to - a "delete" command. Depending on which one has focus, the command will be sent to the - appropriate place, regardless of whether it was triggered by a menu, keypress or some other - method. - - To set up your app to use commands, you'll need to do the following: - - - Create a global ApplicationCommandManager to hold the list of all possible - commands. (This will also manage a set of key-mappings for them). - - - Make some of your UI components (or other objects) inherit from ApplicationCommandTarget. - This allows the object to provide a list of commands that it can perform, and - to handle them. - - - Register each type of command using ApplicationCommandManager::registerAllCommandsForTarget(), - or ApplicationCommandManager::registerCommand(). - - - If you want key-presses to trigger your commands, use the ApplicationCommandManager::getKeyMappings() - method to access the key-mapper object, which you will need to register as a key-listener - in whatever top-level component you're using. See the KeyPressMappingSet class for more help - about setting this up. - - - Use methods such as PopupMenu::addCommandItem() or Button::setCommandToTrigger() to - cause these commands to be invoked automatically. - - - Commands can be invoked directly by your code using ApplicationCommandManager::invokeDirectly(). - - When a command is invoked, the ApplicationCommandManager will try to choose the best - ApplicationCommandTarget to receive the specified command. To do this it will use the - current keyboard focus to see which component might be interested, and will search the - component hierarchy for those that also implement the ApplicationCommandTarget interface. - If an ApplicationCommandTarget isn't interested in the command that is being invoked, then - the next one in line will be tried (see the ApplicationCommandTarget::getNextCommandTarget() - method), and so on until ApplicationCommandTarget::getNextCommandTarget() returns nullptr. - At this point if the command still hasn't been performed, it will be passed to the current - JUCEApplication object (which is itself an ApplicationCommandTarget). - - To exert some custom control over which ApplicationCommandTarget is chosen to invoke a command, - you can override the ApplicationCommandManager::getFirstCommandTarget() method and choose - the object yourself. - - @see ApplicationCommandTarget, ApplicationCommandInfo -*/ -class JUCE_API ApplicationCommandManager : private AsyncUpdater, - private FocusChangeListener -{ -public: - //============================================================================== - /** Creates an ApplicationCommandManager. - - Once created, you'll need to register all your app's commands with it, using - ApplicationCommandManager::registerAllCommandsForTarget() or - ApplicationCommandManager::registerCommand(). - */ - ApplicationCommandManager(); - - /** Destructor. - - Make sure that you don't delete this if pointers to it are still being used by - objects such as PopupMenus or Buttons. - */ - virtual ~ApplicationCommandManager(); - - //============================================================================== - /** Clears the current list of all commands. - Note that this will also clear the contents of the KeyPressMappingSet. - */ - void clearCommands(); - - /** Adds a command to the list of registered commands. - @see registerAllCommandsForTarget - */ - void registerCommand (const ApplicationCommandInfo& newCommand); - - /** Adds all the commands that this target publishes to the manager's list. - - This will use ApplicationCommandTarget::getAllCommands() and ApplicationCommandTarget::getCommandInfo() - to get details about all the commands that this target can do, and will call - registerCommand() to add each one to the manger's list. - - @see registerCommand - */ - void registerAllCommandsForTarget (ApplicationCommandTarget* target); - - /** Removes the command with a specified ID. - Note that this will also remove any key mappings that are mapped to the command. - */ - void removeCommand (CommandID commandID); - - /** This should be called to tell the manager that one of its registered commands may have changed - its active status. - - Because the command manager only finds out whether a command is active or inactive by querying - the current ApplicationCommandTarget, this is used to tell it that things may have changed. It - allows things like buttons to update their enablement, etc. - - This method will cause an asynchronous call to ApplicationCommandManagerListener::applicationCommandListChanged() - for any registered listeners. - */ - void commandStatusChanged(); - - //============================================================================== - /** Returns the number of commands that have been registered. - @see registerCommand - */ - int getNumCommands() const noexcept { return commands.size(); } - - /** Returns the details about one of the registered commands. - The index is between 0 and (getNumCommands() - 1). - */ - const ApplicationCommandInfo* getCommandForIndex (int index) const noexcept { return commands [index]; } - - /** Returns the details about a given command ID. - - This will search the list of registered commands for one with the given command - ID number, and return its associated info. If no matching command is found, this - will return nullptr. - */ - const ApplicationCommandInfo* getCommandForID (CommandID commandID) const noexcept; - - /** Returns the name field for a command. - - An empty string is returned if no command with this ID has been registered. - @see getDescriptionOfCommand - */ - String getNameOfCommand (CommandID commandID) const noexcept; - - /** Returns the description field for a command. - - An empty string is returned if no command with this ID has been registered. If the - command has no description, this will return its short name field instead. - - @see getNameOfCommand - */ - String getDescriptionOfCommand (CommandID commandID) const noexcept; - - /** Returns the list of categories. - - This will go through all registered commands, and return a list of all the distinct - categoryName values from their ApplicationCommandInfo structure. - - @see getCommandsInCategory() - */ - StringArray getCommandCategories() const; - - /** Returns a list of all the command UIDs in a particular category. - @see getCommandCategories() - */ - Array getCommandsInCategory (const String& categoryName) const; - - //============================================================================== - /** Returns the manager's internal set of key mappings. - - This object can be used to edit the keypresses. To actually link this object up - to invoke commands when a key is pressed, see the comments for the KeyPressMappingSet - class. - - @see KeyPressMappingSet - */ - KeyPressMappingSet* getKeyMappings() const noexcept { return keyMappings; } - - - //============================================================================== - /** Invokes the given command directly, sending it to the default target. - This is just an easy way to call invoke() without having to fill out the InvocationInfo - structure. - */ - bool invokeDirectly (CommandID commandID, bool asynchronously); - - /** Sends a command to the default target. - - This will choose a target using getFirstCommandTarget(), and send the specified command - to it using the ApplicationCommandTarget::invoke() method. This means that if the - first target can't handle the command, it will be passed on to targets further down the - chain (see ApplicationCommandTarget::invoke() for more info). - - @param invocationInfo this must be correctly filled-in, describing the context for - the invocation. - @param asynchronously if false, the command will be performed before this method returns. - If true, a message will be posted so that the command will be performed - later on the message thread, and this method will return immediately. - - @see ApplicationCommandTarget::invoke - */ - bool invoke (const ApplicationCommandTarget::InvocationInfo& invocationInfo, - bool asynchronously); - - - //============================================================================== - /** Chooses the ApplicationCommandTarget to which a command should be sent. - - Whenever the manager needs to know which target a command should be sent to, it calls - this method to determine the first one to try. - - By default, this method will return the target that was set by calling setFirstCommandTarget(). - If no target is set, it will return the result of findDefaultComponentTarget(). - - If you need to make sure all commands go via your own custom target, then you can - either use setFirstCommandTarget() to specify a single target, or override this method - if you need more complex logic to choose one. - - It may return nullptr if no targets are available. - - @see getTargetForCommand, invoke, invokeDirectly - */ - virtual ApplicationCommandTarget* getFirstCommandTarget (CommandID commandID); - - /** Sets a target to be returned by getFirstCommandTarget(). - - If this is set to nullptr, then getFirstCommandTarget() will by default return the - result of findDefaultComponentTarget(). - - If you use this to set a target, make sure you call setFirstCommandTarget(nullptr) - before deleting the target object. - */ - void setFirstCommandTarget (ApplicationCommandTarget* newTarget) noexcept; - - /** Tries to find the best target to use to perform a given command. - - This will call getFirstCommandTarget() to find the preferred target, and will - check whether that target can handle the given command. If it can't, then it'll use - ApplicationCommandTarget::getNextCommandTarget() to find the next one to try, and - so on until no more are available. - - If no targets are found that can perform the command, this method will return nullptr. - - If a target is found, then it will get the target to fill-in the upToDateInfo - structure with the latest info about that command, so that the caller can see - whether the command is disabled, ticked, etc. - */ - ApplicationCommandTarget* getTargetForCommand (CommandID commandID, - ApplicationCommandInfo& upToDateInfo); - - //============================================================================== - /** Registers a listener that will be called when various events occur. */ - void addListener (ApplicationCommandManagerListener* listener); - - /** Deregisters a previously-added listener. */ - void removeListener (ApplicationCommandManagerListener* listener); - - //============================================================================== - /** Looks for a suitable command target based on which Components have the keyboard focus. - - This is used by the default implementation of ApplicationCommandTarget::getFirstCommandTarget(), - but is exposed here in case it's useful. - - It tries to pick the best ApplicationCommandTarget by looking at focused components, top level - windows, etc., and using the findTargetForComponent() method. - */ - static ApplicationCommandTarget* findDefaultComponentTarget(); - - /** Examines this component and all its parents in turn, looking for the first one - which is an ApplicationCommandTarget. - - Returns the first ApplicationCommandTarget that it finds, or nullptr if none of them - implement that class. - */ - static ApplicationCommandTarget* findTargetForComponent (Component*); - - -private: - //============================================================================== - OwnedArray commands; - ListenerList listeners; - ScopedPointer keyMappings; - ApplicationCommandTarget* firstTarget; - - void sendListenerInvokeCallback (const ApplicationCommandTarget::InvocationInfo&); - void handleAsyncUpdate() override; - void globalFocusChanged (Component*) override; - ApplicationCommandInfo* getMutableCommandForID (CommandID) const noexcept; - - #if JUCE_CATCH_DEPRECATED_CODE_MISUSE - // This is just here to cause a compile error in old code that hasn't been changed to use the new - // version of this method. - virtual short getFirstCommandTarget() { return 0; } - #endif - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ApplicationCommandManager) -}; - - -//============================================================================== -/** - A listener that receives callbacks from an ApplicationCommandManager when - commands are invoked or the command list is changed. - - @see ApplicationCommandManager::addListener, ApplicationCommandManager::removeListener - -*/ -class JUCE_API ApplicationCommandManagerListener -{ -public: - //============================================================================== - /** Destructor. */ - virtual ~ApplicationCommandManagerListener() {} - - /** Called when an app command is about to be invoked. */ - virtual void applicationCommandInvoked (const ApplicationCommandTarget::InvocationInfo&) = 0; - - /** Called when commands are registered or deregistered from the - command manager, or when commands are made active or inactive. - - Note that if you're using this to watch for changes to whether a command is disabled, - you'll need to make sure that ApplicationCommandManager::commandStatusChanged() is called - whenever the status of your command might have changed. - */ - virtual void applicationCommandListChanged() = 0; -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.cpp b/source/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.cpp deleted file mode 100644 index c074dfc7a..000000000 --- a/source/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -class ApplicationCommandTarget::CommandMessage : public MessageManager::MessageBase -{ -public: - CommandMessage (ApplicationCommandTarget* const target, const InvocationInfo& inf) - : owner (target), info (inf) - { - } - - void messageCallback() override - { - if (ApplicationCommandTarget* const target = owner) - target->tryToInvoke (info, false); - } - -private: - WeakReference owner; - const InvocationInfo info; - - JUCE_DECLARE_NON_COPYABLE (CommandMessage) -}; - -//============================================================================== -ApplicationCommandTarget::ApplicationCommandTarget() {} -ApplicationCommandTarget::~ApplicationCommandTarget() {} - -//============================================================================== -bool ApplicationCommandTarget::tryToInvoke (const InvocationInfo& info, const bool async) -{ - if (isCommandActive (info.commandID)) - { - if (async) - { - (new CommandMessage (this, info))->post(); - return true; - } - - if (perform (info)) - return true; - - // Hmm.. your target claimed that it could perform this command, but failed to do so. - // If it can't do it at the moment for some reason, it should clear the 'isActive' flag - // when it returns the command's info. - jassertfalse; - } - - return false; -} - -ApplicationCommandTarget* ApplicationCommandTarget::findFirstTargetParentComponent() -{ - if (Component* const c = dynamic_cast (this)) - return c->findParentComponentOfClass(); - - return nullptr; -} - -ApplicationCommandTarget* ApplicationCommandTarget::getTargetForCommand (const CommandID commandID) -{ - ApplicationCommandTarget* target = this; - int depth = 0; - - while (target != nullptr) - { - Array commandIDs; - target->getAllCommands (commandIDs); - - if (commandIDs.contains (commandID)) - return target; - - target = target->getNextCommandTarget(); - - ++depth; - jassert (depth < 100); // could be a recursive command chain?? - jassert (target != this); // definitely a recursive command chain! - - if (depth > 100 || target == this) - break; - } - - if (target == nullptr) - { - target = JUCEApplication::getInstance(); - - if (target != nullptr) - { - Array commandIDs; - target->getAllCommands (commandIDs); - - if (commandIDs.contains (commandID)) - return target; - } - } - - return nullptr; -} - -bool ApplicationCommandTarget::isCommandActive (const CommandID commandID) -{ - ApplicationCommandInfo info (commandID); - info.flags = ApplicationCommandInfo::isDisabled; - - getCommandInfo (commandID, info); - - return (info.flags & ApplicationCommandInfo::isDisabled) == 0; -} - -//============================================================================== -bool ApplicationCommandTarget::invoke (const InvocationInfo& info, const bool async) -{ - ApplicationCommandTarget* target = this; - int depth = 0; - - while (target != nullptr) - { - if (target->tryToInvoke (info, async)) - return true; - - target = target->getNextCommandTarget(); - - ++depth; - jassert (depth < 100); // could be a recursive command chain?? - jassert (target != this); // definitely a recursive command chain! - - if (depth > 100 || target == this) - break; - } - - if (target == nullptr) - { - target = JUCEApplication::getInstance(); - - if (target != nullptr) - return target->tryToInvoke (info, async); - } - - return false; -} - -bool ApplicationCommandTarget::invokeDirectly (const CommandID commandID, const bool asynchronously) -{ - ApplicationCommandTarget::InvocationInfo info (commandID); - info.invocationMethod = ApplicationCommandTarget::InvocationInfo::direct; - - return invoke (info, asynchronously); -} - -//============================================================================== -ApplicationCommandTarget::InvocationInfo::InvocationInfo (const CommandID command) - : commandID (command), - commandFlags (0), - invocationMethod (direct), - originatingComponent (nullptr), - isKeyDown (false), - millisecsSinceKeyPressed (0) -{ -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.h b/source/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.h deleted file mode 100644 index 1b31c1f64..000000000 --- a/source/modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.h +++ /dev/null @@ -1,243 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A command target publishes a list of command IDs that it can perform. - - An ApplicationCommandManager despatches commands to targets, which must be - able to provide information about what commands they can handle. - - To create a target, you'll need to inherit from this class, implementing all of - its pure virtual methods. - - For info about how a target is chosen to receive a command, see - ApplicationCommandManager::getFirstCommandTarget(). - - @see ApplicationCommandManager, ApplicationCommandInfo -*/ -class JUCE_API ApplicationCommandTarget -{ -public: - //============================================================================== - /** Creates a command target. */ - ApplicationCommandTarget(); - - /** Destructor. */ - virtual ~ApplicationCommandTarget(); - - //============================================================================== - /** - Contains contextual details about the invocation of a command. - */ - struct JUCE_API InvocationInfo - { - //============================================================================== - InvocationInfo (const CommandID commandID); - - //============================================================================== - /** The UID of the command that should be performed. */ - CommandID commandID; - - /** The command's flags. - See ApplicationCommandInfo for a description of these flag values. - */ - int commandFlags; - - //============================================================================== - /** The types of context in which the command might be called. */ - enum InvocationMethod - { - direct = 0, /**< The command is being invoked directly by a piece of code. */ - fromKeyPress, /**< The command is being invoked by a key-press. */ - fromMenu, /**< The command is being invoked by a menu selection. */ - fromButton /**< The command is being invoked by a button click. */ - }; - - /** The type of event that triggered this command. */ - InvocationMethod invocationMethod; - - //============================================================================== - /** If triggered by a keypress or menu, this will be the component that had the - keyboard focus at the time. - - If triggered by a button, it may be set to that component, or it may be null. - */ - Component* originatingComponent; - - //============================================================================== - /** The keypress that was used to invoke it. - - Note that this will be an invalid keypress if the command was invoked - by some other means than a keyboard shortcut. - */ - KeyPress keyPress; - - /** True if the callback is being invoked when the key is pressed, - false if the key is being released. - - @see KeyPressMappingSet::addCommand() - */ - bool isKeyDown; - - /** If the key is being released, this indicates how long it had been held - down for. - - (Only relevant if isKeyDown is false.) - */ - int millisecsSinceKeyPressed; - }; - - //============================================================================== - /** This must return the next target to try after this one. - - When a command is being sent, and the first target can't handle - that command, this method is used to determine the next target that should - be tried. - - It may return nullptr if it doesn't know of another target. - - If your target is a Component, you would usually use the findFirstTargetParentComponent() - method to return a parent component that might want to handle it. - - @see invoke - */ - virtual ApplicationCommandTarget* getNextCommandTarget() = 0; - - /** This must return a complete list of commands that this target can handle. - - Your target should add all the command IDs that it handles to the array that is - passed-in. - */ - virtual void getAllCommands (Array& commands) = 0; - - /** This must provide details about one of the commands that this target can perform. - - This will be called with one of the command IDs that the target provided in its - getAllCommands() methods. - - It should fill-in all appropriate fields of the ApplicationCommandInfo structure with - suitable information about the command. (The commandID field will already have been filled-in - by the caller). - - The easiest way to set the info is using the ApplicationCommandInfo::setInfo() method to - set all the fields at once. - - If the command is currently inactive for some reason, this method must use - ApplicationCommandInfo::setActive() to make that clear, (or it should set the isDisabled - bit of the ApplicationCommandInfo::flags field). - - Any default key-presses for the command should be appended to the - ApplicationCommandInfo::defaultKeypresses field. - - Note that if you change something that affects the status of the commands - that would be returned by this method (e.g. something that makes some commands - active or inactive), you should call ApplicationCommandManager::commandStatusChanged() - to cause the manager to refresh its status. - */ - virtual void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result) = 0; - - /** This must actually perform the specified command. - - If this target is able to perform the command specified by the commandID field of the - InvocationInfo structure, then it should do so, and must return true. - - If it can't handle this command, it should return false, which tells the caller to pass - the command on to the next target in line. - - @see invoke, ApplicationCommandManager::invoke - */ - virtual bool perform (const InvocationInfo& info) = 0; - - //============================================================================== - /** Makes this target invoke a command. - - Your code can call this method to invoke a command on this target, but normally - you'd call it indirectly via ApplicationCommandManager::invoke() or - ApplicationCommandManager::invokeDirectly(). - - If this target can perform the given command, it will call its perform() method to - do so. If not, then getNextCommandTarget() will be used to determine the next target - to try, and the command will be passed along to it. - - @param invocationInfo this must be correctly filled-in, describing the context for - the invocation. - @param asynchronously if false, the command will be performed before this method returns. - If true, a message will be posted so that the command will be performed - later on the message thread, and this method will return immediately. - @see perform, ApplicationCommandManager::invoke - */ - bool invoke (const InvocationInfo& invocationInfo, - const bool asynchronously); - - /** Invokes a given command directly on this target. - - This is just an easy way to call invoke() without having to fill out the InvocationInfo - structure. - */ - bool invokeDirectly (const CommandID commandID, - const bool asynchronously); - - //============================================================================== - /** Searches this target and all subsequent ones for the first one that can handle - the specified command. - - This will use getNextCommandTarget() to determine the chain of targets to try - after this one. - */ - ApplicationCommandTarget* getTargetForCommand (const CommandID commandID); - - /** Checks whether this command can currently be performed by this target. - - This will return true only if a call to getCommandInfo() doesn't set the - isDisabled flag to indicate that the command is inactive. - */ - bool isCommandActive (const CommandID commandID); - - /** If this object is a Component, this method will search upwards in its current - UI hierarchy for the next parent component that implements the - ApplicationCommandTarget class. - - If your target is a Component, this is a very handy method to use in your - getNextCommandTarget() implementation. - */ - ApplicationCommandTarget* findFirstTargetParentComponent(); - -private: - //============================================================================== - class CommandMessage; - friend class CommandMessage; - - bool tryToInvoke (const InvocationInfo&, bool async); - - JUCE_DECLARE_WEAK_REFERENCEABLE (ApplicationCommandTarget) - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ApplicationCommandTarget) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/commands/juce_KeyPressMappingSet.cpp b/source/modules/juce_gui_basics/commands/juce_KeyPressMappingSet.cpp deleted file mode 100644 index 0a0232843..000000000 --- a/source/modules/juce_gui_basics/commands/juce_KeyPressMappingSet.cpp +++ /dev/null @@ -1,419 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -KeyPressMappingSet::KeyPressMappingSet (ApplicationCommandManager& cm) - : commandManager (cm) -{ - Desktop::getInstance().addFocusChangeListener (this); -} - -KeyPressMappingSet::KeyPressMappingSet (const KeyPressMappingSet& other) - : KeyListener(), ChangeBroadcaster(), FocusChangeListener(), commandManager (other.commandManager) -{ - Desktop::getInstance().addFocusChangeListener (this); -} - -KeyPressMappingSet::~KeyPressMappingSet() -{ - Desktop::getInstance().removeFocusChangeListener (this); -} - -//============================================================================== -Array KeyPressMappingSet::getKeyPressesAssignedToCommand (const CommandID commandID) const -{ - for (int i = 0; i < mappings.size(); ++i) - if (mappings.getUnchecked(i)->commandID == commandID) - return mappings.getUnchecked (i)->keypresses; - - return Array(); -} - -void KeyPressMappingSet::addKeyPress (const CommandID commandID, const KeyPress& newKeyPress, int insertIndex) -{ - // If you specify an upper-case letter but no shift key, how is the user supposed to press it!? - // Stick to lower-case letters when defining a keypress, to avoid ambiguity. - jassert (! (CharacterFunctions::isUpperCase (newKeyPress.getTextCharacter()) - && ! newKeyPress.getModifiers().isShiftDown())); - - if (findCommandForKeyPress (newKeyPress) != commandID) - { - if (newKeyPress.isValid()) - { - for (int i = mappings.size(); --i >= 0;) - { - if (mappings.getUnchecked(i)->commandID == commandID) - { - mappings.getUnchecked(i)->keypresses.insert (insertIndex, newKeyPress); - - sendChangeMessage(); - return; - } - } - - if (const ApplicationCommandInfo* const ci = commandManager.getCommandForID (commandID)) - { - CommandMapping* const cm = new CommandMapping(); - cm->commandID = commandID; - cm->keypresses.add (newKeyPress); - cm->wantsKeyUpDownCallbacks = (ci->flags & ApplicationCommandInfo::wantsKeyUpDownCallbacks) != 0; - - mappings.add (cm); - sendChangeMessage(); - } - else - { - // If you hit this, you're trying to attach a keypress to a command ID that - // doesn't exist, so the key is not being attached. - jassertfalse; - } - } - } -} - -static void addKeyPresses (KeyPressMappingSet& set, const ApplicationCommandInfo* const ci) -{ - for (int j = 0; j < ci->defaultKeypresses.size(); ++j) - set.addKeyPress (ci->commandID, ci->defaultKeypresses.getReference (j)); -} - -void KeyPressMappingSet::resetToDefaultMappings() -{ - mappings.clear(); - - for (int i = 0; i < commandManager.getNumCommands(); ++i) - addKeyPresses (*this, commandManager.getCommandForIndex (i)); - - sendChangeMessage(); -} - -void KeyPressMappingSet::resetToDefaultMapping (const CommandID commandID) -{ - clearAllKeyPresses (commandID); - - if (const ApplicationCommandInfo* const ci = commandManager.getCommandForID (commandID)) - addKeyPresses (*this, ci); -} - -void KeyPressMappingSet::clearAllKeyPresses() -{ - if (mappings.size() > 0) - { - sendChangeMessage(); - mappings.clear(); - } -} - -void KeyPressMappingSet::clearAllKeyPresses (const CommandID commandID) -{ - for (int i = mappings.size(); --i >= 0;) - { - if (mappings.getUnchecked(i)->commandID == commandID) - { - mappings.remove (i); - sendChangeMessage(); - } - } -} - -void KeyPressMappingSet::removeKeyPress (const KeyPress& keypress) -{ - if (keypress.isValid()) - { - for (int i = mappings.size(); --i >= 0;) - { - CommandMapping& cm = *mappings.getUnchecked(i); - - for (int j = cm.keypresses.size(); --j >= 0;) - { - if (keypress == cm.keypresses [j]) - { - cm.keypresses.remove (j); - sendChangeMessage(); - } - } - } - } -} - -void KeyPressMappingSet::removeKeyPress (const CommandID commandID, const int keyPressIndex) -{ - for (int i = mappings.size(); --i >= 0;) - { - if (mappings.getUnchecked(i)->commandID == commandID) - { - mappings.getUnchecked(i)->keypresses.remove (keyPressIndex); - sendChangeMessage(); - break; - } - } -} - -//============================================================================== -CommandID KeyPressMappingSet::findCommandForKeyPress (const KeyPress& keyPress) const noexcept -{ - for (int i = 0; i < mappings.size(); ++i) - if (mappings.getUnchecked(i)->keypresses.contains (keyPress)) - return mappings.getUnchecked(i)->commandID; - - return 0; -} - -bool KeyPressMappingSet::containsMapping (const CommandID commandID, const KeyPress& keyPress) const noexcept -{ - for (int i = mappings.size(); --i >= 0;) - if (mappings.getUnchecked(i)->commandID == commandID) - return mappings.getUnchecked(i)->keypresses.contains (keyPress); - - return false; -} - -void KeyPressMappingSet::invokeCommand (const CommandID commandID, - const KeyPress& key, - const bool isKeyDown, - const int millisecsSinceKeyPressed, - Component* const originatingComponent) const -{ - ApplicationCommandTarget::InvocationInfo info (commandID); - - info.invocationMethod = ApplicationCommandTarget::InvocationInfo::fromKeyPress; - info.isKeyDown = isKeyDown; - info.keyPress = key; - info.millisecsSinceKeyPressed = millisecsSinceKeyPressed; - info.originatingComponent = originatingComponent; - - commandManager.invoke (info, false); -} - -//============================================================================== -bool KeyPressMappingSet::restoreFromXml (const XmlElement& xmlVersion) -{ - if (xmlVersion.hasTagName ("KEYMAPPINGS")) - { - if (xmlVersion.getBoolAttribute ("basedOnDefaults", true)) - { - // if the XML was created as a set of differences from the default mappings, - // (i.e. by calling createXml (true)), then we need to first restore the defaults. - resetToDefaultMappings(); - } - else - { - // if the XML was created calling createXml (false), then we need to clear all - // the keys and treat the xml as describing the entire set of mappings. - clearAllKeyPresses(); - } - - forEachXmlChildElement (xmlVersion, map) - { - const CommandID commandId = map->getStringAttribute ("commandId").getHexValue32(); - - if (commandId != 0) - { - const KeyPress key (KeyPress::createFromDescription (map->getStringAttribute ("key"))); - - if (map->hasTagName ("MAPPING")) - { - addKeyPress (commandId, key); - } - else if (map->hasTagName ("UNMAPPING")) - { - for (int i = mappings.size(); --i >= 0;) - if (mappings.getUnchecked(i)->commandID == commandId) - mappings.getUnchecked(i)->keypresses.removeAllInstancesOf (key); - } - } - } - - return true; - } - - return false; -} - -XmlElement* KeyPressMappingSet::createXml (const bool saveDifferencesFromDefaultSet) const -{ - ScopedPointer defaultSet; - - if (saveDifferencesFromDefaultSet) - { - defaultSet = new KeyPressMappingSet (commandManager); - defaultSet->resetToDefaultMappings(); - } - - XmlElement* const doc = new XmlElement ("KEYMAPPINGS"); - - doc->setAttribute ("basedOnDefaults", saveDifferencesFromDefaultSet); - - for (int i = 0; i < mappings.size(); ++i) - { - const CommandMapping& cm = *mappings.getUnchecked(i); - - for (int j = 0; j < cm.keypresses.size(); ++j) - { - if (defaultSet == nullptr - || ! defaultSet->containsMapping (cm.commandID, cm.keypresses.getReference (j))) - { - XmlElement* const map = doc->createNewChildElement ("MAPPING"); - - map->setAttribute ("commandId", String::toHexString ((int) cm.commandID)); - map->setAttribute ("description", commandManager.getDescriptionOfCommand (cm.commandID)); - map->setAttribute ("key", cm.keypresses.getReference (j).getTextDescription()); - } - } - } - - if (defaultSet != nullptr) - { - for (int i = 0; i < defaultSet->mappings.size(); ++i) - { - const CommandMapping& cm = *defaultSet->mappings.getUnchecked(i); - - for (int j = 0; j < cm.keypresses.size(); ++j) - { - if (! containsMapping (cm.commandID, cm.keypresses.getReference (j))) - { - XmlElement* const map = doc->createNewChildElement ("UNMAPPING"); - - map->setAttribute ("commandId", String::toHexString ((int) cm.commandID)); - map->setAttribute ("description", commandManager.getDescriptionOfCommand (cm.commandID)); - map->setAttribute ("key", cm.keypresses.getReference (j).getTextDescription()); - } - } - } - } - - return doc; -} - -//============================================================================== -bool KeyPressMappingSet::keyPressed (const KeyPress& key, Component* const originatingComponent) -{ - bool commandWasDisabled = false; - - for (int i = 0; i < mappings.size(); ++i) - { - CommandMapping& cm = *mappings.getUnchecked(i); - - if (cm.keypresses.contains (key)) - { - if (const ApplicationCommandInfo* const ci = commandManager.getCommandForID (cm.commandID)) - { - if ((ci->flags & ApplicationCommandInfo::wantsKeyUpDownCallbacks) == 0) - { - ApplicationCommandInfo info (0); - - if (commandManager.getTargetForCommand (cm.commandID, info) != nullptr) - { - if ((info.flags & ApplicationCommandInfo::isDisabled) == 0) - { - invokeCommand (cm.commandID, key, true, 0, originatingComponent); - return true; - } - - commandWasDisabled = true; - } - } - } - } - } - - if (originatingComponent != nullptr && commandWasDisabled) - originatingComponent->getLookAndFeel().playAlertSound(); - - return false; -} - -bool KeyPressMappingSet::keyStateChanged (const bool /*isKeyDown*/, Component* originatingComponent) -{ - bool used = false; - const uint32 now = Time::getMillisecondCounter(); - - for (int i = mappings.size(); --i >= 0;) - { - CommandMapping& cm = *mappings.getUnchecked(i); - - if (cm.wantsKeyUpDownCallbacks) - { - for (int j = cm.keypresses.size(); --j >= 0;) - { - const KeyPress key (cm.keypresses.getReference (j)); - const bool isDown = key.isCurrentlyDown(); - - int keyPressEntryIndex = 0; - bool wasDown = false; - - for (int k = keysDown.size(); --k >= 0;) - { - if (key == keysDown.getUnchecked(k)->key) - { - keyPressEntryIndex = k; - wasDown = true; - used = true; - break; - } - } - - if (isDown != wasDown) - { - int millisecs = 0; - - if (isDown) - { - KeyPressTime* const k = new KeyPressTime(); - k->key = key; - k->timeWhenPressed = now; - - keysDown.add (k); - } - else - { - const uint32 pressTime = keysDown.getUnchecked (keyPressEntryIndex)->timeWhenPressed; - - if (now > pressTime) - millisecs = (int) (now - pressTime); - - keysDown.remove (keyPressEntryIndex); - } - - invokeCommand (cm.commandID, key, isDown, millisecs, originatingComponent); - used = true; - } - } - } - } - - return used; -} - -void KeyPressMappingSet::globalFocusChanged (Component* focusedComponent) -{ - if (focusedComponent != nullptr) - focusedComponent->keyStateChanged (false); -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/commands/juce_KeyPressMappingSet.h b/source/modules/juce_gui_basics/commands/juce_KeyPressMappingSet.h deleted file mode 100644 index d850739bf..000000000 --- a/source/modules/juce_gui_basics/commands/juce_KeyPressMappingSet.h +++ /dev/null @@ -1,245 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Manages and edits a list of keypresses, which it uses to invoke the appropriate - command in an ApplicationCommandManager. - - Normally, you won't actually create a KeyPressMappingSet directly, because - each ApplicationCommandManager contains its own KeyPressMappingSet, so typically - you'd create yourself an ApplicationCommandManager, and call its - ApplicationCommandManager::getKeyMappings() method to get a pointer to its - KeyPressMappingSet. - - For one of these to actually use keypresses, you'll need to add it as a KeyListener - to the top-level component for which you want to handle keystrokes. So for example: - - @code - class MyMainWindow : public Component - { - ApplicationCommandManager* myCommandManager; - - public: - MyMainWindow() - { - myCommandManager = new ApplicationCommandManager(); - - // first, make sure the command manager has registered all the commands that its - // targets can perform.. - myCommandManager->registerAllCommandsForTarget (myCommandTarget1); - myCommandManager->registerAllCommandsForTarget (myCommandTarget2); - - // this will use the command manager to initialise the KeyPressMappingSet with - // the default keypresses that were specified when the targets added their commands - // to the manager. - myCommandManager->getKeyMappings()->resetToDefaultMappings(); - - // having set up the default key-mappings, you might now want to load the last set - // of mappings that the user configured. - myCommandManager->getKeyMappings()->restoreFromXml (lastSavedKeyMappingsXML); - - // Now tell our top-level window to send any keypresses that arrive to the - // KeyPressMappingSet, which will use them to invoke the appropriate commands. - addKeyListener (myCommandManager->getKeyMappings()); - } - - ... - } - @endcode - - KeyPressMappingSet derives from ChangeBroadcaster so that interested parties can - register to be told when a command or mapping is added, removed, etc. - - There's also a UI component called KeyMappingEditorComponent that can be used - to easily edit the key mappings. - - @see Component::addKeyListener(), KeyMappingEditorComponent, ApplicationCommandManager -*/ -class JUCE_API KeyPressMappingSet : public KeyListener, - public ChangeBroadcaster, - private FocusChangeListener -{ -public: - //============================================================================== - /** Creates a KeyPressMappingSet for a given command manager. - - Normally, you won't actually create a KeyPressMappingSet directly, because - each ApplicationCommandManager contains its own KeyPressMappingSet, so the - best thing to do is to create your ApplicationCommandManager, and use the - ApplicationCommandManager::getKeyMappings() method to access its mappings. - - When a suitable keypress happens, the manager's invoke() method will be - used to invoke the appropriate command. - - @see ApplicationCommandManager - */ - explicit KeyPressMappingSet (ApplicationCommandManager&); - - /** Creates an copy of a KeyPressMappingSet. */ - KeyPressMappingSet (const KeyPressMappingSet&); - - /** Destructor. */ - ~KeyPressMappingSet(); - - //============================================================================== - ApplicationCommandManager& getCommandManager() const noexcept { return commandManager; } - - //============================================================================== - /** Returns a list of keypresses that are assigned to a particular command. - - @param commandID the command's ID - */ - Array getKeyPressesAssignedToCommand (CommandID commandID) const; - - /** Assigns a keypress to a command. - - If the keypress is already assigned to a different command, it will first be - removed from that command, to avoid it triggering multiple functions. - - @param commandID the ID of the command that you want to add a keypress to. If - this is 0, the keypress will be removed from anything that it - was previously assigned to, but not re-assigned - @param newKeyPress the new key-press - @param insertIndex if this is less than zero, the key will be appended to the - end of the list of keypresses; otherwise the new keypress will - be inserted into the existing list at this index - */ - void addKeyPress (CommandID commandID, - const KeyPress& newKeyPress, - int insertIndex = -1); - - /** Reset all mappings to the defaults, as dictated by the ApplicationCommandManager. - @see resetToDefaultMapping - */ - void resetToDefaultMappings(); - - /** Resets all key-mappings to the defaults for a particular command. - @see resetToDefaultMappings - */ - void resetToDefaultMapping (CommandID commandID); - - /** Removes all keypresses that are assigned to any commands. */ - void clearAllKeyPresses(); - - /** Removes all keypresses that are assigned to a particular command. */ - void clearAllKeyPresses (CommandID commandID); - - /** Removes one of the keypresses that are assigned to a command. - See the getKeyPressesAssignedToCommand() for the list of keypresses to - which the keyPressIndex refers. - */ - void removeKeyPress (CommandID commandID, int keyPressIndex); - - /** Removes a keypress from any command that it may be assigned to. */ - void removeKeyPress (const KeyPress& keypress); - - /** Returns true if the given command is linked to this key. */ - bool containsMapping (CommandID commandID, const KeyPress& keyPress) const noexcept; - - //============================================================================== - /** Looks for a command that corresponds to a keypress. - @returns the UID of the command or 0 if none was found - */ - CommandID findCommandForKeyPress (const KeyPress& keyPress) const noexcept; - - //============================================================================== - /** Tries to recreate the mappings from a previously stored state. - - The XML passed in must have been created by the createXml() method. - - If the stored state makes any reference to commands that aren't - currently available, these will be ignored. - - If the set of mappings being loaded was a set of differences (using createXml (true)), - then this will call resetToDefaultMappings() and then merge the saved mappings - on top. If the saved set was created with createXml (false), then this method - will first clear all existing mappings and load the saved ones as a complete set. - - @returns true if it manages to load the XML correctly - @see createXml - */ - bool restoreFromXml (const XmlElement& xmlVersion); - - /** Creates an XML representation of the current mappings. - - This will produce a lump of XML that can be later reloaded using - restoreFromXml() to recreate the current mapping state. - - The object that is returned must be deleted by the caller. - - @param saveDifferencesFromDefaultSet if this is false, then all keypresses - will be saved into the XML. If it's true, then the XML will - only store the differences between the current mappings and - the default mappings you'd get from calling resetToDefaultMappings(). - The advantage of saving a set of differences from the default is that - if you change the default mappings (in a new version of your app, for - example), then these will be merged into a user's saved preferences. - - @see restoreFromXml - */ - XmlElement* createXml (bool saveDifferencesFromDefaultSet) const; - - //============================================================================== - /** @internal */ - bool keyPressed (const KeyPress&, Component*) override; - /** @internal */ - bool keyStateChanged (bool isKeyDown, Component*) override; - /** @internal */ - void globalFocusChanged (Component*) override; - -private: - //============================================================================== - ApplicationCommandManager& commandManager; - - struct CommandMapping - { - CommandID commandID; - Array keypresses; - bool wantsKeyUpDownCallbacks; - }; - - OwnedArray mappings; - - struct KeyPressTime - { - KeyPress key; - uint32 timeWhenPressed; - }; - - OwnedArray keysDown; - - void invokeCommand (const CommandID, const KeyPress&, const bool isKeyDown, - const int millisecsSinceKeyPressed, Component* originator) const; - - KeyPressMappingSet& operator= (const KeyPressMappingSet&); - JUCE_LEAK_DETECTOR (KeyPressMappingSet) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/components/juce_CachedComponentImage.h b/source/modules/juce_gui_basics/components/juce_CachedComponentImage.h deleted file mode 100644 index 7e2b5485d..000000000 --- a/source/modules/juce_gui_basics/components/juce_CachedComponentImage.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Base class used internally for structures that can store cached images of - component state. - - Most people are unlikely to ever need to know about this class - it's really - only for power-users! - - @see Component::setCachedComponentImage -*/ -class JUCE_API CachedComponentImage -{ -public: - CachedComponentImage() noexcept {} - virtual ~CachedComponentImage() {} - - //============================================================================== - /** Called as part of the parent component's paint method, this must draw - the given component into the target graphics context, using the cached - version where possible. - */ - virtual void paint (Graphics&) = 0; - - /** Invalidates all cached image data. - @returns true if the peer should also be repainted, or false if this object - handles all repaint work internally. - */ - virtual bool invalidateAll() = 0; - - /** Invalidates a section of the cached image data. - @returns true if the peer should also be repainted, or false if this object - handles all repaint work internally. - */ - virtual bool invalidate (const Rectangle& area) = 0; - - /** Called to indicate that the component is no longer active, so - any cached data should be released if possible. - */ - virtual void releaseResources() = 0; -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/components/juce_Component.cpp b/source/modules/juce_gui_basics/components/juce_Component.cpp deleted file mode 100644 index d69a2bbf7..000000000 --- a/source/modules/juce_gui_basics/components/juce_Component.cpp +++ /dev/null @@ -1,3046 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -Component* Component::currentlyFocusedComponent = nullptr; - - -//============================================================================== -class Component::MouseListenerList -{ -public: - MouseListenerList() noexcept {} - - void addListener (MouseListener* const newListener, const bool wantsEventsForAllNestedChildComponents) - { - if (! listeners.contains (newListener)) - { - if (wantsEventsForAllNestedChildComponents) - { - listeners.insert (0, newListener); - ++numDeepMouseListeners; - } - else - { - listeners.add (newListener); - } - } - } - - void removeListener (MouseListener* const listenerToRemove) - { - auto index = listeners.indexOf (listenerToRemove); - - if (index >= 0) - { - if (index < numDeepMouseListeners) - --numDeepMouseListeners; - - listeners.remove (index); - } - } - - static void sendMouseEvent (Component& comp, Component::BailOutChecker& checker, - void (MouseListener::*eventMethod) (const MouseEvent&), const MouseEvent& e) - { - if (checker.shouldBailOut()) - return; - - if (auto* list = comp.mouseListeners.get()) - { - for (int i = list->listeners.size(); --i >= 0;) - { - (list->listeners.getUnchecked(i)->*eventMethod) (e); - - if (checker.shouldBailOut()) - return; - - i = jmin (i, list->listeners.size()); - } - } - - for (Component* p = comp.parentComponent; p != nullptr; p = p->parentComponent) - { - if (auto* list = p->mouseListeners.get()) - { - if (list->numDeepMouseListeners > 0) - { - BailOutChecker2 checker2 (checker, p); - - for (int i = list->numDeepMouseListeners; --i >= 0;) - { - (list->listeners.getUnchecked(i)->*eventMethod) (e); - - if (checker2.shouldBailOut()) - return; - - i = jmin (i, list->numDeepMouseListeners); - } - } - } - } - } - - static void sendWheelEvent (Component& comp, Component::BailOutChecker& checker, - const MouseEvent& e, const MouseWheelDetails& wheel) - { - if (auto* list = comp.mouseListeners.get()) - { - for (int i = list->listeners.size(); --i >= 0;) - { - list->listeners.getUnchecked(i)->mouseWheelMove (e, wheel); - - if (checker.shouldBailOut()) - return; - - i = jmin (i, list->listeners.size()); - } - } - - for (Component* p = comp.parentComponent; p != nullptr; p = p->parentComponent) - { - if (auto* list = p->mouseListeners.get()) - { - if (list->numDeepMouseListeners > 0) - { - BailOutChecker2 checker2 (checker, p); - - for (int i = list->numDeepMouseListeners; --i >= 0;) - { - list->listeners.getUnchecked(i)->mouseWheelMove (e, wheel); - - if (checker2.shouldBailOut()) - return; - - i = jmin (i, list->numDeepMouseListeners); - } - } - } - } - } - -private: - Array listeners; - int numDeepMouseListeners = 0; - - struct BailOutChecker2 - { - BailOutChecker2 (Component::BailOutChecker& boc, Component* const comp) - : checker (boc), safePointer (comp) - { - } - - bool shouldBailOut() const noexcept - { - return checker.shouldBailOut() || safePointer == nullptr; - } - - private: - Component::BailOutChecker& checker; - const WeakReference safePointer; - - JUCE_DECLARE_NON_COPYABLE (BailOutChecker2) - }; - - JUCE_DECLARE_NON_COPYABLE (MouseListenerList) -}; - -//============================================================================== -struct FocusRestorer -{ - FocusRestorer() : lastFocus (Component::getCurrentlyFocusedComponent()) {} - - ~FocusRestorer() - { - if (lastFocus != nullptr - && lastFocus->isShowing() - && ! lastFocus->isCurrentlyBlockedByAnotherModalComponent()) - lastFocus->grabKeyboardFocus(); - } - - WeakReference lastFocus; - - JUCE_DECLARE_NON_COPYABLE (FocusRestorer) -}; - -//============================================================================== -struct ScalingHelpers -{ - template - static PointOrRect unscaledScreenPosToScaled (float scale, PointOrRect pos) noexcept - { - return scale != 1.0f ? pos / scale : pos; - } - - template - static PointOrRect scaledScreenPosToUnscaled (float scale, PointOrRect pos) noexcept - { - return scale != 1.0f ? pos * scale : pos; - } - - // For these, we need to avoid getSmallestIntegerContainer being used, which causes - // judder when moving windows - static Rectangle unscaledScreenPosToScaled (float scale, Rectangle pos) noexcept - { - return scale != 1.0f ? Rectangle (roundToInt (pos.getX() / scale), - roundToInt (pos.getY() / scale), - roundToInt (pos.getWidth() / scale), - roundToInt (pos.getHeight() / scale)) : pos; - } - - static Rectangle scaledScreenPosToUnscaled (float scale, Rectangle pos) noexcept - { - return scale != 1.0f ? Rectangle (roundToInt (pos.getX() * scale), - roundToInt (pos.getY() * scale), - roundToInt (pos.getWidth() * scale), - roundToInt (pos.getHeight() * scale)) : pos; - } - - template - static PointOrRect unscaledScreenPosToScaled (PointOrRect pos) noexcept - { - return unscaledScreenPosToScaled (Desktop::getInstance().getGlobalScaleFactor(), pos); - } - - template - static PointOrRect scaledScreenPosToUnscaled (PointOrRect pos) noexcept - { - return scaledScreenPosToUnscaled (Desktop::getInstance().getGlobalScaleFactor(), pos); - } - - template - static PointOrRect unscaledScreenPosToScaled (const Component& comp, PointOrRect pos) noexcept - { - return unscaledScreenPosToScaled (comp.getDesktopScaleFactor(), pos); - } - - template - static PointOrRect scaledScreenPosToUnscaled (const Component& comp, PointOrRect pos) noexcept - { - return scaledScreenPosToUnscaled (comp.getDesktopScaleFactor(), pos); - } - - static Point addPosition (Point p, const Component& c) noexcept { return p + c.getPosition(); } - static Rectangle addPosition (Rectangle p, const Component& c) noexcept { return p + c.getPosition(); } - static Point addPosition (Point p, const Component& c) noexcept { return p + c.getPosition().toFloat(); } - static Rectangle addPosition (Rectangle p, const Component& c) noexcept { return p + c.getPosition().toFloat(); } - static Point subtractPosition (Point p, const Component& c) noexcept { return p - c.getPosition(); } - static Rectangle subtractPosition (Rectangle p, const Component& c) noexcept { return p - c.getPosition(); } - static Point subtractPosition (Point p, const Component& c) noexcept { return p - c.getPosition().toFloat(); } - static Rectangle subtractPosition (Rectangle p, const Component& c) noexcept { return p - c.getPosition().toFloat(); } -}; - -//============================================================================== -struct Component::ComponentHelpers -{ - #if JUCE_MODAL_LOOPS_PERMITTED - static void* runModalLoopCallback (void* userData) - { - return (void*) (pointer_sized_int) static_cast (userData)->runModalLoop(); - } - #endif - - static Identifier getColourPropertyId (int colourId) - { - char reversedHex[32]; - char* t = reversedHex; - - for (unsigned int v = (unsigned int) colourId;;) - { - *t++ = "0123456789abcdef" [(int) (v & 15)]; - v >>= 4; - - if (v == 0) - break; - } - - char destBuffer[32]; - char* dest = destBuffer; - memcpy (dest, "jcclr_", 6); - dest += 6; - - while (t > reversedHex) - *dest++ = *--t; - - *dest++ = 0; - return destBuffer; - } - - //============================================================================== - static inline bool hitTest (Component& comp, Point localPoint) - { - return isPositiveAndBelow (localPoint.x, comp.getWidth()) - && isPositiveAndBelow (localPoint.y, comp.getHeight()) - && comp.hitTest (localPoint.x, localPoint.y); - } - - // converts an unscaled position within a peer to the local position within that peer's component - template - static PointOrRect rawPeerPositionToLocal (const Component& comp, PointOrRect pos) noexcept - { - if (comp.isTransformed()) - pos = pos.transformedBy (comp.getTransform().inverted()); - - return ScalingHelpers::unscaledScreenPosToScaled (comp, pos); - } - - // converts a position within a peer's component to the unscaled position within the peer - template - static PointOrRect localPositionToRawPeerPos (const Component& comp, PointOrRect pos) noexcept - { - if (comp.isTransformed()) - pos = pos.transformedBy (comp.getTransform()); - - return ScalingHelpers::scaledScreenPosToUnscaled (comp, pos); - } - - template - static PointOrRect convertFromParentSpace (const Component& comp, PointOrRect pointInParentSpace) - { - if (comp.affineTransform != nullptr) - pointInParentSpace = pointInParentSpace.transformedBy (comp.affineTransform->inverted()); - - if (comp.isOnDesktop()) - { - if (auto* peer = comp.getPeer()) - pointInParentSpace = ScalingHelpers::unscaledScreenPosToScaled - (comp, peer->globalToLocal (ScalingHelpers::scaledScreenPosToUnscaled (pointInParentSpace))); - else - jassertfalse; - } - else - { - pointInParentSpace = ScalingHelpers::subtractPosition (pointInParentSpace, comp); - } - - return pointInParentSpace; - } - - template - static PointOrRect convertToParentSpace (const Component& comp, PointOrRect pointInLocalSpace) - { - if (comp.isOnDesktop()) - { - if (auto* peer = comp.getPeer()) - pointInLocalSpace = ScalingHelpers::unscaledScreenPosToScaled - (peer->localToGlobal (ScalingHelpers::scaledScreenPosToUnscaled (comp, pointInLocalSpace))); - else - jassertfalse; - } - else - { - pointInLocalSpace = ScalingHelpers::addPosition (pointInLocalSpace, comp); - } - - if (comp.affineTransform != nullptr) - pointInLocalSpace = pointInLocalSpace.transformedBy (*comp.affineTransform); - - return pointInLocalSpace; - } - - template - static PointOrRect convertFromDistantParentSpace (const Component* parent, const Component& target, const PointOrRect& coordInParent) - { - auto* directParent = target.getParentComponent(); - jassert (directParent != nullptr); - - if (directParent == parent) - return convertFromParentSpace (target, coordInParent); - - return convertFromParentSpace (target, convertFromDistantParentSpace (parent, *directParent, coordInParent)); - } - - template - static PointOrRect convertCoordinate (const Component* target, const Component* source, PointOrRect p) - { - while (source != nullptr) - { - if (source == target) - return p; - - if (source->isParentOf (target)) - return convertFromDistantParentSpace (source, *target, p); - - p = convertToParentSpace (*source, p); - source = source->getParentComponent(); - } - - jassert (source == nullptr); - if (target == nullptr) - return p; - - auto* topLevelComp = target->getTopLevelComponent(); - - p = convertFromParentSpace (*topLevelComp, p); - - if (topLevelComp == target) - return p; - - return convertFromDistantParentSpace (topLevelComp, *target, p); - } - - static bool clipObscuredRegions (const Component& comp, Graphics& g, const Rectangle clipRect, Point delta) - { - bool wasClipped = false; - - for (int i = comp.childComponentList.size(); --i >= 0;) - { - auto& child = *comp.childComponentList.getUnchecked(i); - - if (child.isVisible() && ! child.isTransformed()) - { - auto newClip = clipRect.getIntersection (child.boundsRelativeToParent); - - if (! newClip.isEmpty()) - { - if (child.isOpaque() && child.componentTransparency == 0) - { - g.excludeClipRegion (newClip + delta); - wasClipped = true; - } - else - { - auto childPos = child.getPosition(); - - if (clipObscuredRegions (child, g, newClip - childPos, childPos + delta)) - wasClipped = true; - } - } - } - } - - return wasClipped; - } - - static Rectangle getParentOrMainMonitorBounds (const Component& comp) - { - if (auto* p = comp.getParentComponent()) - return p->getLocalBounds(); - - return Desktop::getInstance().getDisplays().getMainDisplay().userArea; - } - - static void releaseAllCachedImageResources (Component& c) - { - if (auto* cached = c.getCachedComponentImage()) - cached->releaseResources(); - - for (auto* child : c.childComponentList) - releaseAllCachedImageResources (*child); - } -}; - -//============================================================================== -Component::Component() noexcept - : componentFlags (0) -{ -} - -Component::Component (const String& name) noexcept - : componentName (name), componentFlags (0) -{ -} - -Component::~Component() -{ - static_assert (sizeof (flags) <= sizeof (componentFlags), "componentFlags has too many bits!"); - - componentListeners.call (&ComponentListener::componentBeingDeleted, *this); - - masterReference.clear(); - - while (childComponentList.size() > 0) - removeChildComponent (childComponentList.size() - 1, false, true); - - if (parentComponent != nullptr) - parentComponent->removeChildComponent (parentComponent->childComponentList.indexOf (this), true, false); - else if (currentlyFocusedComponent == this || isParentOf (currentlyFocusedComponent)) - giveAwayFocus (currentlyFocusedComponent != this); - - if (flags.hasHeavyweightPeerFlag) - removeFromDesktop(); - - // Something has added some children to this component during its destructor! Not a smart idea! - jassert (childComponentList.size() == 0); -} - -//============================================================================== -void Component::setName (const String& name) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN - - if (componentName != name) - { - componentName = name; - - if (flags.hasHeavyweightPeerFlag) - if (auto* peer = getPeer()) - peer->setTitle (name); - - BailOutChecker checker (this); - componentListeners.callChecked (checker, &ComponentListener::componentNameChanged, *this); - } -} - -void Component::setComponentID (const String& newID) -{ - componentID = newID; -} - -void Component::setVisible (bool shouldBeVisible) -{ - if (flags.visibleFlag != shouldBeVisible) - { - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN - - const WeakReference safePointer (this); - flags.visibleFlag = shouldBeVisible; - - if (shouldBeVisible) - repaint(); - else - repaintParent(); - - sendFakeMouseMove(); - - if (! shouldBeVisible) - { - ComponentHelpers::releaseAllCachedImageResources (*this); - - if (currentlyFocusedComponent == this || isParentOf (currentlyFocusedComponent)) - { - if (parentComponent != nullptr) - parentComponent->grabKeyboardFocus(); - else - giveAwayFocus (true); - } - } - - if (safePointer != nullptr) - { - sendVisibilityChangeMessage(); - - if (safePointer != nullptr && flags.hasHeavyweightPeerFlag) - { - if (auto* peer = getPeer()) - { - peer->setVisible (shouldBeVisible); - internalHierarchyChanged(); - } - } - } - } -} - -void Component::visibilityChanged() {} - -void Component::sendVisibilityChangeMessage() -{ - BailOutChecker checker (this); - visibilityChanged(); - - if (! checker.shouldBailOut()) - componentListeners.callChecked (checker, &ComponentListener::componentVisibilityChanged, *this); -} - -bool Component::isShowing() const -{ - if (! flags.visibleFlag) - return false; - - if (parentComponent != nullptr) - return parentComponent->isShowing(); - - if (auto* peer = getPeer()) - return ! peer->isMinimised(); - - return false; -} - -//============================================================================== -void* Component::getWindowHandle() const -{ - if (auto* peer = getPeer()) - return peer->getNativeHandle(); - - return nullptr; -} - -//============================================================================== -void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - ASSERT_MESSAGE_MANAGER_IS_LOCKED - - if (isOpaque()) - styleWanted &= ~ComponentPeer::windowIsSemiTransparent; - else - styleWanted |= ComponentPeer::windowIsSemiTransparent; - - // don't use getPeer(), so that we only get the peer that's specifically - // for this comp, and not for one of its parents. - auto* peer = ComponentPeer::getPeerFor (this); - - if (peer == nullptr || styleWanted != peer->getStyleFlags()) - { - const WeakReference safePointer (this); - - #if JUCE_LINUX - // it's wise to give the component a non-zero size before - // putting it on the desktop, as X windows get confused by this, and - // a (1, 1) minimum size is enforced here. - setSize (jmax (1, getWidth()), - jmax (1, getHeight())); - #endif - - auto topLeft = getScreenPosition(); - - bool wasFullscreen = false; - bool wasMinimised = false; - ComponentBoundsConstrainer* currentConstrainer = nullptr; - Rectangle oldNonFullScreenBounds; - int oldRenderingEngine = -1; - - if (peer != nullptr) - { - ScopedPointer oldPeerToDelete (peer); - - wasFullscreen = peer->isFullScreen(); - wasMinimised = peer->isMinimised(); - currentConstrainer = peer->getConstrainer(); - oldNonFullScreenBounds = peer->getNonFullScreenBounds(); - oldRenderingEngine = peer->getCurrentRenderingEngine(); - - flags.hasHeavyweightPeerFlag = false; - Desktop::getInstance().removeDesktopComponent (this); - internalHierarchyChanged(); // give comps a chance to react to the peer change before the old peer is deleted. - - if (safePointer == nullptr) - return; - - setTopLeftPosition (topLeft); - } - - if (parentComponent != nullptr) - parentComponent->removeChildComponent (this); - - if (safePointer != nullptr) - { - flags.hasHeavyweightPeerFlag = true; - - peer = createNewPeer (styleWanted, nativeWindowToAttachTo); - - Desktop::getInstance().addDesktopComponent (this); - - boundsRelativeToParent.setPosition (topLeft); - peer->updateBounds(); - - if (oldRenderingEngine >= 0) - peer->setCurrentRenderingEngine (oldRenderingEngine); - - peer->setVisible (isVisible()); - - peer = ComponentPeer::getPeerFor (this); - if (peer == nullptr) - return; - - if (wasFullscreen) - { - peer->setFullScreen (true); - peer->setNonFullScreenBounds (oldNonFullScreenBounds); - } - - if (wasMinimised) - peer->setMinimised (true); - - #if JUCE_WINDOWS - if (isAlwaysOnTop()) - peer->setAlwaysOnTop (true); - #endif - - peer->setConstrainer (currentConstrainer); - - repaint(); - internalHierarchyChanged(); - } - } -} - -void Component::removeFromDesktop() -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN - - if (flags.hasHeavyweightPeerFlag) - { - auto* peer = ComponentPeer::getPeerFor (this); - jassert (peer != nullptr); - - flags.hasHeavyweightPeerFlag = false; - delete peer; - - Desktop::getInstance().removeDesktopComponent (this); - } -} - -bool Component::isOnDesktop() const noexcept -{ - return flags.hasHeavyweightPeerFlag; -} - -ComponentPeer* Component::getPeer() const -{ - if (flags.hasHeavyweightPeerFlag) - return ComponentPeer::getPeerFor (this); - - if (parentComponent == nullptr) - return nullptr; - - return parentComponent->getPeer(); -} - -void Component::userTriedToCloseWindow() -{ - /* This means that the user's trying to get rid of your window with the 'close window' system - menu option (on windows) or possibly the task manager - you should really handle this - and delete or hide your component in an appropriate way. - - If you want to ignore the event and don't want to trigger this assertion, just override - this method and do nothing. - */ - jassertfalse; -} - -void Component::minimisationStateChanged (bool) {} - -float Component::getDesktopScaleFactor() const { return Desktop::getInstance().getGlobalScaleFactor(); } - -//============================================================================== -void Component::setOpaque (const bool shouldBeOpaque) -{ - if (shouldBeOpaque != flags.opaqueFlag) - { - flags.opaqueFlag = shouldBeOpaque; - - if (flags.hasHeavyweightPeerFlag) - if (auto* peer = ComponentPeer::getPeerFor (this)) - addToDesktop (peer->getStyleFlags()); // recreates the heavyweight window - - repaint(); - } -} - -bool Component::isOpaque() const noexcept -{ - return flags.opaqueFlag; -} - -//============================================================================== -class StandardCachedComponentImage : public CachedComponentImage -{ -public: - StandardCachedComponentImage (Component& c) noexcept : owner (c), scale (1.0f) {} - - void paint (Graphics& g) override - { - scale = g.getInternalContext().getPhysicalPixelScaleFactor(); - auto compBounds = owner.getLocalBounds(); - auto imageBounds = compBounds * scale; - - if (image.isNull() || image.getBounds() != imageBounds) - { - image = Image (owner.isOpaque() ? Image::RGB - : Image::ARGB, - jmax (1, imageBounds.getWidth()), - jmax (1, imageBounds.getHeight()), - ! owner.isOpaque()); - - validArea.clear(); - } - - if (! validArea.containsRectangle (compBounds)) - { - Graphics imG (image); - auto& lg = imG.getInternalContext(); - - lg.addTransform (AffineTransform::scale (scale)); - - for (auto& i : validArea) - lg.excludeClipRectangle (i); - - if (! owner.isOpaque()) - { - lg.setFill (Colours::transparentBlack); - lg.fillRect (compBounds, true); - lg.setFill (Colours::black); - } - - owner.paintEntireComponent (imG, true); - } - - validArea = compBounds; - - g.setColour (Colours::black.withAlpha (owner.getAlpha())); - g.drawImageTransformed (image, AffineTransform::scale (compBounds.getWidth() / (float) imageBounds.getWidth(), - compBounds.getHeight() / (float) imageBounds.getHeight()), false); - } - - bool invalidateAll() override { validArea.clear(); return true; } - bool invalidate (const Rectangle& area) override { validArea.subtract (area); return true; } - void releaseResources() override { image = Image(); } - -private: - Image image; - RectangleList validArea; - Component& owner; - float scale; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StandardCachedComponentImage) -}; - -void Component::setCachedComponentImage (CachedComponentImage* newCachedImage) -{ - if (cachedImage != newCachedImage) - { - cachedImage = newCachedImage; - repaint(); - } -} - -void Component::setBufferedToImage (const bool shouldBeBuffered) -{ - // This assertion means that this component is already using a custom CachedComponentImage, - // so by calling setBufferedToImage, you'll be deleting the custom one - this is almost certainly - // not what you wanted to happen... If you really do know what you're doing here, and want to - // avoid this assertion, just call setCachedComponentImage (nullptr) before setBufferedToImage(). - jassert (cachedImage == nullptr || dynamic_cast (cachedImage.get()) != nullptr); - - if (shouldBeBuffered) - { - if (cachedImage == nullptr) - cachedImage = new StandardCachedComponentImage (*this); - } - else - { - cachedImage = nullptr; - } -} - -//============================================================================== -void Component::reorderChildInternal (const int sourceIndex, const int destIndex) -{ - if (sourceIndex != destIndex) - { - auto* c = childComponentList.getUnchecked (sourceIndex); - jassert (c != nullptr); - c->repaintParent(); - - childComponentList.move (sourceIndex, destIndex); - - sendFakeMouseMove(); - internalChildrenChanged(); - } -} - -void Component::toFront (const bool setAsForeground) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN - - if (flags.hasHeavyweightPeerFlag) - { - if (auto* peer = getPeer()) - { - peer->toFront (setAsForeground); - - if (setAsForeground && ! hasKeyboardFocus (true)) - grabKeyboardFocus(); - } - } - else if (parentComponent != nullptr) - { - auto& childList = parentComponent->childComponentList; - - if (childList.getLast() != this) - { - auto index = childList.indexOf (this); - - if (index >= 0) - { - int insertIndex = -1; - - if (! flags.alwaysOnTopFlag) - { - insertIndex = childList.size() - 1; - - while (insertIndex > 0 && childList.getUnchecked (insertIndex)->isAlwaysOnTop()) - --insertIndex; - } - - parentComponent->reorderChildInternal (index, insertIndex); - } - } - - if (setAsForeground) - { - internalBroughtToFront(); - - if (isShowing()) - grabKeyboardFocus(); - } - } -} - -void Component::toBehind (Component* const other) -{ - if (other != nullptr && other != this) - { - // the two components must belong to the same parent.. - jassert (parentComponent == other->parentComponent); - - if (parentComponent != nullptr) - { - auto& childList = parentComponent->childComponentList; - auto index = childList.indexOf (this); - - if (index >= 0 && childList [index + 1] != other) - { - int otherIndex = childList.indexOf (other); - - if (otherIndex >= 0) - { - if (index < otherIndex) - --otherIndex; - - parentComponent->reorderChildInternal (index, otherIndex); - } - } - } - else if (isOnDesktop()) - { - jassert (other->isOnDesktop()); - - if (other->isOnDesktop()) - { - auto* us = getPeer(); - auto* them = other->getPeer(); - jassert (us != nullptr && them != nullptr); - - if (us != nullptr && them != nullptr) - us->toBehind (them); - } - } - } -} - -void Component::toBack() -{ - if (isOnDesktop()) - { - jassertfalse; //xxx need to add this to native window - } - else if (parentComponent != nullptr) - { - auto& childList = parentComponent->childComponentList; - - if (childList.getFirst() != this) - { - auto index = childList.indexOf (this); - - if (index > 0) - { - int insertIndex = 0; - - if (flags.alwaysOnTopFlag) - while (insertIndex < childList.size() && ! childList.getUnchecked (insertIndex)->isAlwaysOnTop()) - ++insertIndex; - - parentComponent->reorderChildInternal (index, insertIndex); - } - } - } -} - -void Component::setAlwaysOnTop (const bool shouldStayOnTop) -{ - if (shouldStayOnTop != flags.alwaysOnTopFlag) - { - BailOutChecker checker (this); - - flags.alwaysOnTopFlag = shouldStayOnTop; - - if (isOnDesktop()) - { - if (auto* peer = getPeer()) - { - if (! peer->setAlwaysOnTop (shouldStayOnTop)) - { - // some kinds of peer can't change their always-on-top status, so - // for these, we'll need to create a new window - auto oldFlags = peer->getStyleFlags(); - removeFromDesktop(); - addToDesktop (oldFlags); - } - } - } - - if (shouldStayOnTop && ! checker.shouldBailOut()) - toFront (false); - - if (! checker.shouldBailOut()) - internalHierarchyChanged(); - } -} - -bool Component::isAlwaysOnTop() const noexcept -{ - return flags.alwaysOnTopFlag; -} - -//============================================================================== -int Component::proportionOfWidth (const float proportion) const noexcept { return roundToInt (proportion * boundsRelativeToParent.getWidth()); } -int Component::proportionOfHeight (const float proportion) const noexcept { return roundToInt (proportion * boundsRelativeToParent.getHeight()); } - -int Component::getParentWidth() const noexcept -{ - return parentComponent != nullptr ? parentComponent->getWidth() - : getParentMonitorArea().getWidth(); -} - -int Component::getParentHeight() const noexcept -{ - return parentComponent != nullptr ? parentComponent->getHeight() - : getParentMonitorArea().getHeight(); -} - -int Component::getScreenX() const { return getScreenPosition().x; } -int Component::getScreenY() const { return getScreenPosition().y; } - -Point Component::getScreenPosition() const { return localPointToGlobal (Point()); } -Rectangle Component::getScreenBounds() const { return localAreaToGlobal (getLocalBounds()); } - -Rectangle Component::getParentMonitorArea() const -{ - return Desktop::getInstance().getDisplays().getDisplayContaining (getScreenBounds().getCentre()).userArea; -} - -Point Component::getLocalPoint (const Component* source, Point point) const -{ - return ComponentHelpers::convertCoordinate (this, source, point); -} - -Point Component::getLocalPoint (const Component* source, Point point) const -{ - return ComponentHelpers::convertCoordinate (this, source, point); -} - -Rectangle Component::getLocalArea (const Component* source, Rectangle area) const -{ - return ComponentHelpers::convertCoordinate (this, source, area); -} - -Point Component::localPointToGlobal (Point point) const -{ - return ComponentHelpers::convertCoordinate (nullptr, this, point); -} - -Point Component::localPointToGlobal (Point point) const -{ - return ComponentHelpers::convertCoordinate (nullptr, this, point); -} - -Rectangle Component::localAreaToGlobal (Rectangle area) const -{ - return ComponentHelpers::convertCoordinate (nullptr, this, area); -} - -// Deprecated methods... -Point Component::relativePositionToGlobal (Point relativePosition) const -{ - return localPointToGlobal (relativePosition); -} - -Point Component::globalPositionToRelative (Point screenPosition) const -{ - return getLocalPoint (nullptr, screenPosition); -} - -Point Component::relativePositionToOtherComponent (const Component* const targetComponent, Point positionRelativeToThis) const -{ - return targetComponent == nullptr ? localPointToGlobal (positionRelativeToThis) - : targetComponent->getLocalPoint (this, positionRelativeToThis); -} - - -//============================================================================== -void Component::setBounds (const int x, const int y, int w, int h) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN - - if (w < 0) w = 0; - if (h < 0) h = 0; - - const bool wasResized = (getWidth() != w || getHeight() != h); - const bool wasMoved = (getX() != x || getY() != y); - - #if JUCE_DEBUG - // It's a very bad idea to try to resize a window during its paint() method! - jassert (! (flags.isInsidePaintCall && wasResized && isOnDesktop())); - #endif - - if (wasMoved || wasResized) - { - const bool showing = isShowing(); - if (showing) - { - // send a fake mouse move to trigger enter/exit messages if needed.. - sendFakeMouseMove(); - - if (! flags.hasHeavyweightPeerFlag) - repaintParent(); - } - - boundsRelativeToParent.setBounds (x, y, w, h); - - if (showing) - { - if (wasResized) - repaint(); - else if (! flags.hasHeavyweightPeerFlag) - repaintParent(); - } - else if (cachedImage != nullptr) - { - cachedImage->invalidateAll(); - } - - flags.isMoveCallbackPending = wasMoved; - flags.isResizeCallbackPending = wasResized; - - if (flags.hasHeavyweightPeerFlag) - if (auto* peer = getPeer()) - peer->updateBounds(); - - sendMovedResizedMessagesIfPending(); - } -} - -void Component::sendMovedResizedMessagesIfPending() -{ - const bool wasMoved = flags.isMoveCallbackPending; - const bool wasResized = flags.isResizeCallbackPending; - - if (wasMoved || wasResized) - { - flags.isMoveCallbackPending = false; - flags.isResizeCallbackPending = false; - - sendMovedResizedMessages (wasMoved, wasResized); - } -} - -void Component::sendMovedResizedMessages (const bool wasMoved, const bool wasResized) -{ - BailOutChecker checker (this); - - if (wasMoved) - { - moved(); - - if (checker.shouldBailOut()) - return; - } - - if (wasResized) - { - resized(); - - if (checker.shouldBailOut()) - return; - - for (int i = childComponentList.size(); --i >= 0;) - { - childComponentList.getUnchecked(i)->parentSizeChanged(); - - if (checker.shouldBailOut()) - return; - - i = jmin (i, childComponentList.size()); - } - } - - if (parentComponent != nullptr) - parentComponent->childBoundsChanged (this); - - if (! checker.shouldBailOut()) - componentListeners.callChecked (checker, &ComponentListener::componentMovedOrResized, - *this, wasMoved, wasResized); -} - -void Component::setSize (int w, int h) -{ - setBounds (getX(), getY(), w, h); -} - -void Component::setTopLeftPosition (int x, int y) -{ - setBounds (x, y, getWidth(), getHeight()); -} - -void Component::setTopLeftPosition (Point pos) -{ - setBounds (pos.x, pos.y, getWidth(), getHeight()); -} - -void Component::setTopRightPosition (const int x, const int y) -{ - setTopLeftPosition (x - getWidth(), y); -} - -void Component::setBounds (Rectangle r) -{ - setBounds (r.getX(), r.getY(), r.getWidth(), r.getHeight()); -} - -void Component::setBounds (const RelativeRectangle& newBounds) -{ - newBounds.applyToComponent (*this); -} - -void Component::setBounds (const String& newBoundsExpression) -{ - RelativeRectangle (newBoundsExpression).applyToComponent (*this); -} - -void Component::setBoundsRelative (const float x, const float y, - const float w, const float h) -{ - auto pw = getParentWidth(); - auto ph = getParentHeight(); - - setBounds (roundToInt (x * pw), - roundToInt (y * ph), - roundToInt (w * pw), - roundToInt (h * ph)); -} - -void Component::setCentrePosition (Point p) { setBounds (getBounds().withCentre (p)); } -void Component::setCentrePosition (int x, int y) { setCentrePosition ({x, y}); } - -void Component::setCentreRelative (float x, float y) -{ - setCentrePosition (roundToInt (getParentWidth() * x), - roundToInt (getParentHeight() * y)); -} - -void Component::centreWithSize (const int width, const int height) -{ - auto parentArea = ComponentHelpers::getParentOrMainMonitorBounds (*this); - - setBounds (parentArea.getCentreX() - width / 2, - parentArea.getCentreY() - height / 2, - width, height); -} - -void Component::setBoundsInset (BorderSize borders) -{ - setBounds (borders.subtractedFrom (ComponentHelpers::getParentOrMainMonitorBounds (*this))); -} - -void Component::setBoundsToFit (int x, int y, int width, int height, - Justification justification, - const bool onlyReduceInSize) -{ - // it's no good calling this method unless both the component and - // target rectangle have a finite size. - jassert (getWidth() > 0 && getHeight() > 0 && width > 0 && height > 0); - - if (getWidth() > 0 && getHeight() > 0 - && width > 0 && height > 0) - { - int newW, newH; - - if (onlyReduceInSize && getWidth() <= width && getHeight() <= height) - { - newW = getWidth(); - newH = getHeight(); - } - else - { - const double imageRatio = getHeight() / (double) getWidth(); - const double targetRatio = height / (double) width; - - if (imageRatio <= targetRatio) - { - newW = width; - newH = jmin (height, roundToInt (newW * imageRatio)); - } - else - { - newH = height; - newW = jmin (width, roundToInt (newH / imageRatio)); - } - } - - if (newW > 0 && newH > 0) - setBounds (justification.appliedToRectangle (Rectangle (newW, newH), - Rectangle (x, y, width, height))); - } -} - -//============================================================================== -void Component::setTransform (const AffineTransform& newTransform) -{ - // If you pass in a transform with no inverse, the component will have no dimensions, - // and there will be all sorts of maths errors when converting coordinates. - jassert (! newTransform.isSingularity()); - - if (newTransform.isIdentity()) - { - if (affineTransform != nullptr) - { - repaint(); - affineTransform = nullptr; - repaint(); - - sendMovedResizedMessages (false, false); - } - } - else if (affineTransform == nullptr) - { - repaint(); - affineTransform = new AffineTransform (newTransform); - repaint(); - sendMovedResizedMessages (false, false); - } - else if (*affineTransform != newTransform) - { - repaint(); - *affineTransform = newTransform; - repaint(); - sendMovedResizedMessages (false, false); - } -} - -bool Component::isTransformed() const noexcept -{ - return affineTransform != nullptr; -} - -AffineTransform Component::getTransform() const -{ - return affineTransform != nullptr ? *affineTransform : AffineTransform(); -} - -//============================================================================== -bool Component::hitTest (int x, int y) -{ - if (! flags.ignoresMouseClicksFlag) - return true; - - if (flags.allowChildMouseClicksFlag) - { - for (int i = childComponentList.size(); --i >= 0;) - { - auto& child = *childComponentList.getUnchecked (i); - - if (child.isVisible() - && ComponentHelpers::hitTest (child, ComponentHelpers::convertFromParentSpace (child, Point (x, y)))) - return true; - } - } - - return false; -} - -void Component::setInterceptsMouseClicks (const bool allowClicks, - const bool allowClicksOnChildComponents) noexcept -{ - flags.ignoresMouseClicksFlag = ! allowClicks; - flags.allowChildMouseClicksFlag = allowClicksOnChildComponents; -} - -void Component::getInterceptsMouseClicks (bool& allowsClicksOnThisComponent, - bool& allowsClicksOnChildComponents) const noexcept -{ - allowsClicksOnThisComponent = ! flags.ignoresMouseClicksFlag; - allowsClicksOnChildComponents = flags.allowChildMouseClicksFlag; -} - -bool Component::contains (Point point) -{ - if (ComponentHelpers::hitTest (*this, point)) - { - if (parentComponent != nullptr) - return parentComponent->contains (ComponentHelpers::convertToParentSpace (*this, point)); - - if (flags.hasHeavyweightPeerFlag) - if (auto* peer = getPeer()) - return peer->contains (ComponentHelpers::localPositionToRawPeerPos (*this, point), true); - } - - return false; -} - -bool Component::reallyContains (Point point, const bool returnTrueIfWithinAChild) -{ - if (! contains (point)) - return false; - - auto* top = getTopLevelComponent(); - auto* compAtPosition = top->getComponentAt (top->getLocalPoint (this, point)); - - return (compAtPosition == this) || (returnTrueIfWithinAChild && isParentOf (compAtPosition)); -} - -Component* Component::getComponentAt (Point position) -{ - if (flags.visibleFlag && ComponentHelpers::hitTest (*this, position)) - { - for (int i = childComponentList.size(); --i >= 0;) - { - auto* child = childComponentList.getUnchecked(i); - - child = child->getComponentAt (ComponentHelpers::convertFromParentSpace (*child, position)); - - if (child != nullptr) - return child; - } - - return this; - } - - return nullptr; -} - -Component* Component::getComponentAt (const int x, const int y) -{ - return getComponentAt ({ x, y }); -} - -//============================================================================== -void Component::addChildComponent (Component& child, int zOrder) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN - - if (child.parentComponent != this) - { - if (child.parentComponent != nullptr) - child.parentComponent->removeChildComponent (&child); - else - child.removeFromDesktop(); - - child.parentComponent = this; - - if (child.isVisible()) - child.repaintParent(); - - if (! child.isAlwaysOnTop()) - { - if (zOrder < 0 || zOrder > childComponentList.size()) - zOrder = childComponentList.size(); - - while (zOrder > 0) - { - if (! childComponentList.getUnchecked (zOrder - 1)->isAlwaysOnTop()) - break; - - --zOrder; - } - } - - childComponentList.insert (zOrder, &child); - - child.internalHierarchyChanged(); - internalChildrenChanged(); - } -} - -void Component::addAndMakeVisible (Component& child, int zOrder) -{ - child.setVisible (true); - addChildComponent (child, zOrder); -} - -void Component::addChildComponent (Component* const child, int zOrder) -{ - if (child != nullptr) - addChildComponent (*child, zOrder); -} - -void Component::addAndMakeVisible (Component* const child, int zOrder) -{ - if (child != nullptr) - addAndMakeVisible (*child, zOrder); -} - -void Component::addChildAndSetID (Component* const child, const String& childID) -{ - if (child != nullptr) - { - child->setComponentID (childID); - addAndMakeVisible (child); - } -} - -void Component::removeChildComponent (Component* const child) -{ - removeChildComponent (childComponentList.indexOf (child), true, true); -} - -Component* Component::removeChildComponent (const int index) -{ - return removeChildComponent (index, true, true); -} - -Component* Component::removeChildComponent (const int index, bool sendParentEvents, const bool sendChildEvents) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN - - auto* child = childComponentList [index]; - - if (child != nullptr) - { - sendParentEvents = sendParentEvents && child->isShowing(); - - if (sendParentEvents) - { - sendFakeMouseMove(); - - if (child->isVisible()) - child->repaintParent(); - } - - childComponentList.remove (index); - child->parentComponent = nullptr; - - ComponentHelpers::releaseAllCachedImageResources (*child); - - // (NB: there are obscure situations where child->isShowing() = false, but it still has the focus) - if (currentlyFocusedComponent == child || child->isParentOf (currentlyFocusedComponent)) - { - if (sendParentEvents) - { - const WeakReference thisPointer (this); - - giveAwayFocus (sendChildEvents || currentlyFocusedComponent != child); - - if (thisPointer == nullptr) - return child; - - grabKeyboardFocus(); - } - else - { - giveAwayFocus (sendChildEvents || currentlyFocusedComponent != child); - } - } - - if (sendChildEvents) - child->internalHierarchyChanged(); - - if (sendParentEvents) - internalChildrenChanged(); - } - - return child; -} - -//============================================================================== -void Component::removeAllChildren() -{ - while (childComponentList.size() > 0) - removeChildComponent (childComponentList.size() - 1); -} - -void Component::deleteAllChildren() -{ - while (childComponentList.size() > 0) - delete (removeChildComponent (childComponentList.size() - 1)); -} - -int Component::getNumChildComponents() const noexcept -{ - return childComponentList.size(); -} - -Component* Component::getChildComponent (const int index) const noexcept -{ - return childComponentList[index]; -} - -int Component::getIndexOfChildComponent (const Component* const child) const noexcept -{ - return childComponentList.indexOf (const_cast (child)); -} - -Component* Component::findChildWithID (StringRef targetID) const noexcept -{ - for (auto* c : childComponentList) - if (c->componentID == targetID) - return c; - - return nullptr; -} - -Component* Component::getTopLevelComponent() const noexcept -{ - const Component* comp = this; - - while (comp->parentComponent != nullptr) - comp = comp->parentComponent; - - return const_cast (comp); -} - -bool Component::isParentOf (const Component* possibleChild) const noexcept -{ - while (possibleChild != nullptr) - { - possibleChild = possibleChild->parentComponent; - - if (possibleChild == this) - return true; - } - - return false; -} - -//============================================================================== -void Component::parentHierarchyChanged() {} -void Component::childrenChanged() {} - -void Component::internalChildrenChanged() -{ - if (componentListeners.isEmpty()) - { - childrenChanged(); - } - else - { - BailOutChecker checker (this); - - childrenChanged(); - - if (! checker.shouldBailOut()) - componentListeners.callChecked (checker, &ComponentListener::componentChildrenChanged, *this); - } -} - -void Component::internalHierarchyChanged() -{ - BailOutChecker checker (this); - - parentHierarchyChanged(); - - if (checker.shouldBailOut()) - return; - - componentListeners.callChecked (checker, &ComponentListener::componentParentHierarchyChanged, *this); - - if (checker.shouldBailOut()) - return; - - for (int i = childComponentList.size(); --i >= 0;) - { - childComponentList.getUnchecked (i)->internalHierarchyChanged(); - - if (checker.shouldBailOut()) - { - // you really shouldn't delete the parent component during a callback telling you - // that it's changed.. - jassertfalse; - return; - } - - i = jmin (i, childComponentList.size()); - } -} - -//============================================================================== -#if JUCE_MODAL_LOOPS_PERMITTED -int Component::runModalLoop() -{ - if (! MessageManager::getInstance()->isThisTheMessageThread()) - { - // use a callback so this can be called from non-gui threads - return (int) (pointer_sized_int) MessageManager::getInstance() - ->callFunctionOnMessageThread (&ComponentHelpers::runModalLoopCallback, this); - } - - if (! isCurrentlyModal (false)) - enterModalState (true); - - return ModalComponentManager::getInstance()->runEventLoopForCurrentComponent(); -} -#endif - -//============================================================================== -void Component::enterModalState (const bool shouldTakeKeyboardFocus, - ModalComponentManager::Callback* callback, - const bool deleteWhenDismissed) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - ASSERT_MESSAGE_MANAGER_IS_LOCKED - - if (! isCurrentlyModal (false)) - { - auto& mcm = *ModalComponentManager::getInstance(); - mcm.startModal (this, deleteWhenDismissed); - mcm.attachCallback (this, callback); - - setVisible (true); - - if (shouldTakeKeyboardFocus) - grabKeyboardFocus(); - } - else - { - // Probably a bad idea to try to make a component modal twice! - jassertfalse; - } -} - -void Component::exitModalState (const int returnValue) -{ - if (isCurrentlyModal (false)) - { - if (MessageManager::getInstance()->isThisTheMessageThread()) - { - auto& mcm = *ModalComponentManager::getInstance(); - mcm.endModal (this, returnValue); - mcm.bringModalComponentsToFront(); - - // If any of the mouse sources are over another Component when we exit the modal state then send a mouse enter event - for (auto& ms : Desktop::getInstance().getMouseSources()) - if (auto* c = ms.getComponentUnderMouse()) - c->internalMouseEnter (ms, ms.getScreenPosition(), Time::getCurrentTime()); - } - else - { - WeakReference target (this); - - MessageManager::callAsync ([=]() - { - if (auto* c = target.get()) - c->exitModalState (returnValue); - }); - } - } -} - -bool Component::isCurrentlyModal (bool onlyConsiderForemostModalComponent) const noexcept -{ - const int n = onlyConsiderForemostModalComponent ? 1 : getNumCurrentlyModalComponents(); - - for (int i = 0; i < n; ++i) - if (getCurrentlyModalComponent(i) == this) - return true; - - return false; -} - -bool Component::isCurrentlyBlockedByAnotherModalComponent() const -{ - auto* mc = getCurrentlyModalComponent(); - - return ! (mc == nullptr || mc == this || mc->isParentOf (this) - || mc->canModalEventBeSentToComponent (this)); -} - -int JUCE_CALLTYPE Component::getNumCurrentlyModalComponents() noexcept -{ - return ModalComponentManager::getInstance()->getNumModalComponents(); -} - -Component* JUCE_CALLTYPE Component::getCurrentlyModalComponent (int index) noexcept -{ - return ModalComponentManager::getInstance()->getModalComponent (index); -} - -//============================================================================== -void Component::setBroughtToFrontOnMouseClick (const bool shouldBeBroughtToFront) noexcept -{ - flags.bringToFrontOnClickFlag = shouldBeBroughtToFront; -} - -bool Component::isBroughtToFrontOnMouseClick() const noexcept -{ - return flags.bringToFrontOnClickFlag; -} - -//============================================================================== -void Component::setMouseCursor (const MouseCursor& newCursor) -{ - if (cursor != newCursor) - { - cursor = newCursor; - - if (flags.visibleFlag) - updateMouseCursor(); - } -} - -MouseCursor Component::getMouseCursor() -{ - return cursor; -} - -void Component::updateMouseCursor() const -{ - Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate(); -} - -//============================================================================== -void Component::setRepaintsOnMouseActivity (const bool shouldRepaint) noexcept -{ - flags.repaintOnMouseActivityFlag = shouldRepaint; -} - -//============================================================================== -float Component::getAlpha() const noexcept -{ - return (255 - componentTransparency) / 255.0f; -} - -void Component::setAlpha (const float newAlpha) -{ - const uint8 newIntAlpha = (uint8) (255 - jlimit (0, 255, roundToInt (newAlpha * 255.0))); - - if (componentTransparency != newIntAlpha) - { - componentTransparency = newIntAlpha; - alphaChanged(); - } -} - -void Component::alphaChanged() -{ - if (flags.hasHeavyweightPeerFlag) - { - if (auto* peer = getPeer()) - peer->setAlpha (getAlpha()); - } - else - { - repaint(); - } -} - -//============================================================================== -void Component::repaint() -{ - internalRepaintUnchecked (getLocalBounds(), true); -} - -void Component::repaint (const int x, const int y, const int w, const int h) -{ - internalRepaint ({ x, y, w, h }); -} - -void Component::repaint (Rectangle area) -{ - internalRepaint (area); -} - -void Component::repaintParent() -{ - if (parentComponent != nullptr) - parentComponent->internalRepaint (ComponentHelpers::convertToParentSpace (*this, getLocalBounds())); -} - -void Component::internalRepaint (Rectangle area) -{ - area = area.getIntersection (getLocalBounds()); - - if (! area.isEmpty()) - internalRepaintUnchecked (area, false); -} - -void Component::internalRepaintUnchecked (Rectangle area, const bool isEntireComponent) -{ - if (flags.visibleFlag) - { - if (cachedImage != nullptr) - if (! (isEntireComponent ? cachedImage->invalidateAll() - : cachedImage->invalidate (area))) - return; - - if (flags.hasHeavyweightPeerFlag) - { - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - ASSERT_MESSAGE_MANAGER_IS_LOCKED - - if (auto* peer = getPeer()) - { - // Tweak the scaling so that the component's integer size exactly aligns with the peer's scaled size - auto peerBounds = peer->getBounds(); - auto scaled = area * Point (peerBounds.getWidth() / (float) getWidth(), - peerBounds.getHeight() / (float) getHeight()); - - peer->repaint (affineTransform != nullptr ? scaled.transformedBy (*affineTransform) : scaled); - } - } - else - { - if (parentComponent != nullptr) - parentComponent->internalRepaint (ComponentHelpers::convertToParentSpace (*this, area)); - } - } -} - -//============================================================================== -void Component::paint (Graphics&) -{ - // if your component is marked as opaque, you must implement a paint - // method and ensure that its entire area is completely painted. - jassert (getBounds().isEmpty() || ! isOpaque()); -} - -void Component::paintOverChildren (Graphics&) -{ - // all painting is done in the subclasses -} - -//============================================================================== -void Component::paintWithinParentContext (Graphics& g) -{ - g.setOrigin (getPosition()); - - if (cachedImage != nullptr) - cachedImage->paint (g); - else - paintEntireComponent (g, false); -} - -void Component::paintComponentAndChildren (Graphics& g) -{ - auto clipBounds = g.getClipBounds(); - - if (flags.dontClipGraphicsFlag) - { - paint (g); - } - else - { - g.saveState(); - - if (! (ComponentHelpers::clipObscuredRegions (*this, g, clipBounds, {}) && g.isClipEmpty())) - paint (g); - - g.restoreState(); - } - - for (int i = 0; i < childComponentList.size(); ++i) - { - auto& child = *childComponentList.getUnchecked (i); - - if (child.isVisible()) - { - if (child.affineTransform != nullptr) - { - g.saveState(); - g.addTransform (*child.affineTransform); - - if ((child.flags.dontClipGraphicsFlag && ! g.isClipEmpty()) || g.reduceClipRegion (child.getBounds())) - child.paintWithinParentContext (g); - - g.restoreState(); - } - else if (clipBounds.intersects (child.getBounds())) - { - g.saveState(); - - if (child.flags.dontClipGraphicsFlag) - { - child.paintWithinParentContext (g); - } - else if (g.reduceClipRegion (child.getBounds())) - { - bool nothingClipped = true; - - for (int j = i + 1; j < childComponentList.size(); ++j) - { - auto& sibling = *childComponentList.getUnchecked (j); - - if (sibling.flags.opaqueFlag && sibling.isVisible() && sibling.affineTransform == nullptr) - { - nothingClipped = false; - g.excludeClipRegion (sibling.getBounds()); - } - } - - if (nothingClipped || ! g.isClipEmpty()) - child.paintWithinParentContext (g); - } - - g.restoreState(); - } - } - } - - g.saveState(); - paintOverChildren (g); - g.restoreState(); -} - -void Component::paintEntireComponent (Graphics& g, const bool ignoreAlphaLevel) -{ - // If sizing a top-level-window and the OS paint message is delivered synchronously - // before resized() is called, then we'll invoke the callback here, to make sure - // the components inside have had a chance to sort their sizes out.. - #if JUCE_DEBUG - if (! flags.isInsidePaintCall) // (avoids an assertion in plugins hosted in WaveLab) - #endif - sendMovedResizedMessagesIfPending(); - - #if JUCE_DEBUG - flags.isInsidePaintCall = true; - #endif - - if (effect != nullptr) - { - auto scale = g.getInternalContext().getPhysicalPixelScaleFactor(); - - auto scaledBounds = getLocalBounds() * scale; - - Image effectImage (flags.opaqueFlag ? Image::RGB : Image::ARGB, - scaledBounds.getWidth(), scaledBounds.getHeight(), ! flags.opaqueFlag); - { - Graphics g2 (effectImage); - g2.addTransform (AffineTransform::scale (scaledBounds.getWidth() / (float) getWidth(), - scaledBounds.getHeight() / (float) getHeight())); - paintComponentAndChildren (g2); - } - - g.saveState(); - g.addTransform (AffineTransform::scale (1.0f / scale)); - effect->applyEffect (effectImage, g, scale, ignoreAlphaLevel ? 1.0f : getAlpha()); - g.restoreState(); - } - else if (componentTransparency > 0 && ! ignoreAlphaLevel) - { - if (componentTransparency < 255) - { - g.beginTransparencyLayer (getAlpha()); - paintComponentAndChildren (g); - g.endTransparencyLayer(); - } - } - else - { - paintComponentAndChildren (g); - } - - #if JUCE_DEBUG - flags.isInsidePaintCall = false; - #endif -} - -void Component::setPaintingIsUnclipped (const bool shouldPaintWithoutClipping) noexcept -{ - flags.dontClipGraphicsFlag = shouldPaintWithoutClipping; -} - -//============================================================================== -Image Component::createComponentSnapshot (Rectangle areaToGrab, - bool clipImageToComponentBounds, float scaleFactor) -{ - auto r = areaToGrab; - - if (clipImageToComponentBounds) - r = r.getIntersection (getLocalBounds()); - - if (r.isEmpty()) - return Image(); - - const int w = roundToInt (scaleFactor * r.getWidth()); - const int h = roundToInt (scaleFactor * r.getHeight()); - - Image image (flags.opaqueFlag ? Image::RGB : Image::ARGB, w, h, true); - - Graphics g (image); - - if (w != getWidth() || h != getHeight()) - g.addTransform (AffineTransform::scale (w / (float) r.getWidth(), - h / (float) r.getHeight())); - g.setOrigin (-r.getPosition()); - - paintEntireComponent (g, true); - - return image; -} - -void Component::setComponentEffect (ImageEffectFilter* const newEffect) -{ - if (effect != newEffect) - { - effect = newEffect; - repaint(); - } -} - -//============================================================================== -LookAndFeel& Component::getLookAndFeel() const noexcept -{ - for (auto* c = this; c != nullptr; c = c->parentComponent) - if (c->lookAndFeel != nullptr) - return *(c->lookAndFeel); - - return LookAndFeel::getDefaultLookAndFeel(); -} - -void Component::setLookAndFeel (LookAndFeel* const newLookAndFeel) -{ - if (lookAndFeel != newLookAndFeel) - { - lookAndFeel = newLookAndFeel; - sendLookAndFeelChange(); - } -} - -void Component::lookAndFeelChanged() {} -void Component::colourChanged() {} - -void Component::sendLookAndFeelChange() -{ - const WeakReference safePointer (this); - repaint(); - lookAndFeelChanged(); - - if (safePointer != nullptr) - { - colourChanged(); - - if (safePointer != nullptr) - { - for (int i = childComponentList.size(); --i >= 0;) - { - childComponentList.getUnchecked (i)->sendLookAndFeelChange(); - - if (safePointer == nullptr) - return; - - i = jmin (i, childComponentList.size()); - } - } - } -} - -Colour Component::findColour (const int colourId, const bool inheritFromParent) const -{ - if (auto* v = properties.getVarPointer (ComponentHelpers::getColourPropertyId (colourId))) - return Colour ((uint32) static_cast (*v)); - - if (inheritFromParent && parentComponent != nullptr - && (lookAndFeel == nullptr || ! lookAndFeel->isColourSpecified (colourId))) - return parentComponent->findColour (colourId, true); - - return getLookAndFeel().findColour (colourId); -} - -bool Component::isColourSpecified (const int colourId) const -{ - return properties.contains (ComponentHelpers::getColourPropertyId (colourId)); -} - -void Component::removeColour (const int colourId) -{ - if (properties.remove (ComponentHelpers::getColourPropertyId (colourId))) - colourChanged(); -} - -void Component::setColour (const int colourId, Colour colour) -{ - if (properties.set (ComponentHelpers::getColourPropertyId (colourId), (int) colour.getARGB())) - colourChanged(); -} - -void Component::copyAllExplicitColoursTo (Component& target) const -{ - bool changed = false; - - for (int i = properties.size(); --i >= 0;) - { - auto name = properties.getName(i); - - if (name.toString().startsWith ("jcclr_")) - if (target.properties.set (name, properties [name])) - changed = true; - } - - if (changed) - target.colourChanged(); -} - -//============================================================================== -MarkerList* Component::getMarkers (bool /*xAxis*/) -{ - return nullptr; -} - -//============================================================================== -Component::Positioner::Positioner (Component& c) noexcept - : component (c) -{ -} - -Component::Positioner* Component::getPositioner() const noexcept -{ - return positioner; -} - -void Component::setPositioner (Positioner* newPositioner) -{ - // You can only assign a positioner to the component that it was created for! - jassert (newPositioner == nullptr || this == &(newPositioner->getComponent())); - positioner = newPositioner; -} - -//============================================================================== -Rectangle Component::getLocalBounds() const noexcept -{ - return boundsRelativeToParent.withZeroOrigin(); -} - -Rectangle Component::getBoundsInParent() const noexcept -{ - return affineTransform == nullptr ? boundsRelativeToParent - : boundsRelativeToParent.transformedBy (*affineTransform); -} - -//============================================================================== -void Component::mouseEnter (const MouseEvent&) {} -void Component::mouseExit (const MouseEvent&) {} -void Component::mouseDown (const MouseEvent&) {} -void Component::mouseUp (const MouseEvent&) {} -void Component::mouseDrag (const MouseEvent&) {} -void Component::mouseMove (const MouseEvent&) {} -void Component::mouseDoubleClick (const MouseEvent&) {} - -void Component::mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& wheel) -{ - // the base class just passes this event up to its parent.. - if (parentComponent != nullptr) - parentComponent->mouseWheelMove (e.getEventRelativeTo (parentComponent), wheel); -} - -void Component::mouseMagnify (const MouseEvent& e, float magnifyAmount) -{ - // the base class just passes this event up to its parent.. - if (parentComponent != nullptr) - parentComponent->mouseMagnify (e.getEventRelativeTo (parentComponent), magnifyAmount); -} - -//============================================================================== -void Component::resized() {} -void Component::moved() {} -void Component::childBoundsChanged (Component*) {} -void Component::parentSizeChanged() {} - -void Component::addComponentListener (ComponentListener* const newListener) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - #if JUCE_DEBUG || JUCE_LOG_ASSERTIONS - if (getParentComponent() != nullptr) - ASSERT_MESSAGE_MANAGER_IS_LOCKED; - #endif - - componentListeners.add (newListener); -} - -void Component::removeComponentListener (ComponentListener* const listenerToRemove) -{ - componentListeners.remove (listenerToRemove); -} - -//============================================================================== -void Component::inputAttemptWhenModal() -{ - ModalComponentManager::getInstance()->bringModalComponentsToFront(); - getLookAndFeel().playAlertSound(); -} - -bool Component::canModalEventBeSentToComponent (const Component*) -{ - return false; -} - -void Component::internalModalInputAttempt() -{ - if (auto* current = getCurrentlyModalComponent()) - current->inputAttemptWhenModal(); -} - -//============================================================================== -void Component::postCommandMessage (const int commandID) -{ - WeakReference target (this); - - MessageManager::callAsync ([=]() - { - if (auto* c = target.get()) - c->handleCommandMessage (commandID); - }); -} - -void Component::handleCommandMessage (int) -{ - // used by subclasses -} - -//============================================================================== -void Component::addMouseListener (MouseListener* const newListener, - const bool wantsEventsForAllNestedChildComponents) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - ASSERT_MESSAGE_MANAGER_IS_LOCKED - - // If you register a component as a mouselistener for itself, it'll receive all the events - // twice - once via the direct callback that all components get anyway, and then again as a listener! - jassert ((newListener != this) || wantsEventsForAllNestedChildComponents); - - if (mouseListeners == nullptr) - mouseListeners = new MouseListenerList(); - - mouseListeners->addListener (newListener, wantsEventsForAllNestedChildComponents); -} - -void Component::removeMouseListener (MouseListener* const listenerToRemove) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - ASSERT_MESSAGE_MANAGER_IS_LOCKED - - if (mouseListeners != nullptr) - mouseListeners->removeListener (listenerToRemove); -} - -//============================================================================== -void Component::internalMouseEnter (MouseInputSource source, Point relativePos, Time time) -{ - if (isCurrentlyBlockedByAnotherModalComponent()) - { - // if something else is modal, always just show a normal mouse cursor - source.showMouseCursor (MouseCursor::NormalCursor); - return; - } - - if (flags.repaintOnMouseActivityFlag) - repaint(); - - BailOutChecker checker (this); - - const MouseEvent me (source, relativePos, source.getCurrentModifiers(), MouseInputSource::invalidPressure, - MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation, - MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY, - this, this, time, relativePos, time, 0, false); - mouseEnter (me); - - if (checker.shouldBailOut()) - return; - - Desktop::getInstance().getMouseListeners().callChecked (checker, &MouseListener::mouseEnter, me); - - MouseListenerList::sendMouseEvent (*this, checker, &MouseListener::mouseEnter, me); -} - -void Component::internalMouseExit (MouseInputSource source, Point relativePos, Time time) -{ - if (isCurrentlyBlockedByAnotherModalComponent()) - { - // if something else is modal, always just show a normal mouse cursor - source.showMouseCursor (MouseCursor::NormalCursor); - return; - } - - if (flags.repaintOnMouseActivityFlag) - repaint(); - - BailOutChecker checker (this); - - const MouseEvent me (source, relativePos, source.getCurrentModifiers(), MouseInputSource::invalidPressure, - MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation, - MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY, - this, this, time, relativePos, time, 0, false); - - mouseExit (me); - - if (checker.shouldBailOut()) - return; - - Desktop::getInstance().getMouseListeners().callChecked (checker, &MouseListener::mouseExit, me); - - MouseListenerList::sendMouseEvent (*this, checker, &MouseListener::mouseExit, me); -} - -void Component::internalMouseDown (MouseInputSource source, Point relativePos, Time time, - float pressure, float orientation, float rotation, float tiltX, float tiltY) -{ - auto& desktop = Desktop::getInstance(); - BailOutChecker checker (this); - - if (isCurrentlyBlockedByAnotherModalComponent()) - { - flags.mouseDownWasBlocked = true; - internalModalInputAttempt(); - - if (checker.shouldBailOut()) - return; - - // If processing the input attempt has exited the modal loop, we'll allow the event - // to be delivered.. - if (isCurrentlyBlockedByAnotherModalComponent()) - { - // allow blocked mouse-events to go to global listeners.. - const MouseEvent me (source, relativePos, source.getCurrentModifiers(), pressure, - orientation, rotation, tiltX, tiltY, this, this, time, relativePos, - time, source.getNumberOfMultipleClicks(), false); - - desktop.getMouseListeners().callChecked (checker, &MouseListener::mouseDown, me); - return; - } - } - - flags.mouseDownWasBlocked = false; - - for (auto* c = this; c != nullptr; c = c->parentComponent) - { - if (c->isBroughtToFrontOnMouseClick()) - { - c->toFront (true); - - if (checker.shouldBailOut()) - return; - } - } - - if (! flags.dontFocusOnMouseClickFlag) - { - grabFocusInternal (focusChangedByMouseClick, true); - - if (checker.shouldBailOut()) - return; - } - - if (flags.repaintOnMouseActivityFlag) - repaint(); - - const MouseEvent me (source, relativePos, source.getCurrentModifiers(), pressure, - orientation, rotation, tiltX, tiltY, this, this, time, relativePos, - time, source.getNumberOfMultipleClicks(), false); - mouseDown (me); - - if (checker.shouldBailOut()) - return; - - desktop.getMouseListeners().callChecked (checker, &MouseListener::mouseDown, me); - - MouseListenerList::sendMouseEvent (*this, checker, &MouseListener::mouseDown, me); -} - -void Component::internalMouseUp (MouseInputSource source, Point relativePos, Time time, - const ModifierKeys oldModifiers, float pressure, float orientation, float rotation, float tiltX, float tiltY) -{ - if (flags.mouseDownWasBlocked && isCurrentlyBlockedByAnotherModalComponent()) - return; - - BailOutChecker checker (this); - - if (flags.repaintOnMouseActivityFlag) - repaint(); - - const MouseEvent me (source, relativePos, oldModifiers, pressure, orientation, - rotation, tiltX, tiltY, this, this, time, - getLocalPoint (nullptr, source.getLastMouseDownPosition()), - source.getLastMouseDownTime(), - source.getNumberOfMultipleClicks(), - source.hasMouseMovedSignificantlySincePressed()); - mouseUp (me); - - if (checker.shouldBailOut()) - return; - - auto& desktop = Desktop::getInstance(); - desktop.getMouseListeners().callChecked (checker, &MouseListener::mouseUp, me); - - MouseListenerList::sendMouseEvent (*this, checker, &MouseListener::mouseUp, me); - - if (checker.shouldBailOut()) - return; - - // check for double-click - if (me.getNumberOfClicks() >= 2) - { - mouseDoubleClick (me); - - if (checker.shouldBailOut()) - return; - - desktop.mouseListeners.callChecked (checker, &MouseListener::mouseDoubleClick, me); - MouseListenerList::sendMouseEvent (*this, checker, &MouseListener::mouseDoubleClick, me); - } -} - -void Component::internalMouseDrag (MouseInputSource source, Point relativePos, Time time, - float pressure, float orientation, float rotation, float tiltX, float tiltY) -{ - if (! isCurrentlyBlockedByAnotherModalComponent()) - { - BailOutChecker checker (this); - - const MouseEvent me (source, relativePos, source.getCurrentModifiers(), - pressure, orientation, rotation, tiltX, tiltY, this, this, time, - getLocalPoint (nullptr, source.getLastMouseDownPosition()), - source.getLastMouseDownTime(), - source.getNumberOfMultipleClicks(), - source.hasMouseMovedSignificantlySincePressed()); - mouseDrag (me); - - if (checker.shouldBailOut()) - return; - - Desktop::getInstance().getMouseListeners().callChecked (checker, &MouseListener::mouseDrag, me); - - MouseListenerList::sendMouseEvent (*this, checker, &MouseListener::mouseDrag, me); - } -} - -void Component::internalMouseMove (MouseInputSource source, Point relativePos, Time time) -{ - auto& desktop = Desktop::getInstance(); - - if (isCurrentlyBlockedByAnotherModalComponent()) - { - // allow blocked mouse-events to go to global listeners.. - desktop.sendMouseMove(); - } - else - { - BailOutChecker checker (this); - - const MouseEvent me (source, relativePos, source.getCurrentModifiers(), MouseInputSource::invalidPressure, - MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation, - MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY, - this, this, time, relativePos, time, 0, false); - mouseMove (me); - - if (checker.shouldBailOut()) - return; - - desktop.getMouseListeners().callChecked (checker, &MouseListener::mouseMove, me); - - MouseListenerList::sendMouseEvent (*this, checker, &MouseListener::mouseMove, me); - } -} - -void Component::internalMouseWheel (MouseInputSource source, Point relativePos, - Time time, const MouseWheelDetails& wheel) -{ - auto& desktop = Desktop::getInstance(); - BailOutChecker checker (this); - - const MouseEvent me (source, relativePos, source.getCurrentModifiers(), MouseInputSource::invalidPressure, - MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation, - MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY, - this, this, time, relativePos, time, 0, false); - - if (isCurrentlyBlockedByAnotherModalComponent()) - { - // allow blocked mouse-events to go to global listeners.. - desktop.mouseListeners.callChecked (checker, &MouseListener::mouseWheelMove, me, wheel); - } - else - { - mouseWheelMove (me, wheel); - - if (checker.shouldBailOut()) - return; - - desktop.mouseListeners.callChecked (checker, &MouseListener::mouseWheelMove, me, wheel); - - if (! checker.shouldBailOut()) - MouseListenerList::sendWheelEvent (*this, checker, me, wheel); - } -} - -void Component::internalMagnifyGesture (MouseInputSource source, Point relativePos, - Time time, float amount) -{ - if (! isCurrentlyBlockedByAnotherModalComponent()) - { - const MouseEvent me (source, relativePos, source.getCurrentModifiers(), MouseInputSource::invalidPressure, - MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation, - MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY, - this, this, time, relativePos, time, 0, false); - - mouseMagnify (me, amount); - } -} - -void Component::sendFakeMouseMove() const -{ - MouseInputSource mainMouse = Desktop::getInstance().getMainMouseSource(); - - if (! mainMouse.isDragging()) - mainMouse.triggerFakeMove(); -} - -void JUCE_CALLTYPE Component::beginDragAutoRepeat (const int interval) -{ - Desktop::getInstance().beginDragAutoRepeat (interval); -} - -//============================================================================== -void Component::broughtToFront() -{ -} - -void Component::internalBroughtToFront() -{ - if (flags.hasHeavyweightPeerFlag) - Desktop::getInstance().componentBroughtToFront (this); - - BailOutChecker checker (this); - broughtToFront(); - - if (checker.shouldBailOut()) - return; - - componentListeners.callChecked (checker, &ComponentListener::componentBroughtToFront, *this); - - if (checker.shouldBailOut()) - return; - - // When brought to the front and there's a modal component blocking this one, - // we need to bring the modal one to the front instead.. - if (auto* cm = getCurrentlyModalComponent()) - if (cm->getTopLevelComponent() != getTopLevelComponent()) - ModalComponentManager::getInstance()->bringModalComponentsToFront (false); // very important that this is false, otherwise in Windows, - // non-front components can't get focus when another modal comp is - // active, and therefore can't receive mouse-clicks -} - -//============================================================================== -void Component::focusGained (FocusChangeType) {} -void Component::focusLost (FocusChangeType) {} -void Component::focusOfChildComponentChanged (FocusChangeType) {} - -void Component::internalFocusGain (const FocusChangeType cause) -{ - internalFocusGain (cause, WeakReference (this)); -} - -void Component::internalFocusGain (const FocusChangeType cause, const WeakReference& safePointer) -{ - focusGained (cause); - - if (safePointer != nullptr) - internalChildFocusChange (cause, safePointer); -} - -void Component::internalFocusLoss (const FocusChangeType cause) -{ - const WeakReference safePointer (this); - - focusLost (cause); - - if (safePointer != nullptr) - internalChildFocusChange (cause, safePointer); -} - -void Component::internalChildFocusChange (FocusChangeType cause, const WeakReference& safePointer) -{ - const bool childIsNowFocused = hasKeyboardFocus (true); - - if (flags.childCompFocusedFlag != childIsNowFocused) - { - flags.childCompFocusedFlag = childIsNowFocused; - - focusOfChildComponentChanged (cause); - - if (safePointer == nullptr) - return; - } - - if (parentComponent != nullptr) - parentComponent->internalChildFocusChange (cause, WeakReference (parentComponent)); -} - -void Component::setWantsKeyboardFocus (const bool wantsFocus) noexcept -{ - flags.wantsFocusFlag = wantsFocus; -} - -void Component::setMouseClickGrabsKeyboardFocus (const bool shouldGrabFocus) -{ - flags.dontFocusOnMouseClickFlag = ! shouldGrabFocus; -} - -bool Component::getMouseClickGrabsKeyboardFocus() const noexcept -{ - return ! flags.dontFocusOnMouseClickFlag; -} - -bool Component::getWantsKeyboardFocus() const noexcept -{ - return flags.wantsFocusFlag && ! flags.isDisabledFlag; -} - -void Component::setFocusContainer (const bool shouldBeFocusContainer) noexcept -{ - flags.isFocusContainerFlag = shouldBeFocusContainer; -} - -bool Component::isFocusContainer() const noexcept -{ - return flags.isFocusContainerFlag; -} - -static const Identifier juce_explicitFocusOrderId ("_jexfo"); - -int Component::getExplicitFocusOrder() const -{ - return properties [juce_explicitFocusOrderId]; -} - -void Component::setExplicitFocusOrder (const int newFocusOrderIndex) -{ - properties.set (juce_explicitFocusOrderId, newFocusOrderIndex); -} - -KeyboardFocusTraverser* Component::createFocusTraverser() -{ - if (flags.isFocusContainerFlag || parentComponent == nullptr) - return new KeyboardFocusTraverser(); - - return parentComponent->createFocusTraverser(); -} - -void Component::takeKeyboardFocus (const FocusChangeType cause) -{ - // give the focus to this component - if (currentlyFocusedComponent != this) - { - // get the focus onto our desktop window - if (auto* peer = getPeer()) - { - const WeakReference safePointer (this); - peer->grabFocus(); - - if (peer->isFocused() && currentlyFocusedComponent != this) - { - WeakReference componentLosingFocus (currentlyFocusedComponent); - currentlyFocusedComponent = this; - - Desktop::getInstance().triggerFocusCallback(); - - // call this after setting currentlyFocusedComponent so that the one that's - // losing it has a chance to see where focus is going - if (componentLosingFocus != nullptr) - componentLosingFocus->internalFocusLoss (cause); - - if (currentlyFocusedComponent == this) - internalFocusGain (cause, safePointer); - } - } - } -} - -void Component::grabFocusInternal (const FocusChangeType cause, const bool canTryParent) -{ - if (isShowing()) - { - if (flags.wantsFocusFlag && (isEnabled() || parentComponent == nullptr)) - { - takeKeyboardFocus (cause); - } - else - { - if (isParentOf (currentlyFocusedComponent) - && currentlyFocusedComponent->isShowing()) - { - // do nothing if the focused component is actually a child of ours.. - } - else - { - // find the default child component.. - ScopedPointer traverser (createFocusTraverser()); - - if (traverser != nullptr) - { - auto* defaultComp = traverser->getDefaultComponent (this); - traverser = nullptr; - - if (defaultComp != nullptr) - { - defaultComp->grabFocusInternal (cause, false); - return; - } - } - - if (canTryParent && parentComponent != nullptr) - { - // if no children want it and we're allowed to try our parent comp, - // then pass up to parent, which will try our siblings. - parentComponent->grabFocusInternal (cause, true); - } - } - } - } -} - -void Component::grabKeyboardFocus() -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - ASSERT_MESSAGE_MANAGER_IS_LOCKED - - grabFocusInternal (focusChangedDirectly, true); - - // A component can only be focused when it's actually on the screen! - // If this fails then you're probably trying to grab the focus before you've - // added the component to a parent or made it visible. Or maybe one of its parent - // components isn't yet visible. - jassert (isShowing() || isOnDesktop()); -} - -void Component::moveKeyboardFocusToSibling (const bool moveToNext) -{ - // if component methods are being called from threads other than the message - // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. - ASSERT_MESSAGE_MANAGER_IS_LOCKED - - if (parentComponent != nullptr) - { - if (ScopedPointer traverser = createFocusTraverser()) - { - auto* nextComp = moveToNext ? traverser->getNextComponent (this) - : traverser->getPreviousComponent (this); - traverser = nullptr; - - if (nextComp != nullptr) - { - if (nextComp->isCurrentlyBlockedByAnotherModalComponent()) - { - const WeakReference nextCompPointer (nextComp); - internalModalInputAttempt(); - - if (nextCompPointer == nullptr || nextComp->isCurrentlyBlockedByAnotherModalComponent()) - return; - } - - nextComp->grabFocusInternal (focusChangedByTabKey, true); - return; - } - } - - parentComponent->moveKeyboardFocusToSibling (moveToNext); - } -} - -bool Component::hasKeyboardFocus (const bool trueIfChildIsFocused) const -{ - return (currentlyFocusedComponent == this) - || (trueIfChildIsFocused && isParentOf (currentlyFocusedComponent)); -} - -Component* JUCE_CALLTYPE Component::getCurrentlyFocusedComponent() noexcept -{ - return currentlyFocusedComponent; -} - -void JUCE_CALLTYPE Component::unfocusAllComponents() -{ - if (auto* c = getCurrentlyFocusedComponent()) - c->giveAwayFocus (true); -} - -void Component::giveAwayFocus (const bool sendFocusLossEvent) -{ - auto* componentLosingFocus = currentlyFocusedComponent; - currentlyFocusedComponent = nullptr; - - if (sendFocusLossEvent && componentLosingFocus != nullptr) - componentLosingFocus->internalFocusLoss (focusChangedDirectly); - - Desktop::getInstance().triggerFocusCallback(); -} - -//============================================================================== -bool Component::isEnabled() const noexcept -{ - return (! flags.isDisabledFlag) - && (parentComponent == nullptr || parentComponent->isEnabled()); -} - -void Component::setEnabled (const bool shouldBeEnabled) -{ - if (flags.isDisabledFlag == shouldBeEnabled) - { - flags.isDisabledFlag = ! shouldBeEnabled; - - // if any parent components are disabled, setting our flag won't make a difference, - // so no need to send a change message - if (parentComponent == nullptr || parentComponent->isEnabled()) - sendEnablementChangeMessage(); - } -} - -void Component::enablementChanged() {} - -void Component::sendEnablementChangeMessage() -{ - const WeakReference safePointer (this); - - enablementChanged(); - - if (safePointer == nullptr) - return; - - for (int i = getNumChildComponents(); --i >= 0;) - { - if (auto* c = getChildComponent (i)) - { - c->sendEnablementChangeMessage(); - - if (safePointer == nullptr) - return; - } - } -} - -//============================================================================== -bool Component::isMouseOver (const bool includeChildren) const -{ - for (auto& ms : Desktop::getInstance().getMouseSources()) - { - auto* c = ms.getComponentUnderMouse(); - - if ((c == this || (includeChildren && isParentOf (c))) - && c->reallyContains (c->getLocalPoint (nullptr, ms.getScreenPosition()).roundToInt(), false) - && ((! ms.isTouch()) || ms.isDragging())) - return true; - } - - return false; -} - -bool Component::isMouseButtonDown() const -{ - for (auto& ms : Desktop::getInstance().getMouseSources()) - if (ms.isDragging() && ms.getComponentUnderMouse() == this) - return true; - - return false; -} - -bool Component::isMouseOverOrDragging (const bool includeChildren) const -{ - for (auto& ms : Desktop::getInstance().getMouseSources()) - { - auto* c = ms.getComponentUnderMouse(); - - if ((c == this || (includeChildren && isParentOf (c))) - && ((! ms.isTouch()) || ms.isDragging())) - return true; - } - - return false; -} - -bool JUCE_CALLTYPE Component::isMouseButtonDownAnywhere() noexcept -{ - return ModifierKeys::getCurrentModifiers().isAnyMouseButtonDown(); -} - -Point Component::getMouseXYRelative() const -{ - return getLocalPoint (nullptr, Desktop::getMousePosition()); -} - -//============================================================================== -void Component::addKeyListener (KeyListener* const newListener) -{ - if (keyListeners == nullptr) - keyListeners = new Array(); - - keyListeners->addIfNotAlreadyThere (newListener); -} - -void Component::removeKeyListener (KeyListener* const listenerToRemove) -{ - if (keyListeners != nullptr) - keyListeners->removeFirstMatchingValue (listenerToRemove); -} - -bool Component::keyPressed (const KeyPress&) { return false; } -bool Component::keyStateChanged (const bool /*isKeyDown*/) { return false; } - -void Component::modifierKeysChanged (const ModifierKeys& modifiers) -{ - if (parentComponent != nullptr) - parentComponent->modifierKeysChanged (modifiers); -} - -void Component::internalModifierKeysChanged() -{ - sendFakeMouseMove(); - modifierKeysChanged (ModifierKeys::getCurrentModifiers()); -} - -//============================================================================== -Component::BailOutChecker::BailOutChecker (Component* const component) - : safePointer (component) -{ - jassert (component != nullptr); -} - -bool Component::BailOutChecker::shouldBailOut() const noexcept -{ - return safePointer == nullptr; -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/components/juce_Component.h b/source/modules/juce_gui_basics/components/juce_Component.h deleted file mode 100644 index 9c9c55a56..000000000 --- a/source/modules/juce_gui_basics/components/juce_Component.h +++ /dev/null @@ -1,2376 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - The base class for all JUCE user-interface objects. -*/ -class JUCE_API Component : public MouseListener -{ -public: - //============================================================================== - /** Creates a component. - - To get it to actually appear, you'll also need to: - - Either add it to a parent component or use the addToDesktop() method to - make it a desktop window - - Set its size and position to something sensible - - Use setVisible() to make it visible - - And for it to serve any useful purpose, you'll need to write a - subclass of Component or use one of the other types of component from - the library. - */ - Component() noexcept; - - /** Destructor. - - Note that when a component is deleted, any child components it contains are NOT - automatically deleted. It's your responsibilty to manage their lifespan - you - may want to use helper methods like deleteAllChildren(), or less haphazard - approaches like using ScopedPointers or normal object aggregation to manage them. - - If the component being deleted is currently the child of another one, then during - deletion, it will be removed from its parent, and the parent will receive a childrenChanged() - callback. Any ComponentListener objects that have registered with it will also have their - ComponentListener::componentBeingDeleted() methods called. - */ - virtual ~Component(); - - //============================================================================== - /** Creates a component, setting its name at the same time. - @see getName, setName - */ - explicit Component (const String& componentName) noexcept; - - /** Returns the name of this component. - @see setName - */ - const String& getName() const noexcept { return componentName; } - - /** Sets the name of this component. - - When the name changes, all registered ComponentListeners will receive a - ComponentListener::componentNameChanged() callback. - - @see getName - */ - virtual void setName (const String& newName); - - /** Returns the ID string that was set by setComponentID(). - @see setComponentID, findChildWithID - */ - const String& getComponentID() const noexcept { return componentID; } - - /** Sets the component's ID string. - You can retrieve the ID using getComponentID(). - @see getComponentID, findChildWithID - */ - void setComponentID (const String& newID); - - //============================================================================== - /** Makes the component visible or invisible. - - This method will show or hide the component. - Note that components default to being non-visible when first created. - Also note that visible components won't be seen unless all their parent components - are also visible. - - This method will call visibilityChanged() and also componentVisibilityChanged() - for any component listeners that are interested in this component. - - @param shouldBeVisible whether to show or hide the component - @see isVisible, isShowing, visibilityChanged, ComponentListener::componentVisibilityChanged - */ - virtual void setVisible (bool shouldBeVisible); - - /** Tests whether the component is visible or not. - - this doesn't necessarily tell you whether this comp is actually on the screen - because this depends on whether all the parent components are also visible - use - isShowing() to find this out. - - @see isShowing, setVisible - */ - bool isVisible() const noexcept { return flags.visibleFlag; } - - /** Called when this component's visibility changes. - @see setVisible, isVisible - */ - virtual void visibilityChanged(); - - /** Tests whether this component and all its parents are visible. - - @returns true only if this component and all its parents are visible. - @see isVisible - */ - bool isShowing() const; - - //============================================================================== - /** Makes this component appear as a window on the desktop. - - Note that before calling this, you should make sure that the component's opacity is - set correctly using setOpaque(). If the component is non-opaque, the windowing - system will try to create a special transparent window for it, which will generally take - a lot more CPU to operate (and might not even be possible on some platforms). - - If the component is inside a parent component at the time this method is called, it - will be first be removed from that parent. Likewise if a component on the desktop - is subsequently added to another component, it'll be removed from the desktop. - - @param windowStyleFlags a combination of the flags specified in the - ComponentPeer::StyleFlags enum, which define the - window's characteristics. - @param nativeWindowToAttachTo this allows an OS object to be passed-in as the window - in which the juce component should place itself. On Windows, - this would be a HWND, a HIViewRef on the Mac. Not necessarily - supported on all platforms, and best left as 0 unless you know - what you're doing - @see removeFromDesktop, isOnDesktop, userTriedToCloseWindow, - getPeer, ComponentPeer::setMinimised, ComponentPeer::StyleFlags, - ComponentPeer::getStyleFlags, ComponentPeer::setFullScreen - */ - virtual void addToDesktop (int windowStyleFlags, - void* nativeWindowToAttachTo = nullptr); - - /** If the component is currently showing on the desktop, this will hide it. - - You can also use setVisible() to hide a desktop window temporarily, but - removeFromDesktop() will free any system resources that are being used up. - - @see addToDesktop, isOnDesktop - */ - void removeFromDesktop(); - - /** Returns true if this component is currently showing on the desktop. - @see addToDesktop, removeFromDesktop - */ - bool isOnDesktop() const noexcept; - - /** Returns the heavyweight window that contains this component. - - If this component is itself on the desktop, this will return the window - object that it is using. Otherwise, it will return the window of - its top-level parent component. - - This may return nullptr if there isn't a desktop component. - - @see addToDesktop, isOnDesktop - */ - ComponentPeer* getPeer() const; - - /** For components on the desktop, this is called if the system wants to close the window. - - This is a signal that either the user or the system wants the window to close. The - default implementation of this method will trigger an assertion to warn you that your - component should do something about it, but you can override this to ignore the event - if you want. - */ - virtual void userTriedToCloseWindow(); - - /** Called for a desktop component which has just been minimised or un-minimised. - This will only be called for components on the desktop. - @see getPeer, ComponentPeer::setMinimised, ComponentPeer::isMinimised - */ - virtual void minimisationStateChanged (bool isNowMinimised); - - /** Returns the default scale factor to use for this component when it is placed - on the desktop. - The default implementation of this method just returns the value from - Desktop::getGlobalScaleFactor(), but it can be overridden if a particular component - has different requirements. The method only used if this component is added - to the desktop - it has no effect for child components. - */ - virtual float getDesktopScaleFactor() const; - - //============================================================================== - /** Brings the component to the front of its siblings. - - If some of the component's siblings have had their 'always-on-top' flag set, - then they will still be kept in front of this one (unless of course this - one is also 'always-on-top'). - - @param shouldAlsoGainFocus if true, this will also try to assign keyboard focus - to the component (see grabKeyboardFocus() for more details) - @see toBack, toBehind, setAlwaysOnTop - */ - void toFront (bool shouldAlsoGainFocus); - - /** Changes this component's z-order to be at the back of all its siblings. - - If the component is set to be 'always-on-top', it will only be moved to the - back of the other other 'always-on-top' components. - - @see toFront, toBehind, setAlwaysOnTop - */ - void toBack(); - - /** Changes this component's z-order so that it's just behind another component. - @see toFront, toBack - */ - void toBehind (Component* other); - - /** Sets whether the component should always be kept at the front of its siblings. - @see isAlwaysOnTop - */ - void setAlwaysOnTop (bool shouldStayOnTop); - - /** Returns true if this component is set to always stay in front of its siblings. - @see setAlwaysOnTop - */ - bool isAlwaysOnTop() const noexcept; - - //============================================================================== - /** Returns the x coordinate of the component's left edge. - This is a distance in pixels from the left edge of the component's parent. - - Note that if you've used setTransform() to apply a transform, then the component's - bounds will no longer be a direct reflection of the position at which it appears within - its parent, as the transform will be applied to its bounding box. - */ - int getX() const noexcept { return boundsRelativeToParent.getX(); } - - /** Returns the y coordinate of the top of this component. - This is a distance in pixels from the top edge of the component's parent. - - Note that if you've used setTransform() to apply a transform, then the component's - bounds will no longer be a direct reflection of the position at which it appears within - its parent, as the transform will be applied to its bounding box. - */ - int getY() const noexcept { return boundsRelativeToParent.getY(); } - - /** Returns the component's width in pixels. */ - int getWidth() const noexcept { return boundsRelativeToParent.getWidth(); } - - /** Returns the component's height in pixels. */ - int getHeight() const noexcept { return boundsRelativeToParent.getHeight(); } - - /** Returns the x coordinate of the component's right-hand edge. - This is a distance in pixels from the left edge of the component's parent. - - Note that if you've used setTransform() to apply a transform, then the component's - bounds will no longer be a direct reflection of the position at which it appears within - its parent, as the transform will be applied to its bounding box. - */ - int getRight() const noexcept { return boundsRelativeToParent.getRight(); } - - /** Returns the component's top-left position as a Point. */ - Point getPosition() const noexcept { return boundsRelativeToParent.getPosition(); } - - /** Returns the y coordinate of the bottom edge of this component. - This is a distance in pixels from the top edge of the component's parent. - - Note that if you've used setTransform() to apply a transform, then the component's - bounds will no longer be a direct reflection of the position at which it appears within - its parent, as the transform will be applied to its bounding box. - */ - int getBottom() const noexcept { return boundsRelativeToParent.getBottom(); } - - /** Returns this component's bounding box. - The rectangle returned is relative to the top-left of the component's parent. - - Note that if you've used setTransform() to apply a transform, then the component's - bounds will no longer be a direct reflection of the position at which it appears within - its parent, as the transform will be applied to its bounding box. - */ - Rectangle getBounds() const noexcept { return boundsRelativeToParent; } - - /** Returns the component's bounds, relative to its own origin. - This is like getBounds(), but returns the rectangle in local coordinates, In practice, it'll - return a rectangle with position (0, 0), and the same size as this component. - */ - Rectangle getLocalBounds() const noexcept; - - /** Returns the area of this component's parent which this component covers. - - The returned area is relative to the parent's coordinate space. - If the component has an affine transform specified, then the resulting area will be - the smallest rectangle that fully covers the component's transformed bounding box. - If this component has no parent, the return value will simply be the same as getBounds(). - */ - Rectangle getBoundsInParent() const noexcept; - - //============================================================================== - /** Returns this component's x coordinate relative the screen's top-left origin. - @see getX, localPointToGlobal - */ - int getScreenX() const; - - /** Returns this component's y coordinate relative the screen's top-left origin. - @see getY, localPointToGlobal - */ - int getScreenY() const; - - /** Returns the position of this component's top-left corner relative to the screen's top-left. - @see getScreenBounds - */ - Point getScreenPosition() const; - - /** Returns the bounds of this component, relative to the screen's top-left. - @see getScreenPosition - */ - Rectangle getScreenBounds() const; - - /** Converts a point to be relative to this component's coordinate space. - - This takes a point relative to a different component, and returns its position relative to this - component. If the sourceComponent parameter is null, the source point is assumed to be a global - screen coordinate. - */ - Point getLocalPoint (const Component* sourceComponent, - Point pointRelativeToSourceComponent) const; - - /** Converts a point to be relative to this component's coordinate space. - - This takes a point relative to a different component, and returns its position relative to this - component. If the sourceComponent parameter is null, the source point is assumed to be a global - screen coordinate. - */ - Point getLocalPoint (const Component* sourceComponent, - Point pointRelativeToSourceComponent) const; - - /** Converts a rectangle to be relative to this component's coordinate space. - - This takes a rectangle that is relative to a different component, and returns its position relative - to this component. If the sourceComponent parameter is null, the source rectangle is assumed to be - a screen coordinate. - - If you've used setTransform() to apply one or more transforms to components, then the source rectangle - may not actually be rectanglular when converted to the target space, so in that situation this will return - the smallest rectangle that fully contains the transformed area. - */ - Rectangle getLocalArea (const Component* sourceComponent, - Rectangle areaRelativeToSourceComponent) const; - - /** Converts a point relative to this component's top-left into a screen coordinate. - @see getLocalPoint, localAreaToGlobal - */ - Point localPointToGlobal (Point localPoint) const; - - /** Converts a point relative to this component's top-left into a screen coordinate. - @see getLocalPoint, localAreaToGlobal - */ - Point localPointToGlobal (Point localPoint) const; - - /** Converts a rectangle from this component's coordinate space to a screen coordinate. - - If you've used setTransform() to apply one or more transforms to components, then the source rectangle - may not actually be rectanglular when converted to the target space, so in that situation this will return - the smallest rectangle that fully contains the transformed area. - @see getLocalPoint, localPointToGlobal - */ - Rectangle localAreaToGlobal (Rectangle localArea) const; - - //============================================================================== - /** Moves the component to a new position. - - Changes the component's top-left position (without changing its size). - The position is relative to the top-left of the component's parent. - - If the component actually moves, this method will make a synchronous call to moved(). - - Note that if you've used setTransform() to apply a transform, then the component's - bounds will no longer be a direct reflection of the position at which it appears within - its parent, as the transform will be applied to whatever bounds you set for it. - - @see setBounds, ComponentListener::componentMovedOrResized - */ - void setTopLeftPosition (int x, int y); - - /** Moves the component to a new position. - - Changes the component's top-left position (without changing its size). - The position is relative to the top-left of the component's parent. - - If the component actually moves, this method will make a synchronous call to moved(). - - Note that if you've used setTransform() to apply a transform, then the component's - bounds will no longer be a direct reflection of the position at which it appears within - its parent, as the transform will be applied to whatever bounds you set for it. - - @see setBounds, ComponentListener::componentMovedOrResized - */ - void setTopLeftPosition (Point newTopLeftPosition); - - /** Moves the component to a new position. - - Changes the position of the component's top-right corner (keeping it the same size). - The position is relative to the top-left of the component's parent. - - If the component actually moves, this method will make a synchronous call to moved(). - - Note that if you've used setTransform() to apply a transform, then the component's - bounds will no longer be a direct reflection of the position at which it appears within - its parent, as the transform will be applied to whatever bounds you set for it. - */ - void setTopRightPosition (int x, int y); - - /** Changes the size of the component. - - A synchronous call to resized() will occur if the size actually changes. - - Note that if you've used setTransform() to apply a transform, then the component's - bounds will no longer be a direct reflection of the position at which it appears within - its parent, as the transform will be applied to whatever bounds you set for it. - */ - void setSize (int newWidth, int newHeight); - - /** Changes the component's position and size. - - The coordinates are relative to the top-left of the component's parent, or relative - to the origin of the screen if the component is on the desktop. - - If this method changes the component's top-left position, it will make a synchronous - call to moved(). If it changes the size, it will also make a call to resized(). - - Note that if you've used setTransform() to apply a transform, then the component's - bounds will no longer be a direct reflection of the position at which it appears within - its parent, as the transform will be applied to whatever bounds you set for it. - - @see setTopLeftPosition, setSize, ComponentListener::componentMovedOrResized - */ - void setBounds (int x, int y, int width, int height); - - /** Changes the component's position and size. - - The coordinates are relative to the top-left of the component's parent, or relative - to the origin of the screen if the component is on the desktop. - - If this method changes the component's top-left position, it will make a synchronous - call to moved(). If it changes the size, it will also make a call to resized(). - - Note that if you've used setTransform() to apply a transform, then the component's - bounds will no longer be a direct reflection of the position at which it appears within - its parent, as the transform will be applied to whatever bounds you set for it. - - @see setBounds - */ - void setBounds (Rectangle newBounds); - - /** Changes the component's position and size in terms of fractions of its parent's size. - - The values are factors of the parent's size, so for example - setBoundsRelative (0.2f, 0.2f, 0.5f, 0.5f) would give it half the - width and height of the parent, with its top-left position 20% of - the way across and down the parent. - - @see setBounds - */ - void setBoundsRelative (float proportionalX, float proportionalY, - float proportionalWidth, float proportionalHeight); - - /** Changes the component's position and size based on the amount of space to leave around it. - - This will position the component within its parent, leaving the specified number of - pixels around each edge. - - @see setBounds - */ - void setBoundsInset (BorderSize borders); - - /** Positions the component within a given rectangle, keeping its proportions - unchanged. - - If onlyReduceInSize is false, the component will be resized to fill as much of the - rectangle as possible without changing its aspect ratio (the component's - current size is used to determine its aspect ratio, so a zero-size component - won't work here). If onlyReduceInSize is true, it will only be resized if it's - too big to fit inside the rectangle. - - It will then be positioned within the rectangle according to the justification flags - specified. - - @see setBounds - */ - void setBoundsToFit (int x, int y, int width, int height, - Justification justification, - bool onlyReduceInSize); - - /** Changes the position of the component's centre. - - Leaves the component's size unchanged, but sets the position of its centre - relative to its parent's top-left. - - @see setBounds - */ - void setCentrePosition (int x, int y); - - /** Changes the position of the component's centre. - - Leaves the component's size unchanged, but sets the position of its centre - relative to its parent's top-left. - - @see setBounds - */ - void setCentrePosition (Point newCentrePosition); - - /** Changes the position of the component's centre. - - Leaves the size unchanged, but positions its centre relative to its parent's size. - E.g. setCentreRelative (0.5f, 0.5f) would place it centrally in its parent. - */ - void setCentreRelative (float x, float y); - - /** Changes the component's size and centres it within its parent. - - After changing the size, the component will be moved so that it's - centred within its parent. If the component is on the desktop (or has no - parent component), then it'll be centred within the main monitor area. - */ - void centreWithSize (int width, int height); - - //============================================================================== - /** Sets a transform matrix to be applied to this component. - - If you set a transform for a component, the component's position will be warped by it, relative to - the component's parent's top-left origin. This means that the values you pass into setBounds() will no - longer reflect the actual area within the parent that the component covers, as the bounds will be - transformed and the component will probably end up actually appearing somewhere else within its parent. - - When using transforms you need to be extremely careful when converting coordinates between the - coordinate spaces of different components or the screen - you should always use getLocalPoint(), - getLocalArea(), etc to do this, and never just manually add a component's position to a point in order to - convert it between different components (but I'm sure you would never have done that anyway...). - - Currently, transforms are not supported for desktop windows, so the transform will be ignored if you - put a component on the desktop. - - To remove a component's transform, simply pass AffineTransform() as the parameter to this method. - */ - void setTransform (const AffineTransform& transform); - - /** Returns the transform that is currently being applied to this component. - For more details about transforms, see setTransform(). - @see setTransform - */ - AffineTransform getTransform() const; - - /** Returns true if a non-identity transform is being applied to this component. - For more details about transforms, see setTransform(). - @see setTransform - */ - bool isTransformed() const noexcept; - - //============================================================================== - /** Returns a proportion of the component's width. - This is a handy equivalent of (getWidth() * proportion). - */ - int proportionOfWidth (float proportion) const noexcept; - - /** Returns a proportion of the component's height. - This is a handy equivalent of (getHeight() * proportion). - */ - int proportionOfHeight (float proportion) const noexcept; - - /** Returns the width of the component's parent. - - If the component has no parent (i.e. if it's on the desktop), this will return - the width of the screen. - */ - int getParentWidth() const noexcept; - - /** Returns the height of the component's parent. - - If the component has no parent (i.e. if it's on the desktop), this will return - the height of the screen. - */ - int getParentHeight() const noexcept; - - /** Returns the screen coordinates of the monitor that contains this component. - - If there's only one monitor, this will return its size - if there are multiple - monitors, it will return the area of the monitor that contains the component's - centre. - */ - Rectangle getParentMonitorArea() const; - - //============================================================================== - /** Returns the number of child components that this component contains. - - @see getChildren, getChildComponent, getIndexOfChildComponent - */ - int getNumChildComponents() const noexcept; - - /** Returns one of this component's child components, by it index. - - The component with index 0 is at the back of the z-order, the one at the - front will have index (getNumChildComponents() - 1). - - If the index is out-of-range, this will return a null pointer. - - @see getChildren, getNumChildComponents, getIndexOfChildComponent - */ - Component* getChildComponent (int index) const noexcept; - - /** Returns the index of this component in the list of child components. - - A value of 0 means it is first in the list (i.e. behind all other components). Higher - values are further towards the front. - - Returns -1 if the component passed-in is not a child of this component. - - @see getChildren, getNumChildComponents, getChildComponent, addChildComponent, toFront, toBack, toBehind - */ - int getIndexOfChildComponent (const Component* child) const noexcept; - - /** Provides access to the underlying array of child components. - The most likely reason you may want to use this is for iteration in a range-based for loop. - */ - const Array& getChildren() const noexcept { return childComponentList; } - - /** Looks for a child component with the specified ID. - @see setComponentID, getComponentID - */ - Component* findChildWithID (StringRef componentID) const noexcept; - - /** Adds a child component to this one. - - Adding a child component does not mean that the component will own or delete the child - it's - your responsibility to delete the component. Note that it's safe to delete a component - without first removing it from its parent - doing so will automatically remove it and - send out the appropriate notifications before the deletion completes. - - If the child is already a child of this component, then no action will be taken, and its - z-order will be left unchanged. - - @param child the new component to add. If the component passed-in is already - the child of another component, it'll first be removed from it current parent. - @param zOrder The index in the child-list at which this component should be inserted. - A value of -1 will insert it in front of the others, 0 is the back. - @see removeChildComponent, addAndMakeVisible, addChildAndSetID, getChild, ComponentListener::componentChildrenChanged - */ - void addChildComponent (Component* child, int zOrder = -1); - - /** Adds a child component to this one. - - Adding a child component does not mean that the component will own or delete the child - it's - your responsibility to delete the component. Note that it's safe to delete a component - without first removing it from its parent - doing so will automatically remove it and - send out the appropriate notifications before the deletion completes. - - If the child is already a child of this component, then no action will be taken, and its - z-order will be left unchanged. - - @param child the new component to add. If the component passed-in is already - the child of another component, it'll first be removed from it current parent. - @param zOrder The index in the child-list at which this component should be inserted. - A value of -1 will insert it in front of the others, 0 is the back. - @see removeChildComponent, addAndMakeVisible, addChildAndSetID, getChild, ComponentListener::componentChildrenChanged - */ - void addChildComponent (Component& child, int zOrder = -1); - - /** Adds a child component to this one, and also makes the child visible if it isn't already. - - This is the same as calling setVisible (true) on the child and then addChildComponent(). - See addChildComponent() for more details. - */ - void addAndMakeVisible (Component* child, int zOrder = -1); - - /** Adds a child component to this one, and also makes the child visible if it isn't already. - - This is the same as calling setVisible (true) on the child and then addChildComponent(). - See addChildComponent() for more details. - */ - void addAndMakeVisible (Component& child, int zOrder = -1); - - /** Adds a child component to this one, makes it visible, and sets its component ID. - @see addAndMakeVisible, addChildComponent - */ - void addChildAndSetID (Component* child, const String& componentID); - - /** Removes one of this component's child-components. - - If the child passed-in isn't actually a child of this component (either because - it's invalid or is the child of a different parent), then no action is taken. - - Note that removing a child will not delete it! But it's ok to delete a component - without first removing it - doing so will automatically remove it and send out the - appropriate notifications before the deletion completes. - - @see addChildComponent, ComponentListener::componentChildrenChanged - */ - void removeChildComponent (Component* childToRemove); - - /** Removes one of this component's child-components by index. - - This will return a pointer to the component that was removed, or null if - the index was out-of-range. - - Note that removing a child will not delete it! But it's ok to delete a component - without first removing it - doing so will automatically remove it and send out the - appropriate notifications before the deletion completes. - - @see addChildComponent, ComponentListener::componentChildrenChanged - */ - Component* removeChildComponent (int childIndexToRemove); - - /** Removes all this component's children. - Note that this won't delete them! To do that, use deleteAllChildren() instead. - */ - void removeAllChildren(); - - /** Removes and deletes all of this component's children. - My advice is to avoid this method! It's an old function that is only kept here for - backwards-compatibility with legacy code, and should be viewed with extreme - suspicion by anyone attempting to write modern C++. In almost all cases, it's much - smarter to manage the lifetimes of your child components via modern RAII techniques - such as simply making them member variables, or using ScopedPointer, OwnedArray, etc - to manage their lifetimes appropriately. - @see removeAllChildren - */ - void deleteAllChildren(); - - /** Returns the component which this component is inside. - - If this is the highest-level component or hasn't yet been added to - a parent, this will return null. - */ - Component* getParentComponent() const noexcept { return parentComponent; } - - /** Searches the parent components for a component of a specified class. - - For example findParentComponentOfClass \() would return the first parent - component that can be dynamically cast to a MyComp, or will return nullptr if none - of the parents are suitable. - */ - template - TargetClass* findParentComponentOfClass() const - { - for (auto* p = parentComponent; p != nullptr; p = p->parentComponent) - if (auto* target = dynamic_cast (p)) - return target; - - return nullptr; - } - - /** Returns the highest-level component which contains this one or its parents. - - This will search upwards in the parent-hierarchy from this component, until it - finds the highest one that doesn't have a parent (i.e. is on the desktop or - not yet added to a parent), and will return that. - */ - Component* getTopLevelComponent() const noexcept; - - /** Checks whether a component is anywhere inside this component or its children. - - This will recursively check through this component's children to see if the - given component is anywhere inside. - */ - bool isParentOf (const Component* possibleChild) const noexcept; - - //============================================================================== - /** Called to indicate that the component's parents have changed. - - When a component is added or removed from its parent, this method will - be called on all of its children (recursively - so all children of its - children will also be called as well). - - Subclasses can override this if they need to react to this in some way. - - @see getParentComponent, isShowing, ComponentListener::componentParentHierarchyChanged - */ - virtual void parentHierarchyChanged(); - - /** Subclasses can use this callback to be told when children are added or removed, or - when their z-order changes. - @see parentHierarchyChanged, ComponentListener::componentChildrenChanged - */ - virtual void childrenChanged(); - - //============================================================================== - /** Tests whether a given point is inside the component. - - Overriding this method allows you to create components which only intercept - mouse-clicks within a user-defined area. - - This is called to find out whether a particular x, y coordinate is - considered to be inside the component or not, and is used by methods such - as contains() and getComponentAt() to work out which component - the mouse is clicked on. - - Components with custom shapes will probably want to override it to perform - some more complex hit-testing. - - The default implementation of this method returns either true or false, - depending on the value that was set by calling setInterceptsMouseClicks() (true - is the default return value). - - Note that the hit-test region is not related to the opacity with which - areas of a component are painted. - - Applications should never call hitTest() directly - instead use the - contains() method, because this will also test for occlusion by the - component's parent. - - Note that for components on the desktop, this method will be ignored, because it's - not always possible to implement this behaviour on all platforms. - - @param x the x coordinate to test, relative to the left hand edge of this - component. This value is guaranteed to be greater than or equal to - zero, and less than the component's width - @param y the y coordinate to test, relative to the top edge of this - component. This value is guaranteed to be greater than or equal to - zero, and less than the component's height - @returns true if the click is considered to be inside the component - @see setInterceptsMouseClicks, contains - */ - virtual bool hitTest (int x, int y); - - /** Changes the default return value for the hitTest() method. - - Setting this to false is an easy way to make a component pass its mouse-clicks - through to the components behind it. - - When a component is created, the default setting for this is true. - - @param allowClicksOnThisComponent if true, hitTest() will always return true; if false, it will - return false (or true for child components if allowClicksOnChildComponents - is true) - @param allowClicksOnChildComponents if this is true and allowClicksOnThisComponent is false, then child - components can be clicked on as normal but clicks on this component pass - straight through; if this is false and allowClicksOnThisComponent - is false, then neither this component nor any child components can - be clicked on - @see hitTest, getInterceptsMouseClicks - */ - void setInterceptsMouseClicks (bool allowClicksOnThisComponent, - bool allowClicksOnChildComponents) noexcept; - - /** Retrieves the current state of the mouse-click interception flags. - - On return, the two parameters are set to the state used in the last call to - setInterceptsMouseClicks(). - - @see setInterceptsMouseClicks - */ - void getInterceptsMouseClicks (bool& allowsClicksOnThisComponent, - bool& allowsClicksOnChildComponents) const noexcept; - - - /** Returns true if a given point lies within this component or one of its children. - - Never override this method! Use hitTest to create custom hit regions. - - @param localPoint the coordinate to test, relative to this component's top-left. - @returns true if the point is within the component's hit-test area, but only if - that part of the component isn't clipped by its parent component. Note - that this won't take into account any overlapping sibling components - which might be in the way - for that, see reallyContains() - @see hitTest, reallyContains, getComponentAt - */ - bool contains (Point localPoint); - - /** Returns true if a given point lies in this component, taking any overlapping - siblings into account. - - @param localPoint the coordinate to test, relative to this component's top-left. - @param returnTrueIfWithinAChild if the point actually lies within a child of this component, - this determines whether that is counted as a hit. - @see contains, getComponentAt - */ - bool reallyContains (Point localPoint, bool returnTrueIfWithinAChild); - - /** Returns the component at a certain point within this one. - - @param x the x coordinate to test, relative to this component's left edge. - @param y the y coordinate to test, relative to this component's top edge. - @returns the component that is at this position - which may be 0, this component, - or one of its children. Note that overlapping siblings that might actually - be in the way are not taken into account by this method - to account for these, - instead call getComponentAt on the top-level parent of this component. - @see hitTest, contains, reallyContains - */ - Component* getComponentAt (int x, int y); - - /** Returns the component at a certain point within this one. - - @param position the coordinate to test, relative to this component's top-left. - @returns the component that is at this position - which may be 0, this component, - or one of its children. Note that overlapping siblings that might actually - be in the way are not taken into account by this method - to account for these, - instead call getComponentAt on the top-level parent of this component. - @see hitTest, contains, reallyContains - */ - Component* getComponentAt (Point position); - - //============================================================================== - /** Marks the whole component as needing to be redrawn. - - Calling this will not do any repainting immediately, but will mark the component - as 'dirty'. At some point in the near future the operating system will send a paint - message, which will redraw all the dirty regions of all components. - There's no guarantee about how soon after calling repaint() the redraw will actually - happen, and other queued events may be delivered before a redraw is done. - - If the setBufferedToImage() method has been used to cause this component to use a - buffer, the repaint() call will invalidate the cached buffer. If setCachedComponentImage() - has been used to provide a custom image cache, that cache will be invalidated appropriately. - - To redraw just a subsection of the component rather than the whole thing, - use the repaint (int, int, int, int) method. - - @see paint - */ - void repaint(); - - /** Marks a subsection of this component as needing to be redrawn. - - Calling this will not do any repainting immediately, but will mark the given region - of the component as 'dirty'. At some point in the near future the operating system - will send a paint message, which will redraw all the dirty regions of all components. - There's no guarantee about how soon after calling repaint() the redraw will actually - happen, and other queued events may be delivered before a redraw is done. - - The region that is passed in will be clipped to keep it within the bounds of this - component. - - @see repaint() - */ - void repaint (int x, int y, int width, int height); - - /** Marks a subsection of this component as needing to be redrawn. - - Calling this will not do any repainting immediately, but will mark the given region - of the component as 'dirty'. At some point in the near future the operating system - will send a paint message, which will redraw all the dirty regions of all components. - There's no guarantee about how soon after calling repaint() the redraw will actually - happen, and other queued events may be delivered before a redraw is done. - - The region that is passed in will be clipped to keep it within the bounds of this - component. - - @see repaint() - */ - void repaint (Rectangle area); - - //============================================================================== - /** Makes the component use an internal buffer to optimise its redrawing. - - Setting this flag to true will cause the component to allocate an - internal buffer into which it paints itself and all its child components, so that - when asked to redraw itself, it can use this buffer rather than actually calling - the paint() method. - - Parts of the buffer are invalidated when repaint() is called on this component - or its children. The buffer is then repainted at the next paint() callback. - - @see repaint, paint, createComponentSnapshot - */ - void setBufferedToImage (bool shouldBeBuffered); - - /** Generates a snapshot of part of this component. - - This will return a new Image, the size of the rectangle specified, - containing a snapshot of the specified area of the component and all - its children. - - The image may or may not have an alpha-channel, depending on whether the - image is opaque or not. - - If the clipImageToComponentBounds parameter is true and the area is greater than - the size of the component, it'll be clipped. If clipImageToComponentBounds is false - then parts of the component beyond its bounds can be drawn. - - @see paintEntireComponent - */ - Image createComponentSnapshot (Rectangle areaToGrab, - bool clipImageToComponentBounds = true, - float scaleFactor = 1.0f); - - /** Draws this component and all its subcomponents onto the specified graphics - context. - - You should very rarely have to use this method, it's simply there in case you need - to draw a component with a custom graphics context for some reason, e.g. for - creating a snapshot of the component. - - It calls paint(), paintOverChildren() and recursively calls paintEntireComponent() - on its children in order to render the entire tree. - - The graphics context may be left in an undefined state after this method returns, - so you may need to reset it if you're going to use it again. - - If ignoreAlphaLevel is false, then the component will be drawn with the opacity level - specified by getAlpha(); if ignoreAlphaLevel is true, then this will be ignored and - an alpha of 1.0 will be used. - */ - void paintEntireComponent (Graphics& context, bool ignoreAlphaLevel); - - /** This allows you to indicate that this component doesn't require its graphics - context to be clipped when it is being painted. - - Most people will never need to use this setting, but in situations where you have a very large - number of simple components being rendered, and where they are guaranteed never to do any drawing - beyond their own boundaries, setting this to true will reduce the overhead involved in clipping - the graphics context that gets passed to the component's paint() callback. - If you enable this mode, you'll need to make sure your paint method doesn't call anything like - Graphics::fillAll(), and doesn't draw beyond the component's bounds, because that'll produce - artifacts. Your component also can't have any child components that may be placed beyond its - bounds. - */ - void setPaintingIsUnclipped (bool shouldPaintWithoutClipping) noexcept; - - //============================================================================== - /** Adds an effect filter to alter the component's appearance. - - When a component has an effect filter set, then this is applied to the - results of its paint() method. There are a few preset effects, such as - a drop-shadow or glow, but they can be user-defined as well. - - The effect that is passed in will not be deleted by the component - the - caller must take care of deleting it. - - To remove an effect from a component, pass a null pointer in as the parameter. - - @see ImageEffectFilter, DropShadowEffect, GlowEffect - */ - void setComponentEffect (ImageEffectFilter* newEffect); - - /** Returns the current component effect. - @see setComponentEffect - */ - ImageEffectFilter* getComponentEffect() const noexcept { return effect; } - - //============================================================================== - /** Finds the appropriate look-and-feel to use for this component. - - If the component hasn't had a look-and-feel explicitly set, this will - return the parent's look-and-feel, or just the default one if there's no - parent. - - @see setLookAndFeel, lookAndFeelChanged - */ - LookAndFeel& getLookAndFeel() const noexcept; - - /** Sets the look and feel to use for this component. - - This will also change the look and feel for any child components that haven't - had their look set explicitly. - - The object passed in will not be deleted by the component, so it's the caller's - responsibility to manage it. It may be used at any time until this component - has been deleted. - - Calling this method will also invoke the sendLookAndFeelChange() method. - - @see getLookAndFeel, lookAndFeelChanged - */ - void setLookAndFeel (LookAndFeel* newLookAndFeel); - - /** Called to let the component react to a change in the look-and-feel setting. - - When the look-and-feel is changed for a component, this will be called in - all its child components, recursively. - - It can also be triggered manually by the sendLookAndFeelChange() method, in case - an application uses a LookAndFeel class that might have changed internally. - - @see sendLookAndFeelChange, getLookAndFeel - */ - virtual void lookAndFeelChanged(); - - /** Calls the lookAndFeelChanged() method in this component and all its children. - - This will recurse through the children and their children, calling lookAndFeelChanged() - on them all. - - @see lookAndFeelChanged - */ - void sendLookAndFeelChange(); - - //============================================================================== - /** Indicates whether any parts of the component might be transparent. - - Components that always paint all of their contents with solid colour and - thus completely cover any components behind them should use this method - to tell the repaint system that they are opaque. - - This information is used to optimise drawing, because it means that - objects underneath opaque windows don't need to be painted. - - By default, components are considered transparent, unless this is used to - make it otherwise. - - @see isOpaque - */ - void setOpaque (bool shouldBeOpaque); - - /** Returns true if no parts of this component are transparent. - - @returns the value that was set by setOpaque, (the default being false) - @see setOpaque - */ - bool isOpaque() const noexcept; - - //============================================================================== - /** Indicates whether the component should be brought to the front when clicked. - - Setting this flag to true will cause the component to be brought to the front - when the mouse is clicked somewhere inside it or its child components. - - Note that a top-level desktop window might still be brought to the front by the - operating system when it's clicked, depending on how the OS works. - - By default this is set to false. - - @see setMouseClickGrabsKeyboardFocus - */ - void setBroughtToFrontOnMouseClick (bool shouldBeBroughtToFront) noexcept; - - /** Indicates whether the component should be brought to the front when clicked-on. - @see setBroughtToFrontOnMouseClick - */ - bool isBroughtToFrontOnMouseClick() const noexcept; - - //============================================================================== - // Keyboard focus methods - - /** Sets a flag to indicate whether this component needs keyboard focus or not. - - By default components aren't actually interested in gaining the - focus, but this method can be used to turn this on. - - See the grabKeyboardFocus() method for details about the way a component - is chosen to receive the focus. - - @see grabKeyboardFocus, getWantsKeyboardFocus - */ - void setWantsKeyboardFocus (bool wantsFocus) noexcept; - - /** Returns true if the component is interested in getting keyboard focus. - - This returns the flag set by setWantsKeyboardFocus(). The default - setting is false. - - @see setWantsKeyboardFocus - */ - bool getWantsKeyboardFocus() const noexcept; - - //============================================================================== - /** Chooses whether a click on this component automatically grabs the focus. - - By default this is set to true, but you might want a component which can - be focused, but where you don't want the user to be able to affect it directly - by clicking. - */ - void setMouseClickGrabsKeyboardFocus (bool shouldGrabFocus); - - /** Returns the last value set with setMouseClickGrabsKeyboardFocus(). - See setMouseClickGrabsKeyboardFocus() for more info. - */ - bool getMouseClickGrabsKeyboardFocus() const noexcept; - - //============================================================================== - /** Tries to give keyboard focus to this component. - - When the user clicks on a component or its grabKeyboardFocus() - method is called, the following procedure is used to work out which - component should get it: - - - if the component that was clicked on actually wants focus (as indicated - by calling getWantsKeyboardFocus), it gets it. - - if the component itself doesn't want focus, it will try to pass it - on to whichever of its children is the default component, as determined by - KeyboardFocusTraverser::getDefaultComponent() - - if none of its children want focus at all, it will pass it up to its - parent instead, unless it's a top-level component without a parent, - in which case it just takes the focus itself. - - Important note! It's obviously not possible for a component to be focused - unless it's actually visible, on-screen, and inside a window that is also - visible. So there's no point trying to call this in the component's own - constructor or before all of its parent hierarchy has been fully instantiated. - - @see setWantsKeyboardFocus, getWantsKeyboardFocus, hasKeyboardFocus, - getCurrentlyFocusedComponent, focusGained, focusLost, - keyPressed, keyStateChanged - */ - void grabKeyboardFocus(); - - /** Returns true if this component currently has the keyboard focus. - - @param trueIfChildIsFocused if this is true, then the method returns true if - either this component or any of its children (recursively) - have the focus. If false, the method only returns true if - this component has the focus. - - @see grabKeyboardFocus, setWantsKeyboardFocus, getCurrentlyFocusedComponent, - focusGained, focusLost - */ - bool hasKeyboardFocus (bool trueIfChildIsFocused) const; - - /** Returns the component that currently has the keyboard focus. - @returns the focused component, or null if nothing is focused. - */ - static Component* JUCE_CALLTYPE getCurrentlyFocusedComponent() noexcept; - - /** If any component has keyboard focus, this will defocus it. */ - static void JUCE_CALLTYPE unfocusAllComponents(); - - //============================================================================== - /** Tries to move the keyboard focus to one of this component's siblings. - - This will try to move focus to either the next or previous component. (This - is the method that is used when shifting focus by pressing the tab key). - - Components for which getWantsKeyboardFocus() returns false are not looked at. - - @param moveToNext if true, the focus will move forwards; if false, it will - move backwards - @see grabKeyboardFocus, setFocusContainer, setWantsKeyboardFocus - */ - void moveKeyboardFocusToSibling (bool moveToNext); - - /** Creates a KeyboardFocusTraverser object to use to determine the logic by - which focus should be passed from this component. - - The default implementation of this method will return a default - KeyboardFocusTraverser if this component is a focus container (as determined - by the setFocusContainer() method). If the component isn't a focus - container, then it will recursively ask its parents for a KeyboardFocusTraverser. - - If you overrride this to return a custom KeyboardFocusTraverser, then - this component and all its sub-components will use the new object to - make their focusing decisions. - - The method should return a new object, which the caller is required to - delete when no longer needed. - */ - virtual KeyboardFocusTraverser* createFocusTraverser(); - - /** Returns the focus order of this component, if one has been specified. - - By default components don't have a focus order - in that case, this - will return 0. Lower numbers indicate that the component will be - earlier in the focus traversal order. - - To change the order, call setExplicitFocusOrder(). - - The focus order may be used by the KeyboardFocusTraverser class as part of - its algorithm for deciding the order in which components should be traversed. - See the KeyboardFocusTraverser class for more details on this. - - @see moveKeyboardFocusToSibling, createFocusTraverser, KeyboardFocusTraverser - */ - int getExplicitFocusOrder() const; - - /** Sets the index used in determining the order in which focusable components - should be traversed. - - A value of 0 or less is taken to mean that no explicit order is wanted, and - that traversal should use other factors, like the component's position. - - @see getExplicitFocusOrder, moveKeyboardFocusToSibling - */ - void setExplicitFocusOrder (int newFocusOrderIndex); - - /** Indicates whether this component is a parent for components that can have - their focus traversed. - - This flag is used by the default implementation of the createFocusTraverser() - method, which uses the flag to find the first parent component (of the currently - focused one) which wants to be a focus container. - - So using this method to set the flag to 'true' causes this component to - act as the top level within which focus is passed around. - - @see isFocusContainer, createFocusTraverser, moveKeyboardFocusToSibling - */ - void setFocusContainer (bool shouldBeFocusContainer) noexcept; - - /** Returns true if this component has been marked as a focus container. - - See setFocusContainer() for more details. - - @see setFocusContainer, moveKeyboardFocusToSibling, createFocusTraverser - */ - bool isFocusContainer() const noexcept; - - //============================================================================== - /** Returns true if the component (and all its parents) are enabled. - - Components are enabled by default, and can be disabled with setEnabled(). Exactly - what difference this makes to the component depends on the type. E.g. buttons - and sliders will choose to draw themselves differently, etc. - - Note that if one of this component's parents is disabled, this will always - return false, even if this component itself is enabled. - - @see setEnabled, enablementChanged - */ - bool isEnabled() const noexcept; - - /** Enables or disables this component. - - Disabling a component will also cause all of its child components to become - disabled. - - Similarly, enabling a component which is inside a disabled parent - component won't make any difference until the parent is re-enabled. - - @see isEnabled, enablementChanged - */ - void setEnabled (bool shouldBeEnabled); - - /** Callback to indicate that this component has been enabled or disabled. - - This can be triggered by one of the component's parent components - being enabled or disabled, as well as changes to the component itself. - - The default implementation of this method does nothing; your class may - wish to repaint itself or something when this happens. - - @see setEnabled, isEnabled - */ - virtual void enablementChanged(); - - //============================================================================== - /** Returns the component's current transparancy level. - See setAlpha() for more details. - */ - float getAlpha() const noexcept; - - /** Changes the transparency of this component. - When painted, the entire component and all its children will be rendered - with this as the overall opacity level, where 0 is completely invisible, and - 1.0 is fully opaque (i.e. normal). - - @see getAlpha, alphaChanged - */ - void setAlpha (float newAlpha); - - /** Called when setAlpha() is used to change the alpha value of this component. - If you override this, you should also invoke the base class's implementation - during your overridden function, as it performs some repainting behaviour. - */ - virtual void alphaChanged(); - - //============================================================================== - /** Changes the mouse cursor shape to use when the mouse is over this component. - - Note that the cursor set by this method can be overridden by the getMouseCursor - method. - - @see MouseCursor - */ - void setMouseCursor (const MouseCursor& cursorType); - - /** Returns the mouse cursor shape to use when the mouse is over this component. - - The default implementation will return the cursor that was set by setCursor() - but can be overridden for more specialised purposes, e.g. returning different - cursors depending on the mouse position. - - @see MouseCursor - */ - virtual MouseCursor getMouseCursor(); - - /** Forces the current mouse cursor to be updated. - - If you're overriding the getMouseCursor() method to control which cursor is - displayed, then this will only be checked each time the user moves the mouse. So - if you want to force the system to check that the cursor being displayed is - up-to-date (even if the mouse is just sitting there), call this method. - - (If you're changing the cursor using setMouseCursor(), you don't need to bother - calling this). - */ - void updateMouseCursor() const; - - //============================================================================== - /** Components can override this method to draw their content. - - The paint() method gets called when a region of a component needs redrawing, - either because the component's repaint() method has been called, or because - something has happened on the screen that means a section of a window needs - to be redrawn. - - Any child components will draw themselves over whatever this method draws. If - you need to paint over the top of your child components, you can also implement - the paintOverChildren() method to do this. - - If you want to cause a component to redraw itself, this is done asynchronously - - calling the repaint() method marks a region of the component as "dirty", and the - paint() method will automatically be called sometime later, by the message thread, - to paint any bits that need refreshing. In Juce (and almost all modern UI frameworks), - you never redraw something synchronously. - - You should never need to call this method directly - to take a snapshot of the - component you could use createComponentSnapshot() or paintEntireComponent(). - - @param g the graphics context that must be used to do the drawing operations. - @see repaint, paintOverChildren, Graphics - */ - virtual void paint (Graphics& g); - - /** Components can override this method to draw over the top of their children. - - For most drawing operations, it's better to use the normal paint() method, - but if you need to overlay something on top of the children, this can be - used. - - @see paint, Graphics - */ - virtual void paintOverChildren (Graphics& g); - - - //============================================================================== - /** Called when the mouse moves inside a component. - - If the mouse button isn't pressed and the mouse moves over a component, - this will be called to let the component react to this. - - A component will always get a mouseEnter callback before a mouseMove. - - @param event details about the position and status of the mouse event, including - the source component in which it occurred - @see mouseEnter, mouseExit, mouseDrag, contains - */ - virtual void mouseMove (const MouseEvent& event) override; - - /** Called when the mouse first enters a component. - - If the mouse button isn't pressed and the mouse moves into a component, - this will be called to let the component react to this. - - When the mouse button is pressed and held down while being moved in - or out of a component, no mouseEnter or mouseExit callbacks are made - only - mouseDrag messages are sent to the component that the mouse was originally - clicked on, until the button is released. - - @param event details about the position and status of the mouse event, including - the source component in which it occurred - @see mouseExit, mouseDrag, mouseMove, contains - */ - virtual void mouseEnter (const MouseEvent& event) override; - - /** Called when the mouse moves out of a component. - - This will be called when the mouse moves off the edge of this - component. - - If the mouse button was pressed, and it was then dragged off the - edge of the component and released, then this callback will happen - when the button is released, after the mouseUp callback. - - @param event details about the position and status of the mouse event, including - the source component in which it occurred - @see mouseEnter, mouseDrag, mouseMove, contains - */ - virtual void mouseExit (const MouseEvent& event) override; - - /** Called when a mouse button is pressed. - - The MouseEvent object passed in contains lots of methods for finding out - which button was pressed, as well as which modifier keys (e.g. shift, ctrl) - were held down at the time. - - Once a button is held down, the mouseDrag method will be called when the - mouse moves, until the button is released. - - @param event details about the position and status of the mouse event, including - the source component in which it occurred - @see mouseUp, mouseDrag, mouseDoubleClick, contains - */ - virtual void mouseDown (const MouseEvent& event) override; - - /** Called when the mouse is moved while a button is held down. - - When a mouse button is pressed inside a component, that component - receives mouseDrag callbacks each time the mouse moves, even if the - mouse strays outside the component's bounds. - - @param event details about the position and status of the mouse event, including - the source component in which it occurred - @see mouseDown, mouseUp, mouseMove, contains, setDragRepeatInterval - */ - virtual void mouseDrag (const MouseEvent& event) override; - - /** Called when a mouse button is released. - - A mouseUp callback is sent to the component in which a button was pressed - even if the mouse is actually over a different component when the - button is released. - - The MouseEvent object passed in contains lots of methods for finding out - which buttons were down just before they were released. - - @param event details about the position and status of the mouse event, including - the source component in which it occurred - @see mouseDown, mouseDrag, mouseDoubleClick, contains - */ - virtual void mouseUp (const MouseEvent& event) override; - - /** Called when a mouse button has been double-clicked on a component. - - The MouseEvent object passed in contains lots of methods for finding out - which button was pressed, as well as which modifier keys (e.g. shift, ctrl) - were held down at the time. - - @param event details about the position and status of the mouse event, including - the source component in which it occurred - @see mouseDown, mouseUp - */ - virtual void mouseDoubleClick (const MouseEvent& event) override; - - /** Called when the mouse-wheel is moved. - - This callback is sent to the component that the mouse is over when the - wheel is moved. - - If not overridden, a component will forward this message to its parent, so - that parent components can collect mouse-wheel messages that happen to - child components which aren't interested in them. (Bear in mind that if - you attach a component as a mouse-listener to other components, then - those wheel moves will also end up calling this method and being passed up - to the parents, which may not be what you intended to happen). - - @param event details about the mouse event - @param wheel details about the mouse wheel movement - */ - virtual void mouseWheelMove (const MouseEvent& event, - const MouseWheelDetails& wheel) override; - - /** Called when a pinch-to-zoom mouse-gesture is used. - - If not overridden, a component will forward this message to its parent, so - that parent components can collect gesture messages that are unused by child - components. - - @param event details about the mouse event - @param scaleFactor a multiplier to indicate by how much the size of the target - should be changed. A value of 1.0 would indicate no change, - values greater than 1.0 mean it should be enlarged. - */ - virtual void mouseMagnify (const MouseEvent& event, float scaleFactor); - - //============================================================================== - /** Ensures that a non-stop stream of mouse-drag events will be sent during the - current mouse-drag operation. - - This allows you to make sure that mouseDrag() events are sent continuously, even - when the mouse isn't moving. This can be useful for things like auto-scrolling - components when the mouse is near an edge. - - Call this method during a mouseDown() or mouseDrag() callback, specifying the - minimum interval between consecutive mouse drag callbacks. The callbacks - will continue until the mouse is released, and then the interval will be reset, - so you need to make sure it's called every time you begin a drag event. - Passing an interval of 0 or less will cancel the auto-repeat. - - @see mouseDrag, Desktop::beginDragAutoRepeat - */ - static void JUCE_CALLTYPE beginDragAutoRepeat (int millisecondsBetweenCallbacks); - - /** Causes automatic repaints when the mouse enters or exits this component. - - If turned on, then when the mouse enters/exits, or when the button is pressed/released - on the component, it will trigger a repaint. - - This is handy for things like buttons that need to draw themselves differently when - the mouse moves over them, and it avoids having to override all the different mouse - callbacks and call repaint(). - - @see mouseEnter, mouseExit, mouseDown, mouseUp - */ - void setRepaintsOnMouseActivity (bool shouldRepaint) noexcept; - - /** Registers a listener to be told when mouse events occur in this component. - - If you need to get informed about mouse events in a component but can't or - don't want to override its methods, you can attach any number of listeners - to the component, and these will get told about the events in addition to - the component's own callbacks being called. - - Note that a MouseListener can also be attached to more than one component. - - @param newListener the listener to register - @param wantsEventsForAllNestedChildComponents if true, the listener will receive callbacks - for events that happen to any child component - within this component, including deeply-nested - child components. If false, it will only be - told about events that this component handles. - @see MouseListener, removeMouseListener - */ - void addMouseListener (MouseListener* newListener, - bool wantsEventsForAllNestedChildComponents); - - /** Deregisters a mouse listener. - @see addMouseListener, MouseListener - */ - void removeMouseListener (MouseListener* listenerToRemove); - - //============================================================================== - /** Adds a listener that wants to hear about keypresses that this component receives. - - The listeners that are registered with a component are called by its keyPressed() or - keyStateChanged() methods (assuming these haven't been overridden to do something else). - - If you add an object as a key listener, be careful to remove it when the object - is deleted, or the component will be left with a dangling pointer. - - @see keyPressed, keyStateChanged, removeKeyListener - */ - void addKeyListener (KeyListener* newListener); - - /** Removes a previously-registered key listener. - @see addKeyListener - */ - void removeKeyListener (KeyListener* listenerToRemove); - - /** Called when a key is pressed. - - When a key is pressed, the component that has the keyboard focus will have this - method called. Remember that a component will only be given the focus if its - setWantsKeyboardFocus() method has been used to enable this. - - If your implementation returns true, the event will be consumed and not passed - on to any other listeners. If it returns false, the key will be passed to any - KeyListeners that have been registered with this component. As soon as one of these - returns true, the process will stop, but if they all return false, the event will - be passed upwards to this component's parent, and so on. - - The default implementation of this method does nothing and returns false. - - @see keyStateChanged, getCurrentlyFocusedComponent, addKeyListener - */ - virtual bool keyPressed (const KeyPress& key); - - /** Called when a key is pressed or released. - - Whenever a key on the keyboard is pressed or released (including modifier keys - like shift and ctrl), this method will be called on the component that currently - has the keyboard focus. Remember that a component will only be given the focus if - its setWantsKeyboardFocus() method has been used to enable this. - - If your implementation returns true, the event will be consumed and not passed - on to any other listeners. If it returns false, then any KeyListeners that have - been registered with this component will have their keyStateChanged methods called. - As soon as one of these returns true, the process will stop, but if they all return - false, the event will be passed upwards to this component's parent, and so on. - - The default implementation of this method does nothing and returns false. - - To find out which keys are up or down at any time, see the KeyPress::isKeyCurrentlyDown() - method. - - @param isKeyDown true if a key has been pressed; false if it has been released - - @see keyPressed, KeyPress, getCurrentlyFocusedComponent, addKeyListener - */ - virtual bool keyStateChanged (bool isKeyDown); - - /** Called when a modifier key is pressed or released. - - Whenever the shift, control, alt or command keys are pressed or released, - this method will be called on the component that currently has the keyboard focus. - Remember that a component will only be given the focus if its setWantsKeyboardFocus() - method has been used to enable this. - - The default implementation of this method actually calls its parent's modifierKeysChanged - method, so that focused components which aren't interested in this will give their - parents a chance to act on the event instead. - - @see keyStateChanged, ModifierKeys - */ - virtual void modifierKeysChanged (const ModifierKeys& modifiers); - - //============================================================================== - /** Enumeration used by the focusChanged() and focusLost() methods. */ - enum FocusChangeType - { - focusChangedByMouseClick, /**< Means that the user clicked the mouse to change focus. */ - focusChangedByTabKey, /**< Means that the user pressed the tab key to move the focus. */ - focusChangedDirectly /**< Means that the focus was changed by a call to grabKeyboardFocus(). */ - }; - - /** Called to indicate that this component has just acquired the keyboard focus. - @see focusLost, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus - */ - virtual void focusGained (FocusChangeType cause); - - /** Called to indicate that this component has just lost the keyboard focus. - @see focusGained, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus - */ - virtual void focusLost (FocusChangeType cause); - - /** Called to indicate a change in whether or not this component is the parent of the - currently-focused component. - - Essentially this is called when the return value of a call to hasKeyboardFocus (true) has - changed. It happens when focus moves from one of this component's children (at any depth) - to a component that isn't contained in this one, (or vice-versa). - Note that this method does NOT get called to when focus simply moves from one of its - child components to another. - - @see focusGained, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus - */ - virtual void focusOfChildComponentChanged (FocusChangeType cause); - - //============================================================================== - /** Returns true if the mouse is currently over this component. - - If the mouse isn't over the component, this will return false, even if the - mouse is currently being dragged - so you can use this in your mouseDrag - method to find out whether it's really over the component or not. - - Note that when the mouse button is being held down, then the only component - for which this method will return true is the one that was originally - clicked on. - - If includeChildren is true, then this will also return true if the mouse is over - any of the component's children (recursively) as well as the component itself. - - @see isMouseButtonDown. isMouseOverOrDragging, mouseDrag - */ - bool isMouseOver (bool includeChildren = false) const; - - /** Returns true if the mouse button is currently held down in this component. - - Note that this is a test to see whether the mouse is being pressed in this - component, so it'll return false if called on component A when the mouse - is actually being dragged in component B. - - @see isMouseButtonDownAnywhere, isMouseOver, isMouseOverOrDragging - */ - bool isMouseButtonDown() const; - - /** True if the mouse is over this component, or if it's being dragged in this component. - This is a handy equivalent to (isMouseOver() || isMouseButtonDown()). - @see isMouseOver, isMouseButtonDown, isMouseButtonDownAnywhere - */ - bool isMouseOverOrDragging (bool includeChildren = false) const; - - /** Returns true if a mouse button is currently down. - - Unlike isMouseButtonDown, this will test the current state of the - buttons without regard to which component (if any) it has been - pressed in. - - @see isMouseButtonDown, ModifierKeys - */ - static bool JUCE_CALLTYPE isMouseButtonDownAnywhere() noexcept; - - /** Returns the mouse's current position, relative to this component. - The return value is relative to the component's top-left corner. - */ - Point getMouseXYRelative() const; - - //============================================================================== - /** Called when this component's size has been changed. - - A component can implement this method to do things such as laying out its - child components when its width or height changes. - - The method is called synchronously as a result of the setBounds or setSize - methods, so repeatedly changing a components size will repeatedly call its - resized method (unlike things like repainting, where multiple calls to repaint - are coalesced together). - - If the component is a top-level window on the desktop, its size could also - be changed by operating-system factors beyond the application's control. - - @see moved, setSize - */ - virtual void resized(); - - /** Called when this component's position has been changed. - - This is called when the position relative to its parent changes, not when - its absolute position on the screen changes (so it won't be called for - all child components when a parent component is moved). - - The method is called synchronously as a result of the setBounds, setTopLeftPosition - or any of the other repositioning methods, and like resized(), it will be - called each time those methods are called. - - If the component is a top-level window on the desktop, its position could also - be changed by operating-system factors beyond the application's control. - - @see resized, setBounds - */ - virtual void moved(); - - /** Called when one of this component's children is moved or resized. - - If the parent wants to know about changes to its immediate children (not - to children of its children), this is the method to override. - - @see moved, resized, parentSizeChanged - */ - virtual void childBoundsChanged (Component* child); - - /** Called when this component's immediate parent has been resized. - - If the component is a top-level window, this indicates that the screen size - has changed. - - @see childBoundsChanged, moved, resized - */ - virtual void parentSizeChanged(); - - /** Called when this component has been moved to the front of its siblings. - - The component may have been brought to the front by the toFront() method, or - by the operating system if it's a top-level window. - - @see toFront - */ - virtual void broughtToFront(); - - /** Adds a listener to be told about changes to the component hierarchy or position. - - Component listeners get called when this component's size, position or children - change - see the ComponentListener class for more details. - - @param newListener the listener to register - if this is already registered, it - will be ignored. - @see ComponentListener, removeComponentListener - */ - void addComponentListener (ComponentListener* newListener); - - /** Removes a component listener. - @see addComponentListener - */ - void removeComponentListener (ComponentListener* listenerToRemove); - - //============================================================================== - /** Dispatches a numbered message to this component. - - This is a quick and cheap way of allowing simple asynchronous messages to - be sent to components. It's also safe, because if the component that you - send the message to is a null or dangling pointer, this won't cause an error. - - The command ID is later delivered to the component's handleCommandMessage() method by - the application's message queue. - - @see handleCommandMessage - */ - void postCommandMessage (int commandId); - - /** Called to handle a command that was sent by postCommandMessage(). - - This is called by the message thread when a command message arrives, and - the component can override this method to process it in any way it needs to. - - @see postCommandMessage - */ - virtual void handleCommandMessage (int commandId); - - //============================================================================== - #if JUCE_MODAL_LOOPS_PERMITTED - /** Runs a component modally, waiting until the loop terminates. - - This method first makes the component visible, brings it to the front and - gives it the keyboard focus. - - It then runs a loop, dispatching messages from the system message queue, but - blocking all mouse or keyboard messages from reaching any components other - than this one and its children. - - This loop continues until the component's exitModalState() method is called (or - the component is deleted), and then this method returns, returning the value - passed into exitModalState(). - - Note that you SHOULD NEVER USE THIS METHOD! Modal loops are a dangerous construct - because things that happen during the events that they dispatch could affect the - state of objects which are currently in use somewhere on the stack, so when the - loop finishes and the stack unwinds, horrible problems can occur. This is especially - bad in plugins, where the host may choose to delete the plugin during runModalLoop(), - so that when it returns, the entire DLL could have been unloaded from memory! - Also, some OSes deliberately make it impossible to run modal loops (e.g. Android), - so this method won't even exist on some platforms. - - @see enterModalState, exitModalState, isCurrentlyModal, getCurrentlyModalComponent, - isCurrentlyBlockedByAnotherModalComponent, ModalComponentManager - */ - int runModalLoop(); - #endif - - /** Puts the component into a modal state. - - This makes the component modal, so that messages are blocked from reaching - any components other than this one and its children, but unlike runModalLoop(), - this method returns immediately. - - If takeKeyboardFocus is true, the component will use grabKeyboardFocus() to - get the focus, which is usually what you'll want it to do. If not, it will leave - the focus unchanged. - - The callback is an optional object which will receive a callback when the modal - component loses its modal status, either by being hidden or when exitModalState() - is called. If you pass an object in here, the system will take care of deleting it - later, after making the callback - - If deleteWhenDismissed is true, then when it is dismissed, the component will be - deleted and then the callback will be called. (This will safely handle the situation - where the component is deleted before its exitModalState() method is called). - - @see exitModalState, runModalLoop, ModalComponentManager::attachCallback - */ - void enterModalState (bool takeKeyboardFocus = true, - ModalComponentManager::Callback* callback = nullptr, - bool deleteWhenDismissed = false); - - /** Ends a component's modal state. - - If this component is currently modal, this will turn off its modalness, and return - a value to the runModalLoop() method that might have be running its modal loop. - - @see runModalLoop, enterModalState, isCurrentlyModal - */ - void exitModalState (int returnValue); - - /** Returns true if this component is the modal one. - - It's possible to have nested modal components, e.g. a pop-up dialog box - that launches another pop-up. If onlyConsiderForemostModalComponent is - true then isCurrentlyModal will only return true for the one at the top - of the stack. If onlyConsiderForemostModalComponent is false then - isCurrentlyModal will return true for any modal component in the stack. - - @see getCurrentlyModalComponent - */ - bool isCurrentlyModal (bool onlyConsiderForemostModalComponent = true) const noexcept; - - /** Returns the number of components that are currently in a modal state. - @see getCurrentlyModalComponent - */ - static int JUCE_CALLTYPE getNumCurrentlyModalComponents() noexcept; - - /** Returns one of the components that are currently modal. - - The index specifies which of the possible modal components to return. The order - of the components in this list is the reverse of the order in which they became - modal - so the component at index 0 is always the active component, and the others - are progressively earlier ones that are themselves now blocked by later ones. - - @returns the modal component, or null if no components are modal (or if the - index is out of range) - @see getNumCurrentlyModalComponents, runModalLoop, isCurrentlyModal - */ - static Component* JUCE_CALLTYPE getCurrentlyModalComponent (int index = 0) noexcept; - - /** Checks whether there's a modal component somewhere that's stopping this one - from receiving messages. - - If there is a modal component, its canModalEventBeSentToComponent() method - will be called to see if it will still allow this component to receive events. - - @see runModalLoop, getCurrentlyModalComponent - */ - bool isCurrentlyBlockedByAnotherModalComponent() const; - - /** When a component is modal, this callback allows it to choose which other - components can still receive events. - - When a modal component is active and the user clicks on a non-modal component, - this method is called on the modal component, and if it returns true, the - event is allowed to reach its target. If it returns false, the event is blocked - and the inputAttemptWhenModal() callback is made. - - It called by the isCurrentlyBlockedByAnotherModalComponent() method. The default - implementation just returns false in all cases. - */ - virtual bool canModalEventBeSentToComponent (const Component* targetComponent); - - /** Called when the user tries to click on a component that is blocked by another - modal component. - - When a component is modal and the user clicks on one of the other components, - the modal component will receive this callback. - - The default implementation of this method will play a beep, and bring the currently - modal component to the front, but it can be overridden to do other tasks. - - @see isCurrentlyBlockedByAnotherModalComponent, canModalEventBeSentToComponent - */ - virtual void inputAttemptWhenModal(); - - - //============================================================================== - /** Returns the set of properties that belong to this component. - Each component has a NamedValueSet object which you can use to attach arbitrary - items of data to it. - */ - NamedValueSet& getProperties() noexcept { return properties; } - - /** Returns the set of properties that belong to this component. - Each component has a NamedValueSet object which you can use to attach arbitrary - items of data to it. - */ - const NamedValueSet& getProperties() const noexcept { return properties; } - - //============================================================================== - /** Looks for a colour that has been registered with the given colour ID number. - - If a colour has been set for this ID number using setColour(), then it is - returned. If none has been set, the method will try calling the component's - LookAndFeel class's findColour() method. If none has been registered with the - look-and-feel either, it will just return black. - - The colour IDs for various purposes are stored as enums in the components that - they are relevant to - for an example, see Slider::ColourIds, - Label::ColourIds, TextEditor::ColourIds, TreeView::ColourIds, etc. - - @see setColour, isColourSpecified, colourChanged, LookAndFeel::findColour, LookAndFeel::setColour - */ - Colour findColour (int colourId, bool inheritFromParent = false) const; - - /** Registers a colour to be used for a particular purpose. - - Changing a colour will cause a synchronous callback to the colourChanged() - method, which your component can override if it needs to do something when - colours are altered. - - For more details about colour IDs, see the comments for findColour(). - - @see findColour, isColourSpecified, colourChanged, LookAndFeel::findColour, LookAndFeel::setColour - */ - void setColour (int colourId, Colour newColour); - - /** If a colour has been set with setColour(), this will remove it. - This allows you to make a colour revert to its default state. - */ - void removeColour (int colourId); - - /** Returns true if the specified colour ID has been explicitly set for this - component using the setColour() method. - */ - bool isColourSpecified (int colourId) const; - - /** This looks for any colours that have been specified for this component, - and copies them to the specified target component. - */ - void copyAllExplicitColoursTo (Component& target) const; - - /** This method is called when a colour is changed by the setColour() method. - @see setColour, findColour - */ - virtual void colourChanged(); - - //============================================================================== - /** Components can implement this method to provide a MarkerList. - The default implementation of this method returns nullptr, but you can override - it to return a pointer to the component's marker list. If xAxis is true, it should - return the X marker list; if false, it should return the Y markers. - */ - virtual MarkerList* getMarkers (bool xAxis); - - //============================================================================== - /** Returns the underlying native window handle for this component. - - This is platform-dependent and strictly for power-users only! - */ - void* getWindowHandle() const; - - //============================================================================== - /** Holds a pointer to some type of Component, which automatically becomes null if - the component is deleted. - - If you're using a component which may be deleted by another event that's outside - of your control, use a SafePointer instead of a normal pointer to refer to it, - and you can test whether it's null before using it to see if something has deleted - it. - - The ComponentType typedef must be Component, or some subclass of Component. - - You may also want to use a WeakReference object for the same purpose. - */ - template - class SafePointer - { - public: - /** Creates a null SafePointer. */ - SafePointer() noexcept {} - - /** Creates a SafePointer that points at the given component. */ - SafePointer (ComponentType* component) : weakRef (component) {} - - /** Creates a copy of another SafePointer. */ - SafePointer (const SafePointer& other) noexcept : weakRef (other.weakRef) {} - - /** Copies another pointer to this one. */ - SafePointer& operator= (const SafePointer& other) { weakRef = other.weakRef; return *this; } - - /** Copies another pointer to this one. */ - SafePointer& operator= (ComponentType* newComponent) { weakRef = newComponent; return *this; } - - /** Returns the component that this pointer refers to, or null if the component no longer exists. */ - ComponentType* getComponent() const noexcept { return dynamic_cast (weakRef.get()); } - - /** Returns the component that this pointer refers to, or null if the component no longer exists. */ - operator ComponentType*() const noexcept { return getComponent(); } - - /** Returns the component that this pointer refers to, or null if the component no longer exists. */ - ComponentType* operator->() noexcept { return getComponent(); } - - /** Returns the component that this pointer refers to, or null if the component no longer exists. */ - const ComponentType* operator->() const noexcept { return getComponent(); } - - /** If the component is valid, this deletes it and sets this pointer to null. */ - void deleteAndZero() { delete getComponent(); } - - bool operator== (ComponentType* component) const noexcept { return weakRef == component; } - bool operator!= (ComponentType* component) const noexcept { return weakRef != component; } - - private: - WeakReference weakRef; - }; - - //============================================================================== - /** A class to keep an eye on a component and check for it being deleted. - - This is designed for use with the ListenerList::callChecked() methods, to allow - the list iterator to stop cleanly if the component is deleted by a listener callback - while the list is still being iterated. - */ - class JUCE_API BailOutChecker - { - public: - /** Creates a checker that watches one component. */ - BailOutChecker (Component* component); - - /** Returns true if either of the two components have been deleted since this object was created. */ - bool shouldBailOut() const noexcept; - - private: - const WeakReference safePointer; - - JUCE_DECLARE_NON_COPYABLE (BailOutChecker) - }; - - //============================================================================== - /** - Base class for objects that can be used to automatically position a component according to - some kind of algorithm. - - The component class simply holds onto a reference to a Positioner, but doesn't actually do - anything with it - all the functionality must be implemented by the positioner itself (e.g. - it might choose to watch some kind of value and move the component when the value changes). - */ - class JUCE_API Positioner - { - public: - /** Creates a Positioner which can control the specified component. */ - explicit Positioner (Component& component) noexcept; - /** Destructor. */ - virtual ~Positioner() {} - - /** Returns the component that this positioner controls. */ - Component& getComponent() const noexcept { return component; } - - /** Attempts to set the component's position to the given rectangle. - Unlike simply calling Component::setBounds(), this may involve the positioner - being smart enough to adjust itself to fit the new bounds, e.g. a RelativeRectangle's - positioner may try to reverse the expressions used to make them fit these new coordinates. - */ - virtual void applyNewBounds (const Rectangle& newBounds) = 0; - - private: - Component& component; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Positioner) - }; - - /** Returns the Positioner object that has been set for this component. - @see setPositioner() - */ - Positioner* getPositioner() const noexcept; - - /** Sets a new Positioner object for this component. - If there's currently another positioner set, it will be deleted. The object that is passed in - will be deleted automatically by this component when it's no longer required. Pass a null pointer - to clear the current positioner. - @see getPositioner() - */ - void setPositioner (Positioner* newPositioner); - - /** Gives the component a CachedComponentImage that should be used to buffer its painting. - The object that is passed-in will be owned by this component, and will be deleted automatically - later on. - @see setBufferedToImage - */ - void setCachedComponentImage (CachedComponentImage* newCachedImage); - - /** Returns the object that was set by setCachedComponentImage(). - @see setCachedComponentImage - */ - CachedComponentImage* getCachedComponentImage() const noexcept { return cachedImage; } - - /** Sets a flag to indicate whether mouse drag events on this Component should be ignored when it is inside a - Viewport with drag-to-scroll functionality enabled. This is useful for Components such as sliders that - should not move their parent Viewport when dragged. - */ - void setViewportIgnoreDragFlag (bool ignoreDrag) noexcept { flags.viewportIgnoreDragFlag = ignoreDrag; } - - /** Retrieves the current state of the Viewport drag-to-scroll functionality flag. - @see setViewportIgnoreDragFlag - */ - bool getViewportIgnoreDragFlag() const noexcept { return flags.viewportIgnoreDragFlag; } - - //============================================================================== - // These methods are deprecated - use localPointToGlobal, getLocalPoint, getLocalPoint, etc instead. - JUCE_DEPRECATED (Point relativePositionToGlobal (Point) const); - JUCE_DEPRECATED (Point globalPositionToRelative (Point) const); - JUCE_DEPRECATED (Point relativePositionToOtherComponent (const Component*, Point) const); - - // RelativeCoordinates are eventually going to be deprecated - JUCE_DEPRECATED (void setBounds (const RelativeRectangle&)); - JUCE_DEPRECATED (void setBounds (const String&)); - -private: - //============================================================================== - friend class ComponentPeer; - friend class MouseInputSource; - friend class MouseInputSourceInternal; - - #ifndef DOXYGEN - static Component* currentlyFocusedComponent; - - //============================================================================== - String componentName, componentID; - Component* parentComponent = nullptr; - Rectangle boundsRelativeToParent; - ScopedPointer positioner; - ScopedPointer affineTransform; - Array childComponentList; - LookAndFeel* lookAndFeel = nullptr; - MouseCursor cursor; - ImageEffectFilter* effect = nullptr; - ScopedPointer cachedImage; - - class MouseListenerList; - friend class MouseListenerList; - friend struct ContainerDeletePolicy; - ScopedPointer mouseListeners; - ScopedPointer > keyListeners; - ListenerList componentListeners; - NamedValueSet properties; - - friend class WeakReference; - WeakReference::Master masterReference; - - struct ComponentFlags - { - bool hasHeavyweightPeerFlag : 1; - bool visibleFlag : 1; - bool opaqueFlag : 1; - bool ignoresMouseClicksFlag : 1; - bool allowChildMouseClicksFlag : 1; - bool wantsFocusFlag : 1; - bool isFocusContainerFlag : 1; - bool dontFocusOnMouseClickFlag : 1; - bool alwaysOnTopFlag : 1; - bool bufferToImageFlag : 1; - bool bringToFrontOnClickFlag : 1; - bool repaintOnMouseActivityFlag : 1; - bool isDisabledFlag : 1; - bool childCompFocusedFlag : 1; - bool dontClipGraphicsFlag : 1; - bool mouseDownWasBlocked : 1; - bool isMoveCallbackPending : 1; - bool isResizeCallbackPending : 1; - bool viewportIgnoreDragFlag : 1; - #if JUCE_DEBUG - bool isInsidePaintCall : 1; - #endif - }; - - union - { - uint32 componentFlags; - ComponentFlags flags; - }; - - uint8 componentTransparency = 0; - - //============================================================================== - void internalMouseEnter (MouseInputSource, Point, Time); - void internalMouseExit (MouseInputSource, Point, Time); - void internalMouseDown (MouseInputSource, Point, Time, float, float, float, float, float); - void internalMouseUp (MouseInputSource, Point, Time, const ModifierKeys oldModifiers, float, float, float, float, float); - void internalMouseDrag (MouseInputSource, Point, Time, float, float, float, float, float); - void internalMouseMove (MouseInputSource, Point, Time); - void internalMouseWheel (MouseInputSource, Point, Time, const MouseWheelDetails&); - void internalMagnifyGesture (MouseInputSource, Point, Time, float); - void internalBroughtToFront(); - void internalFocusGain (FocusChangeType, const WeakReference&); - void internalFocusGain (FocusChangeType); - void internalFocusLoss (FocusChangeType); - void internalChildFocusChange (FocusChangeType, const WeakReference&); - void internalModalInputAttempt(); - void internalModifierKeysChanged(); - void internalChildrenChanged(); - void internalHierarchyChanged(); - void internalRepaint (Rectangle); - void internalRepaintUnchecked (Rectangle, bool); - Component* removeChildComponent (int index, bool sendParentEvents, bool sendChildEvents); - void reorderChildInternal (int sourceIndex, int destIndex); - void paintComponentAndChildren (Graphics&); - void paintWithinParentContext (Graphics&); - void sendMovedResizedMessages (bool wasMoved, bool wasResized); - void sendMovedResizedMessagesIfPending(); - void repaintParent(); - void sendFakeMouseMove() const; - void takeKeyboardFocus (const FocusChangeType); - void grabFocusInternal (const FocusChangeType, bool canTryParent); - static void giveAwayFocus (bool sendFocusLossEvent); - void sendEnablementChangeMessage(); - void sendVisibilityChangeMessage(); - - struct ComponentHelpers; - friend struct ComponentHelpers; - - /* Components aren't allowed to have copy constructors, as this would mess up parent hierarchies. - You might need to give your subclasses a private dummy constructor to avoid compiler warnings. - */ - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Component) - - //============================================================================== - #if JUCE_CATCH_DEPRECATED_CODE_MISUSE - // This is included here just to cause a compile error if your code is still handling - // drag-and-drop with this method. If so, just update it to use the new FileDragAndDropTarget - // class, which is easy (just make your class inherit from FileDragAndDropTarget, and - // implement its methods instead of this Component method). - virtual void filesDropped (const StringArray&, int, int) {} - - // This is included here to cause an error if you use or overload it - it has been deprecated in - // favour of contains (Point) - void contains (int, int) JUCE_DELETED_FUNCTION; - #endif - -protected: - //============================================================================== - /** @internal */ - virtual ComponentPeer* createNewPeer (int styleFlags, void* nativeWindowToAttachTo); - #endif -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/components/juce_ComponentListener.cpp b/source/modules/juce_gui_basics/components/juce_ComponentListener.cpp deleted file mode 100644 index 4f27a5109..000000000 --- a/source/modules/juce_gui_basics/components/juce_ComponentListener.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -void ComponentListener::componentMovedOrResized (Component&, bool, bool) {} -void ComponentListener::componentBroughtToFront (Component&) {} -void ComponentListener::componentVisibilityChanged (Component&) {} -void ComponentListener::componentChildrenChanged (Component&) {} -void ComponentListener::componentParentHierarchyChanged (Component&) {} -void ComponentListener::componentNameChanged (Component&) {} -void ComponentListener::componentBeingDeleted (Component&) {} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/components/juce_ComponentListener.h b/source/modules/juce_gui_basics/components/juce_ComponentListener.h deleted file mode 100644 index cc657b83a..000000000 --- a/source/modules/juce_gui_basics/components/juce_ComponentListener.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Gets informed about changes to a component's hierarchy or position. - - To monitor a component for changes, register a subclass of ComponentListener - with the component using Component::addComponentListener(). - - Be sure to deregister listeners before you delete them! - - @see Component::addComponentListener, Component::removeComponentListener -*/ -class JUCE_API ComponentListener -{ -public: - /** Destructor. */ - virtual ~ComponentListener() {} - - /** Called when the component's position or size changes. - - @param component the component that was moved or resized - @param wasMoved true if the component's top-left corner has just moved - @param wasResized true if the component's width or height has just changed - @see Component::setBounds, Component::resized, Component::moved - */ - virtual void componentMovedOrResized (Component& component, - bool wasMoved, - bool wasResized); - - /** Called when the component is brought to the top of the z-order. - - @param component the component that was moved - @see Component::toFront, Component::broughtToFront - */ - virtual void componentBroughtToFront (Component& component); - - /** Called when the component is made visible or invisible. - - @param component the component that changed - @see Component::setVisible - */ - virtual void componentVisibilityChanged (Component& component); - - /** Called when the component has children added or removed, or their z-order - changes. - - @param component the component whose children have changed - @see Component::childrenChanged, Component::addChildComponent, - Component::removeChildComponent - */ - virtual void componentChildrenChanged (Component& component); - - /** Called to indicate that the component's parents have changed. - - When a component is added or removed from its parent, all of its children - will produce this notification (recursively - so all children of its - children will also be called as well). - - @param component the component that this listener is registered with - @see Component::parentHierarchyChanged - */ - virtual void componentParentHierarchyChanged (Component& component); - - /** Called when the component's name is changed. - - @see Component::setName, Component::getName - */ - virtual void componentNameChanged (Component& component); - - /** Called when the component is in the process of being deleted. - - This callback is made from inside the destructor, so be very, very cautious - about what you do in here. - - In particular, bear in mind that it's the Component base class's destructor that calls - this - so if the object that's being deleted is a subclass of Component, then the - subclass layers of the object will already have been destructed when it gets to this - point! - */ - virtual void componentBeingDeleted (Component& component); -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/components/juce_Desktop.cpp b/source/modules/juce_gui_basics/components/juce_Desktop.cpp deleted file mode 100644 index edaf72f98..000000000 --- a/source/modules/juce_gui_basics/components/juce_Desktop.cpp +++ /dev/null @@ -1,432 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -Desktop::Desktop() - : mouseSources (new MouseInputSource::SourceList()), - mouseClickCounter (0), mouseWheelCounter (0), - kioskModeComponent (nullptr), - kioskModeReentrant (false), - allowedOrientations (allOrientations), - masterScaleFactor ((float) getDefaultMasterScale()) -{ - displays = new Displays (*this); -} - -Desktop::~Desktop() -{ - setScreenSaverEnabled (true); - animator.cancelAllAnimations (false); - - jassert (instance == this); - instance = nullptr; - - // doh! If you don't delete all your windows before exiting, you're going to - // be leaking memory! - jassert (desktopComponents.size() == 0); -} - -Desktop& JUCE_CALLTYPE Desktop::getInstance() -{ - if (instance == nullptr) - instance = new Desktop(); - - return *instance; -} - -Desktop* Desktop::instance = nullptr; - -//============================================================================== -int Desktop::getNumComponents() const noexcept -{ - return desktopComponents.size(); -} - -Component* Desktop::getComponent (const int index) const noexcept -{ - return desktopComponents [index]; -} - -Component* Desktop::findComponentAt (Point screenPosition) const -{ - ASSERT_MESSAGE_MANAGER_IS_LOCKED - - for (int i = desktopComponents.size(); --i >= 0;) - { - Component* const c = desktopComponents.getUnchecked(i); - - if (c->isVisible()) - { - const Point relative (c->getLocalPoint (nullptr, screenPosition)); - - if (c->contains (relative)) - return c->getComponentAt (relative); - } - } - - return nullptr; -} - -//============================================================================== -LookAndFeel& Desktop::getDefaultLookAndFeel() noexcept -{ - if (currentLookAndFeel == nullptr) - { - if (defaultLookAndFeel == nullptr) - defaultLookAndFeel = new LookAndFeel_V4(); - - currentLookAndFeel = defaultLookAndFeel; - } - - return *currentLookAndFeel; -} - -void Desktop::setDefaultLookAndFeel (LookAndFeel* newDefaultLookAndFeel) -{ - ASSERT_MESSAGE_MANAGER_IS_LOCKED - currentLookAndFeel = newDefaultLookAndFeel; - - for (int i = getNumComponents(); --i >= 0;) - if (Component* const c = getComponent (i)) - c->sendLookAndFeelChange(); -} - -//============================================================================== -void Desktop::addDesktopComponent (Component* const c) -{ - jassert (c != nullptr); - jassert (! desktopComponents.contains (c)); - desktopComponents.addIfNotAlreadyThere (c); -} - -void Desktop::removeDesktopComponent (Component* const c) -{ - desktopComponents.removeFirstMatchingValue (c); -} - -void Desktop::componentBroughtToFront (Component* const c) -{ - const int index = desktopComponents.indexOf (c); - jassert (index >= 0); - - if (index >= 0) - { - int newIndex = -1; - - if (! c->isAlwaysOnTop()) - { - newIndex = desktopComponents.size(); - - while (newIndex > 0 && desktopComponents.getUnchecked (newIndex - 1)->isAlwaysOnTop()) - --newIndex; - - --newIndex; - } - - desktopComponents.move (index, newIndex); - } -} - -//============================================================================== -Point Desktop::getMousePosition() -{ - return getMousePositionFloat().roundToInt(); -} - -Point Desktop::getMousePositionFloat() -{ - return getInstance().getMainMouseSource().getScreenPosition(); -} - -void Desktop::setMousePosition (Point newPosition) -{ - getInstance().getMainMouseSource().setScreenPosition (newPosition.toFloat()); -} - -Point Desktop::getLastMouseDownPosition() -{ - return getInstance().getMainMouseSource().getLastMouseDownPosition().roundToInt(); -} - -int Desktop::getMouseButtonClickCounter() const noexcept { return mouseClickCounter; } -int Desktop::getMouseWheelMoveCounter() const noexcept { return mouseWheelCounter; } - -void Desktop::incrementMouseClickCounter() noexcept { ++mouseClickCounter; } -void Desktop::incrementMouseWheelCounter() noexcept { ++mouseWheelCounter; } - -const Array& Desktop::getMouseSources() const noexcept { return mouseSources->sourceArray; } -int Desktop::getNumMouseSources() const noexcept { return mouseSources->sources.size(); } -int Desktop::getNumDraggingMouseSources() const noexcept { return mouseSources->getNumDraggingMouseSources(); } -MouseInputSource* Desktop::getMouseSource (int index) const noexcept { return mouseSources->getMouseSource (index); } -MouseInputSource* Desktop::getDraggingMouseSource (int index) const noexcept { return mouseSources->getDraggingMouseSource (index); } -MouseInputSource Desktop::getMainMouseSource() const noexcept { return MouseInputSource (mouseSources->sources.getUnchecked(0)); } -void Desktop::beginDragAutoRepeat (int interval) { mouseSources->beginDragAutoRepeat (interval); } - -//============================================================================== -void Desktop::addFocusChangeListener (FocusChangeListener* const listener) { focusListeners.add (listener); } -void Desktop::removeFocusChangeListener (FocusChangeListener* const listener) { focusListeners.remove (listener); } -void Desktop::triggerFocusCallback() { triggerAsyncUpdate(); } - -void Desktop::handleAsyncUpdate() -{ - // The component may be deleted during this operation, but we'll use a SafePointer rather than a - // BailOutChecker so that any remaining listeners will still get a callback (with a null pointer). - WeakReference currentFocus (Component::getCurrentlyFocusedComponent()); - focusListeners.call (&FocusChangeListener::globalFocusChanged, currentFocus); -} - -//============================================================================== -void Desktop::resetTimer() -{ - if (mouseListeners.size() == 0) - stopTimer(); - else - startTimer (100); - - lastFakeMouseMove = getMousePositionFloat(); -} - -ListenerList& Desktop::getMouseListeners() -{ - resetTimer(); - return mouseListeners; -} - -void Desktop::addGlobalMouseListener (MouseListener* const listener) -{ - ASSERT_MESSAGE_MANAGER_IS_LOCKED - mouseListeners.add (listener); - resetTimer(); -} - -void Desktop::removeGlobalMouseListener (MouseListener* const listener) -{ - ASSERT_MESSAGE_MANAGER_IS_LOCKED - mouseListeners.remove (listener); - resetTimer(); -} - -void Desktop::timerCallback() -{ - if (lastFakeMouseMove != getMousePositionFloat()) - sendMouseMove(); -} - -void Desktop::sendMouseMove() -{ - if (! mouseListeners.isEmpty()) - { - startTimer (20); - - lastFakeMouseMove = getMousePositionFloat(); - - if (auto* target = findComponentAt (lastFakeMouseMove.roundToInt())) - { - Component::BailOutChecker checker (target); - const Point pos (target->getLocalPoint (nullptr, lastFakeMouseMove)); - const Time now (Time::getCurrentTime()); - - const MouseEvent me (getMainMouseSource(), pos, ModifierKeys::getCurrentModifiers(), MouseInputSource::invalidPressure, - MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation, - MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY, - target, target, now, pos, now, 0, false); - - if (me.mods.isAnyMouseButtonDown()) - mouseListeners.callChecked (checker, &MouseListener::mouseDrag, me); - else - mouseListeners.callChecked (checker, &MouseListener::mouseMove, me); - } - } -} - - -//============================================================================== -Desktop::Displays::Displays (Desktop& desktop) { init (desktop); } -Desktop::Displays::~Displays() {} - -const Desktop::Displays::Display& Desktop::Displays::getMainDisplay() const noexcept -{ - ASSERT_MESSAGE_MANAGER_IS_LOCKED - jassert (displays.getReference(0).isMain); - return displays.getReference(0); -} - -const Desktop::Displays::Display& Desktop::Displays::getDisplayContaining (Point position) const noexcept -{ - ASSERT_MESSAGE_MANAGER_IS_LOCKED - const Display* best = &displays.getReference(0); - double bestDistance = 1.0e10; - - for (int i = displays.size(); --i >= 0;) - { - const Display& d = displays.getReference(i); - - if (d.totalArea.contains (position)) - { - best = &d; - break; - } - - const double distance = d.totalArea.getCentre().getDistanceFrom (position); - - if (distance < bestDistance) - { - bestDistance = distance; - best = &d; - } - } - - return *best; -} - -RectangleList Desktop::Displays::getRectangleList (bool userAreasOnly) const -{ - ASSERT_MESSAGE_MANAGER_IS_LOCKED - RectangleList rl; - - for (int i = 0; i < displays.size(); ++i) - { - const Display& d = displays.getReference(i); - rl.addWithoutMerging (userAreasOnly ? d.userArea : d.totalArea); - } - - return rl; -} - -Rectangle Desktop::Displays::getTotalBounds (bool userAreasOnly) const -{ - return getRectangleList (userAreasOnly).getBounds(); -} - -bool operator== (const Desktop::Displays::Display& d1, const Desktop::Displays::Display& d2) noexcept; -bool operator== (const Desktop::Displays::Display& d1, const Desktop::Displays::Display& d2) noexcept -{ - return d1.userArea == d2.userArea - && d1.totalArea == d2.totalArea - && d1.scale == d2.scale - && d1.isMain == d2.isMain; -} - -bool operator!= (const Desktop::Displays::Display& d1, const Desktop::Displays::Display& d2) noexcept; -bool operator!= (const Desktop::Displays::Display& d1, const Desktop::Displays::Display& d2) noexcept -{ - return ! (d1 == d2); -} - -void Desktop::Displays::init (Desktop& desktop) -{ - findDisplays (desktop.getGlobalScaleFactor()); -} - -void Desktop::Displays::refresh() -{ - Array oldDisplays; - oldDisplays.swapWith (displays); - - init (Desktop::getInstance()); - - if (oldDisplays != displays) - { - for (int i = ComponentPeer::getNumPeers(); --i >= 0;) - if (ComponentPeer* const peer = ComponentPeer::getPeer (i)) - peer->handleScreenSizeChange(); - } -} - -//============================================================================== -void Desktop::setKioskModeComponent (Component* componentToUse, const bool allowMenusAndBars) -{ - if (kioskModeReentrant) - return; - - const ScopedValueSetter setter (kioskModeReentrant, true, false); - - if (kioskModeComponent != componentToUse) - { - // agh! Don't delete or remove a component from the desktop while it's still the kiosk component! - jassert (kioskModeComponent == nullptr || ComponentPeer::getPeerFor (kioskModeComponent) != nullptr); - - if (Component* const oldKioskComp = kioskModeComponent) - { - kioskModeComponent = nullptr; // (to make sure that isKioskMode() returns false when resizing the old one) - setKioskComponent (oldKioskComp, false, allowMenusAndBars); - oldKioskComp->setBounds (kioskComponentOriginalBounds); - } - - kioskModeComponent = componentToUse; - - if (kioskModeComponent != nullptr) - { - // Only components that are already on the desktop can be put into kiosk mode! - jassert (ComponentPeer::getPeerFor (kioskModeComponent) != nullptr); - - kioskComponentOriginalBounds = kioskModeComponent->getBounds(); - setKioskComponent (kioskModeComponent, true, allowMenusAndBars); - } - } -} - -//============================================================================== -void Desktop::setOrientationsEnabled (const int newOrientations) -{ - if (allowedOrientations != newOrientations) - { - // Dodgy set of flags being passed here! Make sure you specify at least one permitted orientation. - jassert (newOrientations != 0 && (newOrientations & ~allOrientations) == 0); - - allowedOrientations = newOrientations; - allowedOrientationsChanged(); - } -} - -int Desktop::getOrientationsEnabled() const noexcept -{ - return allowedOrientations; -} - -bool Desktop::isOrientationEnabled (const DisplayOrientation orientation) const noexcept -{ - // Make sure you only pass one valid flag in here... - jassert (orientation == upright || orientation == upsideDown - || orientation == rotatedClockwise || orientation == rotatedAntiClockwise); - - return (allowedOrientations & orientation) != 0; -} - -void Desktop::setGlobalScaleFactor (float newScaleFactor) noexcept -{ - ASSERT_MESSAGE_MANAGER_IS_LOCKED - - if (masterScaleFactor != newScaleFactor) - { - masterScaleFactor = newScaleFactor; - displays->refresh(); - } -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/components/juce_Desktop.h b/source/modules/juce_gui_basics/components/juce_Desktop.h deleted file mode 100644 index a7486bfc7..000000000 --- a/source/modules/juce_gui_basics/components/juce_Desktop.h +++ /dev/null @@ -1,474 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Classes can implement this interface and register themselves with the Desktop class - to receive callbacks when the currently focused component changes. - - @see Desktop::addFocusChangeListener, Desktop::removeFocusChangeListener -*/ -class JUCE_API FocusChangeListener -{ -public: - /** Destructor. */ - virtual ~FocusChangeListener() {} - - /** Callback to indicate that the currently focused component has changed. */ - virtual void globalFocusChanged (Component* focusedComponent) = 0; -}; - - -//============================================================================== -/** - Describes and controls aspects of the computer's desktop. - -*/ -class JUCE_API Desktop : private DeletedAtShutdown, - private Timer, - private AsyncUpdater -{ -public: - //============================================================================== - /** There's only one desktop object, and this method will return it. */ - static Desktop& JUCE_CALLTYPE getInstance(); - - //============================================================================== - /** Returns the mouse position. - - The coordinates are relative to the top-left of the main monitor. - - Note that this is just a shortcut for calling getMainMouseSource().getScreenPosition(), and - you should only resort to grabbing the global mouse position if there's really no - way to get the coordinates via a mouse event callback instead. - */ - static Point getMousePosition(); - - /** Makes the mouse pointer jump to a given location. - The coordinates are relative to the top-left of the main monitor. - Note that this is a pretty old method, kept around mainly for backwards-compatibility, - and you should use the MouseInputSource class directly in new code. - */ - static void setMousePosition (Point newPosition); - - /** Returns the last position at which a mouse button was pressed. - - Note that this is just a shortcut for calling getMainMouseSource().getLastMouseDownPosition(), - and in a multi-touch environment, it doesn't make much sense. ALWAYS prefer to - get this information via other means, such as MouseEvent::getMouseDownScreenPosition() - if possible, and only ever call this as a last resort. - */ - static Point getLastMouseDownPosition(); - - /** Returns the number of times the mouse button has been clicked since the app started. - Each mouse-down event increments this number by 1. - @see getMouseWheelMoveCounter - */ - int getMouseButtonClickCounter() const noexcept; - - /** Returns the number of times the mouse wheel has been moved since the app started. - Each mouse-wheel event increments this number by 1. - @see getMouseButtonClickCounter - */ - int getMouseWheelMoveCounter() const noexcept; - - //============================================================================== - /** This lets you prevent the screensaver from becoming active. - - Handy if you're running some sort of presentation app where having a screensaver - appear would be annoying. - - Pass false to disable the screensaver, and true to re-enable it. (Note that this - won't enable a screensaver unless the user has actually set one up). - - The disablement will only happen while the Juce application is the foreground - process - if another task is running in front of it, then the screensaver will - be unaffected. - - @see isScreenSaverEnabled - */ - static void setScreenSaverEnabled (bool isEnabled); - - /** Returns true if the screensaver has not been turned off. - - This will return the last value passed into setScreenSaverEnabled(). Note that - it won't tell you whether the user is actually using a screen saver, just - whether this app is deliberately preventing one from running. - - @see setScreenSaverEnabled - */ - static bool isScreenSaverEnabled(); - - //============================================================================== - /** Registers a MouseListener that will receive all mouse events that occur on - any component. - - @see removeGlobalMouseListener - */ - void addGlobalMouseListener (MouseListener* listener); - - /** Unregisters a MouseListener that was added with the addGlobalMouseListener() - method. - - @see addGlobalMouseListener - */ - void removeGlobalMouseListener (MouseListener* listener); - - //============================================================================== - /** Registers a MouseListener that will receive a callback whenever the focused - component changes. - */ - void addFocusChangeListener (FocusChangeListener* listener); - - /** Unregisters a listener that was added with addFocusChangeListener(). */ - void removeFocusChangeListener (FocusChangeListener* listener); - - //============================================================================== - /** Takes a component and makes it full-screen, removing the taskbar, dock, etc. - - The component must already be on the desktop for this method to work. It will - be resized to completely fill the screen and any extraneous taskbars, menu bars, - etc will be hidden. - - To exit kiosk mode, just call setKioskModeComponent (nullptr). When this is called, - the component that's currently being used will be resized back to the size - and position it was in before being put into this mode. - - If allowMenusAndBars is true, things like the menu and dock (on mac) are still - allowed to pop up when the mouse moves onto them. If this is false, it'll try - to hide as much on-screen paraphernalia as possible. - */ - void setKioskModeComponent (Component* componentToUse, - bool allowMenusAndBars = true); - - /** Returns the component that is currently being used in kiosk-mode. - - This is the component that was last set by setKioskModeComponent(). If none - has been set, this returns nullptr. - */ - Component* getKioskModeComponent() const noexcept { return kioskModeComponent; } - - //============================================================================== - /** Returns the number of components that are currently active as top-level - desktop windows. - - @see getComponent, Component::addToDesktop - */ - int getNumComponents() const noexcept; - - /** Returns one of the top-level desktop window components. - - The index is from 0 to getNumComponents() - 1. This could return 0 if the - index is out-of-range. - - @see getNumComponents, Component::addToDesktop - */ - Component* getComponent (int index) const noexcept; - - /** Finds the component at a given screen location. - - This will drill down into top-level windows to find the child component at - the given position. - - Returns nullptr if the coordinates are inside a non-Juce window. - */ - Component* findComponentAt (Point screenPosition) const; - - /** The Desktop object has a ComponentAnimator instance which can be used for performing - your animations. - - Having a single shared ComponentAnimator object makes it more efficient when multiple - components are being moved around simultaneously. It's also more convenient than having - to manage your own instance of one. - - @see ComponentAnimator - */ - ComponentAnimator& getAnimator() noexcept { return animator; } - - //============================================================================== - /** Returns the current default look-and-feel for components which don't have one - explicitly set. - @see setDefaultLookAndFeel - */ - LookAndFeel& getDefaultLookAndFeel() noexcept; - - /** Changes the default look-and-feel. - @param newDefaultLookAndFeel the new look-and-feel object to use - if this is - set to nullptr, it will revert to using the system's - default one. The object passed-in must be deleted by the - caller when it's no longer needed. - @see getDefaultLookAndFeel - */ - void setDefaultLookAndFeel (LookAndFeel* newDefaultLookAndFeel); - - //============================================================================== - /** Provides access to the array of mouse sources, for iteration. - In a traditional single-mouse system, there might be only one MouseInputSource. On a - multi-touch system, there could be one input source per potential finger. The number - of mouse sources returned here may increase dynamically as the program runs. - To find out how many mouse events are currently happening, use getNumDraggingMouseSources(). - */ - const Array& getMouseSources() const noexcept; - - /** Returns the number of MouseInputSource objects the system has at its disposal. - In a traditional single-mouse system, there might be only one MouseInputSource. On a - multi-touch system, there could be one input source per potential finger. The number - of mouse sources returned here may increase dynamically as the program runs. - To find out how many mouse events are currently happening, use getNumDraggingMouseSources(). - @see getMouseSource - */ - int getNumMouseSources() const noexcept; - - /** Returns one of the system's MouseInputSource objects. - The index should be from 0 to getNumMouseSources() - 1. Out-of-range indexes will return - a null pointer. - In a traditional single-mouse system, there might be only one object. On a multi-touch - system, there could be one input source per potential finger. - */ - MouseInputSource* getMouseSource (int index) const noexcept; - - /** Returns the main mouse input device that the system is using. - @see getNumMouseSources() - */ - MouseInputSource getMainMouseSource() const noexcept; - - /** Returns the number of mouse-sources that are currently being dragged. - In a traditional single-mouse system, this will be 0 or 1, depending on whether a - juce component has the button down on it. In a multi-touch system, this could - be any number from 0 to the number of simultaneous touches that can be detected. - */ - int getNumDraggingMouseSources() const noexcept; - - /** Returns one of the mouse sources that's currently being dragged. - The index should be between 0 and getNumDraggingMouseSources() - 1. If the index is - out of range, or if no mice or fingers are down, this will return a null pointer. - */ - MouseInputSource* getDraggingMouseSource (int index) const noexcept; - - /** Ensures that a non-stop stream of mouse-drag events will be sent during the - current mouse-drag operation. - - This allows you to make sure that mouseDrag() events are sent continuously, even - when the mouse isn't moving. This can be useful for things like auto-scrolling - components when the mouse is near an edge. - - Call this method during a mouseDown() or mouseDrag() callback, specifying the - minimum interval between consecutive mouse drag callbacks. The callbacks - will continue until the mouse is released, and then the interval will be reset, - so you need to make sure it's called every time you begin a drag event. - Passing an interval of 0 or less will cancel the auto-repeat. - - @see mouseDrag - */ - void beginDragAutoRepeat (int millisecondsBetweenCallbacks); - - //============================================================================== - /** In a tablet/mobile device which can be turned around, this is used to indicate the orientation. */ - enum DisplayOrientation - { - upright = 1, /**< Indicates that the device is the normal way up. */ - upsideDown = 2, /**< Indicates that the device is upside-down. */ - rotatedClockwise = 4, /**< Indicates that the device is turned 90 degrees clockwise from its upright position. */ - rotatedAntiClockwise = 8, /**< Indicates that the device is turned 90 degrees anti-clockwise from its upright position. */ - - allOrientations = 1 + 2 + 4 + 8 /**< A combination of all the orientation values */ - }; - - /** In a tablet device which can be turned around, this returns the current orientation. */ - DisplayOrientation getCurrentOrientation() const; - - /** Sets which orientations the display is allowed to auto-rotate to. - - For devices that support rotating desktops, this lets you specify which of the orientations your app can use. - - The parameter is a bitwise or-ed combination of the values in DisplayOrientation, and must contain at least one - set bit. - */ - void setOrientationsEnabled (int allowedOrientations); - - /** Returns the set of orientations the display is allowed to rotate to. - @see setOrientationsEnabled - */ - int getOrientationsEnabled() const noexcept; - - /** Returns whether the display is allowed to auto-rotate to the given orientation. - Each orientation can be enabled using setOrientationEnabled(). By default, all orientations are allowed. - */ - bool isOrientationEnabled (DisplayOrientation orientation) const noexcept; - - //============================================================================== - class JUCE_API Displays - { - public: - /** Contains details about a display device. */ - struct Display - { - /** This is the bounds of the area of this display which isn't covered by - OS-dependent objects like the taskbar, menu bar, etc. */ - Rectangle userArea; - - /** This is the total physical area of this display, including any taskbars, etc */ - Rectangle totalArea; - - /** This is the scale-factor of this display. - If you create a component with size 1x1, this scale factor indicates the actual - size of the component in terms of physical pixels. - For higher-resolution displays, it may be a value greater than 1.0 - */ - double scale; - - /** The DPI of the display. - This is the number of physical pixels per inch. To get the number of logical - pixels per inch, divide this by the Display::scale value. - */ - double dpi; - - /** This will be true if this is the user's main screen. */ - bool isMain; - }; - - /** Returns the display which acts as user's main screen. */ - const Display& getMainDisplay() const noexcept; - - /** Returns the display which contains a particular point. - If the point lies outside all the displays, the nearest one will be returned. - */ - const Display& getDisplayContaining (Point position) const noexcept; - - /** Returns a RectangleList made up of all the displays. */ - RectangleList getRectangleList (bool userAreasOnly) const; - - /** Returns the smallest bounding box which contains all the displays. */ - Rectangle getTotalBounds (bool userAreasOnly) const; - - /** The list of displays. */ - Array displays; - - #ifndef DOXYGEN - /** @internal */ - void refresh(); - #endif - - private: - friend class Desktop; - friend struct ContainerDeletePolicy; - Displays (Desktop&); - ~Displays(); - - void init (Desktop&); - void findDisplays (float masterScale); - }; - - const Displays& getDisplays() const noexcept { return *displays; } - - //============================================================================== - /** Sets a global scale factor to be used for all desktop windows. - Setting this will also scale the monitor sizes that are returned by getDisplays(). - */ - void setGlobalScaleFactor (float newScaleFactor) noexcept; - - /** Returns the current global scale factor, as set by setGlobalScaleFactor(). - @see setGlobalScaleFactor - */ - float getGlobalScaleFactor() const noexcept { return masterScaleFactor; } - - //============================================================================== - /** True if the OS supports semitransparent windows */ - static bool canUseSemiTransparentWindows() noexcept; - - #if JUCE_MAC - /** OSX-specific function to check for the "dark" title-bar and menu mode. */ - static bool isOSXDarkModeActive(); - #endif - -private: - //============================================================================== - static Desktop* instance; - - friend class Component; - friend class ComponentPeer; - friend class MouseInputSourceInternal; - friend class DeletedAtShutdown; - friend class TopLevelWindowManager; - - ScopedPointer mouseSources; - - ListenerList mouseListeners; - ListenerList focusListeners; - - Array desktopComponents; - Array peers; - - ScopedPointer displays; - - Point lastFakeMouseMove; - void sendMouseMove(); - - int mouseClickCounter, mouseWheelCounter; - void incrementMouseClickCounter() noexcept; - void incrementMouseWheelCounter() noexcept; - - ScopedPointer defaultLookAndFeel; - WeakReference currentLookAndFeel; - - Component* kioskModeComponent; - Rectangle kioskComponentOriginalBounds; - bool kioskModeReentrant; - - int allowedOrientations; - void allowedOrientationsChanged(); - - float masterScaleFactor; - - ComponentAnimator animator; - - void timerCallback() override; - void resetTimer(); - ListenerList& getMouseListeners(); - - void addDesktopComponent (Component*); - void removeDesktopComponent (Component*); - void componentBroughtToFront (Component*); - - void setKioskComponent (Component*, bool shouldBeEnabled, bool allowMenusAndBars); - - void triggerFocusCallback(); - void handleAsyncUpdate() override; - - static Point getMousePositionFloat(); - - static double getDefaultMasterScale(); - - Desktop(); - ~Desktop(); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Desktop) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp b/source/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp deleted file mode 100644 index b08f24014..000000000 --- a/source/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp +++ /dev/null @@ -1,318 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -class ModalComponentManager::ModalItem : public ComponentMovementWatcher -{ -public: - ModalItem (Component* const comp, const bool autoDelete_) - : ComponentMovementWatcher (comp), - component (comp), returnValue (0), - isActive (true), autoDelete (autoDelete_) - { - jassert (comp != nullptr); - } - - void componentMovedOrResized (bool, bool) override {} - - void componentPeerChanged() override - { - if (! component->isShowing()) - cancel(); - } - - void componentVisibilityChanged() override - { - if (! component->isShowing()) - cancel(); - } - - void componentBeingDeleted (Component& comp) override - { - ComponentMovementWatcher::componentBeingDeleted (comp); - - if (component == &comp || comp.isParentOf (component)) - { - autoDelete = false; - cancel(); - } - } - - void cancel() - { - if (isActive) - { - isActive = false; - - if (ModalComponentManager* mcm = ModalComponentManager::getInstanceWithoutCreating()) - mcm->triggerAsyncUpdate(); - } - } - - Component* component; - OwnedArray callbacks; - int returnValue; - bool isActive, autoDelete; - -private: - JUCE_DECLARE_NON_COPYABLE (ModalItem) -}; - -//============================================================================== -ModalComponentManager::ModalComponentManager() -{ -} - -ModalComponentManager::~ModalComponentManager() -{ - stack.clear(); - clearSingletonInstance(); -} - -juce_ImplementSingleton_SingleThreaded (ModalComponentManager) - - -//============================================================================== -void ModalComponentManager::startModal (Component* component, bool autoDelete) -{ - if (component != nullptr) - stack.add (new ModalItem (component, autoDelete)); -} - -void ModalComponentManager::attachCallback (Component* component, Callback* callback) -{ - if (callback != nullptr) - { - ScopedPointer callbackDeleter (callback); - - for (int i = stack.size(); --i >= 0;) - { - ModalItem* const item = stack.getUnchecked(i); - - if (item->component == component) - { - item->callbacks.add (callback); - callbackDeleter.release(); - break; - } - } - } -} - -void ModalComponentManager::endModal (Component* component) -{ - for (int i = stack.size(); --i >= 0;) - { - ModalItem* const item = stack.getUnchecked(i); - - if (item->component == component) - item->cancel(); - } -} - -void ModalComponentManager::endModal (Component* component, int returnValue) -{ - for (int i = stack.size(); --i >= 0;) - { - ModalItem* const item = stack.getUnchecked(i); - - if (item->component == component) - { - item->returnValue = returnValue; - item->cancel(); - } - } -} - -int ModalComponentManager::getNumModalComponents() const -{ - int n = 0; - for (int i = 0; i < stack.size(); ++i) - if (stack.getUnchecked(i)->isActive) - ++n; - - return n; -} - -Component* ModalComponentManager::getModalComponent (const int index) const -{ - int n = 0; - for (int i = stack.size(); --i >= 0;) - { - const ModalItem* const item = stack.getUnchecked(i); - if (item->isActive) - if (n++ == index) - return item->component; - } - - return nullptr; -} - -bool ModalComponentManager::isModal (Component* const comp) const -{ - for (int i = stack.size(); --i >= 0;) - { - const ModalItem* const item = stack.getUnchecked(i); - if (item->isActive && item->component == comp) - return true; - } - - return false; -} - -bool ModalComponentManager::isFrontModalComponent (Component* const comp) const -{ - return comp == getModalComponent (0); -} - -void ModalComponentManager::handleAsyncUpdate() -{ - for (int i = stack.size(); --i >= 0;) - { - const ModalItem* const item = stack.getUnchecked(i); - - if (! item->isActive) - { - ScopedPointer deleter (stack.removeAndReturn (i)); - Component::SafePointer compToDelete (item->autoDelete ? item->component : nullptr); - - for (int j = item->callbacks.size(); --j >= 0;) - item->callbacks.getUnchecked(j)->modalStateFinished (item->returnValue); - - compToDelete.deleteAndZero(); - } - } -} - -void ModalComponentManager::bringModalComponentsToFront (bool topOneShouldGrabFocus) -{ - ComponentPeer* lastOne = nullptr; - - for (int i = 0; i < getNumModalComponents(); ++i) - { - Component* const c = getModalComponent (i); - - if (c == nullptr) - break; - - ComponentPeer* peer = c->getPeer(); - - if (peer != nullptr && peer != lastOne) - { - if (lastOne == nullptr) - { - peer->toFront (topOneShouldGrabFocus); - - if (topOneShouldGrabFocus) - peer->grabFocus(); - } - else - peer->toBehind (lastOne); - - lastOne = peer; - } - } -} - -bool ModalComponentManager::cancelAllModalComponents() -{ - const int numModal = getNumModalComponents(); - - for (int i = numModal; --i >= 0;) - if (Component* const c = getModalComponent(i)) - c->exitModalState (0); - - return numModal > 0; -} - -//============================================================================== -#if JUCE_MODAL_LOOPS_PERMITTED -class ModalComponentManager::ReturnValueRetriever : public ModalComponentManager::Callback -{ -public: - ReturnValueRetriever (int& v, bool& done) : value (v), finished (done) {} - - void modalStateFinished (int returnValue) override - { - finished = true; - value = returnValue; - } - -private: - int& value; - bool& finished; - - JUCE_DECLARE_NON_COPYABLE (ReturnValueRetriever) -}; - -int ModalComponentManager::runEventLoopForCurrentComponent() -{ - // This can only be run from the message thread! - jassert (MessageManager::getInstance()->isThisTheMessageThread()); - - int returnValue = 0; - - if (Component* currentlyModal = getModalComponent (0)) - { - FocusRestorer focusRestorer; - - bool finished = false; - attachCallback (currentlyModal, new ReturnValueRetriever (returnValue, finished)); - - JUCE_TRY - { - while (! finished) - { - if (! MessageManager::getInstance()->runDispatchLoopUntil (20)) - break; - } - } - JUCE_CATCH_EXCEPTION - } - - return returnValue; -} -#endif - -//============================================================================== -struct LambdaCallback : public ModalComponentManager::Callback -{ - LambdaCallback (std::function fn) noexcept : function (fn) {} - void modalStateFinished (int result) override { function (result); } - - std::function function; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LambdaCallback) -}; - -ModalComponentManager::Callback* ModalCallbackFunction::create (std::function f) -{ - return new LambdaCallback (f); -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/components/juce_ModalComponentManager.h b/source/modules/juce_gui_basics/components/juce_ModalComponentManager.h deleted file mode 100644 index 0d9df70dc..000000000 --- a/source/modules/juce_gui_basics/components/juce_ModalComponentManager.h +++ /dev/null @@ -1,374 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - Manages the system's stack of modal components. - - Normally you'll just use the Component methods to invoke modal states in components, - and won't have to deal with this class directly, but this is the singleton object that's - used internally to manage the stack. - - @see Component::enterModalState, Component::exitModalState, Component::isCurrentlyModal, - Component::getCurrentlyModalComponent, Component::isCurrentlyBlockedByAnotherModalComponent -*/ -class JUCE_API ModalComponentManager : private AsyncUpdater, - private DeletedAtShutdown -{ -public: - //============================================================================== - /** Receives callbacks when a modal component is dismissed. - - You can register a callback using Component::enterModalState() or - ModalComponentManager::attachCallback(). - - For some quick ways of creating callback objects, see the ModalCallbackFunction class. - @see ModalCallbackFunction - */ - class JUCE_API Callback - { - public: - /** */ - Callback() {} - - /** Destructor. */ - virtual ~Callback() {} - - /** Called to indicate that a modal component has been dismissed. - - You can register a callback using Component::enterModalState() or - ModalComponentManager::attachCallback(). - - The returnValue parameter is the value that was passed to Component::exitModalState() - when the component was dismissed. - - The callback object will be deleted shortly after this method is called. - */ - virtual void modalStateFinished (int returnValue) = 0; - }; - - //============================================================================== - juce_DeclareSingleton_SingleThreaded_Minimal (ModalComponentManager) - - //============================================================================== - /** Returns the number of components currently being shown modally. - @see getModalComponent - */ - int getNumModalComponents() const; - - /** Returns one of the components being shown modally. - An index of 0 is the most recently-shown, topmost component. - */ - Component* getModalComponent (int index) const; - - /** Returns true if the specified component is in a modal state. */ - bool isModal (Component* component) const; - - /** Returns true if the specified component is currently the topmost modal component. */ - bool isFrontModalComponent (Component* component) const; - - /** Adds a new callback that will be called when the specified modal component is dismissed. - - If the component is modal, then when it is dismissed, either by being hidden, or by calling - Component::exitModalState(), then the Callback::modalStateFinished() method will be - called. - - Each component can have any number of callbacks associated with it, and this one is added - to that list. - - The object that is passed in will be deleted by the manager when it's no longer needed. If - the given component is not currently modal, the callback object is deleted immediately and - no action is taken. - */ - void attachCallback (Component* component, Callback* callback); - - /** Brings any modal components to the front. */ - void bringModalComponentsToFront (bool topOneShouldGrabFocus = true); - - /** Calls exitModalState (0) on any components that are currently modal. - @returns true if any components were modal; false if nothing needed cancelling - */ - bool cancelAllModalComponents(); - - #if JUCE_MODAL_LOOPS_PERMITTED - /** Runs the event loop until the currently topmost modal component is dismissed, and - returns the exit code for that component. - */ - int runEventLoopForCurrentComponent(); - #endif - -protected: - /** Creates a ModalComponentManager. - You shouldn't ever call the constructor - it's a singleton, so use ModalComponentManager::getInstance() - */ - ModalComponentManager(); - - /** Destructor. */ - ~ModalComponentManager(); - - /** @internal */ - void handleAsyncUpdate() override; - -private: - //============================================================================== - class ModalItem; - class ReturnValueRetriever; - - friend class Component; - friend struct ContainerDeletePolicy; - OwnedArray stack; - - void startModal (Component*, bool autoDelete); - void endModal (Component*, int returnValue); - void endModal (Component*); - - JUCE_DECLARE_NON_COPYABLE (ModalComponentManager) -}; - -//============================================================================== -/** - This class provides some handy utility methods for creating ModalComponentManager::Callback - objects that will invoke a static function with some parameters when a modal component is dismissed. -*/ -class ModalCallbackFunction -{ -public: - //============================================================================== - /** This is a utility function to create a ModalComponentManager::Callback that will - call a static function with a parameter. - - The function that you supply must take two parameters - the first being an int, which is - the result code that was used when the modal component was dismissed, and the second - can be a custom type. Note that this custom value will be copied and stored, so it must - be a primitive type or a class that provides copy-by-value semantics. - - E.g. @code - static void myCallbackFunction (int modalResult, double customValue) - { - if (modalResult == 1) - doSomethingWith (customValue); - } - - Component* someKindOfComp; - ... - someKindOfComp->enterModalState (ModalCallbackFunction::create (myCallbackFunction, 3.0)); - @endcode - @see ModalComponentManager::Callback - */ - template - static ModalComponentManager::Callback* create (void (*functionToCall) (int, ParamType), - ParamType parameterValue) - { - return new FunctionCaller1 (functionToCall, parameterValue); - } - - /** This is a utility function to create a ModalComponentManager::Callback that will - call a lambda function. - The lambda that you supply must take an integer parameter, which is the result code that - was returned when the modal component was dismissed. - - @see ModalComponentManager::Callback - */ - static ModalComponentManager::Callback* create (std::function); - - //============================================================================== - /** This is a utility function to create a ModalComponentManager::Callback that will - call a static function with two custom parameters. - - The function that you supply must take three parameters - the first being an int, which is - the result code that was used when the modal component was dismissed, and the next two are - your custom types. Note that these custom values will be copied and stored, so they must - be primitive types or classes that provide copy-by-value semantics. - - E.g. @code - static void myCallbackFunction (int modalResult, double customValue1, String customValue2) - { - if (modalResult == 1) - doSomethingWith (customValue1, customValue2); - } - - Component* someKindOfComp; - ... - someKindOfComp->enterModalState (ModalCallbackFunction::create (myCallbackFunction, 3.0, String ("xyz"))); - @endcode - @see ModalComponentManager::Callback - */ - template - static ModalComponentManager::Callback* withParam (void (*functionToCall) (int, ParamType1, ParamType2), - ParamType1 parameterValue1, - ParamType2 parameterValue2) - { - return new FunctionCaller2 (functionToCall, parameterValue1, parameterValue2); - } - - //============================================================================== - /** This is a utility function to create a ModalComponentManager::Callback that will - call a static function with a component. - - The function that you supply must take two parameters - the first being an int, which is - the result code that was used when the modal component was dismissed, and the second - can be a Component class. The component will be stored as a WeakReference, so that if it gets - deleted before this callback is invoked, the pointer that is passed to the function will be null. - - E.g. @code - static void myCallbackFunction (int modalResult, Slider* mySlider) - { - if (modalResult == 1 && mySlider != nullptr) // (must check that mySlider isn't null in case it was deleted..) - mySlider->setValue (0.0); - } - - Component* someKindOfComp; - Slider* mySlider; - ... - someKindOfComp->enterModalState (ModalCallbackFunction::forComponent (myCallbackFunction, mySlider)); - @endcode - @see ModalComponentManager::Callback - */ - template - static ModalComponentManager::Callback* forComponent (void (*functionToCall) (int, ComponentType*), - ComponentType* component) - { - return new ComponentCaller1 (functionToCall, component); - } - - //============================================================================== - /** Creates a ModalComponentManager::Callback that will call a static function with a component. - - The function that you supply must take three parameters - the first being an int, which is - the result code that was used when the modal component was dismissed, the second being a Component - class, and the third being a custom type (which must be a primitive type or have copy-by-value semantics). - The component will be stored as a WeakReference, so that if it gets deleted before this callback is - invoked, the pointer that is passed into the function will be null. - - E.g. @code - static void myCallbackFunction (int modalResult, Slider* mySlider, String customParam) - { - if (modalResult == 1 && mySlider != nullptr) // (must check that mySlider isn't null in case it was deleted..) - mySlider->setName (customParam); - } - - Component* someKindOfComp; - Slider* mySlider; - ... - someKindOfComp->enterModalState (ModalCallbackFunction::forComponent (myCallbackFunction, mySlider, String ("hello"))); - @endcode - @see ModalComponentManager::Callback - */ - template - static ModalComponentManager::Callback* forComponent (void (*functionToCall) (int, ComponentType*, ParamType), - ComponentType* component, - ParamType param) - { - return new ComponentCaller2 (functionToCall, component, param); - } - -private: - //============================================================================== - template - struct FunctionCaller1 : public ModalComponentManager::Callback - { - typedef void (*FunctionType) (int, ParamType); - - FunctionCaller1 (FunctionType& f, ParamType& p1) - : function (f), param (p1) {} - - void modalStateFinished (int returnValue) override { function (returnValue, param); } - - private: - const FunctionType function; - ParamType param; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FunctionCaller1) - }; - - template - struct FunctionCaller2 : public ModalComponentManager::Callback - { - typedef void (*FunctionType) (int, ParamType1, ParamType2); - - FunctionCaller2 (FunctionType& f, ParamType1& p1, ParamType2& p2) - : function (f), param1 (p1), param2 (p2) {} - - void modalStateFinished (int returnValue) override { function (returnValue, param1, param2); } - - private: - const FunctionType function; - ParamType1 param1; - ParamType2 param2; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FunctionCaller2) - }; - - template - struct ComponentCaller1 : public ModalComponentManager::Callback - { - typedef void (*FunctionType) (int, ComponentType*); - - ComponentCaller1 (FunctionType& f, ComponentType* c) - : function (f), comp (c) {} - - void modalStateFinished (int returnValue) override - { - function (returnValue, static_cast (comp.get())); - } - - private: - const FunctionType function; - WeakReference comp; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComponentCaller1) - }; - - template - struct ComponentCaller2 : public ModalComponentManager::Callback - { - typedef void (*FunctionType) (int, ComponentType*, ParamType1); - - ComponentCaller2 (FunctionType& f, ComponentType* c, ParamType1 p1) - : function (f), comp (c), param1 (p1) {} - - void modalStateFinished (int returnValue) override - { - function (returnValue, static_cast (comp.get()), param1); - } - - private: - const FunctionType function; - WeakReference comp; - ParamType1 param1; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComponentCaller2) - }; - - ModalCallbackFunction(); - ~ModalCallbackFunction(); - JUCE_DECLARE_NON_COPYABLE (ModalCallbackFunction) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/drawables/juce_Drawable.cpp b/source/modules/juce_gui_basics/drawables/juce_Drawable.cpp deleted file mode 100644 index 0589ee986..000000000 --- a/source/modules/juce_gui_basics/drawables/juce_Drawable.cpp +++ /dev/null @@ -1,282 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -Drawable::Drawable() -{ - setInterceptsMouseClicks (false, false); - setPaintingIsUnclipped (true); -} - -Drawable::Drawable (const Drawable& other) - : Component (other.getName()) -{ - setInterceptsMouseClicks (false, false); - setPaintingIsUnclipped (true); - - setComponentID (other.getComponentID()); - setTransform (other.getTransform()); -} - -Drawable::~Drawable() -{ -} - -void Drawable::applyDrawableClipPath (Graphics& g) -{ - if (drawableClipPath != nullptr) - { - auto clipPath = drawableClipPath->getOutlineAsPath(); - - if (! clipPath.isEmpty()) - g.getInternalContext().clipToPath (clipPath, {}); - } -} - -//============================================================================== -void Drawable::draw (Graphics& g, float opacity, const AffineTransform& transform) const -{ - const_cast (this)->nonConstDraw (g, opacity, transform); -} - -void Drawable::nonConstDraw (Graphics& g, float opacity, const AffineTransform& transform) -{ - Graphics::ScopedSaveState ss (g); - - g.addTransform (AffineTransform::translation ((float) -(originRelativeToComponent.x), - (float) -(originRelativeToComponent.y)) - .followedBy (getTransform()) - .followedBy (transform)); - - applyDrawableClipPath (g); - - if (! g.isClipEmpty()) - { - if (opacity < 1.0f) - { - g.beginTransparencyLayer (opacity); - paintEntireComponent (g, true); - g.endTransparencyLayer(); - } - else - { - paintEntireComponent (g, true); - } - } -} - -void Drawable::drawAt (Graphics& g, float x, float y, float opacity) const -{ - draw (g, opacity, AffineTransform::translation (x, y)); -} - -void Drawable::drawWithin (Graphics& g, Rectangle destArea, - RectanglePlacement placement, float opacity) const -{ - draw (g, opacity, placement.getTransformToFit (getDrawableBounds(), destArea)); -} - -//============================================================================== -DrawableComposite* Drawable::getParent() const -{ - return dynamic_cast (getParentComponent()); -} - -void Drawable::setClipPath (Drawable* clipPath) -{ - if (drawableClipPath != clipPath) - { - drawableClipPath = clipPath; - repaint(); - } -} - -void Drawable::transformContextToCorrectOrigin (Graphics& g) -{ - g.setOrigin (originRelativeToComponent); -} - -void Drawable::parentHierarchyChanged() -{ - setBoundsToEnclose (getDrawableBounds()); -} - -void Drawable::setBoundsToEnclose (Rectangle area) -{ - Point parentOrigin; - - if (auto* parent = getParent()) - parentOrigin = parent->originRelativeToComponent; - - auto newBounds = area.getSmallestIntegerContainer() + parentOrigin; - originRelativeToComponent = parentOrigin - newBounds.getPosition(); - setBounds (newBounds); -} - -//============================================================================== -bool Drawable::replaceColour (Colour original, Colour replacement) -{ - bool changed = false; - - for (auto* c : getChildren()) - if (auto* d = dynamic_cast (c)) - changed = d->replaceColour (original, replacement) || changed; - - return changed; -} - -//============================================================================== -void Drawable::setOriginWithOriginalSize (Point originWithinParent) -{ - setTransform (AffineTransform::translation (originWithinParent.x, originWithinParent.y)); -} - -void Drawable::setTransformToFit (const Rectangle& area, RectanglePlacement placement) -{ - if (! area.isEmpty()) - setTransform (placement.getTransformToFit (getDrawableBounds(), area)); -} - -//============================================================================== -Drawable* Drawable::createFromImageData (const void* data, const size_t numBytes) -{ - Drawable* result = nullptr; - - auto image = ImageFileFormat::loadFrom (data, numBytes); - - if (image.isValid()) - { - auto* di = new DrawableImage(); - di->setImage (image); - result = di; - } - else - { - auto asString = String::createStringFromData (data, (int) numBytes); - - XmlDocument doc (asString); - ScopedPointer outer (doc.getDocumentElement (true)); - - if (outer != nullptr && outer->hasTagName ("svg")) - { - ScopedPointer svg (doc.getDocumentElement()); - - if (svg != nullptr) - result = Drawable::createFromSVG (*svg); - } - } - - return result; -} - -Drawable* Drawable::createFromImageDataStream (InputStream& dataSource) -{ - MemoryOutputStream mo; - mo << dataSource; - - return createFromImageData (mo.getData(), mo.getDataSize()); -} - -Drawable* Drawable::createFromImageFile (const File& file) -{ - FileInputStream fin (file); - - return fin.openedOk() ? createFromImageDataStream (fin) : nullptr; -} - -//============================================================================== -template -struct DrawableTypeHandler : public ComponentBuilder::TypeHandler -{ - DrawableTypeHandler() : ComponentBuilder::TypeHandler (DrawableClass::valueTreeType) - { - } - - Component* addNewComponentFromState (const ValueTree& state, Component* parent) - { - auto* d = new DrawableClass(); - - if (parent != nullptr) - parent->addAndMakeVisible (d); - - updateComponentFromState (d, state); - return d; - } - - void updateComponentFromState (Component* component, const ValueTree& state) - { - if (auto* d = dynamic_cast (component)) - d->refreshFromValueTree (state, *this->getBuilder()); - else - jassertfalse; - } -}; - -void Drawable::registerDrawableTypeHandlers (ComponentBuilder& builder) -{ - builder.registerTypeHandler (new DrawableTypeHandler()); - builder.registerTypeHandler (new DrawableTypeHandler()); - builder.registerTypeHandler (new DrawableTypeHandler()); - builder.registerTypeHandler (new DrawableTypeHandler()); - builder.registerTypeHandler (new DrawableTypeHandler()); -} - -Drawable* Drawable::createFromValueTree (const ValueTree& tree, ComponentBuilder::ImageProvider* imageProvider) -{ - ComponentBuilder builder (tree); - builder.setImageProvider (imageProvider); - registerDrawableTypeHandlers (builder); - - ScopedPointer comp (builder.createComponent()); - auto* d = dynamic_cast (static_cast (comp)); - - if (d != nullptr) - comp.release(); - - return d; -} - -//============================================================================== -Drawable::ValueTreeWrapperBase::ValueTreeWrapperBase (const ValueTree& s) : state (s) -{ -} - -String Drawable::ValueTreeWrapperBase::getID() const -{ - return state [ComponentBuilder::idProperty]; -} - -void Drawable::ValueTreeWrapperBase::setID (const String& newID) -{ - if (newID.isEmpty()) - state.removeProperty (ComponentBuilder::idProperty, nullptr); - else - state.setProperty (ComponentBuilder::idProperty, newID, nullptr); -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/drawables/juce_Drawable.h b/source/modules/juce_gui_basics/drawables/juce_Drawable.h deleted file mode 100644 index 95b39b49d..000000000 --- a/source/modules/juce_gui_basics/drawables/juce_Drawable.h +++ /dev/null @@ -1,285 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - The base class for objects which can draw themselves, e.g. polygons, images, etc. - - @see DrawableComposite, DrawableImage, DrawablePath, DrawableText -*/ -class JUCE_API Drawable : public Component -{ -protected: - //============================================================================== - /** The base class can't be instantiated directly. - - @see DrawableComposite, DrawableImage, DrawablePath, DrawableText - */ - Drawable(); - -public: - /** Destructor. */ - virtual ~Drawable(); - - //============================================================================== - /** Creates a deep copy of this Drawable object. - - Use this to create a new copy of this and any sub-objects in the tree. - */ - virtual Drawable* createCopy() const = 0; - - /** Creates a path that describes the outline of this drawable. */ - virtual Path getOutlineAsPath() const = 0; - - //============================================================================== - /** Renders this Drawable object. - - Note that the preferred way to render a drawable in future is by using it - as a component and adding it to a parent, so you might want to consider that - before using this method. - - @see drawWithin - */ - void draw (Graphics& g, float opacity, - const AffineTransform& transform = AffineTransform()) const; - - /** Renders the Drawable at a given offset within the Graphics context. - - The coordinates passed-in are used to translate the object relative to its own - origin before drawing it - this is basically a quick way of saying: - - @code - draw (g, AffineTransform::translation (x, y)). - @endcode - - Note that the preferred way to render a drawable in future is by using it - as a component and adding it to a parent, so you might want to consider that - before using this method. - */ - void drawAt (Graphics& g, float x, float y, float opacity) const; - - /** Renders the Drawable within a rectangle, scaling it to fit neatly inside without - changing its aspect-ratio. - - The object can placed arbitrarily within the rectangle based on a Justification type, - and can either be made as big as possible, or just reduced to fit. - - Note that the preferred way to render a drawable in future is by using it - as a component and adding it to a parent, so you might want to consider that - before using this method. - - @param g the graphics context to render onto - @param destArea the target rectangle to fit the drawable into - @param placement defines the alignment and rescaling to use to fit - this object within the target rectangle. - @param opacity the opacity to use, in the range 0 to 1.0 - */ - void drawWithin (Graphics& g, - Rectangle destArea, - RectanglePlacement placement, - float opacity) const; - - - //============================================================================== - /** Resets any transformations on this drawable, and positions its origin within - its parent component. - */ - void setOriginWithOriginalSize (Point originWithinParent); - - /** Sets a transform for this drawable that will position it within the specified - area of its parent component. - */ - void setTransformToFit (const Rectangle& areaInParent, RectanglePlacement placement); - - /** Returns the DrawableComposite that contains this object, if there is one. */ - DrawableComposite* getParent() const; - - /** Sets a the clipping region of this drawable using another drawable. - The drawbale passed in ill be deleted when no longer needed. - */ - void setClipPath (Drawable* drawableClipPath); - - //============================================================================== - /** Tries to turn some kind of image file into a drawable. - - The data could be an image that the ImageFileFormat class understands, or it - could be SVG. - */ - static Drawable* createFromImageData (const void* data, size_t numBytes); - - /** Tries to turn a stream containing some kind of image data into a drawable. - - The data could be an image that the ImageFileFormat class understands, or it - could be SVG. - */ - static Drawable* createFromImageDataStream (InputStream& dataSource); - - /** Tries to turn a file containing some kind of image data into a drawable. - - The data could be an image that the ImageFileFormat class understands, or it - could be SVG. - */ - static Drawable* createFromImageFile (const File& file); - - /** Attempts to parse an SVG (Scalable Vector Graphics) document, and to turn this - into a Drawable tree. - - The object returned must be deleted by the caller. If something goes wrong - while parsing, it may return nullptr. - - SVG is a pretty large and complex spec, and this doesn't aim to be a full - implementation, but it can return the basic vector objects. - */ - static Drawable* createFromSVG (const XmlElement& svgDocument); - - /** Attempts to parse an SVG (Scalable Vector Graphics) document from a file, - and to turn this into a Drawable tree. - - The object returned must be deleted by the caller. If something goes wrong - while parsing, it may return nullptr. - - SVG is a pretty large and complex spec, and this doesn't aim to be a full - implementation, but it can return the basic vector objects. - - Any references to references to external image files will be relative to - the parent directory of the file passed. - */ - static Drawable* createFromSVGFile (const File& svgFile); - - /** Parses an SVG path string and returns it. */ - static Path parseSVGPath (const String& svgPath); - - //============================================================================== - /** Tries to create a Drawable from a previously-saved ValueTree. - The ValueTree must have been created by the createValueTree() method. - If there are any images used within the drawable, you'll need to provide a valid - ImageProvider object that can be used to retrieve these images from whatever type - of identifier is used to represent them. - Internally, this uses a ComponentBuilder, and registerDrawableTypeHandlers(). - */ - static Drawable* createFromValueTree (const ValueTree& tree, ComponentBuilder::ImageProvider* imageProvider); - - /** Creates a ValueTree to represent this Drawable. - The ValueTree that is returned can be turned back into a Drawable with createFromValueTree(). - If there are any images used in this drawable, you'll need to provide a valid ImageProvider - object that can be used to create storable representations of them. - */ - virtual ValueTree createValueTree (ComponentBuilder::ImageProvider* imageProvider) const = 0; - - /** Returns the area that this drawble covers. - The result is expressed in this drawable's own coordinate space, and does not take - into account any transforms that may be applied to the component. - */ - virtual Rectangle getDrawableBounds() const = 0; - - /** Recursively replaces a colour that might be used for filling or stroking. - return true if any instances of this colour were found. - */ - virtual bool replaceColour (Colour originalColour, Colour replacementColour); - - //============================================================================== - /** Internal class used to manage ValueTrees that represent Drawables. */ - class ValueTreeWrapperBase - { - public: - ValueTreeWrapperBase (const ValueTree& state); - - ValueTree& getState() noexcept { return state; } - - String getID() const; - void setID (const String& newID); - - ValueTree state; - }; - - //============================================================================== - /** Registers a set of ComponentBuilder::TypeHandler objects that can be used to - load all the different Drawable types from a saved state. - @see ComponentBuilder::registerTypeHandler() - */ - static void registerDrawableTypeHandlers (ComponentBuilder& componentBuilder); - -protected: - //============================================================================== - friend class DrawableComposite; - friend class DrawableShape; - - /** @internal */ - void transformContextToCorrectOrigin (Graphics&); - /** @internal */ - void parentHierarchyChanged() override; - /** @internal */ - void setBoundsToEnclose (Rectangle); - /** @internal */ - void applyDrawableClipPath (Graphics&); - - Point originRelativeToComponent; - ScopedPointer drawableClipPath; - - #ifndef DOXYGEN - /** Internal utility class used by Drawables. */ - template - class Positioner : public RelativeCoordinatePositionerBase - { - public: - Positioner (DrawableType& c) - : RelativeCoordinatePositionerBase (c), - owner (c) - {} - - bool registerCoordinates() override { return owner.registerCoordinates (*this); } - - void applyToComponentBounds() override - { - ComponentScope scope (getComponent()); - owner.recalculateCoordinates (&scope); - } - - void applyNewBounds (const Rectangle&) override - { - jassertfalse; // drawables can't be resized directly! - } - - private: - DrawableType& owner; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Positioner) - }; - - Drawable (const Drawable&); - #endif - -private: - void nonConstDraw (Graphics&, float opacity, const AffineTransform&); - - Drawable& operator= (const Drawable&); - JUCE_LEAK_DETECTOR (Drawable) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/drawables/juce_DrawableComposite.cpp b/source/modules/juce_gui_basics/drawables/juce_DrawableComposite.cpp deleted file mode 100644 index 3792a1638..000000000 --- a/source/modules/juce_gui_basics/drawables/juce_DrawableComposite.cpp +++ /dev/null @@ -1,334 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -DrawableComposite::DrawableComposite() - : bounds (Point(), Point (100.0f, 0.0f), Point (0.0f, 100.0f)) -{ - setContentArea (RelativeRectangle (Rectangle (0.0f, 0.0f, 100.0f, 100.0f))); -} - -DrawableComposite::DrawableComposite (const DrawableComposite& other) - : Drawable (other), - bounds (other.bounds), - markersX (other.markersX), - markersY (other.markersY) -{ - for (auto* c : other.getChildren()) - if (auto* d = dynamic_cast (c)) - addAndMakeVisible (d->createCopy()); -} - -DrawableComposite::~DrawableComposite() -{ - deleteAllChildren(); -} - -Drawable* DrawableComposite::createCopy() const -{ - return new DrawableComposite (*this); -} - -//============================================================================== -Rectangle DrawableComposite::getDrawableBounds() const -{ - Rectangle r; - - for (auto* c : getChildren()) - if (auto* d = dynamic_cast (c)) - r = r.getUnion (d->isTransformed() ? d->getDrawableBounds().transformedBy (d->getTransform()) - : d->getDrawableBounds()); - - return r; -} - -MarkerList* DrawableComposite::getMarkers (bool xAxis) -{ - return xAxis ? &markersX : &markersY; -} - -RelativeRectangle DrawableComposite::getContentArea() const -{ - jassert (markersX.getNumMarkers() >= 2 && markersX.getMarker (0)->name == contentLeftMarkerName && markersX.getMarker (1)->name == contentRightMarkerName); - jassert (markersY.getNumMarkers() >= 2 && markersY.getMarker (0)->name == contentTopMarkerName && markersY.getMarker (1)->name == contentBottomMarkerName); - - return RelativeRectangle (markersX.getMarker(0)->position, markersX.getMarker(1)->position, - markersY.getMarker(0)->position, markersY.getMarker(1)->position); -} - -void DrawableComposite::setContentArea (const RelativeRectangle& newArea) -{ - markersX.setMarker (contentLeftMarkerName, newArea.left); - markersX.setMarker (contentRightMarkerName, newArea.right); - markersY.setMarker (contentTopMarkerName, newArea.top); - markersY.setMarker (contentBottomMarkerName, newArea.bottom); -} - -void DrawableComposite::setBoundingBox (const RelativeParallelogram& newBounds) -{ - if (bounds != newBounds) - { - bounds = newBounds; - - if (bounds.isDynamic()) - { - auto p = new Drawable::Positioner (*this); - setPositioner (p); - p->apply(); - } - else - { - setPositioner (nullptr); - recalculateCoordinates (nullptr); - } - } -} - -void DrawableComposite::resetBoundingBoxToContentArea() -{ - const RelativeRectangle content (getContentArea()); - - setBoundingBox (RelativeParallelogram (RelativePoint (content.left, content.top), - RelativePoint (content.right, content.top), - RelativePoint (content.left, content.bottom))); -} - -void DrawableComposite::resetContentAreaAndBoundingBoxToFitChildren() -{ - setContentArea (RelativeRectangle (getDrawableBounds())); - resetBoundingBoxToContentArea(); -} - -bool DrawableComposite::registerCoordinates (RelativeCoordinatePositionerBase& pos) -{ - bool ok = pos.addPoint (bounds.topLeft); - ok = pos.addPoint (bounds.topRight) && ok; - return pos.addPoint (bounds.bottomLeft) && ok; -} - -void DrawableComposite::recalculateCoordinates (Expression::Scope* scope) -{ - Point resolved[3]; - bounds.resolveThreePoints (resolved, scope); - - auto content = getContentArea().resolve (scope); - - auto t = AffineTransform::fromTargetPoints (content.getX(), content.getY(), resolved[0].x, resolved[0].y, - content.getRight(), content.getY(), resolved[1].x, resolved[1].y, - content.getX(), content.getBottom(), resolved[2].x, resolved[2].y); - - if (t.isSingularity()) - t = AffineTransform(); - - setTransform (t); -} - -void DrawableComposite::parentHierarchyChanged() -{ - if (auto* parent = getParent()) - originRelativeToComponent = parent->originRelativeToComponent - getPosition(); -} - -void DrawableComposite::childBoundsChanged (Component*) -{ - updateBoundsToFitChildren(); -} - -void DrawableComposite::childrenChanged() -{ - updateBoundsToFitChildren(); -} - -void DrawableComposite::updateBoundsToFitChildren() -{ - if (! updateBoundsReentrant) - { - const ScopedValueSetter setter (updateBoundsReentrant, true, false); - - Rectangle childArea; - - for (auto* c : getChildren()) - childArea = childArea.getUnion (c->getBoundsInParent()); - - auto delta = childArea.getPosition(); - childArea += getPosition(); - - if (childArea != getBounds()) - { - if (! delta.isOrigin()) - { - originRelativeToComponent -= delta; - - for (auto* c : getChildren()) - c->setBounds (c->getBounds() - delta); - } - - setBounds (childArea); - } - } -} - -//============================================================================== -const char* const DrawableComposite::contentLeftMarkerName = "left"; -const char* const DrawableComposite::contentRightMarkerName = "right"; -const char* const DrawableComposite::contentTopMarkerName = "top"; -const char* const DrawableComposite::contentBottomMarkerName = "bottom"; - -//============================================================================== -const Identifier DrawableComposite::valueTreeType ("Group"); - -const Identifier DrawableComposite::ValueTreeWrapper::topLeft ("topLeft"); -const Identifier DrawableComposite::ValueTreeWrapper::topRight ("topRight"); -const Identifier DrawableComposite::ValueTreeWrapper::bottomLeft ("bottomLeft"); -const Identifier DrawableComposite::ValueTreeWrapper::childGroupTag ("Drawables"); -const Identifier DrawableComposite::ValueTreeWrapper::markerGroupTagX ("MarkersX"); -const Identifier DrawableComposite::ValueTreeWrapper::markerGroupTagY ("MarkersY"); - -//============================================================================== -DrawableComposite::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_) - : ValueTreeWrapperBase (state_) -{ - jassert (state.hasType (valueTreeType)); -} - -ValueTree DrawableComposite::ValueTreeWrapper::getChildList() const -{ - return state.getChildWithName (childGroupTag); -} - -ValueTree DrawableComposite::ValueTreeWrapper::getChildListCreating (UndoManager* undoManager) -{ - return state.getOrCreateChildWithName (childGroupTag, undoManager); -} - -RelativeParallelogram DrawableComposite::ValueTreeWrapper::getBoundingBox() const -{ - return RelativeParallelogram (state.getProperty (topLeft, "0, 0"), - state.getProperty (topRight, "100, 0"), - state.getProperty (bottomLeft, "0, 100")); -} - -void DrawableComposite::ValueTreeWrapper::setBoundingBox (const RelativeParallelogram& newBounds, UndoManager* undoManager) -{ - state.setProperty (topLeft, newBounds.topLeft.toString(), undoManager); - state.setProperty (topRight, newBounds.topRight.toString(), undoManager); - state.setProperty (bottomLeft, newBounds.bottomLeft.toString(), undoManager); -} - -void DrawableComposite::ValueTreeWrapper::resetBoundingBoxToContentArea (UndoManager* undoManager) -{ - const RelativeRectangle content (getContentArea()); - - setBoundingBox (RelativeParallelogram (RelativePoint (content.left, content.top), - RelativePoint (content.right, content.top), - RelativePoint (content.left, content.bottom)), undoManager); -} - -RelativeRectangle DrawableComposite::ValueTreeWrapper::getContentArea() const -{ - MarkerList::ValueTreeWrapper marksX (getMarkerList (true)); - MarkerList::ValueTreeWrapper marksY (getMarkerList (false)); - - return RelativeRectangle (marksX.getMarker (marksX.getMarkerState (0)).position, - marksX.getMarker (marksX.getMarkerState (1)).position, - marksY.getMarker (marksY.getMarkerState (0)).position, - marksY.getMarker (marksY.getMarkerState (1)).position); -} - -void DrawableComposite::ValueTreeWrapper::setContentArea (const RelativeRectangle& newArea, UndoManager* undoManager) -{ - MarkerList::ValueTreeWrapper marksX (getMarkerListCreating (true, nullptr)); - MarkerList::ValueTreeWrapper marksY (getMarkerListCreating (false, nullptr)); - - marksX.setMarker (MarkerList::Marker (contentLeftMarkerName, newArea.left), undoManager); - marksX.setMarker (MarkerList::Marker (contentRightMarkerName, newArea.right), undoManager); - marksY.setMarker (MarkerList::Marker (contentTopMarkerName, newArea.top), undoManager); - marksY.setMarker (MarkerList::Marker (contentBottomMarkerName, newArea.bottom), undoManager); -} - -MarkerList::ValueTreeWrapper DrawableComposite::ValueTreeWrapper::getMarkerList (bool xAxis) const -{ - return state.getChildWithName (xAxis ? markerGroupTagX : markerGroupTagY); -} - -MarkerList::ValueTreeWrapper DrawableComposite::ValueTreeWrapper::getMarkerListCreating (bool xAxis, UndoManager* undoManager) -{ - return state.getOrCreateChildWithName (xAxis ? markerGroupTagX : markerGroupTagY, undoManager); -} - -//============================================================================== -void DrawableComposite::refreshFromValueTree (const ValueTree& tree, ComponentBuilder& builder) -{ - const ValueTreeWrapper wrapper (tree); - setComponentID (wrapper.getID()); - - wrapper.getMarkerList (true).applyTo (markersX); - wrapper.getMarkerList (false).applyTo (markersY); - - setBoundingBox (wrapper.getBoundingBox()); - - builder.updateChildComponents (*this, wrapper.getChildList()); -} - -ValueTree DrawableComposite::createValueTree (ComponentBuilder::ImageProvider* imageProvider) const -{ - ValueTree tree (valueTreeType); - ValueTreeWrapper v (tree); - - v.setID (getComponentID()); - v.setBoundingBox (bounds, nullptr); - - ValueTree childList (v.getChildListCreating (nullptr)); - - for (auto* c : getChildren()) - { - auto* d = dynamic_cast (c); - jassert (d != nullptr); // You can't save a mix of Drawables and normal components! - - childList.addChild (d->createValueTree (imageProvider), -1, nullptr); - } - - v.getMarkerListCreating (true, nullptr).readFrom (markersX, nullptr); - v.getMarkerListCreating (false, nullptr).readFrom (markersY, nullptr); - - return tree; -} - -Path DrawableComposite::getOutlineAsPath() const -{ - Path p; - - for (auto* c : getChildren()) - if (auto* d = dynamic_cast (c)) - p.addPath (d->getOutlineAsPath()); - - p.applyTransform (getTransform()); - return p; -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/drawables/juce_DrawableComposite.h b/source/modules/juce_gui_basics/drawables/juce_DrawableComposite.h deleted file mode 100644 index b98bb6237..000000000 --- a/source/modules/juce_gui_basics/drawables/juce_DrawableComposite.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A drawable object which acts as a container for a set of other Drawables. - - Note that although this is a Component, it takes ownership of its child components - and will delete them, so that you can use it as a self-contained graphic object. - The intention is that you should not add your own components to it, only add other - Drawable objects. - - @see Drawable -*/ -class JUCE_API DrawableComposite : public Drawable -{ -public: - //============================================================================== - /** Creates a composite Drawable. */ - DrawableComposite(); - - /** Creates a copy of a DrawableComposite. */ - DrawableComposite (const DrawableComposite&); - - /** Destructor. */ - ~DrawableComposite(); - - //============================================================================== - /** Sets the parallelogram that defines the target position of the content rectangle when the drawable is rendered. - @see setContentArea - */ - void setBoundingBox (const RelativeParallelogram& newBoundingBox); - - /** Returns the parallelogram that defines the target position of the content rectangle when the drawable is rendered. - @see setBoundingBox - */ - const RelativeParallelogram& getBoundingBox() const noexcept { return bounds; } - - /** Changes the bounding box transform to match the content area, so that any sub-items will - be drawn at their untransformed positions. - */ - void resetBoundingBoxToContentArea(); - - /** Returns the main content rectangle. - The content area is actually defined by the markers named "left", "right", "top" and - "bottom", but this method is a shortcut that returns them all at once. - @see contentLeftMarkerName, contentRightMarkerName, contentTopMarkerName, contentBottomMarkerName - */ - RelativeRectangle getContentArea() const; - - /** Changes the main content area. - The content area is actually defined by the markers named "left", "right", "top" and - "bottom", but this method is a shortcut that sets them all at once. - @see setBoundingBox, contentLeftMarkerName, contentRightMarkerName, contentTopMarkerName, contentBottomMarkerName - */ - void setContentArea (const RelativeRectangle& newArea); - - /** Resets the content area and the bounding transform to fit around the area occupied - by the child components (ignoring any markers). - */ - void resetContentAreaAndBoundingBoxToFitChildren(); - - //============================================================================== - /** The name of the marker that defines the left edge of the content area. */ - static const char* const contentLeftMarkerName; - /** The name of the marker that defines the right edge of the content area. */ - static const char* const contentRightMarkerName; - /** The name of the marker that defines the top edge of the content area. */ - static const char* const contentTopMarkerName; - /** The name of the marker that defines the bottom edge of the content area. */ - static const char* const contentBottomMarkerName; - - //============================================================================== - /** @internal */ - Drawable* createCopy() const override; - /** @internal */ - void refreshFromValueTree (const ValueTree&, ComponentBuilder&); - /** @internal */ - ValueTree createValueTree (ComponentBuilder::ImageProvider* imageProvider) const override; - /** @internal */ - static const Identifier valueTreeType; - /** @internal */ - Rectangle getDrawableBounds() const override; - /** @internal */ - void childBoundsChanged (Component*) override; - /** @internal */ - void childrenChanged() override; - /** @internal */ - void parentHierarchyChanged() override; - /** @internal */ - MarkerList* getMarkers (bool xAxis) override; - /** @internal */ - Path getOutlineAsPath() const override; - - //============================================================================== - /** Internally-used class for wrapping a DrawableComposite's state into a ValueTree. */ - class ValueTreeWrapper : public Drawable::ValueTreeWrapperBase - { - public: - ValueTreeWrapper (const ValueTree& state); - - ValueTree getChildList() const; - ValueTree getChildListCreating (UndoManager* undoManager); - - RelativeParallelogram getBoundingBox() const; - void setBoundingBox (const RelativeParallelogram& newBounds, UndoManager* undoManager); - void resetBoundingBoxToContentArea (UndoManager* undoManager); - - RelativeRectangle getContentArea() const; - void setContentArea (const RelativeRectangle& newArea, UndoManager* undoManager); - - MarkerList::ValueTreeWrapper getMarkerList (bool xAxis) const; - MarkerList::ValueTreeWrapper getMarkerListCreating (bool xAxis, UndoManager* undoManager); - - static const Identifier topLeft, topRight, bottomLeft; - - private: - static const Identifier childGroupTag, markerGroupTagX, markerGroupTagY; - }; - -private: - //============================================================================== - RelativeParallelogram bounds; - MarkerList markersX, markersY; - bool updateBoundsReentrant = false; - - friend class Drawable::Positioner; - bool registerCoordinates (RelativeCoordinatePositionerBase&); - void recalculateCoordinates (Expression::Scope*); - - void updateBoundsToFitChildren(); - - DrawableComposite& operator= (const DrawableComposite&); - JUCE_LEAK_DETECTOR (DrawableComposite) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/drawables/juce_DrawableImage.cpp b/source/modules/juce_gui_basics/drawables/juce_DrawableImage.cpp deleted file mode 100644 index c7675afce..000000000 --- a/source/modules/juce_gui_basics/drawables/juce_DrawableImage.cpp +++ /dev/null @@ -1,302 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -DrawableImage::DrawableImage() - : opacity (1.0f), - overlayColour (0x00000000) -{ - bounds.topRight = RelativePoint (Point (1.0f, 0.0f)); - bounds.bottomLeft = RelativePoint (Point (0.0f, 1.0f)); -} - -DrawableImage::DrawableImage (const DrawableImage& other) - : Drawable (other), - image (other.image), - opacity (other.opacity), - overlayColour (other.overlayColour), - bounds (other.bounds) -{ - setBounds (other.getBounds()); -} - -DrawableImage::~DrawableImage() -{ -} - -//============================================================================== -void DrawableImage::setImage (const Image& imageToUse) -{ - image = imageToUse; - setBounds (imageToUse.getBounds()); - - bounds.topLeft = RelativePoint (Point (0.0f, 0.0f)); - bounds.topRight = RelativePoint (Point ((float) image.getWidth(), 0.0f)); - bounds.bottomLeft = RelativePoint (Point (0.0f, (float) image.getHeight())); - recalculateCoordinates (nullptr); - - repaint(); -} - -void DrawableImage::setOpacity (const float newOpacity) -{ - opacity = newOpacity; -} - -void DrawableImage::setOverlayColour (Colour newOverlayColour) -{ - overlayColour = newOverlayColour; -} - -void DrawableImage::setBoundingBox (const RelativeParallelogram& newBounds) -{ - if (bounds != newBounds) - { - bounds = newBounds; - - if (bounds.isDynamic()) - { - Drawable::Positioner* const p = new Drawable::Positioner (*this); - setPositioner (p); - p->apply(); - } - else - { - setPositioner (nullptr); - recalculateCoordinates (nullptr); - } - } -} - -//============================================================================== -bool DrawableImage::registerCoordinates (RelativeCoordinatePositionerBase& pos) -{ - bool ok = pos.addPoint (bounds.topLeft); - ok = pos.addPoint (bounds.topRight) && ok; - return pos.addPoint (bounds.bottomLeft) && ok; -} - -void DrawableImage::recalculateCoordinates (Expression::Scope* scope) -{ - if (image.isValid()) - { - Point resolved[3]; - bounds.resolveThreePoints (resolved, scope); - - const Point tr (resolved[0] + (resolved[1] - resolved[0]) / (float) image.getWidth()); - const Point bl (resolved[0] + (resolved[2] - resolved[0]) / (float) image.getHeight()); - - AffineTransform t (AffineTransform::fromTargetPoints (resolved[0].x, resolved[0].y, - tr.x, tr.y, - bl.x, bl.y)); - - if (t.isSingularity()) - t = AffineTransform(); - - setTransform (t); - } -} - -//============================================================================== -void DrawableImage::paint (Graphics& g) -{ - if (image.isValid()) - { - if (opacity > 0.0f && ! overlayColour.isOpaque()) - { - g.setOpacity (opacity); - g.drawImageAt (image, 0, 0, false); - } - - if (! overlayColour.isTransparent()) - { - g.setColour (overlayColour.withMultipliedAlpha (opacity)); - g.drawImageAt (image, 0, 0, true); - } - } -} - -Rectangle DrawableImage::getDrawableBounds() const -{ - return image.getBounds().toFloat(); -} - -bool DrawableImage::hitTest (int x, int y) -{ - return Drawable::hitTest (x, y) && image.isValid() && image.getPixelAt (x, y).getAlpha() >= 127; -} - -Drawable* DrawableImage::createCopy() const -{ - return new DrawableImage (*this); -} - -//============================================================================== -const Identifier DrawableImage::valueTreeType ("Image"); - -const Identifier DrawableImage::ValueTreeWrapper::opacity ("opacity"); -const Identifier DrawableImage::ValueTreeWrapper::overlay ("overlay"); -const Identifier DrawableImage::ValueTreeWrapper::image ("image"); -const Identifier DrawableImage::ValueTreeWrapper::topLeft ("topLeft"); -const Identifier DrawableImage::ValueTreeWrapper::topRight ("topRight"); -const Identifier DrawableImage::ValueTreeWrapper::bottomLeft ("bottomLeft"); - -//============================================================================== -DrawableImage::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_) - : ValueTreeWrapperBase (state_) -{ - jassert (state.hasType (valueTreeType)); -} - -var DrawableImage::ValueTreeWrapper::getImageIdentifier() const -{ - return state [image]; -} - -Value DrawableImage::ValueTreeWrapper::getImageIdentifierValue (UndoManager* undoManager) -{ - return state.getPropertyAsValue (image, undoManager); -} - -void DrawableImage::ValueTreeWrapper::setImageIdentifier (const var& newIdentifier, UndoManager* undoManager) -{ - state.setProperty (image, newIdentifier, undoManager); -} - -float DrawableImage::ValueTreeWrapper::getOpacity() const -{ - return (float) state.getProperty (opacity, 1.0); -} - -Value DrawableImage::ValueTreeWrapper::getOpacityValue (UndoManager* undoManager) -{ - if (! state.hasProperty (opacity)) - state.setProperty (opacity, 1.0, undoManager); - - return state.getPropertyAsValue (opacity, undoManager); -} - -void DrawableImage::ValueTreeWrapper::setOpacity (float newOpacity, UndoManager* undoManager) -{ - state.setProperty (opacity, newOpacity, undoManager); -} - -Colour DrawableImage::ValueTreeWrapper::getOverlayColour() const -{ - return Colour::fromString (state [overlay].toString()); -} - -void DrawableImage::ValueTreeWrapper::setOverlayColour (Colour newColour, UndoManager* undoManager) -{ - if (newColour.isTransparent()) - state.removeProperty (overlay, undoManager); - else - state.setProperty (overlay, String::toHexString ((int) newColour.getARGB()), undoManager); -} - -Value DrawableImage::ValueTreeWrapper::getOverlayColourValue (UndoManager* undoManager) -{ - return state.getPropertyAsValue (overlay, undoManager); -} - -RelativeParallelogram DrawableImage::ValueTreeWrapper::getBoundingBox() const -{ - return RelativeParallelogram (state.getProperty (topLeft, "0, 0"), - state.getProperty (topRight, "100, 0"), - state.getProperty (bottomLeft, "0, 100")); -} - -void DrawableImage::ValueTreeWrapper::setBoundingBox (const RelativeParallelogram& newBounds, UndoManager* undoManager) -{ - state.setProperty (topLeft, newBounds.topLeft.toString(), undoManager); - state.setProperty (topRight, newBounds.topRight.toString(), undoManager); - state.setProperty (bottomLeft, newBounds.bottomLeft.toString(), undoManager); -} - - -//============================================================================== -void DrawableImage::refreshFromValueTree (const ValueTree& tree, ComponentBuilder& builder) -{ - const ValueTreeWrapper controller (tree); - setComponentID (controller.getID()); - - const float newOpacity = controller.getOpacity(); - const Colour newOverlayColour (controller.getOverlayColour()); - - Image newImage; - const var imageIdentifier (controller.getImageIdentifier()); - - - jassert (builder.getImageProvider() != 0 || imageIdentifier.isVoid()); // if you're using images, you need to provide something that can load and save them! - - if (builder.getImageProvider() != nullptr) - newImage = builder.getImageProvider()->getImageForIdentifier (imageIdentifier); - - const RelativeParallelogram newBounds (controller.getBoundingBox()); - - if (bounds != newBounds || newOpacity != opacity - || overlayColour != newOverlayColour || image != newImage) - { - repaint(); - opacity = newOpacity; - overlayColour = newOverlayColour; - - if (image != newImage) - setImage (newImage); - - setBoundingBox (newBounds); - } -} - -ValueTree DrawableImage::createValueTree (ComponentBuilder::ImageProvider* imageProvider) const -{ - ValueTree tree (valueTreeType); - ValueTreeWrapper v (tree); - - v.setID (getComponentID()); - v.setOpacity (opacity, nullptr); - v.setOverlayColour (overlayColour, nullptr); - v.setBoundingBox (bounds, nullptr); - - if (image.isValid()) - { - jassert (imageProvider != nullptr); // if you're using images, you need to provide something that can load and save them! - - if (imageProvider != nullptr) - v.setImageIdentifier (imageProvider->getIdentifierForImage (image), nullptr); - } - - return tree; -} - -Path DrawableImage::getOutlineAsPath() const -{ - return {}; // not applicable for images -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/drawables/juce_DrawableImage.h b/source/modules/juce_gui_basics/drawables/juce_DrawableImage.h deleted file mode 100644 index d1277174a..000000000 --- a/source/modules/juce_gui_basics/drawables/juce_DrawableImage.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A drawable object which is a bitmap image. - - @see Drawable -*/ -class JUCE_API DrawableImage : public Drawable -{ -public: - //============================================================================== - DrawableImage(); - DrawableImage (const DrawableImage&); - - /** Destructor. */ - ~DrawableImage(); - - //============================================================================== - /** Sets the image that this drawable will render. */ - void setImage (const Image& imageToUse); - - /** Returns the current image. */ - const Image& getImage() const noexcept { return image; } - - /** Sets the opacity to use when drawing the image. */ - void setOpacity (float newOpacity); - - /** Returns the image's opacity. */ - float getOpacity() const noexcept { return opacity; } - - /** Sets a colour to draw over the image's alpha channel. - - By default this is transparent so isn't drawn, but if you set a non-transparent - colour here, then it will be overlaid on the image, using the image's alpha - channel as a mask. - - This is handy for doing things like darkening or lightening an image by overlaying - it with semi-transparent black or white. - */ - void setOverlayColour (Colour newOverlayColour); - - /** Returns the overlay colour. */ - Colour getOverlayColour() const noexcept { return overlayColour; } - - /** Sets the bounding box within which the image should be displayed. */ - void setBoundingBox (const RelativeParallelogram& newBounds); - - /** Returns the position to which the image's top-left corner should be remapped in the target - coordinate space when rendering this object. - @see setTransform - */ - const RelativeParallelogram& getBoundingBox() const noexcept { return bounds; } - - //============================================================================== - /** @internal */ - void paint (Graphics&) override; - /** @internal */ - bool hitTest (int x, int y) override; - /** @internal */ - Drawable* createCopy() const override; - /** @internal */ - Rectangle getDrawableBounds() const override; - /** @internal */ - void refreshFromValueTree (const ValueTree& tree, ComponentBuilder&); - /** @internal */ - ValueTree createValueTree (ComponentBuilder::ImageProvider*) const override; - /** @internal */ - static const Identifier valueTreeType; - /** @internal */ - Path getOutlineAsPath() const override; - - //============================================================================== - /** Internally-used class for wrapping a DrawableImage's state into a ValueTree. */ - class ValueTreeWrapper : public Drawable::ValueTreeWrapperBase - { - public: - ValueTreeWrapper (const ValueTree& state); - - var getImageIdentifier() const; - void setImageIdentifier (const var&, UndoManager*); - Value getImageIdentifierValue (UndoManager*); - - float getOpacity() const; - void setOpacity (float newOpacity, UndoManager*); - Value getOpacityValue (UndoManager*); - - Colour getOverlayColour() const; - void setOverlayColour (Colour newColour, UndoManager*); - Value getOverlayColourValue (UndoManager*); - - RelativeParallelogram getBoundingBox() const; - void setBoundingBox (const RelativeParallelogram&, UndoManager*); - - static const Identifier opacity, overlay, image, topLeft, topRight, bottomLeft; - }; - -private: - //============================================================================== - Image image; - float opacity; - Colour overlayColour; - RelativeParallelogram bounds; - - friend class Drawable::Positioner; - bool registerCoordinates (RelativeCoordinatePositionerBase&); - void recalculateCoordinates (Expression::Scope*); - - DrawableImage& operator= (const DrawableImage&); - JUCE_LEAK_DETECTOR (DrawableImage) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/drawables/juce_DrawablePath.cpp b/source/modules/juce_gui_basics/drawables/juce_DrawablePath.cpp deleted file mode 100644 index a581e980f..000000000 --- a/source/modules/juce_gui_basics/drawables/juce_DrawablePath.cpp +++ /dev/null @@ -1,577 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -DrawablePath::DrawablePath() -{ -} - -DrawablePath::DrawablePath (const DrawablePath& other) - : DrawableShape (other) -{ - if (other.relativePath != nullptr) - setPath (*other.relativePath); - else - setPath (other.path); -} - -DrawablePath::~DrawablePath() -{ -} - -Drawable* DrawablePath::createCopy() const -{ - return new DrawablePath (*this); -} - -//============================================================================== -void DrawablePath::setPath (const Path& newPath) -{ - path = newPath; - pathChanged(); -} - -const Path& DrawablePath::getPath() const -{ - return path; -} - -const Path& DrawablePath::getStrokePath() const -{ - return strokePath; -} - -void DrawablePath::applyRelativePath (const RelativePointPath& newRelativePath, Expression::Scope* scope) -{ - Path newPath; - newRelativePath.createPath (newPath, scope); - - if (path != newPath) - { - path.swapWithPath (newPath); - pathChanged(); - } -} - -//============================================================================== -class DrawablePath::RelativePositioner : public RelativeCoordinatePositionerBase -{ -public: - RelativePositioner (DrawablePath& comp) - : RelativeCoordinatePositionerBase (comp), - owner (comp) - { - } - - bool registerCoordinates() override - { - bool ok = true; - - jassert (owner.relativePath != nullptr); - const RelativePointPath& relPath = *owner.relativePath; - - for (int i = 0; i < relPath.elements.size(); ++i) - { - RelativePointPath::ElementBase* const e = relPath.elements.getUnchecked(i); - - int numPoints; - RelativePoint* const points = e->getControlPoints (numPoints); - - for (int j = numPoints; --j >= 0;) - ok = addPoint (points[j]) && ok; - } - - return ok; - } - - void applyToComponentBounds() override - { - jassert (owner.relativePath != nullptr); - - ComponentScope scope (getComponent()); - owner.applyRelativePath (*owner.relativePath, &scope); - } - - void applyNewBounds (const Rectangle&) override - { - jassertfalse; // drawables can't be resized directly! - } - -private: - DrawablePath& owner; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativePositioner) -}; - -void DrawablePath::setPath (const RelativePointPath& newRelativePath) -{ - if (newRelativePath.containsAnyDynamicPoints()) - { - if (relativePath == nullptr || newRelativePath != *relativePath) - { - relativePath = new RelativePointPath (newRelativePath); - - RelativePositioner* const p = new RelativePositioner (*this); - setPositioner (p); - p->apply(); - } - } - else - { - relativePath = nullptr; - applyRelativePath (newRelativePath, nullptr); - } -} - -//============================================================================== -const Identifier DrawablePath::valueTreeType ("Path"); - -const Identifier DrawablePath::ValueTreeWrapper::nonZeroWinding ("nonZeroWinding"); -const Identifier DrawablePath::ValueTreeWrapper::point1 ("p1"); -const Identifier DrawablePath::ValueTreeWrapper::point2 ("p2"); -const Identifier DrawablePath::ValueTreeWrapper::point3 ("p3"); - -//============================================================================== -DrawablePath::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_) - : FillAndStrokeState (state_) -{ - jassert (state.hasType (valueTreeType)); -} - -ValueTree DrawablePath::ValueTreeWrapper::getPathState() -{ - return state.getOrCreateChildWithName (path, nullptr); -} - -bool DrawablePath::ValueTreeWrapper::usesNonZeroWinding() const -{ - return state [nonZeroWinding]; -} - -void DrawablePath::ValueTreeWrapper::setUsesNonZeroWinding (bool b, UndoManager* undoManager) -{ - state.setProperty (nonZeroWinding, b, undoManager); -} - -void DrawablePath::ValueTreeWrapper::readFrom (const RelativePointPath& p, UndoManager* undoManager) -{ - setUsesNonZeroWinding (p.usesNonZeroWinding, undoManager); - - ValueTree pathTree (getPathState()); - pathTree.removeAllChildren (undoManager); - - for (int i = 0; i < p.elements.size(); ++i) - pathTree.addChild (p.elements.getUnchecked(i)->createTree(), -1, undoManager); -} - -void DrawablePath::ValueTreeWrapper::writeTo (RelativePointPath& p) const -{ - p.usesNonZeroWinding = usesNonZeroWinding(); - RelativePoint points[3]; - - const ValueTree pathTree (state.getChildWithName (path)); - const int num = pathTree.getNumChildren(); - for (int i = 0; i < num; ++i) - { - const Element e (pathTree.getChild(i)); - - const int numCps = e.getNumControlPoints(); - for (int j = 0; j < numCps; ++j) - points[j] = e.getControlPoint (j); - - RelativePointPath::ElementBase* newElement = nullptr; - const Identifier t (e.getType()); - - if (t == Element::startSubPathElement) newElement = new RelativePointPath::StartSubPath (points[0]); - else if (t == Element::closeSubPathElement) newElement = new RelativePointPath::CloseSubPath(); - else if (t == Element::lineToElement) newElement = new RelativePointPath::LineTo (points[0]); - else if (t == Element::quadraticToElement) newElement = new RelativePointPath::QuadraticTo (points[0], points[1]); - else if (t == Element::cubicToElement) newElement = new RelativePointPath::CubicTo (points[0], points[1], points[2]); - else jassertfalse; - - p.addElement (newElement); - } -} - -//============================================================================== -const Identifier DrawablePath::ValueTreeWrapper::Element::mode ("mode"); -const Identifier DrawablePath::ValueTreeWrapper::Element::startSubPathElement ("Move"); -const Identifier DrawablePath::ValueTreeWrapper::Element::closeSubPathElement ("Close"); -const Identifier DrawablePath::ValueTreeWrapper::Element::lineToElement ("Line"); -const Identifier DrawablePath::ValueTreeWrapper::Element::quadraticToElement ("Quad"); -const Identifier DrawablePath::ValueTreeWrapper::Element::cubicToElement ("Cubic"); - -const char* DrawablePath::ValueTreeWrapper::Element::cornerMode = "corner"; -const char* DrawablePath::ValueTreeWrapper::Element::roundedMode = "round"; -const char* DrawablePath::ValueTreeWrapper::Element::symmetricMode = "symm"; - -DrawablePath::ValueTreeWrapper::Element::Element (const ValueTree& state_) - : state (state_) -{ -} - -DrawablePath::ValueTreeWrapper::Element::~Element() -{ -} - -DrawablePath::ValueTreeWrapper DrawablePath::ValueTreeWrapper::Element::getParent() const -{ - return ValueTreeWrapper (state.getParent().getParent()); -} - -DrawablePath::ValueTreeWrapper::Element DrawablePath::ValueTreeWrapper::Element::getPreviousElement() const -{ - return Element (state.getSibling (-1)); -} - -int DrawablePath::ValueTreeWrapper::Element::getNumControlPoints() const noexcept -{ - const Identifier i (state.getType()); - if (i == startSubPathElement || i == lineToElement) return 1; - if (i == quadraticToElement) return 2; - if (i == cubicToElement) return 3; - return 0; -} - -RelativePoint DrawablePath::ValueTreeWrapper::Element::getControlPoint (const int index) const -{ - jassert (index >= 0 && index < getNumControlPoints()); - return RelativePoint (state [index == 0 ? point1 : (index == 1 ? point2 : point3)].toString()); -} - -Value DrawablePath::ValueTreeWrapper::Element::getControlPointValue (int index, UndoManager* undoManager) -{ - jassert (index >= 0 && index < getNumControlPoints()); - return state.getPropertyAsValue (index == 0 ? point1 : (index == 1 ? point2 : point3), undoManager); -} - -void DrawablePath::ValueTreeWrapper::Element::setControlPoint (const int index, const RelativePoint& point, UndoManager* undoManager) -{ - jassert (index >= 0 && index < getNumControlPoints()); - state.setProperty (index == 0 ? point1 : (index == 1 ? point2 : point3), point.toString(), undoManager); -} - -RelativePoint DrawablePath::ValueTreeWrapper::Element::getStartPoint() const -{ - const Identifier i (state.getType()); - - if (i == startSubPathElement) - return getControlPoint (0); - - jassert (i == lineToElement || i == quadraticToElement || i == cubicToElement || i == closeSubPathElement); - - return getPreviousElement().getEndPoint(); -} - -RelativePoint DrawablePath::ValueTreeWrapper::Element::getEndPoint() const -{ - const Identifier i (state.getType()); - if (i == startSubPathElement || i == lineToElement) return getControlPoint (0); - if (i == quadraticToElement) return getControlPoint (1); - if (i == cubicToElement) return getControlPoint (2); - - jassert (i == closeSubPathElement); - return RelativePoint(); -} - -float DrawablePath::ValueTreeWrapper::Element::getLength (Expression::Scope* scope) const -{ - const Identifier i (state.getType()); - - if (i == lineToElement || i == closeSubPathElement) - return getEndPoint().resolve (scope).getDistanceFrom (getStartPoint().resolve (scope)); - - if (i == cubicToElement) - { - Path p; - p.startNewSubPath (getStartPoint().resolve (scope)); - p.cubicTo (getControlPoint (0).resolve (scope), getControlPoint (1).resolve (scope), getControlPoint (2).resolve (scope)); - return p.getLength(); - } - - if (i == quadraticToElement) - { - Path p; - p.startNewSubPath (getStartPoint().resolve (scope)); - p.quadraticTo (getControlPoint (0).resolve (scope), getControlPoint (1).resolve (scope)); - return p.getLength(); - } - - jassert (i == startSubPathElement); - return 0; -} - -String DrawablePath::ValueTreeWrapper::Element::getModeOfEndPoint() const -{ - return state [mode].toString(); -} - -void DrawablePath::ValueTreeWrapper::Element::setModeOfEndPoint (const String& newMode, UndoManager* undoManager) -{ - if (state.hasType (cubicToElement)) - state.setProperty (mode, newMode, undoManager); -} - -void DrawablePath::ValueTreeWrapper::Element::convertToLine (UndoManager* undoManager) -{ - const Identifier i (state.getType()); - - if (i == quadraticToElement || i == cubicToElement) - { - ValueTree newState (lineToElement); - Element e (newState); - e.setControlPoint (0, getEndPoint(), undoManager); - state = newState; - } -} - -void DrawablePath::ValueTreeWrapper::Element::convertToCubic (Expression::Scope* scope, UndoManager* undoManager) -{ - const Identifier i (state.getType()); - - if (i == lineToElement || i == quadraticToElement) - { - ValueTree newState (cubicToElement); - Element e (newState); - - const RelativePoint start (getStartPoint()); - const RelativePoint end (getEndPoint()); - const Point startResolved (start.resolve (scope)); - const Point endResolved (end.resolve (scope)); - e.setControlPoint (0, startResolved + (endResolved - startResolved) * 0.3f, undoManager); - e.setControlPoint (1, startResolved + (endResolved - startResolved) * 0.7f, undoManager); - e.setControlPoint (2, end, undoManager); - - state = newState; - } -} - -void DrawablePath::ValueTreeWrapper::Element::convertToPathBreak (UndoManager* undoManager) -{ - const Identifier i (state.getType()); - - if (i != startSubPathElement) - { - ValueTree newState (startSubPathElement); - Element e (newState); - e.setControlPoint (0, getEndPoint(), undoManager); - state = newState; - } -} - -namespace DrawablePathHelpers -{ - static Point findCubicSubdivisionPoint (float proportion, const Point points[4]) - { - const Point mid1 (points[0] + (points[1] - points[0]) * proportion), - mid2 (points[1] + (points[2] - points[1]) * proportion), - mid3 (points[2] + (points[3] - points[2]) * proportion); - - const Point newCp1 (mid1 + (mid2 - mid1) * proportion), - newCp2 (mid2 + (mid3 - mid2) * proportion); - - return newCp1 + (newCp2 - newCp1) * proportion; - } - - static Point findQuadraticSubdivisionPoint (float proportion, const Point points[3]) - { - const Point mid1 (points[0] + (points[1] - points[0]) * proportion), - mid2 (points[1] + (points[2] - points[1]) * proportion); - - return mid1 + (mid2 - mid1) * proportion; - } -} - -float DrawablePath::ValueTreeWrapper::Element::findProportionAlongLine (Point targetPoint, Expression::Scope* scope) const -{ - using namespace DrawablePathHelpers; - const Identifier pointType (state.getType()); - float bestProp = 0; - - if (pointType == cubicToElement) - { - RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getControlPoint (1)), rp4 (getEndPoint()); - - const Point points[] = { rp1.resolve (scope), rp2.resolve (scope), rp3.resolve (scope), rp4.resolve (scope) }; - - float bestDistance = std::numeric_limits::max(); - - for (int i = 110; --i >= 0;) - { - float prop = i > 10 ? ((i - 10) / 100.0f) : (bestProp + ((i - 5) / 1000.0f)); - const Point centre (findCubicSubdivisionPoint (prop, points)); - const float distance = centre.getDistanceFrom (targetPoint); - - if (distance < bestDistance) - { - bestProp = prop; - bestDistance = distance; - } - } - } - else if (pointType == quadraticToElement) - { - RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getEndPoint()); - const Point points[] = { rp1.resolve (scope), rp2.resolve (scope), rp3.resolve (scope) }; - - float bestDistance = std::numeric_limits::max(); - - for (int i = 110; --i >= 0;) - { - float prop = i > 10 ? ((i - 10) / 100.0f) : (bestProp + ((i - 5) / 1000.0f)); - const Point centre (findQuadraticSubdivisionPoint ((float) prop, points)); - const float distance = centre.getDistanceFrom (targetPoint); - - if (distance < bestDistance) - { - bestProp = prop; - bestDistance = distance; - } - } - } - else if (pointType == lineToElement) - { - RelativePoint rp1 (getStartPoint()), rp2 (getEndPoint()); - const Line line (rp1.resolve (scope), rp2.resolve (scope)); - bestProp = line.findNearestProportionalPositionTo (targetPoint); - } - - return bestProp; -} - -ValueTree DrawablePath::ValueTreeWrapper::Element::insertPoint (Point targetPoint, Expression::Scope* scope, UndoManager* undoManager) -{ - ValueTree newTree; - const Identifier pointType (state.getType()); - - if (pointType == cubicToElement) - { - float bestProp = findProportionAlongLine (targetPoint, scope); - - RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getControlPoint (1)), rp4 (getEndPoint()); - const Point points[] = { rp1.resolve (scope), rp2.resolve (scope), rp3.resolve (scope), rp4.resolve (scope) }; - - const Point mid1 (points[0] + (points[1] - points[0]) * bestProp), - mid2 (points[1] + (points[2] - points[1]) * bestProp), - mid3 (points[2] + (points[3] - points[2]) * bestProp); - - const Point newCp1 (mid1 + (mid2 - mid1) * bestProp), - newCp2 (mid2 + (mid3 - mid2) * bestProp); - - const Point newCentre (newCp1 + (newCp2 - newCp1) * bestProp); - - setControlPoint (0, mid1, undoManager); - setControlPoint (1, newCp1, undoManager); - setControlPoint (2, newCentre, undoManager); - setModeOfEndPoint (roundedMode, undoManager); - - Element newElement (newTree = ValueTree (cubicToElement)); - newElement.setControlPoint (0, newCp2, nullptr); - newElement.setControlPoint (1, mid3, nullptr); - newElement.setControlPoint (2, rp4, nullptr); - - state.getParent().addChild (newTree, state.getParent().indexOf (state) + 1, undoManager); - } - else if (pointType == quadraticToElement) - { - float bestProp = findProportionAlongLine (targetPoint, scope); - - RelativePoint rp1 (getStartPoint()), rp2 (getControlPoint (0)), rp3 (getEndPoint()); - const Point points[] = { rp1.resolve (scope), rp2.resolve (scope), rp3.resolve (scope) }; - - const Point mid1 (points[0] + (points[1] - points[0]) * bestProp), - mid2 (points[1] + (points[2] - points[1]) * bestProp); - - const Point newCentre (mid1 + (mid2 - mid1) * bestProp); - - setControlPoint (0, mid1, undoManager); - setControlPoint (1, newCentre, undoManager); - setModeOfEndPoint (roundedMode, undoManager); - - Element newElement (newTree = ValueTree (quadraticToElement)); - newElement.setControlPoint (0, mid2, nullptr); - newElement.setControlPoint (1, rp3, nullptr); - - state.getParent().addChild (newTree, state.getParent().indexOf (state) + 1, undoManager); - } - else if (pointType == lineToElement) - { - RelativePoint rp1 (getStartPoint()), rp2 (getEndPoint()); - const Line line (rp1.resolve (scope), rp2.resolve (scope)); - const Point newPoint (line.findNearestPointTo (targetPoint)); - - setControlPoint (0, newPoint, undoManager); - - Element newElement (newTree = ValueTree (lineToElement)); - newElement.setControlPoint (0, rp2, nullptr); - - state.getParent().addChild (newTree, state.getParent().indexOf (state) + 1, undoManager); - } - else if (pointType == closeSubPathElement) - { - } - - return newTree; -} - -void DrawablePath::ValueTreeWrapper::Element::removePoint (UndoManager* undoManager) -{ - state.getParent().removeChild (state, undoManager); -} - -//============================================================================== -void DrawablePath::refreshFromValueTree (const ValueTree& tree, ComponentBuilder& builder) -{ - ValueTreeWrapper v (tree); - setComponentID (v.getID()); - - refreshFillTypes (v, builder.getImageProvider()); - setStrokeType (v.getStrokeType()); - - RelativePointPath newRelativePath; - v.writeTo (newRelativePath); - setPath (newRelativePath); -} - -ValueTree DrawablePath::createValueTree (ComponentBuilder::ImageProvider* imageProvider) const -{ - ValueTree tree (valueTreeType); - ValueTreeWrapper v (tree); - - v.setID (getComponentID()); - writeTo (v, imageProvider, nullptr); - - if (relativePath != nullptr) - v.readFrom (*relativePath, nullptr); - else - v.readFrom (RelativePointPath (path), nullptr); - - return tree; -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/drawables/juce_DrawablePath.h b/source/modules/juce_gui_basics/drawables/juce_DrawablePath.h deleted file mode 100644 index 66254d44c..000000000 --- a/source/modules/juce_gui_basics/drawables/juce_DrawablePath.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A drawable object which renders a filled or outlined shape. - - For details on how to change the fill and stroke, see the DrawableShape class. - - @see Drawable, DrawableShape -*/ -class JUCE_API DrawablePath : public DrawableShape -{ -public: - //============================================================================== - /** Creates a DrawablePath. */ - DrawablePath(); - DrawablePath (const DrawablePath&); - - /** Destructor. */ - ~DrawablePath(); - - //============================================================================== - /** Changes the path that will be drawn. - @see setFillColour, setStrokeType - */ - void setPath (const Path& newPath); - - /** Sets the path using a RelativePointPath. - Calling this will set up a Component::Positioner to automatically update the path - if any of the points in the source path are dynamic. - */ - void setPath (const RelativePointPath& newPath); - - /** Returns the current path. */ - const Path& getPath() const; - - /** Returns the current path for the outline. */ - const Path& getStrokePath() const; - - //============================================================================== - /** @internal */ - Drawable* createCopy() const; - /** @internal */ - void refreshFromValueTree (const ValueTree& tree, ComponentBuilder& builder); - /** @internal */ - ValueTree createValueTree (ComponentBuilder::ImageProvider* imageProvider) const; - /** @internal */ - static const Identifier valueTreeType; - - //============================================================================== - /** Internally-used class for wrapping a DrawablePath's state into a ValueTree. */ - class ValueTreeWrapper : public DrawableShape::FillAndStrokeState - { - public: - ValueTreeWrapper (const ValueTree& state); - - bool usesNonZeroWinding() const; - void setUsesNonZeroWinding (bool b, UndoManager* undoManager); - - class Element - { - public: - explicit Element (const ValueTree& state); - ~Element(); - - const Identifier getType() const noexcept { return state.getType(); } - int getNumControlPoints() const noexcept; - - RelativePoint getControlPoint (int index) const; - Value getControlPointValue (int index, UndoManager*); - RelativePoint getStartPoint() const; - RelativePoint getEndPoint() const; - void setControlPoint (int index, const RelativePoint& point, UndoManager*); - float getLength (Expression::Scope*) const; - - ValueTreeWrapper getParent() const; - Element getPreviousElement() const; - - String getModeOfEndPoint() const; - void setModeOfEndPoint (const String& newMode, UndoManager*); - - void convertToLine (UndoManager*); - void convertToCubic (Expression::Scope*, UndoManager*); - void convertToPathBreak (UndoManager* undoManager); - ValueTree insertPoint (Point targetPoint, Expression::Scope*, UndoManager*); - void removePoint (UndoManager* undoManager); - float findProportionAlongLine (Point targetPoint, Expression::Scope*) const; - - static const Identifier mode, startSubPathElement, closeSubPathElement, - lineToElement, quadraticToElement, cubicToElement; - static const char* cornerMode; - static const char* roundedMode; - static const char* symmetricMode; - - ValueTree state; - }; - - ValueTree getPathState(); - - void readFrom (const RelativePointPath& relativePath, UndoManager* undoManager); - void writeTo (RelativePointPath& relativePath) const; - - static const Identifier nonZeroWinding, point1, point2, point3; - }; - -private: - //============================================================================== - ScopedPointer relativePath; - - class RelativePositioner; - friend class RelativePositioner; - void applyRelativePath (const RelativePointPath&, Expression::Scope*); - - DrawablePath& operator= (const DrawablePath&); - JUCE_LEAK_DETECTOR (DrawablePath) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/drawables/juce_DrawableRectangle.cpp b/source/modules/juce_gui_basics/drawables/juce_DrawableRectangle.cpp deleted file mode 100644 index 52a24ecd9..000000000 --- a/source/modules/juce_gui_basics/drawables/juce_DrawableRectangle.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -DrawableRectangle::DrawableRectangle() -{ -} - -DrawableRectangle::DrawableRectangle (const DrawableRectangle& other) - : DrawableShape (other), - bounds (other.bounds), - cornerSize (other.cornerSize) -{ - rebuildPath(); -} - -DrawableRectangle::~DrawableRectangle() -{ -} - -Drawable* DrawableRectangle::createCopy() const -{ - return new DrawableRectangle (*this); -} - -//============================================================================== -void DrawableRectangle::setRectangle (const RelativeParallelogram& newBounds) -{ - if (bounds != newBounds) - { - bounds = newBounds; - rebuildPath(); - } -} - -void DrawableRectangle::setCornerSize (const RelativePoint& newSize) -{ - if (cornerSize != newSize) - { - cornerSize = newSize; - rebuildPath(); - } -} - -void DrawableRectangle::rebuildPath() -{ - if (bounds.isDynamic() || cornerSize.isDynamic()) - { - Drawable::Positioner* const p = new Drawable::Positioner (*this); - setPositioner (p); - p->apply(); - } - else - { - setPositioner (nullptr); - recalculateCoordinates (nullptr); - } -} - -bool DrawableRectangle::registerCoordinates (RelativeCoordinatePositionerBase& pos) -{ - bool ok = pos.addPoint (bounds.topLeft); - ok = pos.addPoint (bounds.topRight) && ok; - ok = pos.addPoint (bounds.bottomLeft) && ok; - return pos.addPoint (cornerSize) && ok; -} - -void DrawableRectangle::recalculateCoordinates (Expression::Scope* scope) -{ - Point points[3]; - bounds.resolveThreePoints (points, scope); - - const float cornerSizeX = (float) cornerSize.x.resolve (scope); - const float cornerSizeY = (float) cornerSize.y.resolve (scope); - - const float w = Line (points[0], points[1]).getLength(); - const float h = Line (points[0], points[2]).getLength(); - - Path newPath; - - if (cornerSizeX > 0 && cornerSizeY > 0) - newPath.addRoundedRectangle (0, 0, w, h, cornerSizeX, cornerSizeY); - else - newPath.addRectangle (0, 0, w, h); - - newPath.applyTransform (AffineTransform::fromTargetPoints (0, 0, points[0].x, points[0].y, - w, 0, points[1].x, points[1].y, - 0, h, points[2].x, points[2].y)); - - if (path != newPath) - { - path.swapWithPath (newPath); - pathChanged(); - } -} - -//============================================================================== -const Identifier DrawableRectangle::valueTreeType ("Rectangle"); -const Identifier DrawableRectangle::ValueTreeWrapper::topLeft ("topLeft"); -const Identifier DrawableRectangle::ValueTreeWrapper::topRight ("topRight"); -const Identifier DrawableRectangle::ValueTreeWrapper::bottomLeft ("bottomLeft"); -const Identifier DrawableRectangle::ValueTreeWrapper::cornerSize ("cornerSize"); - -//============================================================================== -DrawableRectangle::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_) - : FillAndStrokeState (state_) -{ - jassert (state.hasType (valueTreeType)); -} - -RelativeParallelogram DrawableRectangle::ValueTreeWrapper::getRectangle() const -{ - return RelativeParallelogram (state.getProperty (topLeft, "0, 0"), - state.getProperty (topRight, "100, 0"), - state.getProperty (bottomLeft, "0, 100")); -} - -void DrawableRectangle::ValueTreeWrapper::setRectangle (const RelativeParallelogram& newBounds, UndoManager* undoManager) -{ - state.setProperty (topLeft, newBounds.topLeft.toString(), undoManager); - state.setProperty (topRight, newBounds.topRight.toString(), undoManager); - state.setProperty (bottomLeft, newBounds.bottomLeft.toString(), undoManager); -} - -void DrawableRectangle::ValueTreeWrapper::setCornerSize (const RelativePoint& newSize, UndoManager* undoManager) -{ - state.setProperty (cornerSize, newSize.toString(), undoManager); -} - -RelativePoint DrawableRectangle::ValueTreeWrapper::getCornerSize() const -{ - return RelativePoint (state [cornerSize]); -} - -Value DrawableRectangle::ValueTreeWrapper::getCornerSizeValue (UndoManager* undoManager) -{ - return state.getPropertyAsValue (cornerSize, undoManager); -} - -//============================================================================== -void DrawableRectangle::refreshFromValueTree (const ValueTree& tree, ComponentBuilder& builder) -{ - ValueTreeWrapper v (tree); - setComponentID (v.getID()); - - refreshFillTypes (v, builder.getImageProvider()); - setStrokeType (v.getStrokeType()); - setRectangle (v.getRectangle()); - setCornerSize (v.getCornerSize()); -} - -ValueTree DrawableRectangle::createValueTree (ComponentBuilder::ImageProvider* imageProvider) const -{ - ValueTree tree (valueTreeType); - ValueTreeWrapper v (tree); - - v.setID (getComponentID()); - writeTo (v, imageProvider, nullptr); - v.setRectangle (bounds, nullptr); - v.setCornerSize (cornerSize, nullptr); - - return tree; -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/drawables/juce_DrawableRectangle.h b/source/modules/juce_gui_basics/drawables/juce_DrawableRectangle.h deleted file mode 100644 index fbb3f77cc..000000000 --- a/source/modules/juce_gui_basics/drawables/juce_DrawableRectangle.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A Drawable object which draws a rectangle. - - For details on how to change the fill and stroke, see the DrawableShape class. - - @see Drawable, DrawableShape -*/ -class JUCE_API DrawableRectangle : public DrawableShape -{ -public: - //============================================================================== - DrawableRectangle(); - DrawableRectangle (const DrawableRectangle&); - - /** Destructor. */ - ~DrawableRectangle(); - - //============================================================================== - /** Sets the rectangle's bounds. */ - void setRectangle (const RelativeParallelogram& newBounds); - - /** Returns the rectangle's bounds. */ - const RelativeParallelogram& getRectangle() const noexcept { return bounds; } - - /** Returns the corner size to be used. */ - const RelativePoint& getCornerSize() const noexcept { return cornerSize; } - - /** Sets a new corner size for the rectangle */ - void setCornerSize (const RelativePoint& newSize); - - //============================================================================== - /** @internal */ - Drawable* createCopy() const; - /** @internal */ - void refreshFromValueTree (const ValueTree& tree, ComponentBuilder& builder); - /** @internal */ - ValueTree createValueTree (ComponentBuilder::ImageProvider* imageProvider) const; - /** @internal */ - static const Identifier valueTreeType; - - //============================================================================== - /** Internally-used class for wrapping a DrawableRectangle's state into a ValueTree. */ - class ValueTreeWrapper : public DrawableShape::FillAndStrokeState - { - public: - ValueTreeWrapper (const ValueTree& state); - - RelativeParallelogram getRectangle() const; - void setRectangle (const RelativeParallelogram& newBounds, UndoManager*); - - void setCornerSize (const RelativePoint& cornerSize, UndoManager*); - RelativePoint getCornerSize() const; - Value getCornerSizeValue (UndoManager*); - - static const Identifier topLeft, topRight, bottomLeft, cornerSize; - }; - - -private: - friend class Drawable::Positioner; - - RelativeParallelogram bounds; - RelativePoint cornerSize; - - void rebuildPath(); - bool registerCoordinates (RelativeCoordinatePositionerBase&); - void recalculateCoordinates (Expression::Scope*); - - DrawableRectangle& operator= (const DrawableRectangle&); - JUCE_LEAK_DETECTOR (DrawableRectangle) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/drawables/juce_DrawableShape.cpp b/source/modules/juce_gui_basics/drawables/juce_DrawableShape.cpp deleted file mode 100644 index e93130a71..000000000 --- a/source/modules/juce_gui_basics/drawables/juce_DrawableShape.cpp +++ /dev/null @@ -1,503 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -DrawableShape::DrawableShape() - : strokeType (0.0f), - mainFill (Colours::black), - strokeFill (Colours::black) -{ -} - -DrawableShape::DrawableShape (const DrawableShape& other) - : Drawable (other), - strokeType (other.strokeType), - dashLengths (other.dashLengths), - mainFill (other.mainFill), - strokeFill (other.strokeFill) -{ -} - -DrawableShape::~DrawableShape() -{ -} - -//============================================================================== -class DrawableShape::RelativePositioner : public RelativeCoordinatePositionerBase -{ -public: - RelativePositioner (DrawableShape& comp, const DrawableShape::RelativeFillType& f, bool isMain) - : RelativeCoordinatePositionerBase (comp), - owner (comp), - fill (f), - isMainFill (isMain) - { - } - - bool registerCoordinates() override - { - bool ok = addPoint (fill.gradientPoint1); - ok = addPoint (fill.gradientPoint2) && ok; - return addPoint (fill.gradientPoint3) && ok; - } - - void applyToComponentBounds() override - { - ComponentScope scope (owner); - if (isMainFill ? owner.mainFill.recalculateCoords (&scope) - : owner.strokeFill.recalculateCoords (&scope)) - owner.repaint(); - } - - void applyNewBounds (const Rectangle&) override - { - jassertfalse; // drawables can't be resized directly! - } - -private: - DrawableShape& owner; - const DrawableShape::RelativeFillType fill; - const bool isMainFill; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativePositioner) -}; - -void DrawableShape::setFill (const FillType& newFill) -{ - setFill (RelativeFillType (newFill)); -} - -void DrawableShape::setStrokeFill (const FillType& newFill) -{ - setStrokeFill (RelativeFillType (newFill)); -} - -void DrawableShape::setFillInternal (RelativeFillType& fill, const RelativeFillType& newFill, - ScopedPointer& pos) -{ - if (fill != newFill) - { - fill = newFill; - pos = nullptr; - - if (fill.isDynamic()) - { - pos = new RelativePositioner (*this, fill, true); - pos->apply(); - } - else - { - fill.recalculateCoords (nullptr); - } - - repaint(); - } -} - -void DrawableShape::setFill (const RelativeFillType& newFill) -{ - setFillInternal (mainFill, newFill, mainFillPositioner); -} - -void DrawableShape::setStrokeFill (const RelativeFillType& newFill) -{ - setFillInternal (strokeFill, newFill, strokeFillPositioner); -} - -void DrawableShape::setStrokeType (const PathStrokeType& newStrokeType) -{ - if (strokeType != newStrokeType) - { - strokeType = newStrokeType; - strokeChanged(); - } -} - -void DrawableShape::setDashLengths (const Array& newDashLengths) -{ - if (dashLengths != newDashLengths) - { - dashLengths = newDashLengths; - strokeChanged(); - } -} - -void DrawableShape::setStrokeThickness (const float newThickness) -{ - setStrokeType (PathStrokeType (newThickness, strokeType.getJointStyle(), strokeType.getEndStyle())); -} - -bool DrawableShape::isStrokeVisible() const noexcept -{ - return strokeType.getStrokeThickness() > 0.0f && ! strokeFill.fill.isInvisible(); -} - -void DrawableShape::refreshFillTypes (const FillAndStrokeState& newState, ComponentBuilder::ImageProvider* imageProvider) -{ - setFill (newState.getFill (FillAndStrokeState::fill, imageProvider)); - setStrokeFill (newState.getFill (FillAndStrokeState::stroke, imageProvider)); -} - -void DrawableShape::writeTo (FillAndStrokeState& state, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) const -{ - state.setFill (FillAndStrokeState::fill, mainFill, imageProvider, undoManager); - state.setFill (FillAndStrokeState::stroke, strokeFill, imageProvider, undoManager); - state.setStrokeType (strokeType, undoManager); -} - -//============================================================================== -void DrawableShape::paint (Graphics& g) -{ - transformContextToCorrectOrigin (g); - applyDrawableClipPath (g); - - g.setFillType (mainFill.fill); - g.fillPath (path); - - if (isStrokeVisible()) - { - g.setFillType (strokeFill.fill); - g.fillPath (strokePath); - } -} - -void DrawableShape::pathChanged() -{ - strokeChanged(); -} - -void DrawableShape::strokeChanged() -{ - strokePath.clear(); - const float extraAccuracy = 4.0f; - - if (dashLengths.isEmpty()) - strokeType.createStrokedPath (strokePath, path, AffineTransform(), extraAccuracy); - else - strokeType.createDashedStroke (strokePath, path, dashLengths.getRawDataPointer(), - dashLengths.size(), AffineTransform(), extraAccuracy); - - setBoundsToEnclose (getDrawableBounds()); - repaint(); -} - -Rectangle DrawableShape::getDrawableBounds() const -{ - if (isStrokeVisible()) - return strokePath.getBounds(); - - return path.getBounds(); -} - -bool DrawableShape::hitTest (int x, int y) -{ - bool allowsClicksOnThisComponent, allowsClicksOnChildComponents; - getInterceptsMouseClicks (allowsClicksOnThisComponent, allowsClicksOnChildComponents); - - if (! allowsClicksOnThisComponent) - return false; - - const float globalX = (float) (x - originRelativeToComponent.x); - const float globalY = (float) (y - originRelativeToComponent.y); - - return path.contains (globalX, globalY) - || (isStrokeVisible() && strokePath.contains (globalX, globalY)); -} - -//============================================================================== -DrawableShape::RelativeFillType::RelativeFillType() -{ -} - -DrawableShape::RelativeFillType::RelativeFillType (const FillType& fill_) - : fill (fill_) -{ - if (fill.isGradient()) - { - const ColourGradient& g = *fill.gradient; - - gradientPoint1 = g.point1.transformedBy (fill.transform); - gradientPoint2 = g.point2.transformedBy (fill.transform); - gradientPoint3 = Point (g.point1.x + g.point2.y - g.point1.y, - g.point1.y + g.point1.x - g.point2.x) - .transformedBy (fill.transform); - fill.transform = AffineTransform(); - } -} - -DrawableShape::RelativeFillType::RelativeFillType (const RelativeFillType& other) - : fill (other.fill), - gradientPoint1 (other.gradientPoint1), - gradientPoint2 (other.gradientPoint2), - gradientPoint3 (other.gradientPoint3) -{ -} - -DrawableShape::RelativeFillType& DrawableShape::RelativeFillType::operator= (const RelativeFillType& other) -{ - fill = other.fill; - gradientPoint1 = other.gradientPoint1; - gradientPoint2 = other.gradientPoint2; - gradientPoint3 = other.gradientPoint3; - return *this; -} - -bool DrawableShape::RelativeFillType::operator== (const RelativeFillType& other) const -{ - return fill == other.fill - && ((! fill.isGradient()) - || (gradientPoint1 == other.gradientPoint1 - && gradientPoint2 == other.gradientPoint2 - && gradientPoint3 == other.gradientPoint3)); -} - -bool DrawableShape::RelativeFillType::operator!= (const RelativeFillType& other) const -{ - return ! operator== (other); -} - -bool DrawableShape::RelativeFillType::recalculateCoords (Expression::Scope* scope) -{ - if (fill.isGradient()) - { - const Point g1 (gradientPoint1.resolve (scope)); - const Point g2 (gradientPoint2.resolve (scope)); - AffineTransform t; - - ColourGradient& g = *fill.gradient; - - if (g.isRadial) - { - const Point g3 (gradientPoint3.resolve (scope)); - const Point g3Source (g1.x + g2.y - g1.y, - g1.y + g1.x - g2.x); - - t = AffineTransform::fromTargetPoints (g1.x, g1.y, g1.x, g1.y, - g2.x, g2.y, g2.x, g2.y, - g3Source.x, g3Source.y, g3.x, g3.y); - } - - if (g.point1 != g1 || g.point2 != g2 || fill.transform != t) - { - g.point1 = g1; - g.point2 = g2; - fill.transform = t; - return true; - } - } - - return false; -} - -bool DrawableShape::RelativeFillType::isDynamic() const -{ - return gradientPoint1.isDynamic() || gradientPoint2.isDynamic() || gradientPoint3.isDynamic(); -} - -void DrawableShape::RelativeFillType::writeTo (ValueTree& v, ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) const -{ - if (fill.isColour()) - { - v.setProperty (FillAndStrokeState::type, "solid", undoManager); - v.setProperty (FillAndStrokeState::colour, String::toHexString ((int) fill.colour.getARGB()), undoManager); - } - else if (fill.isGradient()) - { - v.setProperty (FillAndStrokeState::type, "gradient", undoManager); - v.setProperty (FillAndStrokeState::gradientPoint1, gradientPoint1.toString(), undoManager); - v.setProperty (FillAndStrokeState::gradientPoint2, gradientPoint2.toString(), undoManager); - v.setProperty (FillAndStrokeState::gradientPoint3, gradientPoint3.toString(), undoManager); - - const ColourGradient& cg = *fill.gradient; - v.setProperty (FillAndStrokeState::radial, cg.isRadial, undoManager); - - String s; - for (int i = 0; i < cg.getNumColours(); ++i) - s << ' ' << cg.getColourPosition (i) - << ' ' << String::toHexString ((int) cg.getColour(i).getARGB()); - - v.setProperty (FillAndStrokeState::colours, s.trimStart(), undoManager); - } - else if (fill.isTiledImage()) - { - v.setProperty (FillAndStrokeState::type, "image", undoManager); - - if (imageProvider != nullptr) - v.setProperty (FillAndStrokeState::imageId, imageProvider->getIdentifierForImage (fill.image), undoManager); - - if (fill.getOpacity() < 1.0f) - v.setProperty (FillAndStrokeState::imageOpacity, fill.getOpacity(), undoManager); - else - v.removeProperty (FillAndStrokeState::imageOpacity, undoManager); - } - else - { - jassertfalse; - } -} - -bool DrawableShape::RelativeFillType::readFrom (const ValueTree& v, ComponentBuilder::ImageProvider* imageProvider) -{ - const String newType (v [FillAndStrokeState::type].toString()); - - if (newType == "solid") - { - const String colourString (v [FillAndStrokeState::colour].toString()); - fill.setColour (colourString.isEmpty() ? Colours::black - : Colour::fromString (colourString)); - return true; - } - else if (newType == "gradient") - { - ColourGradient g; - g.isRadial = v [FillAndStrokeState::radial]; - - StringArray colourSteps; - colourSteps.addTokens (v [FillAndStrokeState::colours].toString(), false); - - for (int i = 0; i < colourSteps.size() / 2; ++i) - g.addColour (colourSteps[i * 2].getDoubleValue(), - Colour::fromString (colourSteps[i * 2 + 1])); - - fill.setGradient (g); - - gradientPoint1 = RelativePoint (v [FillAndStrokeState::gradientPoint1]); - gradientPoint2 = RelativePoint (v [FillAndStrokeState::gradientPoint2]); - gradientPoint3 = RelativePoint (v [FillAndStrokeState::gradientPoint3]); - return true; - } - else if (newType == "image") - { - Image im; - if (imageProvider != nullptr) - im = imageProvider->getImageForIdentifier (v [FillAndStrokeState::imageId]); - - fill.setTiledImage (im, AffineTransform()); - fill.setOpacity ((float) v.getProperty (FillAndStrokeState::imageOpacity, 1.0f)); - return true; - } - - jassertfalse; - return false; -} - -//============================================================================== -const Identifier DrawableShape::FillAndStrokeState::type ("type"); -const Identifier DrawableShape::FillAndStrokeState::colour ("colour"); -const Identifier DrawableShape::FillAndStrokeState::colours ("colours"); -const Identifier DrawableShape::FillAndStrokeState::fill ("Fill"); -const Identifier DrawableShape::FillAndStrokeState::stroke ("Stroke"); -const Identifier DrawableShape::FillAndStrokeState::path ("Path"); -const Identifier DrawableShape::FillAndStrokeState::jointStyle ("jointStyle"); -const Identifier DrawableShape::FillAndStrokeState::capStyle ("capStyle"); -const Identifier DrawableShape::FillAndStrokeState::strokeWidth ("strokeWidth"); -const Identifier DrawableShape::FillAndStrokeState::gradientPoint1 ("point1"); -const Identifier DrawableShape::FillAndStrokeState::gradientPoint2 ("point2"); -const Identifier DrawableShape::FillAndStrokeState::gradientPoint3 ("point3"); -const Identifier DrawableShape::FillAndStrokeState::radial ("radial"); -const Identifier DrawableShape::FillAndStrokeState::imageId ("imageId"); -const Identifier DrawableShape::FillAndStrokeState::imageOpacity ("imageOpacity"); - -DrawableShape::FillAndStrokeState::FillAndStrokeState (const ValueTree& state_) - : Drawable::ValueTreeWrapperBase (state_) -{ -} - -DrawableShape::RelativeFillType DrawableShape::FillAndStrokeState::getFill (const Identifier& fillOrStrokeType, ComponentBuilder::ImageProvider* imageProvider) const -{ - DrawableShape::RelativeFillType f; - f.readFrom (state.getChildWithName (fillOrStrokeType), imageProvider); - return f; -} - -ValueTree DrawableShape::FillAndStrokeState::getFillState (const Identifier& fillOrStrokeType) -{ - ValueTree v (state.getChildWithName (fillOrStrokeType)); - if (v.isValid()) - return v; - - setFill (fillOrStrokeType, FillType (Colours::black), nullptr, nullptr); - return getFillState (fillOrStrokeType); -} - -void DrawableShape::FillAndStrokeState::setFill (const Identifier& fillOrStrokeType, const RelativeFillType& newFill, - ComponentBuilder::ImageProvider* imageProvider, UndoManager* undoManager) -{ - ValueTree v (state.getOrCreateChildWithName (fillOrStrokeType, undoManager)); - newFill.writeTo (v, imageProvider, undoManager); -} - -PathStrokeType DrawableShape::FillAndStrokeState::getStrokeType() const -{ - const String jointStyleString (state [jointStyle].toString()); - const String capStyleString (state [capStyle].toString()); - - return PathStrokeType (state [strokeWidth], - jointStyleString == "curved" ? PathStrokeType::curved - : (jointStyleString == "bevel" ? PathStrokeType::beveled - : PathStrokeType::mitered), - capStyleString == "square" ? PathStrokeType::square - : (capStyleString == "round" ? PathStrokeType::rounded - : PathStrokeType::butt)); -} - -void DrawableShape::FillAndStrokeState::setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager) -{ - state.setProperty (strokeWidth, (double) newStrokeType.getStrokeThickness(), undoManager); - state.setProperty (jointStyle, newStrokeType.getJointStyle() == PathStrokeType::mitered - ? "miter" : (newStrokeType.getJointStyle() == PathStrokeType::curved ? "curved" : "bevel"), undoManager); - state.setProperty (capStyle, newStrokeType.getEndStyle() == PathStrokeType::butt - ? "butt" : (newStrokeType.getEndStyle() == PathStrokeType::square ? "square" : "round"), undoManager); -} - -static bool replaceColourInFill (DrawableShape::RelativeFillType& fill, Colour original, Colour replacement) -{ - if (fill.fill.colour == original && fill.fill.isColour()) - { - fill = FillType (replacement); - return true; - } - - return false; -} - -bool DrawableShape::replaceColour (Colour original, Colour replacement) -{ - bool changed1 = replaceColourInFill (mainFill, original, replacement); - bool changed2 = replaceColourInFill (strokeFill, original, replacement); - return changed1 || changed2; -} - -Path DrawableShape::getOutlineAsPath() const -{ - Path outline (isStrokeVisible() ? strokePath : path); - outline.applyTransform (getTransform()); - return outline; -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/drawables/juce_DrawableShape.h b/source/modules/juce_gui_basics/drawables/juce_DrawableShape.h deleted file mode 100644 index 10a89dd1d..000000000 --- a/source/modules/juce_gui_basics/drawables/juce_DrawableShape.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A base class implementing common functionality for Drawable classes which - consist of some kind of filled and stroked outline. - - @see DrawablePath, DrawableRectangle -*/ -class JUCE_API DrawableShape : public Drawable -{ -protected: - //============================================================================== - DrawableShape(); - DrawableShape (const DrawableShape&); - -public: - /** Destructor. */ - ~DrawableShape(); - - //============================================================================== - /** A FillType wrapper that allows the gradient coordinates to be implemented using RelativePoint. - */ - class RelativeFillType - { - public: - RelativeFillType(); - RelativeFillType (const FillType& fill); - RelativeFillType (const RelativeFillType&); - RelativeFillType& operator= (const RelativeFillType&); - - bool operator== (const RelativeFillType&) const; - bool operator!= (const RelativeFillType&) const; - - bool isDynamic() const; - bool recalculateCoords (Expression::Scope* scope); - - void writeTo (ValueTree& v, ComponentBuilder::ImageProvider*, UndoManager*) const; - bool readFrom (const ValueTree& v, ComponentBuilder::ImageProvider*); - - //============================================================================== - FillType fill; - RelativePoint gradientPoint1, gradientPoint2, gradientPoint3; - }; - - //============================================================================== - /** Sets a fill type for the path. - This colour is used to fill the path - if you don't want the path to be - filled (e.g. if you're just drawing an outline), set this to a transparent - colour. - - @see setPath, setStrokeFill - */ - void setFill (const FillType& newFill); - - /** Sets a fill type for the path. - This colour is used to fill the path - if you don't want the path to be - filled (e.g. if you're just drawing an outline), set this to a transparent - colour. - - @see setPath, setStrokeFill - */ - void setFill (const RelativeFillType& newFill); - - /** Returns the current fill type. - @see setFill - */ - const RelativeFillType& getFill() const noexcept { return mainFill; } - - /** Sets the fill type with which the outline will be drawn. - @see setFill - */ - void setStrokeFill (const FillType& newStrokeFill); - - /** Sets the fill type with which the outline will be drawn. - @see setFill - */ - void setStrokeFill (const RelativeFillType& newStrokeFill); - - /** Returns the current stroke fill. - @see setStrokeFill - */ - const RelativeFillType& getStrokeFill() const noexcept { return strokeFill; } - - /** Changes the properties of the outline that will be drawn around the path. - If the stroke has 0 thickness, no stroke will be drawn. - @see setStrokeThickness, setStrokeColour - */ - void setStrokeType (const PathStrokeType& newStrokeType); - - /** Changes the stroke thickness. - This is a shortcut for calling setStrokeType. - */ - void setStrokeThickness (float newThickness); - - /** Returns the current outline style. */ - const PathStrokeType& getStrokeType() const noexcept { return strokeType; } - - /** Provides a set of dash lengths to use for stroking the path. */ - void setDashLengths (const Array& newDashLengths); - - /** Returns the set of dash lengths that the path is using. */ - const Array& getDashLengths() const noexcept { return dashLengths; } - - //============================================================================== - /** @internal */ - class FillAndStrokeState : public Drawable::ValueTreeWrapperBase - { - public: - FillAndStrokeState (const ValueTree& state); - - ValueTree getFillState (const Identifier& fillOrStrokeType); - RelativeFillType getFill (const Identifier& fillOrStrokeType, ComponentBuilder::ImageProvider*) const; - void setFill (const Identifier& fillOrStrokeType, const RelativeFillType& newFill, - ComponentBuilder::ImageProvider*, UndoManager*); - - PathStrokeType getStrokeType() const; - void setStrokeType (const PathStrokeType& newStrokeType, UndoManager*); - - static const Identifier type, colour, colours, fill, stroke, path, jointStyle, capStyle, strokeWidth, - gradientPoint1, gradientPoint2, gradientPoint3, radial, imageId, imageOpacity; - }; - - /** @internal */ - Rectangle getDrawableBounds() const override; - /** @internal */ - void paint (Graphics&) override; - /** @internal */ - bool hitTest (int x, int y) override; - /** @internal */ - bool replaceColour (Colour originalColour, Colour replacementColour) override; - /** @internal */ - Path getOutlineAsPath() const override; - -protected: - //============================================================================== - /** Called when the cached path should be updated. */ - void pathChanged(); - /** Called when the cached stroke should be updated. */ - void strokeChanged(); - /** True if there's a stroke with a non-zero thickness and non-transparent colour. */ - bool isStrokeVisible() const noexcept; - /** Updates the details from a FillAndStrokeState object, returning true if something changed. */ - void refreshFillTypes (const FillAndStrokeState& newState, ComponentBuilder::ImageProvider*); - /** Writes the stroke and fill details to a FillAndStrokeState object. */ - void writeTo (FillAndStrokeState& state, ComponentBuilder::ImageProvider*, UndoManager*) const; - - //============================================================================== - PathStrokeType strokeType; - Array dashLengths; - Path path, strokePath; - -private: - class RelativePositioner; - RelativeFillType mainFill, strokeFill; - ScopedPointer mainFillPositioner, strokeFillPositioner; - - void setFillInternal (RelativeFillType& fill, const RelativeFillType& newFill, - ScopedPointer& positioner); - - DrawableShape& operator= (const DrawableShape&); -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/drawables/juce_DrawableText.cpp b/source/modules/juce_gui_basics/drawables/juce_DrawableText.cpp deleted file mode 100644 index de6d7c2a2..000000000 --- a/source/modules/juce_gui_basics/drawables/juce_DrawableText.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -DrawableText::DrawableText() - : colour (Colours::black), - justification (Justification::centredLeft) -{ - setBoundingBox (RelativeParallelogram (RelativePoint (0.0f, 0.0f), - RelativePoint (50.0f, 0.0f), - RelativePoint (0.0f, 20.0f))); - setFont (Font (15.0f), true); -} - -DrawableText::DrawableText (const DrawableText& other) - : Drawable (other), - bounds (other.bounds), - fontHeight (other.fontHeight), - fontHScale (other.fontHScale), - font (other.font), - text (other.text), - colour (other.colour), - justification (other.justification) -{ - refreshBounds(); -} - -DrawableText::~DrawableText() -{ -} - -//============================================================================== -void DrawableText::setText (const String& newText) -{ - if (text != newText) - { - text = newText; - refreshBounds(); - } -} - -void DrawableText::setColour (Colour newColour) -{ - if (colour != newColour) - { - colour = newColour; - repaint(); - } -} - -void DrawableText::setFont (const Font& newFont, bool applySizeAndScale) -{ - if (font != newFont) - { - font = newFont; - - if (applySizeAndScale) - { - fontHeight = font.getHeight(); - fontHScale = font.getHorizontalScale(); - } - - refreshBounds(); - } -} - -void DrawableText::setJustification (Justification newJustification) -{ - justification = newJustification; - repaint(); -} - -void DrawableText::setBoundingBox (const RelativeParallelogram& newBounds) -{ - if (bounds != newBounds) - { - bounds = newBounds; - refreshBounds(); - } -} - -void DrawableText::setFontHeight (const RelativeCoordinate& newHeight) -{ - if (fontHeight != newHeight) - { - fontHeight = newHeight; - refreshBounds(); - } -} - -void DrawableText::setFontHorizontalScale (const RelativeCoordinate& newScale) -{ - if (fontHScale != newScale) - { - fontHScale = newScale; - refreshBounds(); - } -} - -void DrawableText::refreshBounds() -{ - if (bounds.isDynamic() || fontHeight.isDynamic() || fontHScale.isDynamic()) - { - Drawable::Positioner* const p = new Drawable::Positioner (*this); - setPositioner (p); - p->apply(); - } - else - { - setPositioner (0); - recalculateCoordinates (0); - } -} - -bool DrawableText::registerCoordinates (RelativeCoordinatePositionerBase& pos) -{ - bool ok = pos.addPoint (bounds.topLeft); - ok = pos.addPoint (bounds.topRight) && ok; - ok = pos.addPoint (bounds.bottomLeft) && ok; - ok = pos.addCoordinate (fontHeight) && ok; - return pos.addCoordinate (fontHScale) && ok; -} - -void DrawableText::recalculateCoordinates (Expression::Scope* scope) -{ - bounds.resolveThreePoints (resolvedPoints, scope); - - const float w = Line (resolvedPoints[0], resolvedPoints[1]).getLength(); - const float h = Line (resolvedPoints[0], resolvedPoints[2]).getLength(); - - const float height = jlimit (0.01f, jmax (0.01f, h), (float) fontHeight.resolve (scope)); - const float hscale = jlimit (0.01f, jmax (0.01f, w), (float) fontHScale.resolve (scope)); - - scaledFont = font; - scaledFont.setHeight (height); - scaledFont.setHorizontalScale (hscale); - - setBoundsToEnclose (getDrawableBounds()); - repaint(); -} - -//============================================================================== -Rectangle DrawableText::getTextArea (float w, float h) const -{ - return Rectangle (w, h).getSmallestIntegerContainer(); -} - -AffineTransform DrawableText::getTextTransform (float w, float h) const -{ - return AffineTransform::fromTargetPoints (0, 0, resolvedPoints[0].x, resolvedPoints[0].y, - w, 0, resolvedPoints[1].x, resolvedPoints[1].y, - 0, h, resolvedPoints[2].x, resolvedPoints[2].y); -} - -void DrawableText::paint (Graphics& g) -{ - transformContextToCorrectOrigin (g); - - const float w = Line (resolvedPoints[0], resolvedPoints[1]).getLength(); - const float h = Line (resolvedPoints[0], resolvedPoints[2]).getLength(); - - g.addTransform (getTextTransform (w, h)); - g.setFont (scaledFont); - g.setColour (colour); - - g.drawFittedText (text, getTextArea (w, h), justification, 0x100000); -} - -Rectangle DrawableText::getDrawableBounds() const -{ - return RelativeParallelogram::getBoundingBox (resolvedPoints); -} - -Drawable* DrawableText::createCopy() const -{ - return new DrawableText (*this); -} - -//============================================================================== -const Identifier DrawableText::valueTreeType ("Text"); - -const Identifier DrawableText::ValueTreeWrapper::text ("text"); -const Identifier DrawableText::ValueTreeWrapper::colour ("colour"); -const Identifier DrawableText::ValueTreeWrapper::font ("font"); -const Identifier DrawableText::ValueTreeWrapper::justification ("justification"); -const Identifier DrawableText::ValueTreeWrapper::topLeft ("topLeft"); -const Identifier DrawableText::ValueTreeWrapper::topRight ("topRight"); -const Identifier DrawableText::ValueTreeWrapper::bottomLeft ("bottomLeft"); -const Identifier DrawableText::ValueTreeWrapper::fontHeight ("fontHeight"); -const Identifier DrawableText::ValueTreeWrapper::fontHScale ("fontHScale"); - -//============================================================================== -DrawableText::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_) - : ValueTreeWrapperBase (state_) -{ - jassert (state.hasType (valueTreeType)); -} - -String DrawableText::ValueTreeWrapper::getText() const -{ - return state [text].toString(); -} - -void DrawableText::ValueTreeWrapper::setText (const String& newText, UndoManager* undoManager) -{ - state.setProperty (text, newText, undoManager); -} - -Value DrawableText::ValueTreeWrapper::getTextValue (UndoManager* undoManager) -{ - return state.getPropertyAsValue (text, undoManager); -} - -Colour DrawableText::ValueTreeWrapper::getColour() const -{ - return Colour::fromString (state [colour].toString()); -} - -void DrawableText::ValueTreeWrapper::setColour (Colour newColour, UndoManager* undoManager) -{ - state.setProperty (colour, newColour.toString(), undoManager); -} - -Justification DrawableText::ValueTreeWrapper::getJustification() const -{ - return Justification ((int) state [justification]); -} - -void DrawableText::ValueTreeWrapper::setJustification (Justification newJustification, UndoManager* undoManager) -{ - state.setProperty (justification, newJustification.getFlags(), undoManager); -} - -Font DrawableText::ValueTreeWrapper::getFont() const -{ - return Font::fromString (state [font]); -} - -void DrawableText::ValueTreeWrapper::setFont (const Font& newFont, UndoManager* undoManager) -{ - state.setProperty (font, newFont.toString(), undoManager); -} - -Value DrawableText::ValueTreeWrapper::getFontValue (UndoManager* undoManager) -{ - return state.getPropertyAsValue (font, undoManager); -} - -RelativeParallelogram DrawableText::ValueTreeWrapper::getBoundingBox() const -{ - return RelativeParallelogram (state [topLeft].toString(), state [topRight].toString(), state [bottomLeft].toString()); -} - -void DrawableText::ValueTreeWrapper::setBoundingBox (const RelativeParallelogram& newBounds, UndoManager* undoManager) -{ - state.setProperty (topLeft, newBounds.topLeft.toString(), undoManager); - state.setProperty (topRight, newBounds.topRight.toString(), undoManager); - state.setProperty (bottomLeft, newBounds.bottomLeft.toString(), undoManager); -} - -RelativeCoordinate DrawableText::ValueTreeWrapper::getFontHeight() const -{ - return state [fontHeight].toString(); -} - -void DrawableText::ValueTreeWrapper::setFontHeight (const RelativeCoordinate& coord, UndoManager* undoManager) -{ - state.setProperty (fontHeight, coord.toString(), undoManager); -} - -RelativeCoordinate DrawableText::ValueTreeWrapper::getFontHorizontalScale() const -{ - return state [fontHScale].toString(); -} - -void DrawableText::ValueTreeWrapper::setFontHorizontalScale (const RelativeCoordinate& coord, UndoManager* undoManager) -{ - state.setProperty (fontHScale, coord.toString(), undoManager); -} - -//============================================================================== -void DrawableText::refreshFromValueTree (const ValueTree& tree, ComponentBuilder&) -{ - ValueTreeWrapper v (tree); - setComponentID (v.getID()); - - const RelativeParallelogram newBounds (v.getBoundingBox()); - const RelativeCoordinate newFontHeight (v.getFontHeight()); - const RelativeCoordinate newFontHScale (v.getFontHorizontalScale()); - const Colour newColour (v.getColour()); - const Justification newJustification (v.getJustification()); - const String newText (v.getText()); - const Font newFont (v.getFont()); - - if (text != newText || font != newFont || justification != newJustification - || colour != newColour || bounds != newBounds - || newFontHeight != fontHeight || newFontHScale != fontHScale) - { - setBoundingBox (newBounds); - setFontHeight (newFontHeight); - setFontHorizontalScale (newFontHScale); - setColour (newColour); - setFont (newFont, false); - setJustification (newJustification); - setText (newText); - } -} - -ValueTree DrawableText::createValueTree (ComponentBuilder::ImageProvider*) const -{ - ValueTree tree (valueTreeType); - ValueTreeWrapper v (tree); - - v.setID (getComponentID()); - v.setText (text, nullptr); - v.setFont (font, nullptr); - v.setJustification (justification, nullptr); - v.setColour (colour, nullptr); - v.setBoundingBox (bounds, nullptr); - v.setFontHeight (fontHeight, nullptr); - v.setFontHorizontalScale (fontHScale, nullptr); - - return tree; -} - -Path DrawableText::getOutlineAsPath() const -{ - auto w = Line (resolvedPoints[0], resolvedPoints[1]).getLength(); - auto h = Line (resolvedPoints[0], resolvedPoints[2]).getLength(); - const auto area = getTextArea (w, h).toFloat(); - - GlyphArrangement arr; - arr.addFittedText (scaledFont, text, - area.getX(), area.getY(), - area.getWidth(), area.getHeight(), - justification, - 0x100000); - - Path pathOfAllGlyphs; - - for (int i = 0; i < arr.getNumGlyphs(); ++i) - { - Path gylphPath; - arr.getGlyph (i).createPath (gylphPath); - pathOfAllGlyphs.addPath (gylphPath); - } - - pathOfAllGlyphs.applyTransform (getTextTransform (w, h) - .followedBy (getTransform())); - - return pathOfAllGlyphs; -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/drawables/juce_DrawableText.h b/source/modules/juce_gui_basics/drawables/juce_DrawableText.h deleted file mode 100644 index 637659ed8..000000000 --- a/source/modules/juce_gui_basics/drawables/juce_DrawableText.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A drawable object which renders a line of text. - - @see Drawable -*/ -class JUCE_API DrawableText : public Drawable -{ -public: - //============================================================================== - /** Creates a DrawableText object. */ - DrawableText(); - DrawableText (const DrawableText&); - - /** Destructor. */ - ~DrawableText(); - - //============================================================================== - /** Sets the text to display.*/ - void setText (const String& newText); - - /** Returns the currently displayed text */ - const String& getText() const noexcept { return text;} - - /** Sets the colour of the text. */ - void setColour (Colour newColour); - - /** Returns the current text colour. */ - Colour getColour() const noexcept { return colour; } - - /** Sets the font to use. - Note that the font height and horizontal scale are set as RelativeCoordinates using - setFontHeight and setFontHorizontalScale. If applySizeAndScale is true, then these height - and scale values will be changed to match the dimensions of the font supplied; - if it is false, then the new font object's height and scale are ignored. - */ - void setFont (const Font& newFont, bool applySizeAndScale); - - /** Returns the current font. */ - const Font& getFont() const noexcept { return font; } - - /** Changes the justification of the text within the bounding box. */ - void setJustification (Justification newJustification); - - /** Returns the current justification. */ - Justification getJustification() const noexcept { return justification; } - - /** Returns the parallelogram that defines the text bounding box. */ - const RelativeParallelogram& getBoundingBox() const noexcept { return bounds; } - - /** Sets the bounding box that contains the text. */ - void setBoundingBox (const RelativeParallelogram& newBounds); - - const RelativeCoordinate& getFontHeight() const { return fontHeight; } - void setFontHeight (const RelativeCoordinate& newHeight); - - const RelativeCoordinate& getFontHorizontalScale() const { return fontHScale; } - void setFontHorizontalScale (const RelativeCoordinate& newScale); - - //============================================================================== - /** @internal */ - void paint (Graphics&) override; - /** @internal */ - Drawable* createCopy() const override; - /** @internal */ - void refreshFromValueTree (const ValueTree& tree, ComponentBuilder& builder); - /** @internal */ - ValueTree createValueTree (ComponentBuilder::ImageProvider* imageProvider) const override; - /** @internal */ - static const Identifier valueTreeType; - /** @internal */ - Rectangle getDrawableBounds() const override; - /** @internal */ - Path getOutlineAsPath() const override; - - //============================================================================== - /** Internally-used class for wrapping a DrawableText's state into a ValueTree. */ - class ValueTreeWrapper : public Drawable::ValueTreeWrapperBase - { - public: - ValueTreeWrapper (const ValueTree& state); - - String getText() const; - void setText (const String& newText, UndoManager* undoManager); - Value getTextValue (UndoManager* undoManager); - - Colour getColour() const; - void setColour (Colour newColour, UndoManager* undoManager); - - Justification getJustification() const; - void setJustification (Justification newJustification, UndoManager* undoManager); - - Font getFont() const; - void setFont (const Font& newFont, UndoManager* undoManager); - Value getFontValue (UndoManager* undoManager); - - RelativeParallelogram getBoundingBox() const; - void setBoundingBox (const RelativeParallelogram& newBounds, UndoManager* undoManager); - - RelativeCoordinate getFontHeight() const; - void setFontHeight (const RelativeCoordinate& newHeight, UndoManager* undoManager); - - RelativeCoordinate getFontHorizontalScale() const; - void setFontHorizontalScale (const RelativeCoordinate& newScale, UndoManager* undoManager); - - static const Identifier text, colour, font, justification, topLeft, topRight, bottomLeft, fontHeight, fontHScale; - }; - -private: - //============================================================================== - RelativeParallelogram bounds; - RelativeCoordinate fontHeight, fontHScale; - Point resolvedPoints[3]; - Font font, scaledFont; - String text; - Colour colour; - Justification justification; - - friend class Drawable::Positioner; - bool registerCoordinates (RelativeCoordinatePositionerBase&); - void recalculateCoordinates (Expression::Scope*); - void refreshBounds(); - Rectangle getTextArea (float width, float height) const; - AffineTransform getTextTransform (float width, float height) const; - - DrawableText& operator= (const DrawableText&); - JUCE_LEAK_DETECTOR (DrawableText) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/drawables/juce_SVGParser.cpp b/source/modules/juce_gui_basics/drawables/juce_SVGParser.cpp deleted file mode 100644 index a2aaef12d..000000000 --- a/source/modules/juce_gui_basics/drawables/juce_SVGParser.cpp +++ /dev/null @@ -1,1735 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -class SVGState -{ -public: - //============================================================================== - explicit SVGState (const XmlElement* topLevel, const File& svgFile = {}) - : originalFile (svgFile), topLevelXml (topLevel, nullptr) - { - } - - struct XmlPath - { - XmlPath (const XmlElement* e, const XmlPath* p) noexcept : xml (e), parent (p) {} - - const XmlElement& operator*() const noexcept { jassert (xml != nullptr); return *xml; } - const XmlElement* operator->() const noexcept { return xml; } - XmlPath getChild (const XmlElement* e) const noexcept { return XmlPath (e, this); } - - template - bool applyOperationToChildWithID (const String& id, OperationType& op) const - { - forEachXmlChildElement (*xml, e) - { - XmlPath child (e, this); - - if (e->compareAttribute ("id", id) - && ! child->hasTagName ("defs")) - return op (child); - - if (child.applyOperationToChildWithID (id, op)) - return true; - } - - return false; - } - - const XmlElement* xml; - const XmlPath* parent; - }; - - //============================================================================== - struct UsePathOp - { - const SVGState* state; - Path* targetPath; - - bool operator() (const XmlPath& xmlPath) const - { - return state->parsePathElement (xmlPath, *targetPath); - } - }; - - struct UseTextOp - { - const SVGState* state; - AffineTransform* transform; - Drawable* target; - - bool operator() (const XmlPath& xmlPath) - { - target = state->parseText (xmlPath, true, transform); - return target != nullptr; - } - }; - - struct UseImageOp - { - const SVGState* state; - AffineTransform* transform; - Drawable* target; - - bool operator() (const XmlPath& xmlPath) - { - target = state->parseImage (xmlPath, true, transform); - return target != nullptr; - } - }; - - struct GetClipPathOp - { - SVGState* state; - Drawable* target; - - bool operator() (const XmlPath& xmlPath) - { - return state->applyClipPath (*target, xmlPath); - } - }; - - struct SetGradientStopsOp - { - const SVGState* state; - ColourGradient* gradient; - - bool operator() (const XmlPath& xml) const - { - return state->addGradientStopsIn (*gradient, xml); - } - }; - - struct GetFillTypeOp - { - const SVGState* state; - const Path* path; - float opacity; - FillType fillType; - - bool operator() (const XmlPath& xml) - { - if (xml->hasTagNameIgnoringNamespace ("linearGradient") - || xml->hasTagNameIgnoringNamespace ("radialGradient")) - { - fillType = state->getGradientFillType (xml, *path, opacity); - return true; - } - - return false; - } - }; - - //============================================================================== - Drawable* parseSVGElement (const XmlPath& xml) - { - auto drawable = new DrawableComposite(); - setCommonAttributes (*drawable, xml); - - SVGState newState (*this); - - if (xml->hasAttribute ("transform")) - newState.addTransform (xml); - - newState.width = getCoordLength (xml->getStringAttribute ("width", String (newState.width)), viewBoxW); - newState.height = getCoordLength (xml->getStringAttribute ("height", String (newState.height)), viewBoxH); - - if (newState.width <= 0) newState.width = 100; - if (newState.height <= 0) newState.height = 100; - - Point viewboxXY; - - if (xml->hasAttribute ("viewBox")) - { - auto viewBoxAtt = xml->getStringAttribute ("viewBox"); - auto viewParams = viewBoxAtt.getCharPointer(); - Point vwh; - - if (parseCoords (viewParams, viewboxXY, true) - && parseCoords (viewParams, vwh, true) - && vwh.x > 0 - && vwh.y > 0) - { - newState.viewBoxW = vwh.x; - newState.viewBoxH = vwh.y; - - auto placementFlags = parsePlacementFlags (xml->getStringAttribute ("preserveAspectRatio").trim()); - - if (placementFlags != 0) - newState.transform = RectanglePlacement (placementFlags) - .getTransformToFit (Rectangle (viewboxXY.x, viewboxXY.y, vwh.x, vwh.y), - Rectangle (newState.width, newState.height)) - .followedBy (newState.transform); - } - } - else - { - if (viewBoxW == 0.0f) newState.viewBoxW = newState.width; - if (viewBoxH == 0.0f) newState.viewBoxH = newState.height; - } - - newState.parseSubElements (xml, *drawable); - - drawable->setContentArea (RelativeRectangle (RelativeCoordinate (viewboxXY.x), - RelativeCoordinate (viewboxXY.x + newState.viewBoxW), - RelativeCoordinate (viewboxXY.y), - RelativeCoordinate (viewboxXY.y + newState.viewBoxH))); - drawable->resetBoundingBoxToContentArea(); - - return drawable; - } - - //============================================================================== - void parsePathString (Path& path, const String& pathString) const - { - auto d = pathString.getCharPointer().findEndOfWhitespace(); - - Point subpathStart, last, last2, p1, p2, p3; - juce_wchar currentCommand = 0, previousCommand = 0; - bool isRelative = true; - bool carryOn = true; - - while (! d.isEmpty()) - { - if (CharPointer_ASCII ("MmLlHhVvCcSsQqTtAaZz").indexOf (*d) >= 0) - { - currentCommand = d.getAndAdvance(); - isRelative = currentCommand >= 'a'; - } - - switch (currentCommand) - { - case 'M': - case 'm': - case 'L': - case 'l': - if (parseCoordsOrSkip (d, p1, false)) - { - if (isRelative) - p1 += last; - - if (currentCommand == 'M' || currentCommand == 'm') - { - subpathStart = p1; - path.startNewSubPath (p1); - currentCommand = 'l'; - } - else - path.lineTo (p1); - - last2 = last; - last = p1; - } - break; - - case 'H': - case 'h': - if (parseCoord (d, p1.x, false, true)) - { - if (isRelative) - p1.x += last.x; - - path.lineTo (p1.x, last.y); - - last2.x = last.x; - last.x = p1.x; - } - else - { - ++d; - } - break; - - case 'V': - case 'v': - if (parseCoord (d, p1.y, false, false)) - { - if (isRelative) - p1.y += last.y; - - path.lineTo (last.x, p1.y); - - last2.y = last.y; - last.y = p1.y; - } - else - { - ++d; - } - break; - - case 'C': - case 'c': - if (parseCoordsOrSkip (d, p1, false) - && parseCoordsOrSkip (d, p2, false) - && parseCoordsOrSkip (d, p3, false)) - { - if (isRelative) - { - p1 += last; - p2 += last; - p3 += last; - } - - path.cubicTo (p1, p2, p3); - - last2 = p2; - last = p3; - } - break; - - case 'S': - case 's': - if (parseCoordsOrSkip (d, p1, false) - && parseCoordsOrSkip (d, p3, false)) - { - if (isRelative) - { - p1 += last; - p3 += last; - } - - p2 = last + (last - last2); - path.cubicTo (p2, p1, p3); - - last2 = p1; - last = p3; - } - break; - - case 'Q': - case 'q': - if (parseCoordsOrSkip (d, p1, false) - && parseCoordsOrSkip (d, p2, false)) - { - if (isRelative) - { - p1 += last; - p2 += last; - } - - path.quadraticTo (p1, p2); - - last2 = p1; - last = p2; - } - break; - - case 'T': - case 't': - if (parseCoordsOrSkip (d, p1, false)) - { - if (isRelative) - p1 += last; - - p2 = CharPointer_ASCII ("QqTt").indexOf (previousCommand) >= 0 ? last + (last - last2) - : p1; - path.quadraticTo (p2, p1); - - last2 = p2; - last = p1; - } - break; - - case 'A': - case 'a': - if (parseCoordsOrSkip (d, p1, false)) - { - String num; - - if (parseNextNumber (d, num, false)) - { - const float angle = degreesToRadians (num.getFloatValue()); - - if (parseNextNumber (d, num, false)) - { - const bool largeArc = num.getIntValue() != 0; - - if (parseNextNumber (d, num, false)) - { - const bool sweep = num.getIntValue() != 0; - - if (parseCoordsOrSkip (d, p2, false)) - { - if (isRelative) - p2 += last; - - if (last != p2) - { - double centreX, centreY, startAngle, deltaAngle; - double rx = p1.x, ry = p1.y; - - endpointToCentreParameters (last.x, last.y, p2.x, p2.y, - angle, largeArc, sweep, - rx, ry, centreX, centreY, - startAngle, deltaAngle); - - path.addCentredArc ((float) centreX, (float) centreY, - (float) rx, (float) ry, - angle, (float) startAngle, (float) (startAngle + deltaAngle), - false); - - path.lineTo (p2); - } - - last2 = last; - last = p2; - } - } - } - } - } - - break; - - case 'Z': - case 'z': - path.closeSubPath(); - last = last2 = subpathStart; - d = d.findEndOfWhitespace(); - currentCommand = 'M'; - break; - - default: - carryOn = false; - break; - } - - if (! carryOn) - break; - - previousCommand = currentCommand; - } - - // paths that finish back at their start position often seem to be - // left without a 'z', so need to be closed explicitly.. - if (path.getCurrentPosition() == subpathStart) - path.closeSubPath(); - } - -private: - //============================================================================== - const File originalFile; - const XmlPath topLevelXml; - float width = 512, height = 512, viewBoxW = 0, viewBoxH = 0; - AffineTransform transform; - String cssStyleText; - - static bool isNone (const String& s) noexcept - { - return s.equalsIgnoreCase ("none"); - } - - static void setCommonAttributes (Drawable& d, const XmlPath& xml) - { - auto compID = xml->getStringAttribute ("id"); - d.setName (compID); - d.setComponentID (compID); - - if (isNone (xml->getStringAttribute ("display"))) - d.setVisible (false); - } - - //============================================================================== - void parseSubElements (const XmlPath& xml, DrawableComposite& parentDrawable, const bool shouldParseClip = true) - { - forEachXmlChildElement (*xml, e) - { - const XmlPath child (xml.getChild (e)); - - if (auto* drawable = parseSubElement (child)) - { - parentDrawable.addChildComponent (drawable); - - if (! isNone (getStyleAttribute (child, "display"))) - drawable->setVisible (true); - - if (shouldParseClip) - parseClipPath (child, *drawable); - } - } - } - - Drawable* parseSubElement (const XmlPath& xml) - { - { - Path path; - if (parsePathElement (xml, path)) - return parseShape (xml, path); - } - - auto tag = xml->getTagNameWithoutNamespace(); - - if (tag == "g") return parseGroupElement (xml, true); - if (tag == "svg") return parseSVGElement (xml); - if (tag == "text") return parseText (xml, true); - if (tag == "image") return parseImage (xml, true); - if (tag == "switch") return parseSwitch (xml); - if (tag == "a") return parseLinkElement (xml); - if (tag == "use") return parseUseOther (xml); - if (tag == "style") parseCSSStyle (xml); - if (tag == "defs") parseDefs (xml); - - return nullptr; - } - - bool parsePathElement (const XmlPath& xml, Path& path) const - { - auto tag = xml->getTagNameWithoutNamespace(); - - if (tag == "path") { parsePath (xml, path); return true; } - if (tag == "rect") { parseRect (xml, path); return true; } - if (tag == "circle") { parseCircle (xml, path); return true; } - if (tag == "ellipse") { parseEllipse (xml, path); return true; } - if (tag == "line") { parseLine (xml, path); return true; } - if (tag == "polyline") { parsePolygon (xml, true, path); return true; } - if (tag == "polygon") { parsePolygon (xml, false, path); return true; } - if (tag == "use") { return parseUsePath (xml, path); } - - return false; - } - - DrawableComposite* parseSwitch (const XmlPath& xml) - { - if (auto* group = xml->getChildByName ("g")) - return parseGroupElement (xml.getChild (group), true); - - return nullptr; - } - - DrawableComposite* parseGroupElement (const XmlPath& xml, bool shouldParseTransform) - { - if (shouldParseTransform && xml->hasAttribute ("transform")) - { - SVGState newState (*this); - newState.addTransform (xml); - - return newState.parseGroupElement (xml, false); - } - - auto* drawable = new DrawableComposite(); - setCommonAttributes (*drawable, xml); - parseSubElements (xml, *drawable); - - drawable->resetContentAreaAndBoundingBoxToFitChildren(); - return drawable; - } - - DrawableComposite* parseLinkElement (const XmlPath& xml) - { - return parseGroupElement (xml, true); // TODO: support for making this clickable - } - - //============================================================================== - void parsePath (const XmlPath& xml, Path& path) const - { - parsePathString (path, xml->getStringAttribute ("d")); - - if (getStyleAttribute (xml, "fill-rule").trim().equalsIgnoreCase ("evenodd")) - path.setUsingNonZeroWinding (false); - } - - void parseRect (const XmlPath& xml, Path& rect) const - { - const bool hasRX = xml->hasAttribute ("rx"); - const bool hasRY = xml->hasAttribute ("ry"); - - if (hasRX || hasRY) - { - float rx = getCoordLength (xml, "rx", viewBoxW); - float ry = getCoordLength (xml, "ry", viewBoxH); - - if (! hasRX) - rx = ry; - else if (! hasRY) - ry = rx; - - rect.addRoundedRectangle (getCoordLength (xml, "x", viewBoxW), - getCoordLength (xml, "y", viewBoxH), - getCoordLength (xml, "width", viewBoxW), - getCoordLength (xml, "height", viewBoxH), - rx, ry); - } - else - { - rect.addRectangle (getCoordLength (xml, "x", viewBoxW), - getCoordLength (xml, "y", viewBoxH), - getCoordLength (xml, "width", viewBoxW), - getCoordLength (xml, "height", viewBoxH)); - } - } - - void parseCircle (const XmlPath& xml, Path& circle) const - { - auto cx = getCoordLength (xml, "cx", viewBoxW); - auto cy = getCoordLength (xml, "cy", viewBoxH); - auto radius = getCoordLength (xml, "r", viewBoxW); - - circle.addEllipse (cx - radius, cy - radius, radius * 2.0f, radius * 2.0f); - } - - void parseEllipse (const XmlPath& xml, Path& ellipse) const - { - auto cx = getCoordLength (xml, "cx", viewBoxW); - auto cy = getCoordLength (xml, "cy", viewBoxH); - auto radiusX = getCoordLength (xml, "rx", viewBoxW); - auto radiusY = getCoordLength (xml, "ry", viewBoxH); - - ellipse.addEllipse (cx - radiusX, cy - radiusY, radiusX * 2.0f, radiusY * 2.0f); - } - - void parseLine (const XmlPath& xml, Path& line) const - { - auto x1 = getCoordLength (xml, "x1", viewBoxW); - auto y1 = getCoordLength (xml, "y1", viewBoxH); - auto x2 = getCoordLength (xml, "x2", viewBoxW); - auto y2 = getCoordLength (xml, "y2", viewBoxH); - - line.startNewSubPath (x1, y1); - line.lineTo (x2, y2); - } - - void parsePolygon (const XmlPath& xml, const bool isPolyline, Path& path) const - { - auto pointsAtt = xml->getStringAttribute ("points"); - auto points = pointsAtt.getCharPointer(); - Point p; - - if (parseCoords (points, p, true)) - { - Point first (p), last; - - path.startNewSubPath (first); - - while (parseCoords (points, p, true)) - { - last = p; - path.lineTo (p); - } - - if ((! isPolyline) || first == last) - path.closeSubPath(); - } - } - - static String getLinkedID (const XmlPath& xml) - { - auto link = xml->getStringAttribute ("xlink:href"); - - if (link.startsWithChar ('#')) - return link.substring (1); - - return {}; - } - - bool parseUsePath (const XmlPath& xml, Path& path) const - { - auto linkedID = getLinkedID (xml); - - if (linkedID.isNotEmpty()) - { - UsePathOp op = { this, &path }; - return topLevelXml.applyOperationToChildWithID (linkedID, op); - } - - return false; - } - - Drawable* parseUseOther (const XmlPath& xml) const - { - if (auto* drawableText = parseText (xml, false)) return drawableText; - if (auto* drawableImage = parseImage (xml, false)) return drawableImage; - - return nullptr; - } - - static String parseURL (const String& str) - { - if (str.startsWithIgnoreCase ("url")) - return str.fromFirstOccurrenceOf ("#", false, false) - .upToLastOccurrenceOf (")", false, false).trim(); - - return {}; - } - - //============================================================================== - Drawable* parseShape (const XmlPath& xml, Path& path, - const bool shouldParseTransform = true, - AffineTransform* additonalTransform = nullptr) const - { - if (shouldParseTransform && xml->hasAttribute ("transform")) - { - SVGState newState (*this); - newState.addTransform (xml); - - return newState.parseShape (xml, path, false, additonalTransform); - } - - auto dp = new DrawablePath(); - setCommonAttributes (*dp, xml); - dp->setFill (Colours::transparentBlack); - - path.applyTransform (transform); - - if (additonalTransform != nullptr) - path.applyTransform (*additonalTransform); - - dp->setPath (path); - - dp->setFill (getPathFillType (path, xml, "fill", - getStyleAttribute (xml, "fill-opacity"), - getStyleAttribute (xml, "opacity"), - pathContainsClosedSubPath (path) ? Colours::black - : Colours::transparentBlack)); - - auto strokeType = getStyleAttribute (xml, "stroke"); - - if (strokeType.isNotEmpty() && ! isNone (strokeType)) - { - dp->setStrokeFill (getPathFillType (path, xml, "stroke", - getStyleAttribute (xml, "stroke-opacity"), - getStyleAttribute (xml, "opacity"), - Colours::transparentBlack)); - - dp->setStrokeType (getStrokeFor (xml)); - } - - auto strokeDashArray = getStyleAttribute (xml, "stroke-dasharray"); - - if (strokeDashArray.isNotEmpty()) - parseDashArray (strokeDashArray, *dp); - - return dp; - } - - static bool pathContainsClosedSubPath (const Path& path) noexcept - { - for (Path::Iterator iter (path); iter.next();) - if (iter.elementType == Path::Iterator::closePath) - return true; - - return false; - } - - void parseDashArray (const String& dashList, DrawablePath& dp) const - { - if (dashList.equalsIgnoreCase ("null") || isNone (dashList)) - return; - - Array dashLengths; - - for (auto t = dashList.getCharPointer();;) - { - float value; - if (! parseCoord (t, value, true, true)) - break; - - dashLengths.add (value); - - t = t.findEndOfWhitespace(); - - if (*t == ',') - ++t; - } - - if (dashLengths.size() > 0) - { - auto* dashes = dashLengths.getRawDataPointer(); - - for (int i = 0; i < dashLengths.size(); ++i) - { - if (dashes[i] <= 0) // SVG uses zero-length dashes to mean a dotted line - { - if (dashLengths.size() == 1) - return; - - const float nonZeroLength = 0.001f; - dashes[i] = nonZeroLength; - - const int pairedIndex = i ^ 1; - - if (isPositiveAndBelow (pairedIndex, dashLengths.size()) - && dashes[pairedIndex] > nonZeroLength) - dashes[pairedIndex] -= nonZeroLength; - } - } - - dp.setDashLengths (dashLengths); - } - } - - bool parseClipPath (const XmlPath& xml, Drawable& d) - { - const String clipPath (getStyleAttribute (xml, "clip-path")); - - if (clipPath.isNotEmpty()) - { - auto urlID = parseURL (clipPath); - - if (urlID.isNotEmpty()) - { - GetClipPathOp op = { this, &d }; - return topLevelXml.applyOperationToChildWithID (urlID, op); - } - } - - return false; - } - - bool applyClipPath (Drawable& target, const XmlPath& xmlPath) - { - if (xmlPath->hasTagNameIgnoringNamespace ("clipPath")) - { - ScopedPointer drawableClipPath (new DrawableComposite()); - - parseSubElements (xmlPath, *drawableClipPath, false); - - if (drawableClipPath->getNumChildComponents() > 0) - { - setCommonAttributes (*drawableClipPath, xmlPath); - target.setClipPath (drawableClipPath.release()); - return true; - } - } - - return false; - } - - bool addGradientStopsIn (ColourGradient& cg, const XmlPath& fillXml) const - { - bool result = false; - - if (fillXml.xml != nullptr) - { - forEachXmlChildElementWithTagName (*fillXml, e, "stop") - { - auto col = parseColour (fillXml.getChild (e), "stop-color", Colours::black); - - auto opacity = getStyleAttribute (fillXml.getChild (e), "stop-opacity", "1"); - col = col.withMultipliedAlpha (jlimit (0.0f, 1.0f, opacity.getFloatValue())); - - double offset = e->getDoubleAttribute ("offset"); - - if (e->getStringAttribute ("offset").containsChar ('%')) - offset *= 0.01; - - cg.addColour (jlimit (0.0, 1.0, offset), col); - result = true; - } - } - - return result; - } - - FillType getGradientFillType (const XmlPath& fillXml, - const Path& path, - const float opacity) const - { - ColourGradient gradient; - - { - auto linkedID = getLinkedID (fillXml); - - if (linkedID.isNotEmpty()) - { - SetGradientStopsOp op = { this, &gradient, }; - topLevelXml.applyOperationToChildWithID (linkedID, op); - } - } - - addGradientStopsIn (gradient, fillXml); - - if (int numColours = gradient.getNumColours()) - { - if (gradient.getColourPosition (0) > 0) - gradient.addColour (0.0, gradient.getColour (0)); - - if (gradient.getColourPosition (numColours - 1) < 1.0) - gradient.addColour (1.0, gradient.getColour (numColours - 1)); - } - else - { - gradient.addColour (0.0, Colours::black); - gradient.addColour (1.0, Colours::black); - } - - if (opacity < 1.0f) - gradient.multiplyOpacity (opacity); - - jassert (gradient.getNumColours() > 0); - - gradient.isRadial = fillXml->hasTagNameIgnoringNamespace ("radialGradient"); - - float gradientWidth = viewBoxW; - float gradientHeight = viewBoxH; - float dx = 0.0f; - float dy = 0.0f; - - const bool userSpace = fillXml->getStringAttribute ("gradientUnits").equalsIgnoreCase ("userSpaceOnUse"); - - if (! userSpace) - { - auto bounds = path.getBounds(); - dx = bounds.getX(); - dy = bounds.getY(); - gradientWidth = bounds.getWidth(); - gradientHeight = bounds.getHeight(); - } - - if (gradient.isRadial) - { - if (userSpace) - gradient.point1.setXY (dx + getCoordLength (fillXml->getStringAttribute ("cx", "50%"), gradientWidth), - dy + getCoordLength (fillXml->getStringAttribute ("cy", "50%"), gradientHeight)); - else - gradient.point1.setXY (dx + gradientWidth * getCoordLength (fillXml->getStringAttribute ("cx", "50%"), 1.0f), - dy + gradientHeight * getCoordLength (fillXml->getStringAttribute ("cy", "50%"), 1.0f)); - - auto radius = getCoordLength (fillXml->getStringAttribute ("r", "50%"), gradientWidth); - gradient.point2 = gradient.point1 + Point (radius, 0.0f); - - //xxx (the fx, fy focal point isn't handled properly here..) - } - else - { - if (userSpace) - { - gradient.point1.setXY (dx + getCoordLength (fillXml->getStringAttribute ("x1", "0%"), gradientWidth), - dy + getCoordLength (fillXml->getStringAttribute ("y1", "0%"), gradientHeight)); - - gradient.point2.setXY (dx + getCoordLength (fillXml->getStringAttribute ("x2", "100%"), gradientWidth), - dy + getCoordLength (fillXml->getStringAttribute ("y2", "0%"), gradientHeight)); - } - else - { - gradient.point1.setXY (dx + gradientWidth * getCoordLength (fillXml->getStringAttribute ("x1", "0%"), 1.0f), - dy + gradientHeight * getCoordLength (fillXml->getStringAttribute ("y1", "0%"), 1.0f)); - - gradient.point2.setXY (dx + gradientWidth * getCoordLength (fillXml->getStringAttribute ("x2", "100%"), 1.0f), - dy + gradientHeight * getCoordLength (fillXml->getStringAttribute ("y2", "0%"), 1.0f)); - } - - if (gradient.point1 == gradient.point2) - return Colour (gradient.getColour (gradient.getNumColours() - 1)); - } - - FillType type (gradient); - - auto gradientTransform = parseTransform (fillXml->getStringAttribute ("gradientTransform")) - .followedBy (transform); - - if (gradient.isRadial) - { - type.transform = gradientTransform; - } - else - { - // Transform the perpendicular vector into the new coordinate space for the gradient. - // This vector is now the slope of the linear gradient as it should appear in the new coord space - auto perpendicular = Point (gradient.point2.y - gradient.point1.y, - gradient.point1.x - gradient.point2.x) - .transformedBy (gradientTransform.withAbsoluteTranslation (0, 0)); - - auto newGradPoint1 = gradient.point1.transformedBy (gradientTransform); - auto newGradPoint2 = gradient.point2.transformedBy (gradientTransform); - - // Project the transformed gradient vector onto the transformed slope of the linear - // gradient as it should appear in the new coordinate space - const float scale = perpendicular.getDotProduct (newGradPoint2 - newGradPoint1) - / perpendicular.getDotProduct (perpendicular); - - type.gradient->point1 = newGradPoint1; - type.gradient->point2 = newGradPoint2 - perpendicular * scale; - } - - return type; - } - - FillType getPathFillType (const Path& path, - const XmlPath& xml, - StringRef fillAttribute, - const String& fillOpacity, - const String& overallOpacity, - const Colour defaultColour) const - { - float opacity = 1.0f; - - if (overallOpacity.isNotEmpty()) - opacity = jlimit (0.0f, 1.0f, overallOpacity.getFloatValue()); - - if (fillOpacity.isNotEmpty()) - opacity *= (jlimit (0.0f, 1.0f, fillOpacity.getFloatValue())); - - String fill (getStyleAttribute (xml, fillAttribute)); - String urlID = parseURL (fill); - - if (urlID.isNotEmpty()) - { - GetFillTypeOp op = { this, &path, opacity, FillType() }; - - if (topLevelXml.applyOperationToChildWithID (urlID, op)) - return op.fillType; - } - - if (isNone (fill)) - return Colours::transparentBlack; - - return parseColour (xml, fillAttribute, defaultColour).withMultipliedAlpha (opacity); - } - - static PathStrokeType::JointStyle getJointStyle (const String& join) noexcept - { - if (join.equalsIgnoreCase ("round")) return PathStrokeType::curved; - if (join.equalsIgnoreCase ("bevel")) return PathStrokeType::beveled; - - return PathStrokeType::mitered; - } - - static PathStrokeType::EndCapStyle getEndCapStyle (const String& cap) noexcept - { - if (cap.equalsIgnoreCase ("round")) return PathStrokeType::rounded; - if (cap.equalsIgnoreCase ("square")) return PathStrokeType::square; - - return PathStrokeType::butt; - } - - float getStrokeWidth (const String& strokeWidth) const noexcept - { - return transform.getScaleFactor() * getCoordLength (strokeWidth, viewBoxW); - } - - PathStrokeType getStrokeFor (const XmlPath& xml) const - { - return PathStrokeType (getStrokeWidth (getStyleAttribute (xml, "stroke-width", "1")), - getJointStyle (getStyleAttribute (xml, "stroke-linejoin")), - getEndCapStyle (getStyleAttribute (xml, "stroke-linecap"))); - } - - //============================================================================== - - Drawable* useText (const XmlPath& xml) const - { - auto translation = AffineTransform::translation ((float) xml->getDoubleAttribute ("x", 0.0), - (float) xml->getDoubleAttribute ("y", 0.0)); - - UseTextOp op = { this, &translation, nullptr }; - - auto linkedID = getLinkedID (xml); - - if (linkedID.isNotEmpty()) - topLevelXml.applyOperationToChildWithID (linkedID, op); - - return op.target; - } - - Drawable* parseText (const XmlPath& xml, bool shouldParseTransform, - AffineTransform* additonalTransform = nullptr) const - { - if (shouldParseTransform && xml->hasAttribute ("transform")) - { - SVGState newState (*this); - newState.addTransform (xml); - - return newState.parseText (xml, false, additonalTransform); - } - - if (xml->hasTagName ("use")) - return useText (xml); - - if (! xml->hasTagName ("text")) - return nullptr; - - Array xCoords, yCoords, dxCoords, dyCoords; - - getCoordList (xCoords, getInheritedAttribute (xml, "x"), true, true); - getCoordList (yCoords, getInheritedAttribute (xml, "y"), true, false); - getCoordList (dxCoords, getInheritedAttribute (xml, "dx"), true, true); - getCoordList (dyCoords, getInheritedAttribute (xml, "dy"), true, false); - - auto font = getFont (xml); - auto anchorStr = getStyleAttribute (xml, "text-anchor"); - - auto dc = new DrawableComposite(); - setCommonAttributes (*dc, xml); - - forEachXmlChildElement (*xml, e) - { - if (e->isTextElement()) - { - auto text = e->getText().trim(); - - auto dt = new DrawableText(); - dc->addAndMakeVisible (dt); - - dt->setText (text); - dt->setFont (font, true); - - if (additonalTransform != nullptr) - dt->setTransform (transform.followedBy (*additonalTransform)); - else - dt->setTransform (transform); - - dt->setColour (parseColour (xml, "fill", Colours::black) - .withMultipliedAlpha (getStyleAttribute (xml, "fill-opacity", "1").getFloatValue())); - - Rectangle bounds (xCoords[0], yCoords[0] - font.getAscent(), - font.getStringWidthFloat (text), font.getHeight()); - - if (anchorStr == "middle") bounds.setX (bounds.getX() - bounds.getWidth() / 2.0f); - else if (anchorStr == "end") bounds.setX (bounds.getX() - bounds.getWidth()); - - dt->setBoundingBox (bounds); - } - else if (e->hasTagNameIgnoringNamespace ("tspan")) - { - dc->addAndMakeVisible (parseText (xml.getChild (e), true)); - } - } - - return dc; - } - - Font getFont (const XmlPath& xml) const - { - Font f; - auto family = getStyleAttribute (xml, "font-family").unquoted(); - - if (family.isNotEmpty()) - f.setTypefaceName (family); - - if (getStyleAttribute (xml, "font-style").containsIgnoreCase ("italic")) - f.setItalic (true); - - if (getStyleAttribute (xml, "font-weight").containsIgnoreCase ("bold")) - f.setBold (true); - - return f.withPointHeight (getCoordLength (getStyleAttribute (xml, "font-size", "15"), 1.0f)); - } - - //============================================================================== - Drawable* useImage (const XmlPath& xml) const - { - auto translation = AffineTransform::translation ((float) xml->getDoubleAttribute ("x", 0.0), - (float) xml->getDoubleAttribute ("y", 0.0)); - - UseImageOp op = { this, &translation, nullptr }; - - auto linkedID = getLinkedID (xml); - - if (linkedID.isNotEmpty()) - topLevelXml.applyOperationToChildWithID (linkedID, op); - - return op.target; - } - - Drawable* parseImage (const XmlPath& xml, bool shouldParseTransform, - AffineTransform* additionalTransform = nullptr) const - { - if (shouldParseTransform && xml->hasAttribute ("transform")) - { - SVGState newState (*this); - newState.addTransform (xml); - - return newState.parseImage (xml, false, additionalTransform); - } - - if (xml->hasTagName ("use")) - return useImage (xml); - - if (! xml->hasTagName ("image")) - return nullptr; - - auto link = xml->getStringAttribute ("xlink:href"); - - ScopedPointer inputStream; - MemoryOutputStream imageStream; - - if (link.startsWith ("data:")) - { - const auto indexOfComma = link.indexOf (","); - auto format = link.substring (5, indexOfComma).trim(); - - const auto indexOfSemi = format.indexOf (";"); - - if (format.substring (indexOfSemi + 1).trim().equalsIgnoreCase ("base64")) - { - auto mime = format.substring (0, indexOfSemi).trim(); - - if (mime.equalsIgnoreCase ("image/png") || mime.equalsIgnoreCase ("image/jpeg")) - { - const String base64text = link.substring (indexOfComma + 1).removeCharacters ("\t\n\r "); - - if (Base64::convertFromBase64 (imageStream, base64text)) - inputStream = new MemoryInputStream (imageStream.getData(), imageStream.getDataSize(), false); - } - } - } - else - { - auto linkedFile = originalFile.getParentDirectory().getChildFile (link); - - if (linkedFile.existsAsFile()) - inputStream = linkedFile.createInputStream(); - } - - if (inputStream != nullptr) - { - auto image = ImageFileFormat::loadFrom (*inputStream); - - if (image.isValid()) - { - auto* di = new DrawableImage(); - - setCommonAttributes (*di, xml); - di->setImage (image); - - if (additionalTransform != nullptr) - di->setTransform (transform.followedBy (*additionalTransform)); - else - di->setTransform (transform); - - return di; - } - } - - return nullptr; - } - - //============================================================================== - void addTransform (const XmlPath& xml) - { - transform = parseTransform (xml->getStringAttribute ("transform")) - .followedBy (transform); - } - - //============================================================================== - bool parseCoord (String::CharPointerType& s, float& value, const bool allowUnits, const bool isX) const - { - String number; - - if (! parseNextNumber (s, number, allowUnits)) - { - value = 0; - return false; - } - - value = getCoordLength (number, isX ? viewBoxW : viewBoxH); - return true; - } - - bool parseCoords (String::CharPointerType& s, Point& p, const bool allowUnits) const - { - return parseCoord (s, p.x, allowUnits, true) - && parseCoord (s, p.y, allowUnits, false); - } - - bool parseCoordsOrSkip (String::CharPointerType& s, Point& p, const bool allowUnits) const - { - if (parseCoords (s, p, allowUnits)) - return true; - - if (! s.isEmpty()) ++s; - return false; - } - - float getCoordLength (const String& s, const float sizeForProportions) const noexcept - { - float n = s.getFloatValue(); - const int len = s.length(); - - if (len > 2) - { - const float dpi = 96.0f; - - const juce_wchar n1 = s [len - 2]; - const juce_wchar n2 = s [len - 1]; - - if (n1 == 'i' && n2 == 'n') n *= dpi; - else if (n1 == 'm' && n2 == 'm') n *= dpi / 25.4f; - else if (n1 == 'c' && n2 == 'm') n *= dpi / 2.54f; - else if (n1 == 'p' && n2 == 'c') n *= 15.0f; - else if (n2 == '%') n *= 0.01f * sizeForProportions; - } - - return n; - } - - float getCoordLength (const XmlPath& xml, const char* attName, const float sizeForProportions) const noexcept - { - return getCoordLength (xml->getStringAttribute (attName), sizeForProportions); - } - - void getCoordList (Array& coords, const String& list, bool allowUnits, const bool isX) const - { - auto text = list.getCharPointer(); - float value; - - while (parseCoord (text, value, allowUnits, isX)) - coords.add (value); - } - - //============================================================================== - void parseCSSStyle (const XmlPath& xml) - { - cssStyleText = xml->getAllSubText() + "\n" + cssStyleText; - } - - void parseDefs (const XmlPath& xml) - { - if (auto* style = xml->getChildByName ("style")) - parseCSSStyle (xml.getChild (style)); - } - - static String::CharPointerType findStyleItem (String::CharPointerType source, String::CharPointerType name) - { - auto nameLength = (int) name.length(); - - while (! source.isEmpty()) - { - if (source.getAndAdvance() == '.' - && CharacterFunctions::compareIgnoreCaseUpTo (source, name, nameLength) == 0) - { - auto endOfName = (source + nameLength).findEndOfWhitespace(); - - if (*endOfName == '{') - return endOfName; - - if (*endOfName == ',') - return CharacterFunctions::find (endOfName, (juce_wchar) '{'); - } - } - - return source; - } - - String getStyleAttribute (const XmlPath& xml, StringRef attributeName, const String& defaultValue = String()) const - { - if (xml->hasAttribute (attributeName)) - return xml->getStringAttribute (attributeName, defaultValue); - - auto styleAtt = xml->getStringAttribute ("style"); - - if (styleAtt.isNotEmpty()) - { - auto value = getAttributeFromStyleList (styleAtt, attributeName, {}); - - if (value.isNotEmpty()) - return value; - } - else if (xml->hasAttribute ("class")) - { - for (auto i = cssStyleText.getCharPointer();;) - { - auto openBrace = findStyleItem (i, xml->getStringAttribute ("class").getCharPointer()); - - if (openBrace.isEmpty()) - break; - - auto closeBrace = CharacterFunctions::find (openBrace, (juce_wchar) '}'); - - if (closeBrace.isEmpty()) - break; - - auto value = getAttributeFromStyleList (String (openBrace + 1, closeBrace), - attributeName, defaultValue); - if (value.isNotEmpty()) - return value; - - i = closeBrace + 1; - } - } - - if (xml.parent != nullptr) - return getStyleAttribute (*xml.parent, attributeName, defaultValue); - - return defaultValue; - } - - String getInheritedAttribute (const XmlPath& xml, StringRef attributeName) const - { - if (xml->hasAttribute (attributeName)) - return xml->getStringAttribute (attributeName); - - if (xml.parent != nullptr) - return getInheritedAttribute (*xml.parent, attributeName); - - return {}; - } - - static int parsePlacementFlags (const String& align) noexcept - { - if (align.isEmpty()) - return 0; - - if (isNone (align)) - return RectanglePlacement::stretchToFit; - - return (align.containsIgnoreCase ("slice") ? RectanglePlacement::fillDestination : 0) - | (align.containsIgnoreCase ("xMin") ? RectanglePlacement::xLeft - : (align.containsIgnoreCase ("xMax") ? RectanglePlacement::xRight - : RectanglePlacement::xMid)) - | (align.containsIgnoreCase ("yMin") ? RectanglePlacement::yTop - : (align.containsIgnoreCase ("yMax") ? RectanglePlacement::yBottom - : RectanglePlacement::yMid)); - } - - //============================================================================== - static bool isIdentifierChar (const juce_wchar c) - { - return CharacterFunctions::isLetter (c) || c == '-'; - } - - static String getAttributeFromStyleList (const String& list, StringRef attributeName, const String& defaultValue) - { - int i = 0; - - for (;;) - { - i = list.indexOf (i, attributeName); - - if (i < 0) - break; - - if ((i == 0 || (i > 0 && ! isIdentifierChar (list [i - 1]))) - && ! isIdentifierChar (list [i + attributeName.length()])) - { - i = list.indexOfChar (i, ':'); - - if (i < 0) - break; - - int end = list.indexOfChar (i, ';'); - - if (end < 0) - end = 0x7ffff; - - return list.substring (i + 1, end).trim(); - } - - ++i; - } - - return defaultValue; - } - - //============================================================================== - static bool isStartOfNumber (juce_wchar c) noexcept - { - return CharacterFunctions::isDigit (c) || c == '-' || c == '+'; - } - - static bool parseNextNumber (String::CharPointerType& text, String& value, const bool allowUnits) - { - String::CharPointerType s (text); - - while (s.isWhitespace() || *s == ',') - ++s; - - auto start = s; - - if (isStartOfNumber (*s)) - ++s; - - while (s.isDigit()) - ++s; - - if (*s == '.') - { - ++s; - - while (s.isDigit()) - ++s; - } - - if ((*s == 'e' || *s == 'E') && isStartOfNumber (s[1])) - { - s += 2; - - while (s.isDigit()) - ++s; - } - - if (allowUnits) - while (s.isLetter()) - ++s; - - if (s == start) - { - text = s; - return false; - } - - value = String (start, s); - - while (s.isWhitespace() || *s == ',') - ++s; - - text = s; - return true; - } - - //============================================================================== - Colour parseColour (const XmlPath& xml, StringRef attributeName, const Colour defaultColour) const - { - auto text = getStyleAttribute (xml, attributeName); - - if (text.startsWithChar ('#')) - { - uint32 hex[6] = { 0 }; - int numChars = 0; - auto s = text.getCharPointer(); - - while (numChars < 6) - { - auto hexValue = CharacterFunctions::getHexDigitValue (*++s); - - if (hexValue >= 0) - hex [numChars++] = (uint32) hexValue; - else - break; - } - - if (numChars <= 3) - return Colour ((uint8) (hex[0] * 0x11), - (uint8) (hex[1] * 0x11), - (uint8) (hex[2] * 0x11)); - - return Colour ((uint8) ((hex[0] << 4) + hex[1]), - (uint8) ((hex[2] << 4) + hex[3]), - (uint8) ((hex[4] << 4) + hex[5])); - } - - if (text.startsWith ("rgb")) - { - auto openBracket = text.indexOfChar ('('); - auto closeBracket = text.indexOfChar (openBracket, ')'); - - if (openBracket >= 3 && closeBracket > openBracket) - { - StringArray tokens; - tokens.addTokens (text.substring (openBracket + 1, closeBracket), ",", ""); - tokens.trim(); - tokens.removeEmptyStrings(); - - if (tokens[0].containsChar ('%')) - return Colour ((uint8) roundToInt (2.55 * tokens[0].getDoubleValue()), - (uint8) roundToInt (2.55 * tokens[1].getDoubleValue()), - (uint8) roundToInt (2.55 * tokens[2].getDoubleValue())); - - return Colour ((uint8) tokens[0].getIntValue(), - (uint8) tokens[1].getIntValue(), - (uint8) tokens[2].getIntValue()); - } - } - - if (text == "inherit") - { - for (const XmlPath* p = xml.parent; p != nullptr; p = p->parent) - if (getStyleAttribute (*p, attributeName).isNotEmpty()) - return parseColour (*p, attributeName, defaultColour); - } - - return Colours::findColourForName (text, defaultColour); - } - - static AffineTransform parseTransform (String t) - { - AffineTransform result; - - while (t.isNotEmpty()) - { - StringArray tokens; - tokens.addTokens (t.fromFirstOccurrenceOf ("(", false, false) - .upToFirstOccurrenceOf (")", false, false), - ", ", ""); - - tokens.removeEmptyStrings (true); - - float numbers[6]; - - for (int i = 0; i < numElementsInArray (numbers); ++i) - numbers[i] = tokens[i].getFloatValue(); - - AffineTransform trans; - - if (t.startsWithIgnoreCase ("matrix")) - { - trans = AffineTransform (numbers[0], numbers[2], numbers[4], - numbers[1], numbers[3], numbers[5]); - } - else if (t.startsWithIgnoreCase ("translate")) - { - trans = AffineTransform::translation (numbers[0], numbers[1]); - } - else if (t.startsWithIgnoreCase ("scale")) - { - trans = AffineTransform::scale (numbers[0], numbers[tokens.size() > 1 ? 1 : 0]); - } - else if (t.startsWithIgnoreCase ("rotate")) - { - trans = AffineTransform::rotation (degreesToRadians (numbers[0]), numbers[1], numbers[2]); - } - else if (t.startsWithIgnoreCase ("skewX")) - { - trans = AffineTransform::shear (std::tan (degreesToRadians (numbers[0])), 0.0f); - } - else if (t.startsWithIgnoreCase ("skewY")) - { - trans = AffineTransform::shear (0.0f, std::tan (degreesToRadians (numbers[0]))); - } - - result = trans.followedBy (result); - t = t.fromFirstOccurrenceOf (")", false, false).trimStart(); - } - - return result; - } - - static void endpointToCentreParameters (const double x1, const double y1, - const double x2, const double y2, - const double angle, - const bool largeArc, const bool sweep, - double& rx, double& ry, - double& centreX, double& centreY, - double& startAngle, double& deltaAngle) noexcept - { - const double midX = (x1 - x2) * 0.5; - const double midY = (y1 - y2) * 0.5; - - const double cosAngle = std::cos (angle); - const double sinAngle = std::sin (angle); - const double xp = cosAngle * midX + sinAngle * midY; - const double yp = cosAngle * midY - sinAngle * midX; - const double xp2 = xp * xp; - const double yp2 = yp * yp; - - double rx2 = rx * rx; - double ry2 = ry * ry; - - const double s = (xp2 / rx2) + (yp2 / ry2); - double c; - - if (s <= 1.0) - { - c = std::sqrt (jmax (0.0, ((rx2 * ry2) - (rx2 * yp2) - (ry2 * xp2)) - / (( rx2 * yp2) + (ry2 * xp2)))); - - if (largeArc == sweep) - c = -c; - } - else - { - const double s2 = std::sqrt (s); - rx *= s2; - ry *= s2; - c = 0; - } - - const double cpx = ((rx * yp) / ry) * c; - const double cpy = ((-ry * xp) / rx) * c; - - centreX = ((x1 + x2) * 0.5) + (cosAngle * cpx) - (sinAngle * cpy); - centreY = ((y1 + y2) * 0.5) + (sinAngle * cpx) + (cosAngle * cpy); - - const double ux = (xp - cpx) / rx; - const double uy = (yp - cpy) / ry; - const double vx = (-xp - cpx) / rx; - const double vy = (-yp - cpy) / ry; - - const double length = juce_hypot (ux, uy); - - startAngle = acos (jlimit (-1.0, 1.0, ux / length)); - - if (uy < 0) - startAngle = -startAngle; - - startAngle += double_Pi * 0.5; - - deltaAngle = acos (jlimit (-1.0, 1.0, ((ux * vx) + (uy * vy)) - / (length * juce_hypot (vx, vy)))); - - if ((ux * vy) - (uy * vx) < 0) - deltaAngle = -deltaAngle; - - if (sweep) - { - if (deltaAngle < 0) - deltaAngle += double_Pi * 2.0; - } - else - { - if (deltaAngle > 0) - deltaAngle -= double_Pi * 2.0; - } - - deltaAngle = fmod (deltaAngle, double_Pi * 2.0); - } - - SVGState& operator= (const SVGState&) JUCE_DELETED_FUNCTION; -}; - - -//============================================================================== -Drawable* Drawable::createFromSVG (const XmlElement& svgDocument) -{ - if (! svgDocument.hasTagNameIgnoringNamespace ("svg")) - return nullptr; - - SVGState state (&svgDocument); - return state.parseSVGElement (SVGState::XmlPath (&svgDocument, nullptr)); -} - -Drawable* Drawable::createFromSVGFile (const File& svgFile) -{ - XmlDocument doc (svgFile); - ScopedPointer outer (doc.getDocumentElement (true)); - - if (outer != nullptr && outer->hasTagName ("svg")) - { - ScopedPointer svgDocument (doc.getDocumentElement()); - - if (svgDocument != nullptr) - { - SVGState state (svgDocument, svgFile); - return state.parseSVGElement (SVGState::XmlPath (svgDocument, nullptr)); - } - } - - return nullptr; -} - -Path Drawable::parseSVGPath (const String& svgPath) -{ - SVGState state (nullptr); - Path p; - state.parsePathString (p, svgPath); - return p; -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsDisplayComponent.cpp b/source/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsDisplayComponent.cpp deleted file mode 100644 index b83d35625..000000000 --- a/source/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsDisplayComponent.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -DirectoryContentsDisplayComponent::DirectoryContentsDisplayComponent (DirectoryContentsList& l) - : directoryContentsList (l) -{ -} - -DirectoryContentsDisplayComponent::~DirectoryContentsDisplayComponent() -{ -} - -//============================================================================== -FileBrowserListener::~FileBrowserListener() -{ -} - -void DirectoryContentsDisplayComponent::addListener (FileBrowserListener* l) { listeners.add (l); } -void DirectoryContentsDisplayComponent::removeListener (FileBrowserListener* l) { listeners.remove (l); } - -void DirectoryContentsDisplayComponent::sendSelectionChangeMessage() -{ - Component::BailOutChecker checker (dynamic_cast (this)); - listeners.callChecked (checker, &FileBrowserListener::selectionChanged); -} - -void DirectoryContentsDisplayComponent::sendMouseClickMessage (const File& file, const MouseEvent& e) -{ - if (directoryContentsList.getDirectory().exists()) - { - Component::BailOutChecker checker (dynamic_cast (this)); - listeners.callChecked (checker, &FileBrowserListener::fileClicked, file, e); - } -} - -void DirectoryContentsDisplayComponent::sendDoubleClickMessage (const File& file) -{ - if (directoryContentsList.getDirectory().exists()) - { - Component::BailOutChecker checker (dynamic_cast (this)); - listeners.callChecked (checker, &FileBrowserListener::fileDoubleClicked, file); - } -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsDisplayComponent.h b/source/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsDisplayComponent.h deleted file mode 100644 index d01427f68..000000000 --- a/source/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsDisplayComponent.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A base class for components that display a list of the files in a directory. - - @see DirectoryContentsList -*/ -class JUCE_API DirectoryContentsDisplayComponent -{ -public: - //============================================================================== - /** Creates a DirectoryContentsDisplayComponent for a given list of files. */ - DirectoryContentsDisplayComponent (DirectoryContentsList& listToShow); - - /** Destructor. */ - virtual ~DirectoryContentsDisplayComponent(); - - //============================================================================== - /** The list that this component is displaying */ - DirectoryContentsList& directoryContentsList; - - //============================================================================== - /** Returns the number of files the user has got selected. - @see getSelectedFile - */ - virtual int getNumSelectedFiles() const = 0; - - /** Returns one of the files that the user has currently selected. - The index should be in the range 0 to (getNumSelectedFiles() - 1). - @see getNumSelectedFiles - */ - virtual File getSelectedFile (int index) const = 0; - - /** Deselects any selected files. */ - virtual void deselectAllFiles() = 0; - - /** Scrolls this view to the top. */ - virtual void scrollToTop() = 0; - - /** If the specified file is in the list, it will become the only selected item - (and if the file isn't in the list, all other items will be deselected). */ - virtual void setSelectedFile (const File&) = 0; - - //============================================================================== - /** Adds a listener to be told when files are selected or clicked. - @see removeListener - */ - void addListener (FileBrowserListener* listener); - - /** Removes a listener. - @see addListener - */ - void removeListener (FileBrowserListener* listener); - - - //============================================================================== - /** A set of colour IDs to use to change the colour of various aspects of the list. - - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. - - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour - */ - enum ColourIds - { - highlightColourId = 0x1000540, /**< The colour to use to fill a highlighted row of the list. */ - textColourId = 0x1000541, /**< The colour for the text. */ - }; - - //============================================================================== - /** @internal */ - void sendSelectionChangeMessage(); - /** @internal */ - void sendDoubleClickMessage (const File&); - /** @internal */ - void sendMouseClickMessage (const File&, const MouseEvent&); - -protected: - //============================================================================== - ListenerList listeners; - -private: - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectoryContentsDisplayComponent) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsList.cpp b/source/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsList.cpp deleted file mode 100644 index 7db6e282c..000000000 --- a/source/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsList.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -DirectoryContentsList::DirectoryContentsList (const FileFilter* f, TimeSliceThread& t) - : fileFilter (f), thread (t), - fileTypeFlags (File::ignoreHiddenFiles | File::findFiles), - shouldStop (true) -{ -} - -DirectoryContentsList::~DirectoryContentsList() -{ - stopSearching(); -} - -void DirectoryContentsList::setIgnoresHiddenFiles (const bool shouldIgnoreHiddenFiles) -{ - setTypeFlags (shouldIgnoreHiddenFiles ? (fileTypeFlags | File::ignoreHiddenFiles) - : (fileTypeFlags & ~File::ignoreHiddenFiles)); -} - -bool DirectoryContentsList::ignoresHiddenFiles() const -{ - return (fileTypeFlags & File::ignoreHiddenFiles) != 0; -} - -//============================================================================== -void DirectoryContentsList::setDirectory (const File& directory, - const bool includeDirectories, - const bool includeFiles) -{ - jassert (includeDirectories || includeFiles); // you have to speciify at least one of these! - - if (directory != root) - { - clear(); - root = directory; - changed(); - - // (this forces a refresh when setTypeFlags() is called, rather than triggering two refreshes) - fileTypeFlags &= ~(File::findDirectories | File::findFiles); - } - - int newFlags = fileTypeFlags; - if (includeDirectories) newFlags |= File::findDirectories; else newFlags &= ~File::findDirectories; - if (includeFiles) newFlags |= File::findFiles; else newFlags &= ~File::findFiles; - - setTypeFlags (newFlags); -} - -void DirectoryContentsList::setTypeFlags (const int newFlags) -{ - if (fileTypeFlags != newFlags) - { - fileTypeFlags = newFlags; - refresh(); - } -} - -void DirectoryContentsList::stopSearching() -{ - shouldStop = true; - thread.removeTimeSliceClient (this); - fileFindHandle = nullptr; -} - -void DirectoryContentsList::clear() -{ - stopSearching(); - - if (files.size() > 0) - { - files.clear(); - changed(); - } -} - -void DirectoryContentsList::refresh() -{ - clear(); - - if (root.isDirectory()) - { - fileFindHandle = new DirectoryIterator (root, false, "*", fileTypeFlags); - shouldStop = false; - thread.addTimeSliceClient (this); - } -} - -void DirectoryContentsList::setFileFilter (const FileFilter* newFileFilter) -{ - const ScopedLock sl (fileListLock); - fileFilter = newFileFilter; -} - -//============================================================================== -bool DirectoryContentsList::getFileInfo (const int index, FileInfo& result) const -{ - const ScopedLock sl (fileListLock); - - if (auto* info = files [index]) - { - result = *info; - return true; - } - - return false; -} - -File DirectoryContentsList::getFile (const int index) const -{ - const ScopedLock sl (fileListLock); - - if (auto* info = files [index]) - return root.getChildFile (info->filename); - - return {}; -} - -bool DirectoryContentsList::contains (const File& targetFile) const -{ - const ScopedLock sl (fileListLock); - - for (int i = files.size(); --i >= 0;) - if (root.getChildFile (files.getUnchecked(i)->filename) == targetFile) - return true; - - return false; -} - -bool DirectoryContentsList::isStillLoading() const -{ - return fileFindHandle != nullptr; -} - -void DirectoryContentsList::changed() -{ - sendChangeMessage(); -} - -//============================================================================== -int DirectoryContentsList::useTimeSlice() -{ - const uint32 startTime = Time::getApproximateMillisecondCounter(); - bool hasChanged = false; - - for (int i = 100; --i >= 0;) - { - if (! checkNextFile (hasChanged)) - { - if (hasChanged) - changed(); - - return 500; - } - - if (shouldStop || (Time::getApproximateMillisecondCounter() > startTime + 150)) - break; - } - - if (hasChanged) - changed(); - - return 0; -} - -bool DirectoryContentsList::checkNextFile (bool& hasChanged) -{ - if (fileFindHandle != nullptr) - { - bool fileFoundIsDir, isHidden, isReadOnly; - int64 fileSize; - Time modTime, creationTime; - - if (fileFindHandle->next (&fileFoundIsDir, &isHidden, &fileSize, - &modTime, &creationTime, &isReadOnly)) - { - if (addFile (fileFindHandle->getFile(), fileFoundIsDir, - fileSize, modTime, creationTime, isReadOnly)) - { - hasChanged = true; - } - - return true; - } - - fileFindHandle = nullptr; - } - - return false; -} - -struct FileInfoComparator -{ - static int compareElements (const DirectoryContentsList::FileInfo* const first, - const DirectoryContentsList::FileInfo* const second) - { - #if JUCE_WINDOWS - if (first->isDirectory != second->isDirectory) - return first->isDirectory ? -1 : 1; - #endif - - return first->filename.compareNatural (second->filename); - } -}; - -bool DirectoryContentsList::addFile (const File& file, const bool isDir, - const int64 fileSize, - Time modTime, Time creationTime, - const bool isReadOnly) -{ - const ScopedLock sl (fileListLock); - - if (fileFilter == nullptr - || ((! isDir) && fileFilter->isFileSuitable (file)) - || (isDir && fileFilter->isDirectorySuitable (file))) - { - ScopedPointer info (new FileInfo()); - - info->filename = file.getFileName(); - info->fileSize = fileSize; - info->modificationTime = modTime; - info->creationTime = creationTime; - info->isDirectory = isDir; - info->isReadOnly = isReadOnly; - - for (int i = files.size(); --i >= 0;) - if (files.getUnchecked(i)->filename == info->filename) - return false; - - FileInfoComparator comp; - files.addSorted (comp, info.release()); - return true; - } - - return false; -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsList.h b/source/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsList.h deleted file mode 100644 index 50877c395..000000000 --- a/source/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsList.h +++ /dev/null @@ -1,223 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A class to asynchronously scan for details about the files in a directory. - - This keeps a list of files and some information about them, using a background - thread to scan for more files. As files are found, it broadcasts change messages - to tell any listeners. - - @see FileListComponent, FileBrowserComponent -*/ -class JUCE_API DirectoryContentsList : public ChangeBroadcaster, - private TimeSliceClient -{ -public: - //============================================================================== - /** Creates a directory list. - - To set the directory it should point to, use setDirectory(), which will - also start it scanning for files on the background thread. - - When the background thread finds and adds new files to this list, the - ChangeBroadcaster class will send a change message, so you can register - listeners and update them when the list changes. - - @param fileFilter an optional filter to select which files are - included in the list. If this is nullptr, then all files - and directories are included. Make sure that the filter - doesn't get deleted during the lifetime of this object - @param threadToUse a thread object that this list can use - to scan for files as a background task. Make sure - that the thread you give it has been started, or you - won't get any files! - */ - DirectoryContentsList (const FileFilter* fileFilter, - TimeSliceThread& threadToUse); - - /** Destructor. */ - ~DirectoryContentsList(); - - - //============================================================================== - /** Returns the directory that's currently being used. */ - const File& getDirectory() const noexcept { return root; } - - /** Sets the directory to look in for files. - - If the directory that's passed in is different to the current one, this will - also start the background thread scanning it for files. - */ - void setDirectory (const File& directory, - bool includeDirectories, - bool includeFiles); - - /** Returns true if this list contains directories. - @see setDirectory - */ - bool isFindingDirectories() const noexcept { return (fileTypeFlags & File::findDirectories) != 0; } - - /** Returns true if this list contains files. - @see setDirectory - */ - bool isFindingFiles() const noexcept { return (fileTypeFlags & File::findFiles) != 0; } - - /** Clears the list, and stops the thread scanning for files. */ - void clear(); - - /** Clears the list and restarts scanning the directory for files. */ - void refresh(); - - /** True if the background thread hasn't yet finished scanning for files. */ - bool isStillLoading() const; - - /** Tells the list whether or not to ignore hidden files. - By default these are ignored. - */ - void setIgnoresHiddenFiles (bool shouldIgnoreHiddenFiles); - - /** Returns true if hidden files are ignored. - @see setIgnoresHiddenFiles - */ - bool ignoresHiddenFiles() const; - - /** Replaces the current FileFilter. - This can be nullptr to have no filter. The DirectoryContentList does not take - ownership of this object - it just keeps a pointer to it, so you must manage its - lifetime. - Note that this only replaces the filter, it doesn't refresh the list - you'll - probably want to call refresh() after calling this. - */ - void setFileFilter (const FileFilter* newFileFilter); - - //============================================================================== - /** Contains cached information about one of the files in a DirectoryContentsList. - */ - struct FileInfo - { - //============================================================================== - /** The filename. - - This isn't a full pathname, it's just the last part of the path, same as you'd - get from File::getFileName(). - - To get the full pathname, use DirectoryContentsList::getDirectory().getChildFile (filename). - */ - String filename; - - /** File size in bytes. */ - int64 fileSize; - - /** File modification time. - As supplied by File::getLastModificationTime(). - */ - Time modificationTime; - - /** File creation time. - As supplied by File::getCreationTime(). - */ - Time creationTime; - - /** True if the file is a directory. */ - bool isDirectory; - - /** True if the file is read-only. */ - bool isReadOnly; - }; - - //============================================================================== - /** Returns the number of files currently available in the list. - - The info about one of these files can be retrieved with getFileInfo() or getFile(). - - Obviously as the background thread runs and scans the directory for files, this - number will change. - - @see getFileInfo, getFile - */ - int getNumFiles() const noexcept { return files.size(); } - - /** Returns the cached information about one of the files in the list. - - If the index is in-range, this will return true and will copy the file's details - to the structure that is passed-in. - - If it returns false, then the index wasn't in range, and the structure won't - be affected. - - @see getNumFiles, getFile - */ - bool getFileInfo (int index, FileInfo& resultInfo) const; - - /** Returns one of the files in the list. - - @param index should be less than getNumFiles(). If this is out-of-range, the - return value will be a default File() object - @see getNumFiles, getFileInfo - */ - File getFile (int index) const; - - /** Returns the file filter being used. - The filter is specified in the constructor. - */ - const FileFilter* getFilter() const noexcept { return fileFilter; } - - /** Returns true if the list contains the specified file. */ - bool contains (const File&) const; - - //============================================================================== - /** @internal */ - TimeSliceThread& getTimeSliceThread() const noexcept { return thread; } - -private: - File root; - const FileFilter* fileFilter; - TimeSliceThread& thread; - int fileTypeFlags; - - CriticalSection fileListLock; - OwnedArray files; - - ScopedPointer fileFindHandle; - bool volatile shouldStop; - - int useTimeSlice() override; - void stopSearching(); - void changed(); - bool checkNextFile (bool& hasChanged); - bool addFile (const File&, bool isDir, int64 fileSize, Time modTime, - Time creationTime, bool isReadOnly); - void setTypeFlags (int); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectoryContentsList) -}; - -} // namespace juce diff --git a/source/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.cpp b/source/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.cpp deleted file mode 100644 index eb367095b..000000000 --- a/source/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.cpp +++ /dev/null @@ -1,613 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -FileBrowserComponent::FileBrowserComponent (int flags_, - const File& initialFileOrDirectory, - const FileFilter* fileFilter_, - FilePreviewComponent* previewComp_) - : FileFilter (String()), - fileFilter (fileFilter_), - flags (flags_), - previewComp (previewComp_), - currentPathBox ("path"), - fileLabel ("f", TRANS ("file:")), - thread ("Juce FileBrowser"), - wasProcessActive (true) -{ - // You need to specify one or other of the open/save flags.. - jassert ((flags & (saveMode | openMode)) != 0); - jassert ((flags & (saveMode | openMode)) != (saveMode | openMode)); - - // You need to specify at least one of these flags.. - jassert ((flags & (canSelectFiles | canSelectDirectories)) != 0); - - String filename; - - if (initialFileOrDirectory == File()) - { - currentRoot = File::getCurrentWorkingDirectory(); - } - else if (initialFileOrDirectory.isDirectory()) - { - currentRoot = initialFileOrDirectory; - } - else - { - chosenFiles.add (initialFileOrDirectory); - currentRoot = initialFileOrDirectory.getParentDirectory(); - filename = initialFileOrDirectory.getFileName(); - } - - fileList = new DirectoryContentsList (this, thread); - - if ((flags & useTreeView) != 0) - { - FileTreeComponent* const tree = new FileTreeComponent (*fileList); - fileListComponent = tree; - - if ((flags & canSelectMultipleItems) != 0) - tree->setMultiSelectEnabled (true); - - addAndMakeVisible (tree); - } - else - { - FileListComponent* const list = new FileListComponent (*fileList); - fileListComponent = list; - list->setOutlineThickness (1); - - if ((flags & canSelectMultipleItems) != 0) - list->setMultipleSelectionEnabled (true); - - addAndMakeVisible (list); - } - - fileListComponent->addListener (this); - - addAndMakeVisible (currentPathBox); - currentPathBox.setEditableText (true); - resetRecentPaths(); - currentPathBox.addListener (this); - - addAndMakeVisible (filenameBox); - filenameBox.setMultiLine (false); - filenameBox.setSelectAllWhenFocused (true); - filenameBox.setText (filename, false); - filenameBox.addListener (this); - filenameBox.setReadOnly ((flags & (filenameBoxIsReadOnly | canSelectMultipleItems)) != 0); - - addAndMakeVisible (fileLabel); - fileLabel.attachToComponent (&filenameBox, true); - - addAndMakeVisible (goUpButton = getLookAndFeel().createFileBrowserGoUpButton()); - goUpButton->addListener (this); - goUpButton->setTooltip (TRANS ("Go up to parent directory")); - - if (previewComp != nullptr) - addAndMakeVisible (previewComp); - - setRoot (currentRoot); - - thread.startThread (4); - - startTimer (2000); -} - -FileBrowserComponent::~FileBrowserComponent() -{ - fileListComponent = nullptr; - fileList = nullptr; - thread.stopThread (10000); -} - -//============================================================================== -void FileBrowserComponent::addListener (FileBrowserListener* const newListener) -{ - listeners.add (newListener); -} - -void FileBrowserComponent::removeListener (FileBrowserListener* const listener) -{ - listeners.remove (listener); -} - -//============================================================================== -bool FileBrowserComponent::isSaveMode() const noexcept -{ - return (flags & saveMode) != 0; -} - -int FileBrowserComponent::getNumSelectedFiles() const noexcept -{ - if (chosenFiles.size() == 0 && currentFileIsValid()) - return 1; - - return chosenFiles.size(); -} - -File FileBrowserComponent::getSelectedFile (int index) const noexcept -{ - if ((flags & canSelectDirectories) != 0 && filenameBox.getText().isEmpty()) - return currentRoot; - - if (! filenameBox.isReadOnly()) - return currentRoot.getChildFile (filenameBox.getText()); - - return chosenFiles[index]; -} - -bool FileBrowserComponent::currentFileIsValid() const -{ - const File f (getSelectedFile (0)); - - if (isSaveMode()) - return (flags & canSelectDirectories) != 0 || ! f.isDirectory(); - - return f.exists(); -} - -File FileBrowserComponent::getHighlightedFile() const noexcept -{ - return fileListComponent->getSelectedFile (0); -} - -void FileBrowserComponent::deselectAllFiles() -{ - fileListComponent->deselectAllFiles(); -} - -//============================================================================== -bool FileBrowserComponent::isFileSuitable (const File& file) const -{ - return (flags & canSelectFiles) != 0 - && (fileFilter == nullptr || fileFilter->isFileSuitable (file)); -} - -bool FileBrowserComponent::isDirectorySuitable (const File&) const -{ - return true; -} - -bool FileBrowserComponent::isFileOrDirSuitable (const File& f) const -{ - if (f.isDirectory()) - return (flags & canSelectDirectories) != 0 - && (fileFilter == nullptr || fileFilter->isDirectorySuitable (f)); - - return (flags & canSelectFiles) != 0 && f.exists() - && (fileFilter == nullptr || fileFilter->isFileSuitable (f)); -} - -//============================================================================== -const File& FileBrowserComponent::getRoot() const -{ - return currentRoot; -} - -void FileBrowserComponent::setRoot (const File& newRootDirectory) -{ - bool callListeners = false; - - if (currentRoot != newRootDirectory) - { - callListeners = true; - fileListComponent->scrollToTop(); - - String path (newRootDirectory.getFullPathName()); - - if (path.isEmpty()) - path = File::separatorString; - - StringArray rootNames, rootPaths; - getRoots (rootNames, rootPaths); - - if (! rootPaths.contains (path, true)) - { - bool alreadyListed = false; - - for (int i = currentPathBox.getNumItems(); --i >= 0;) - { - if (currentPathBox.getItemText (i).equalsIgnoreCase (path)) - { - alreadyListed = true; - break; - } - } - - if (! alreadyListed) - currentPathBox.addItem (path, currentPathBox.getNumItems() + 2); - } - } - - currentRoot = newRootDirectory; - fileList->setDirectory (currentRoot, true, true); - - if (FileTreeComponent* tree = dynamic_cast (fileListComponent.get())) - tree->refresh(); - - String currentRootName (currentRoot.getFullPathName()); - if (currentRootName.isEmpty()) - currentRootName = File::separatorString; - - currentPathBox.setText (currentRootName, dontSendNotification); - - goUpButton->setEnabled (currentRoot.getParentDirectory().isDirectory() - && currentRoot.getParentDirectory() != currentRoot); - - if (callListeners) - { - Component::BailOutChecker checker (this); - listeners.callChecked (checker, &FileBrowserListener::browserRootChanged, currentRoot); - } -} - -void FileBrowserComponent::setFileName (const String& newName) -{ - filenameBox.setText (newName, true); - - fileListComponent->setSelectedFile (currentRoot.getChildFile (newName)); -} - -void FileBrowserComponent::resetRecentPaths() -{ - currentPathBox.clear(); - - StringArray rootNames, rootPaths; - getRoots (rootNames, rootPaths); - - for (int i = 0; i < rootNames.size(); ++i) - { - if (rootNames[i].isEmpty()) - currentPathBox.addSeparator(); - else - currentPathBox.addItem (rootNames[i], i + 1); - } - - currentPathBox.addSeparator(); -} - -void FileBrowserComponent::goUp() -{ - setRoot (getRoot().getParentDirectory()); -} - -void FileBrowserComponent::refresh() -{ - fileList->refresh(); -} - -void FileBrowserComponent::setFileFilter (const FileFilter* const newFileFilter) -{ - if (fileFilter != newFileFilter) - { - fileFilter = newFileFilter; - refresh(); - } -} - -String FileBrowserComponent::getActionVerb() const -{ - return isSaveMode() ? ((flags & canSelectDirectories) != 0 ? TRANS("Choose") - : TRANS("Save")) - : TRANS("Open"); -} - -void FileBrowserComponent::setFilenameBoxLabel (const String& name) -{ - fileLabel.setText (name, dontSendNotification); -} - -FilePreviewComponent* FileBrowserComponent::getPreviewComponent() const noexcept -{ - return previewComp; -} - -DirectoryContentsDisplayComponent* FileBrowserComponent::getDisplayComponent() const noexcept -{ - return fileListComponent; -} - -//============================================================================== -void FileBrowserComponent::resized() -{ - getLookAndFeel() - .layoutFileBrowserComponent (*this, fileListComponent, previewComp, - ¤tPathBox, &filenameBox, goUpButton); -} - -//============================================================================== -void FileBrowserComponent::sendListenerChangeMessage() -{ - Component::BailOutChecker checker (this); - - if (previewComp != nullptr) - previewComp->selectedFileChanged (getSelectedFile (0)); - - // You shouldn't delete the browser when the file gets changed! - jassert (! checker.shouldBailOut()); - - listeners.callChecked (checker, &FileBrowserListener::selectionChanged); -} - -void FileBrowserComponent::selectionChanged() -{ - StringArray newFilenames; - bool resetChosenFiles = true; - - for (int i = 0; i < fileListComponent->getNumSelectedFiles(); ++i) - { - const File f (fileListComponent->getSelectedFile (i)); - - if (isFileOrDirSuitable (f)) - { - if (resetChosenFiles) - { - chosenFiles.clear(); - resetChosenFiles = false; - } - - chosenFiles.add (f); - newFilenames.add (f.getRelativePathFrom (getRoot())); - } - } - - if (newFilenames.size() > 0) - filenameBox.setText (newFilenames.joinIntoString (", "), false); - - sendListenerChangeMessage(); -} - -void FileBrowserComponent::fileClicked (const File& f, const MouseEvent& e) -{ - Component::BailOutChecker checker (this); - listeners.callChecked (checker, &FileBrowserListener::fileClicked, f, e); -} - -void FileBrowserComponent::fileDoubleClicked (const File& f) -{ - if (f.isDirectory()) - { - setRoot (f); - - if ((flags & canSelectDirectories) != 0 && (flags & doNotClearFileNameOnRootChange) == 0) - filenameBox.setText (String()); - } - else - { - Component::BailOutChecker checker (this); - listeners.callChecked (checker, &FileBrowserListener::fileDoubleClicked, f); - } -} - -void FileBrowserComponent::browserRootChanged (const File&) {} - -bool FileBrowserComponent::keyPressed (const KeyPress& key) -{ - #if JUCE_LINUX || JUCE_WINDOWS - if (key.getModifiers().isCommandDown() - && (key.getKeyCode() == 'H' || key.getKeyCode() == 'h')) - { - fileList->setIgnoresHiddenFiles (! fileList->ignoresHiddenFiles()); - fileList->refresh(); - return true; - } - #endif - - ignoreUnused (key); - return false; -} - -//============================================================================== -void FileBrowserComponent::textEditorTextChanged (TextEditor&) -{ - sendListenerChangeMessage(); -} - -void FileBrowserComponent::textEditorReturnKeyPressed (TextEditor&) -{ - if (filenameBox.getText().containsChar (File::separator)) - { - const File f (currentRoot.getChildFile (filenameBox.getText())); - - if (f.isDirectory()) - { - setRoot (f); - chosenFiles.clear(); - - if ((flags & doNotClearFileNameOnRootChange) == 0) - filenameBox.setText (String()); - } - else - { - setRoot (f.getParentDirectory()); - chosenFiles.clear(); - chosenFiles.add (f); - filenameBox.setText (f.getFileName()); - } - } - else - { - fileDoubleClicked (getSelectedFile (0)); - } -} - -void FileBrowserComponent::textEditorEscapeKeyPressed (TextEditor&) -{ -} - -void FileBrowserComponent::textEditorFocusLost (TextEditor&) -{ - if (! isSaveMode()) - selectionChanged(); -} - -//============================================================================== -void FileBrowserComponent::buttonClicked (Button*) -{ - goUp(); -} - -void FileBrowserComponent::comboBoxChanged (ComboBox*) -{ - const String newText (currentPathBox.getText().trim().unquoted()); - - if (newText.isNotEmpty()) - { - const int index = currentPathBox.getSelectedId() - 1; - - StringArray rootNames, rootPaths; - getRoots (rootNames, rootPaths); - - if (rootPaths [index].isNotEmpty()) - { - setRoot (File (rootPaths [index])); - } - else - { - File f (newText); - - for (;;) - { - if (f.isDirectory()) - { - setRoot (f); - break; - } - - if (f.getParentDirectory() == f) - break; - - f = f.getParentDirectory(); - } - } - } -} - -void FileBrowserComponent::getDefaultRoots (StringArray& rootNames, StringArray& rootPaths) -{ - #if JUCE_WINDOWS - Array roots; - File::findFileSystemRoots (roots); - rootPaths.clear(); - - for (int i = 0; i < roots.size(); ++i) - { - const File& drive = roots.getReference(i); - - String name (drive.getFullPathName()); - rootPaths.add (name); - - if (drive.isOnHardDisk()) - { - String volume (drive.getVolumeLabel()); - - if (volume.isEmpty()) - volume = TRANS("Hard Drive"); - - name << " [" << volume << ']'; - } - else if (drive.isOnCDRomDrive()) - { - name << " [" << TRANS("CD/DVD drive") << ']'; - } - - rootNames.add (name); - } - - rootPaths.add (String()); - rootNames.add (String()); - - rootPaths.add (File::getSpecialLocation (File::userDocumentsDirectory).getFullPathName()); - rootNames.add (TRANS("Documents")); - rootPaths.add (File::getSpecialLocation (File::userMusicDirectory).getFullPathName()); - rootNames.add (TRANS("Music")); - rootPaths.add (File::getSpecialLocation (File::userPicturesDirectory).getFullPathName()); - rootNames.add (TRANS("Pictures")); - rootPaths.add (File::getSpecialLocation (File::userDesktopDirectory).getFullPathName()); - rootNames.add (TRANS("Desktop")); - - #elif JUCE_MAC - rootPaths.add (File::getSpecialLocation (File::userHomeDirectory).getFullPathName()); - rootNames.add (TRANS("Home folder")); - rootPaths.add (File::getSpecialLocation (File::userDocumentsDirectory).getFullPathName()); - rootNames.add (TRANS("Documents")); - rootPaths.add (File::getSpecialLocation (File::userMusicDirectory).getFullPathName()); - rootNames.add (TRANS("Music")); - rootPaths.add (File::getSpecialLocation (File::userPicturesDirectory).getFullPathName()); - rootNames.add (TRANS("Pictures")); - rootPaths.add (File::getSpecialLocation (File::userDesktopDirectory).getFullPathName()); - rootNames.add (TRANS("Desktop")); - - rootPaths.add (String()); - rootNames.add (String()); - - Array volumes; - File vol ("/Volumes"); - vol.findChildFiles (volumes, File::findDirectories, false); - - for (int i = 0; i < volumes.size(); ++i) - { - const File& volume = volumes.getReference(i); - - if (volume.isDirectory() && ! volume.getFileName().startsWithChar ('.')) - { - rootPaths.add (volume.getFullPathName()); - rootNames.add (volume.getFileName()); - } - } - - #else - rootPaths.add ("/"); - rootNames.add ("/"); - rootPaths.add (File::getSpecialLocation (File::userHomeDirectory).getFullPathName()); - rootNames.add (TRANS("Home folder")); - rootPaths.add (File::getSpecialLocation (File::userDesktopDirectory).getFullPathName()); - rootNames.add (TRANS("Desktop")); - #endif -} - -void FileBrowserComponent::getRoots (StringArray& rootNames, StringArray& rootPaths) -{ - getDefaultRoots (rootNames, rootPaths); -} - -void FileBrowserComponent::timerCallback() -{ - const bool isProcessActive = Process::isForegroundProcess(); - - if (wasProcessActive != isProcessActive) - { - wasProcessActive = isProcessActive; - - if (isProcessActive && fileList != nullptr) - refresh(); - } -} - -} // namespace juce diff --git a/source/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.h b/source/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.h deleted file mode 100644 index 148adeaeb..000000000 --- a/source/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.h +++ /dev/null @@ -1,289 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2017 - ROLI Ltd. - - JUCE is an open source library subject to commercial or open-source - licensing. - - By using JUCE, you agree to the terms of both the JUCE 5 End-User License - Agreement and JUCE 5 Privacy Policy (both updated and effective as of the - 27th April 2017). - - End User License Agreement: www.juce.com/juce-5-licence - Privacy Policy: www.juce.com/juce-5-privacy-policy - - Or: You may also use this code under the terms of the GPL v3 (see - www.gnu.org/licenses). - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -/** - A component for browsing and selecting a file or directory to open or save. - - This contains a FileListComponent and adds various boxes and controls for - navigating and selecting a file. It can work in different modes so that it can - be used for loading or saving a file, or for choosing a directory. - - @see FileChooserDialogBox, FileChooser, FileListComponent -*/ -class JUCE_API FileBrowserComponent : public Component, - private FileBrowserListener, - private TextEditor::Listener, - private Button::Listener, - private ComboBox::Listener, - private FileFilter, - private Timer -{ -public: - //============================================================================== - /** Various options for the browser. - - A combination of these is passed into the FileBrowserComponent constructor. - */ - enum FileChooserFlags - { - openMode = 1, /**< specifies that the component should allow the user to - choose an existing file with the intention of opening it. */ - saveMode = 2, /**< specifies that the component should allow the user to specify - the name of a file that will be used to save something. */ - canSelectFiles = 4, /**< specifies that the user can select files (can be used in - conjunction with canSelectDirectories). */ - canSelectDirectories = 8, /**< specifies that the user can select directories (can be used in - conjunction with canSelectFiles). */ - canSelectMultipleItems = 16, /**< specifies that the user can select multiple items. */ - useTreeView = 32, /**< specifies that a tree-view should be shown instead of a file list. */ - filenameBoxIsReadOnly = 64, /**< specifies that the user can't type directly into the filename box. */ - warnAboutOverwriting = 128, /**< specifies that the dialog should warn about overwriting existing files (if possible). */ - doNotClearFileNameOnRootChange = 256 /**< specifies that the file name should not be cleared upon root change. */ - }; - - //============================================================================== - /** Creates a FileBrowserComponent. - - @param flags A combination of flags from the FileChooserFlags enumeration, used to - specify the component's behaviour. The flags must contain either openMode - or saveMode, and canSelectFiles and/or canSelectDirectories. - @param initialFileOrDirectory The file or directory that should be selected when the component begins. - If this is File(), a default directory will be chosen. - @param fileFilter an optional filter to use to determine which files are shown. - If this is nullptr then all files are displayed. Note that a pointer - is kept internally to this object, so make sure that it is not deleted - before the FileBrowserComponent object is deleted. - @param previewComp an optional preview component that will be used to show previews of - files that the user selects - */ - FileBrowserComponent (int flags, - const File& initialFileOrDirectory, - const FileFilter* fileFilter, - FilePreviewComponent* previewComp); - - /** Destructor. */ - ~FileBrowserComponent(); - - //============================================================================== - /** Returns the number of files that the user has got selected. - If multiple select isn't active, this will only be 0 or 1. To get the complete - list of files they've chosen, pass an index to getCurrentFile(). - */ - int getNumSelectedFiles() const noexcept; - - /** Returns one of the files that the user has chosen. - If the box has multi-select enabled, the index lets you specify which of the files - to get - see getNumSelectedFiles() to find out how many files were chosen. - @see getHighlightedFile - */ - File getSelectedFile (int index) const noexcept; - - /** Deselects any files that are currently selected. */ - void deselectAllFiles(); - - /** Returns true if the currently selected file(s) are usable. - - This can be used to decide whether the user can press "ok" for the - current file. What it does depends on the mode, so for example in an "open" - mode, this only returns true if a file has been selected and if it exists. - In a "save" mode, a non-existent file would also be valid. - */ - bool currentFileIsValid() const; - - /** This returns the last item in the view that the user has highlighted. - This may be different from getCurrentFile(), which returns the value - that is shown in the filename box, and if there are multiple selections, - this will only return one of them. - @see getSelectedFile - */ - File getHighlightedFile() const noexcept; - - //============================================================================== - /** Returns the directory whose contents are currently being shown in the listbox. */ - const File& getRoot() const; - - /** Changes the directory that's being shown in the listbox. */ - void setRoot (const File& newRootDirectory); - - /** Changes the name that is currently shown in the filename box. */ - void setFileName (const String& newName); - - /** Equivalent to pressing the "up" button to browse the parent directory. */ - void goUp(); - - /** Refreshes the directory that's currently being listed. */ - void refresh(); - - /** Changes the filter that's being used to sift the files. */ - void setFileFilter (const FileFilter* newFileFilter); - - /** Returns a verb to describe what should happen when the file is accepted. - - E.g. if browsing in "load file" mode, this will be "Open", if in "save file" - mode, it'll be "Save", etc. - */ - virtual String getActionVerb() const; - - /** Returns true if the saveMode flag was set when this component was created. */ - bool isSaveMode() const noexcept; - - /** Sets the label that will be displayed next to the filename entry box. - By default this is just "file", but you might want to change it to something more - appropriate for your app. - */ - void setFilenameBoxLabel (const String& name); - - //============================================================================== - /** Adds a listener to be told when the user selects and clicks on files. - @see removeListener - */ - void addListener (FileBrowserListener* listener); - - /** Removes a listener. - @see addListener - */ - void removeListener (FileBrowserListener* listener); - - /** Returns a platform-specific list of names and paths for some suggested places the user - might want to use as root folders. - The list returned contains empty strings to indicate section breaks. - @see getRoots() - */ - static void getDefaultRoots (StringArray& rootNames, StringArray& rootPaths); - - //============================================================================== - /** This abstract base class is implemented by LookAndFeel classes to provide - various file-browser layout and drawing methods. - */ - struct JUCE_API LookAndFeelMethods - { - virtual ~LookAndFeelMethods() {} - - // These return a pointer to an internally cached drawable - make sure you don't keep - // a copy of this pointer anywhere, as it may become invalid in the future. - virtual const Drawable* getDefaultFolderImage() = 0; - virtual const Drawable* getDefaultDocumentFileImage() = 0; - - virtual AttributedString createFileChooserHeaderText (const String& title, - const String& instructions) = 0; - - virtual void drawFileBrowserRow (Graphics&, int width, int height, - const File& file, - const String& filename, - Image* optionalIcon, - const String& fileSizeDescription, - const String& fileTimeDescription, - bool isDirectory, - bool isItemSelected, - int itemIndex, - DirectoryContentsDisplayComponent&) = 0; - - virtual Button* createFileBrowserGoUpButton() = 0; - - virtual void layoutFileBrowserComponent (FileBrowserComponent& browserComp, - DirectoryContentsDisplayComponent* fileListComponent, - FilePreviewComponent* previewComp, - ComboBox* currentPathBox, - TextEditor* filenameBox, - Button* goUpButton) = 0; - }; - - //============================================================================== - /** @internal */ - void resized() override; - /** @internal */ - void buttonClicked (Button*) override; - /** @internal */ - void comboBoxChanged (ComboBox*) override; - /** @internal */ - void textEditorTextChanged (TextEditor&) override; - /** @internal */ - void textEditorReturnKeyPressed (TextEditor&) override; - /** @internal */ - void textEditorEscapeKeyPressed (TextEditor&) override; - /** @internal */ - void textEditorFocusLost (TextEditor&) override; - /** @internal */ - bool keyPressed (const KeyPress&) override; - /** @internal */ - void selectionChanged() override; - /** @internal */ - void fileClicked (const File&, const MouseEvent&) override; - /** @internal */ - void fileDoubleClicked (const File&) override; - /** @internal */ - void browserRootChanged (const File&) override; - /** @internal */ - bool isFileSuitable (const File&) const override; - /** @internal */ - bool isDirectorySuitable (const File&) const override; - /** @internal */ - FilePreviewComponent* getPreviewComponent() const noexcept; - /** @internal */ - DirectoryContentsDisplayComponent* getDisplayComponent() const noexcept; - -protected: - /** Returns a list of names and paths for the default places the user might want to look. - - By default this just calls getDefaultRoots(), but you may want to override it to - return a custom list. - */ - virtual void getRoots (StringArray& rootNames, StringArray& rootPaths); - - /** Updates the items in the dropdown list of recent paths with the values from getRoots(). */ - void resetRecentPaths(); - -private: - //============================================================================== - ScopedPointer fileList; - const FileFilter* fileFilter; - - int flags; - File currentRoot; - Array chosenFiles; - ListenerList listeners; - - ScopedPointer fileListComponent; - FilePreviewComponent* previewComp; - ComboBox currentPathBox; - TextEditor filenameBox; - Label fileLabel; - ScopedPointer